conf, schema, docs: Add support for TSEG size setting

TSEG (Top of Memory Segment) is one of many regions that SMM (System Management
Mode) can occupy.  This one, however is special, because a) most of the SMM code
lives in TSEG nowadays and b) QEMU just (well, some time ago) added support for
so called 'extended' TSEG.  The difference to the TSEG implemented in real q35's
MCH (Memory Controller Hub) is that it can offer one extra size to the guest OS
apart from the standard TSEG's 1, 2, and 8 MiB and that size can be selected in
1 MiB increments.  Maximum may vary based on QEMU and is way too big, so we
don't need to check for the maximum here.  Similarly to the memory size we'll
leave it to the hypervisor to try satisfying that and giving us an error message
in case it is not possible.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Martin Kletzander 2018-05-10 21:32:26 +02:00
parent 3f2499d7d7
commit 1bd5a08d38
6 changed files with 147 additions and 2 deletions

View File

@ -1924,6 +1924,9 @@
&lt;ioapic driver='qemu'/&gt;
&lt;hpt resizing='required'/&gt;
&lt;vmcoreinfo state='on'/&gt;
&lt;smm state='on'&gt;
&lt;tseg unit='MiB'&gt;48&lt;/tseg&gt;
&lt;/smm&gt;
&lt;/features&gt;
...</pre>
@ -2079,10 +2082,55 @@
<span class="since">Since 1.2.16</span>
</dd>
<dt><code>smm</code></dt>
<dd>Depending on the <code>state</code> attribute (values <code>on</code>,
<dd>
<p>
Depending on the <code>state</code> attribute (values <code>on</code>,
<code>off</code>, default <code>on</code>) enable or disable
System Management Mode.
<span class="since">Since 2.1.0</span>
</p><p> Optional sub-element <code>tseg</code> can be used to specify
the amount of memory dedicated to SMM's extended TSEG. That offers a
fourth option size apart from the existing ones (1 MiB, 2 MiB and 8
MiB) that the guest OS (or rather loader) can choose from. The size
can be specified as a value of that element, optional attribute
<code>unit</code> can be used to specify the unit of the
aforementioned value (defaults to 'MiB'). If set to 0 the extended
size is not advertised and only the default ones (see above) are
available.
</p><p>
<b>If the VM is booting you should leave this option alone, unless you
are very certain you know what you are doing.</b>
</p><p>
This value is configurable due to the fact that the calculation cannot
be done right with the guarantee that it will work correctly. In
QEMU, the user-configurable extended TSEG feature was unavailable up
to and including <code>pc-q35-2.9</code>. Starting with
<code>pc-q35-2.10</code> the feature is available, with default size
16 MiB. That should suffice for up to roughly 272 VCPUs, 5 GiB guest
RAM in total, no hotplug memory range, and 32 GiB of 64-bit PCI MMIO
aperture. Or for 48 VCPUs, with 1TB of guest RAM, no hotplug DIMM
range, and 32GB of 64-bit PCI MMIO aperture. The values may also vary
based on the loader the VM is using.
</p><p>
Additional size might be needed for significantly higher VCPU counts
or increased address space (that can be memory, maxMemory, 64-bit PCI
MMIO aperture size; roughly 8 MiB of TSEG per 1 TiB of address space)
which can also be rounded up.
</p><p>
Due to the nature of this setting being similar to "how much RAM
should the guest have" users are advised to either consult the
documentation of the guest OS or loader (if there is any), or test
this by trial-and-error changing the value until the VM boots
successfully. Yet another guiding value for users might be the fact
that 48 MiB should be enough for pretty large guests (240 VCPUs and
4TB guest RAM), but it is on purpose not set as default as 48 MiB of
unavailable RAM might be too much for small guests (e.g. with 512 MiB
of RAM).
</p><p>
See <a href="#elementsMemoryAllocation">Memory Allocation</a>
for more details about the <code>unit</code> attribute.
<span class="since">Since 4.5.0</span> (QEMU only)
</p>
</dd>
<dt><code>ioapic</code></dt>
<dd>Tune the I/O APIC. Possible values for the

View File

@ -4846,6 +4846,11 @@
<attribute name="state">
<ref name="virOnOff"/>
</attribute>
<optional>
<element name="tseg">
<ref name="scaledInteger"/>
</element>
</optional>
</optional>
</element>
</optional>

View File

@ -19898,6 +19898,19 @@ virDomainDefParseXML(xmlDocPtr xml,
VIR_FREE(nodes);
}
if (def->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) {
int rv = virDomainParseScaledValue("string(./features/smm/tseg)",
"string(./features/smm/tseg/@unit)",
ctxt,
&def->tseg_size,
1024 * 1024, /* Defaults to mebibytes */
ULLONG_MAX,
false);
if (rv < 0)
goto error;
def->tseg_specified = rv;
}
if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0)
goto error;
@ -22020,6 +22033,33 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
}
}
/* smm */
if (src->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) {
if (src->tseg_specified != dst->tseg_specified) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("SMM TSEG differs: source: %s, destination: '%s'"),
src->tseg_specified ? _("specified") : _("not specified"),
dst->tseg_specified ? _("specified") : _("not specified"));
return false;
}
if (src->tseg_specified &&
src->tseg_size != dst->tseg_size) {
const char *unit_src, *unit_dst;
unsigned long long short_size_src = virFormatIntPretty(src->tseg_size,
&unit_src);
unsigned long long short_size_dst = virFormatIntPretty(dst->tseg_size,
&unit_dst);
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Size of SMM TSEG size differs: "
"source: '%llu %s', destination: '%llu %s'"),
short_size_src, unit_src,
short_size_dst, unit_dst);
return false;
}
}
return true;
}
@ -27446,7 +27486,6 @@ virDomainDefFormatInternal(virDomainDefPtr def,
case VIR_DOMAIN_FEATURE_PMU:
case VIR_DOMAIN_FEATURE_PVSPINLOCK:
case VIR_DOMAIN_FEATURE_VMPORT:
case VIR_DOMAIN_FEATURE_SMM:
switch ((virTristateSwitch) def->features[i]) {
case VIR_TRISTATE_SWITCH_LAST:
case VIR_TRISTATE_SWITCH_ABSENT:
@ -27463,6 +27502,31 @@ virDomainDefFormatInternal(virDomainDefPtr def,
break;
case VIR_DOMAIN_FEATURE_SMM:
if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT) {
virTristateSwitch state = def->features[i];
virBuffer attrBuf = VIR_BUFFER_INITIALIZER;
virBuffer childBuf = VIR_BUFFER_INITIALIZER;
virBufferAsprintf(&attrBuf, " state='%s'",
virTristateSwitchTypeToString(state));
if (state == VIR_TRISTATE_SWITCH_ON &&
def->tseg_specified) {
const char *unit;
unsigned long long short_size = virFormatIntPretty(def->tseg_size,
&unit);
virBufferSetChildIndent(&childBuf, buf);
virBufferAsprintf(&childBuf, "<tseg unit='%s'>%llu</tseg>\n",
unit, short_size);
}
virXMLFormatElement(buf, "smm", &attrBuf, &childBuf);
}
break;
case VIR_DOMAIN_FEATURE_APIC:
if (def->features[i] == VIR_TRISTATE_SWITCH_ON) {
virBufferAddLit(buf, "<apic");

View File

@ -2421,6 +2421,9 @@ struct _virDomainDef {
char *hyperv_vendor_id;
int apic_eoi;
bool tseg_specified;
unsigned long long tseg_size;
virDomainClockDef clock;
size_t ngraphics;

View File

@ -0,0 +1,23 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219100</memory>
<currentMemory unit='KiB'>219100</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<smm state='on'>
<tseg unit='MiB'>48</tseg>
</smm>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
</devices>
</domain>

View File

@ -141,6 +141,8 @@ mymain(void)
DO_TEST_FULL("cachetune-colliding-types", false, true,
TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_PARSE);
DO_TEST("tseg");
virObjectUnref(caps);
virObjectUnref(xmlopt);