conf: Add support for specifying CPU max physical address size

This patch introduces the

    <maxphysaddr mode='passthrough'/>
    <maxphysaddr mode='emulate' bits='42'/>

sub element of /domain/cpu, which allows specifying the guest virtual CPU
address size. This can be useful if the guest needs to have a large amount
of memory.

If mode='passthrough', the virtual CPU will have the same number of address
bits as the host. If mode='emulate', the mandatory bits attribute specifies
the number of address bits.

Signed-off-by: Dario Faggioli <dfaggioli@suse.com>
Signed-off-by: Jim Fehlig <jfehlig@suse.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Dario Faggioli 2022-07-29 13:34:33 -06:00 committed by Michal Privoznik
parent 67b03faaf1
commit e6c29f09e5
9 changed files with 190 additions and 0 deletions

View File

@ -1336,6 +1336,7 @@ following collection of elements. :since:`Since 0.7.5`
<vendor>Intel</vendor> <vendor>Intel</vendor>
<topology sockets='1' dies='1' cores='2' threads='1'/> <topology sockets='1' dies='1' cores='2' threads='1'/>
<cache level='3' mode='emulate'/> <cache level='3' mode='emulate'/>
<maxphysaddr mode='emulate' bits='42'>
<feature policy='disable' name='lahf_lm'/> <feature policy='disable' name='lahf_lm'/>
</cpu> </cpu>
... ...
@ -1352,6 +1353,7 @@ following collection of elements. :since:`Since 0.7.5`
<cpu mode='host-passthrough' migratable='off'> <cpu mode='host-passthrough' migratable='off'>
<cache mode='passthrough'/> <cache mode='passthrough'/>
<maxphysaddr mode='passthrough'>
<feature policy='disable' name='lahf_lm'/> <feature policy='disable' name='lahf_lm'/>
... ...
@ -1600,6 +1602,27 @@ In case no restrictions need to be put on CPU model and its features, a simpler
The virtual CPU will report no CPU cache of the specified level (or no The virtual CPU will report no CPU cache of the specified level (or no
cache at all if the ``level`` attribute is missing). cache at all if the ``level`` attribute is missing).
``maxphysaddr``
:since:`Since 8.7.0` the ``maxphysaddr`` element describes the virtual CPU
address size in bits. The hypervisor default is used if the element is missing.
``mode``
This mandatory attribute specifies how the address size is presented. The
follow modes are supported:
``passthrough``
The number of physical address bits reported by the host CPU will be
passed through to the virtual CPUs
``emulate``
The hypervisor will define a specific value for the number of bits
of physical addresses via the ``bits`` attribute, which is mandatory.
The number of bits cannot exceed the number of physical address bits
supported by the hypervisor.
``bits``
The ``bits`` attribute is mandatory if the ``mode`` attribute is set to
``emulate`` and specifies the virtual CPU address size in bits.
Guest NUMA topology can be specified using the ``numa`` element. :since:`Since Guest NUMA topology can be specified using the ``numa`` element. :since:`Since
0.9.8` 0.9.8`

View File

@ -82,6 +82,12 @@ VIR_ENUM_IMPL(virCPUCacheMode,
"disable", "disable",
); );
VIR_ENUM_IMPL(virCPUMaxPhysAddrMode,
VIR_CPU_MAX_PHYS_ADDR_MODE_LAST,
"emulate",
"passthrough",
);
virCPUDef *virCPUDefNew(void) virCPUDef *virCPUDefNew(void)
{ {
@ -127,6 +133,7 @@ virCPUDefFree(virCPUDef *def)
if (g_atomic_int_dec_and_test(&def->refs)) { if (g_atomic_int_dec_and_test(&def->refs)) {
virCPUDefFreeModel(def); virCPUDefFreeModel(def);
g_free(def->cache); g_free(def->cache);
g_free(def->addr);
g_free(def->tsc); g_free(def->tsc);
g_free(def); g_free(def);
} }
@ -252,6 +259,11 @@ virCPUDefCopyWithoutModel(const virCPUDef *cpu)
*copy->cache = *cpu->cache; *copy->cache = *cpu->cache;
} }
if (cpu->addr) {
copy->addr = g_new0(virCPUMaxPhysAddrDef, 1);
*copy->addr = *cpu->addr;
}
if (cpu->tsc) { if (cpu->tsc) {
copy->tsc = g_new0(virHostCPUTscInfo, 1); copy->tsc = g_new0(virHostCPUTscInfo, 1);
*copy->tsc = *cpu->tsc; *copy->tsc = *cpu->tsc;
@ -322,6 +334,7 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt,
g_autoptr(virCPUDef) def = NULL; g_autoptr(virCPUDef) def = NULL;
g_autofree xmlNodePtr *nodes = NULL; g_autofree xmlNodePtr *nodes = NULL;
xmlNodePtr topology = NULL; xmlNodePtr topology = NULL;
xmlNodePtr maxphysaddrNode = NULL;
VIR_XPATH_NODE_AUTORESTORE(ctxt) VIR_XPATH_NODE_AUTORESTORE(ctxt)
int n; int n;
int rv; int rv;
@ -644,6 +657,21 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt,
def->cache->mode = mode; def->cache->mode = mode;
} }
if ((maxphysaddrNode = virXPathNode("./maxphysaddr[1]", ctxt))) {
def->addr = g_new0(virCPUMaxPhysAddrDef, 1);
if (virXMLPropEnum(maxphysaddrNode, "mode",
virCPUMaxPhysAddrModeTypeFromString,
VIR_XML_PROP_REQUIRED,
&def->addr->mode) < 0)
return -1;
if (virXMLPropInt(maxphysaddrNode, "bits", 10,
VIR_XML_PROP_NONNEGATIVE,
&def->addr->bits, -1) < 0)
return -1;
}
*cpu = g_steal_pointer(&def); *cpu = g_steal_pointer(&def);
return 0; return 0;
} }
@ -811,6 +839,15 @@ virCPUDefFormatBuf(virBuffer *buf,
virBufferAddLit(buf, "/>\n"); virBufferAddLit(buf, "/>\n");
} }
if (def->addr) {
virBufferAddLit(buf, "<maxphysaddr ");
virBufferAsprintf(buf, "mode='%s'",
virCPUMaxPhysAddrModeTypeToString(def->addr->mode));
if (def->addr->bits != -1)
virBufferAsprintf(buf, " bits='%d'", def->addr->bits);
virBufferAddLit(buf, "/>\n");
}
for (i = 0; i < def->nfeatures; i++) { for (i = 0; i < def->nfeatures; i++) {
virCPUFeatureDef *feature = def->features + i; virCPUFeatureDef *feature = def->features + i;
@ -1073,6 +1110,15 @@ virCPUDefIsEqual(virCPUDef *src,
return false; return false;
} }
if ((src->addr && !dst->addr) ||
(!src->addr && dst->addr) ||
(src->addr && dst->addr &&
(src->addr->mode != dst->addr->mode ||
src->addr->bits != dst->addr->bits))) {
MISMATCH("%s", _("Target CPU maxphysaddr does not match source"));
return false;
}
if (src->nfeatures != dst->nfeatures) { if (src->nfeatures != dst->nfeatures) {
MISMATCH(_("Target CPU feature count %zu does not match source %zu"), MISMATCH(_("Target CPU feature count %zu does not match source %zu"),
dst->nfeatures, src->nfeatures); dst->nfeatures, src->nfeatures);

View File

@ -116,6 +116,22 @@ struct _virCPUCacheDef {
}; };
typedef enum {
VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE,
VIR_CPU_MAX_PHYS_ADDR_MODE_PASSTHROUGH,
VIR_CPU_MAX_PHYS_ADDR_MODE_LAST
} virCPUMaxPhysAddrMode;
VIR_ENUM_DECL(virCPUMaxPhysAddrMode);
typedef struct _virCPUMaxPhysAddrDef virCPUMaxPhysAddrDef;
struct _virCPUMaxPhysAddrDef {
int bits; /* -1 for unspecified */
virCPUMaxPhysAddrMode mode;
};
typedef struct _virCPUDef virCPUDef; typedef struct _virCPUDef virCPUDef;
struct _virCPUDef { struct _virCPUDef {
int refs; int refs;
@ -140,6 +156,7 @@ struct _virCPUDef {
size_t nfeatures_max; size_t nfeatures_max;
virCPUFeatureDef *features; virCPUFeatureDef *features;
virCPUCacheDef *cache; virCPUCacheDef *cache;
virCPUMaxPhysAddrDef *addr;
virHostCPUTscInfo *tsc; virHostCPUTscInfo *tsc;
virTristateSwitch migratable; /* for host-passthrough mode */ virTristateSwitch migratable; /* for host-passthrough mode */
}; };

View File

@ -305,6 +305,22 @@
</element> </element>
</define> </define>
<define name="cpuMaxPhysAddr">
<element name="maxphysaddr">
<attribute name="mode">
<choice>
<value>emulate</value>
<value>passthrough</value>
</choice>
</attribute>
<optional>
<attribute name="bits">
<ref name="unsignedInt"/>
</attribute>
</optional>
</element>
</define>
<define name="hostcpu"> <define name="hostcpu">
<element name="cpu"> <element name="cpu">
<element name="arch"> <element name="arch">
@ -432,6 +448,9 @@
<optional> <optional>
<ref name="cpuCache"/> <ref name="cpuCache"/>
</optional> </optional>
<optional>
<ref name="cpuMaxPhysAddr"/>
</optional>
</interleave> </interleave>
</element> </element>
</define> </define>

View File

@ -120,6 +120,8 @@ virCPUDefParseXMLString;
virCPUDefRef; virCPUDefRef;
virCPUDefStealModel; virCPUDefStealModel;
virCPUDefUpdateFeature; virCPUDefUpdateFeature;
virCPUMaxPhysAddrModeTypeFromString;
virCPUMaxPhysAddrModeTypeToString;
virCPUModeTypeToString; virCPUModeTypeToString;

View File

@ -332,6 +332,47 @@ qemuValidateDomainDefCpu(virQEMUDriver *driver,
if (!cpu) if (!cpu)
return 0; return 0;
if (cpu->addr) {
const virCPUMaxPhysAddrDef *addr = cpu->addr;
if (!ARCH_IS_X86(def->os.arch)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("CPU maximum physical address bits specification is not supported for '%s' architecture"),
virArchToString(def->os.arch));
return -1;
}
switch (addr->mode) {
case VIR_CPU_MAX_PHYS_ADDR_MODE_PASSTHROUGH:
if (def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("CPU maximum physical address bits mode '%s' can only be used with '%s' CPUs"),
virCPUMaxPhysAddrModeTypeToString(addr->mode),
virCPUModeTypeToString(VIR_CPU_MODE_HOST_PASSTHROUGH));
return -1;
}
if (addr->bits != -1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("CPU maximum physical address bits number specification cannot be used with mode='%s'"),
virCPUMaxPhysAddrModeTypeToString(VIR_CPU_MAX_PHYS_ADDR_MODE_PASSTHROUGH));
return -1;
}
break;
case VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE:
if (addr->bits == -1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("if using CPU maximum physical address mode='%s', bits= must be specified too"),
virCPUMaxPhysAddrModeTypeToString(VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE));
return -1;
}
break;
case VIR_CPU_MAX_PHYS_ADDR_MODE_LAST:
break;
}
}
if (def->cpu->cache) { if (def->cpu->cache) {
virCPUCacheDef *cache = def->cpu->cache; virCPUCacheDef *cache = def->cpu->cache;

View File

@ -0,0 +1,20 @@
<domain type='kvm'>
<name>foo</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<cpu mode='host-passthrough'>
<maxphysaddr mode='emulate' bits='42'/>
</cpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
</devices>
</domain>

View File

@ -0,0 +1,20 @@
<domain type='kvm'>
<name>foo</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<cpu mode='host-passthrough'>
<maxphysaddr mode='passthrough'/>
</cpu>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
</devices>
</domain>

View File

@ -246,6 +246,8 @@ mymain(void)
DO_TEST_BACKUP_FULL("backup-pull-internal-invalid", true); DO_TEST_BACKUP_FULL("backup-pull-internal-invalid", true);
DO_TEST("cpu-phys-bits-emulate");
DO_TEST("cpu-phys-bits-passthrough");
virObjectUnref(caps); virObjectUnref(caps);
virObjectUnref(xmlopt); virObjectUnref(xmlopt);