[PATCH V2 0/4] Handle physical address bits

Hi All, This is a V2 of Dario's old patches adding support for specifying the virtual CPU address size in bits https://listman.redhat.com/archives/libvir-list/2020-October/210901.html I've rebased those patches to latest master and tweaked them a bit. E.g. I removed the qemucaps code since phys-bits and host-phys-bits have been around before the minimum qemu version supported by libvirt. I also added patches to expose the number of host address bits and ensure ABI stability as requested in the old review comments. Dario Faggioli (2): conf: Add support for specifying CPU max physical address size qemu: Add support for max physical address size Jim Fehlig (2): capabilities: Report number of host CPU physical address bits cpu conf: Check ABI stability of CPU maxphysaddr config docs/formatdomain.rst | 23 +++++++ src/conf/cpu_conf.c | 63 +++++++++++++++++++ src/conf/cpu_conf.h | 17 +++++ src/conf/schemas/cputypes.rng | 19 ++++++ src/cpu/cpu_x86.c | 8 +++ src/libvirt_private.syms | 2 + src/qemu/qemu_command.c | 21 +++++++ src/qemu/qemu_domain.c | 46 ++++++++++++++ src/qemu/qemu_validate.c | 12 ++++ src/util/virhostcpu.c | 55 ++++++++++++++++ src/util/virhostcpu.h | 3 + .../cpu-phys-bits-emulate.xml | 20 ++++++ .../cpu-phys-bits-passthrough.xml | 20 ++++++ tests/genericxml2xmltest.c | 3 + .../cpu-phys-bits-emulate.args | 32 ++++++++++ .../cpu-phys-bits-emulate.xml | 20 ++++++ .../cpu-phys-bits-emulate2.args | 32 ++++++++++ .../cpu-phys-bits-emulate2.xml | 20 ++++++ .../cpu-phys-bits-emulate3.err | 1 + .../cpu-phys-bits-emulate3.xml | 20 ++++++ .../cpu-phys-bits-passthrough.args | 32 ++++++++++ .../cpu-phys-bits-passthrough.xml | 20 ++++++ .../cpu-phys-bits-passthrough2.err | 1 + .../cpu-phys-bits-passthrough2.xml | 20 ++++++ .../cpu-phys-bits-passthrough3.err | 1 + .../cpu-phys-bits-passthrough3.xml | 20 ++++++ tests/qemuxml2argvtest.c | 7 +++ 27 files changed, 538 insertions(+) create mode 100644 tests/genericxml2xmlindata/cpu-phys-bits-emulate.xml create mode 100644 tests/genericxml2xmlindata/cpu-phys-bits-passthrough.xml create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-emulate.args create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-emulate.xml create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-emulate2.args create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-emulate2.xml create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-emulate3.err create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-emulate3.xml create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-passthrough.args create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-passthrough.xml create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.err create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.xml create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.err create mode 100644 tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.xml -- 2.36.1

From: Dario Faggioli <dfaggioli@suse.com> 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> --- docs/formatdomain.rst | 23 ++++++++ src/conf/cpu_conf.c | 54 +++++++++++++++++++ src/conf/cpu_conf.h | 17 ++++++ src/conf/schemas/cputypes.rng | 19 +++++++ src/libvirt_private.syms | 2 + .../cpu-phys-bits-emulate.xml | 20 +++++++ .../cpu-phys-bits-passthrough.xml | 20 +++++++ tests/genericxml2xmltest.c | 3 ++ 8 files changed, 158 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 1ed969ac3e..adfdd7b7a5 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -1336,6 +1336,7 @@ following collection of elements. :since:`Since 0.7.5` <vendor>Intel</vendor> <topology sockets='1' dies='1' cores='2' threads='1'/> <cache level='3' mode='emulate'/> + <maxphysaddr mode='emulate' bits='42'> <feature policy='disable' name='lahf_lm'/> </cpu> ... @@ -1352,6 +1353,7 @@ following collection of elements. :since:`Since 0.7.5` <cpu mode='host-passthrough' migratable='off'> <cache mode='passthrough'/> + <maxphysaddr mode='passthrough'> <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 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 0.9.8` diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 8d80bbd842..e31c4ab467 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -82,6 +82,12 @@ VIR_ENUM_IMPL(virCPUCacheMode, "disable", ); +VIR_ENUM_IMPL(virCPUMaxPhysAddrMode, + VIR_CPU_MAX_PHYS_ADDR_MODE_LAST, + "emulate", + "passthrough", +); + virCPUDef *virCPUDefNew(void) { @@ -127,6 +133,7 @@ virCPUDefFree(virCPUDef *def) if (g_atomic_int_dec_and_test(&def->refs)) { virCPUDefFreeModel(def); g_free(def->cache); + g_free(def->addr); g_free(def->tsc); g_free(def); } @@ -252,6 +259,11 @@ virCPUDefCopyWithoutModel(const virCPUDef *cpu) *copy->cache = *cpu->cache; } + if (cpu->addr) { + copy->addr = g_new0(virCPUMaxPhysAddrDef, 1); + *copy->addr = *cpu->addr; + } + if (cpu->tsc) { copy->tsc = g_new0(virHostCPUTscInfo, 1); *copy->tsc = *cpu->tsc; @@ -644,6 +656,39 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt, def->cache->mode = mode; } + if (virXPathInt("count(./maxphysaddr)", ctxt, &n) < 0) { + return -1; + } else if (n > 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("at most one CPU maximum physical address bits " + "element may be specified")); + return -1; + } else if (n == 1) { + g_autofree char *strmode = NULL; + int mode; + int bits = -1; + + if (!(strmode = virXPathString("string(./maxphysaddr[1]/@mode)", ctxt)) || + (mode = virCPUMaxPhysAddrModeTypeFromString(strmode)) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or invalid CPU maximum physical " + "address bits mode")); + return -1; + } + + if (virXPathBoolean("boolean(./maxphysaddr[1]/@bits)", ctxt) == 1 && + (virXPathInt("string(./maxphysaddr[1]/@bits)", ctxt, &bits) < 0 || + bits < 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("CPU maximum physical address bits < 0")); + return -1; + } + + def->addr = g_new0(virCPUMaxPhysAddrDef, 1); + def->addr->bits = bits; + def->addr->mode = mode; + } + *cpu = g_steal_pointer(&def); return 0; } @@ -811,6 +856,15 @@ virCPUDefFormatBuf(virBuffer *buf, 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++) { virCPUFeatureDef *feature = def->features + i; diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 5d2980edbd..113d349708 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -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; struct _virCPUDef { int refs; @@ -140,6 +156,7 @@ struct _virCPUDef { size_t nfeatures_max; virCPUFeatureDef *features; virCPUCacheDef *cache; + virCPUMaxPhysAddrDef *addr; virHostCPUTscInfo *tsc; virTristateSwitch migratable; /* for host-passthrough mode */ }; diff --git a/src/conf/schemas/cputypes.rng b/src/conf/schemas/cputypes.rng index 122880fb2e..4ae386c3c0 100644 --- a/src/conf/schemas/cputypes.rng +++ b/src/conf/schemas/cputypes.rng @@ -305,6 +305,22 @@ </element> </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"> <element name="cpu"> <element name="arch"> @@ -432,6 +448,9 @@ <optional> <ref name="cpuCache"/> </optional> + <optional> + <ref name="cpuMaxPhysAddr"/> + </optional> </interleave> </element> </define> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6a5c5600df..774a594983 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -120,6 +120,8 @@ virCPUDefParseXMLString; virCPUDefRef; virCPUDefStealModel; virCPUDefUpdateFeature; +virCPUMaxPhysAddrModeTypeFromString; +virCPUMaxPhysAddrModeTypeToString; virCPUModeTypeToString; diff --git a/tests/genericxml2xmlindata/cpu-phys-bits-emulate.xml b/tests/genericxml2xmlindata/cpu-phys-bits-emulate.xml new file mode 100644 index 0000000000..e463e0b3e0 --- /dev/null +++ b/tests/genericxml2xmlindata/cpu-phys-bits-emulate.xml @@ -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> diff --git a/tests/genericxml2xmlindata/cpu-phys-bits-passthrough.xml b/tests/genericxml2xmlindata/cpu-phys-bits-passthrough.xml new file mode 100644 index 0000000000..cce676eaa6 --- /dev/null +++ b/tests/genericxml2xmlindata/cpu-phys-bits-passthrough.xml @@ -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> diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c index b83367cb4b..bbe0d02226 100644 --- a/tests/genericxml2xmltest.c +++ b/tests/genericxml2xmltest.c @@ -246,6 +246,9 @@ mymain(void) DO_TEST_BACKUP_FULL("backup-pull-internal-invalid", true); + DO_TEST("cpu-phys-bits-emulate"); + DO_TEST("cpu-phys-bits-passthrough"); + virObjectUnref(caps); virObjectUnref(xmlopt); -- 2.36.1

On 7/29/22 21:34, Jim Fehlig wrote:
From: Dario Faggioli <dfaggioli@suse.com>
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> --- docs/formatdomain.rst | 23 ++++++++ src/conf/cpu_conf.c | 54 +++++++++++++++++++ src/conf/cpu_conf.h | 17 ++++++ src/conf/schemas/cputypes.rng | 19 +++++++ src/libvirt_private.syms | 2 + .../cpu-phys-bits-emulate.xml | 20 +++++++ .../cpu-phys-bits-passthrough.xml | 20 +++++++ tests/genericxml2xmltest.c | 3 ++ 8 files changed, 158 insertions(+)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 1ed969ac3e..adfdd7b7a5 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -1336,6 +1336,7 @@ following collection of elements. :since:`Since 0.7.5` <vendor>Intel</vendor> <topology sockets='1' dies='1' cores='2' threads='1'/> <cache level='3' mode='emulate'/> + <maxphysaddr mode='emulate' bits='42'> <feature policy='disable' name='lahf_lm'/> </cpu> ... @@ -1352,6 +1353,7 @@ following collection of elements. :since:`Since 0.7.5`
<cpu mode='host-passthrough' migratable='off'> <cache mode='passthrough'/> + <maxphysaddr mode='passthrough'> <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 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 0.9.8`
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 8d80bbd842..e31c4ab467 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -82,6 +82,12 @@ VIR_ENUM_IMPL(virCPUCacheMode, "disable", );
+VIR_ENUM_IMPL(virCPUMaxPhysAddrMode, + VIR_CPU_MAX_PHYS_ADDR_MODE_LAST, + "emulate", + "passthrough", +); +
virCPUDef *virCPUDefNew(void) { @@ -127,6 +133,7 @@ virCPUDefFree(virCPUDef *def) if (g_atomic_int_dec_and_test(&def->refs)) { virCPUDefFreeModel(def); g_free(def->cache); + g_free(def->addr); g_free(def->tsc); g_free(def); } @@ -252,6 +259,11 @@ virCPUDefCopyWithoutModel(const virCPUDef *cpu) *copy->cache = *cpu->cache; }
+ if (cpu->addr) { + copy->addr = g_new0(virCPUMaxPhysAddrDef, 1); + *copy->addr = *cpu->addr; + } + if (cpu->tsc) { copy->tsc = g_new0(virHostCPUTscInfo, 1); *copy->tsc = *cpu->tsc; @@ -644,6 +656,39 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt, def->cache->mode = mode; }
+ if (virXPathInt("count(./maxphysaddr)", ctxt, &n) < 0) { + return -1; + } else if (n > 1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("at most one CPU maximum physical address bits " + "element may be specified")); + return -1; + } else if (n == 1) { + g_autofree char *strmode = NULL; + int mode; + int bits = -1; + + if (!(strmode = virXPathString("string(./maxphysaddr[1]/@mode)", ctxt)) || + (mode = virCPUMaxPhysAddrModeTypeFromString(strmode)) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or invalid CPU maximum physical " + "address bits mode")); + return -1; + } + + if (virXPathBoolean("boolean(./maxphysaddr[1]/@bits)", ctxt) == 1 && + (virXPathInt("string(./maxphysaddr[1]/@bits)", ctxt, &bits) < 0 || + bits < 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("CPU maximum physical address bits < 0")); + return -1; + }
We have a bit better option here: virXMLProp*(). Which reminds me, the validation (which you put into PostParse callback in patch 3/4) should be moved into this patch. Therefore, I suggest squashing this in: diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index e31c4ab467..d385d76e23 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -334,6 +334,7 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt, g_autoptr(virCPUDef) def = NULL; g_autofree xmlNodePtr *nodes = NULL; xmlNodePtr topology = NULL; + xmlNodePtr maxphysaddrNode = NULL; VIR_XPATH_NODE_AUTORESTORE(ctxt) int n; int rv; @@ -656,37 +657,19 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt, def->cache->mode = mode; } - if (virXPathInt("count(./maxphysaddr)", ctxt, &n) < 0) { - return -1; - } else if (n > 1) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("at most one CPU maximum physical address bits " - "element may be specified")); - return -1; - } else if (n == 1) { - g_autofree char *strmode = NULL; - int mode; - int bits = -1; - - if (!(strmode = virXPathString("string(./maxphysaddr[1]/@mode)", ctxt)) || - (mode = virCPUMaxPhysAddrModeTypeFromString(strmode)) < 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing or invalid CPU maximum physical " - "address bits mode")); - return -1; - } - - if (virXPathBoolean("boolean(./maxphysaddr[1]/@bits)", ctxt) == 1 && - (virXPathInt("string(./maxphysaddr[1]/@bits)", ctxt, &bits) < 0 || - bits < 0)) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("CPU maximum physical address bits < 0")); - return -1; - } - + if ((maxphysaddrNode = virXPathNode("./maxphysaddr[1]", ctxt))) { def->addr = g_new0(virCPUMaxPhysAddrDef, 1); - def->addr->bits = bits; - def->addr->mode = mode; + + 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); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 7fa899e411..36e236f08e 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -332,6 +332,47 @@ qemuValidateDomainDefCpu(virQEMUDriver *driver, if (!cpu) 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) { virCPUCacheDef *cache = def->cpu->cache; diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c index bbe0d02226..3501eadf55 100644 --- a/tests/genericxml2xmltest.c +++ b/tests/genericxml2xmltest.c @@ -249,7 +249,6 @@ mymain(void) DO_TEST("cpu-phys-bits-emulate"); DO_TEST("cpu-phys-bits-passthrough"); - virObjectUnref(caps); virObjectUnref(xmlopt); Michal

Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/cpu/cpu_x86.c | 8 +++++++ src/util/virhostcpu.c | 55 +++++++++++++++++++++++++++++++++++++++++++ src/util/virhostcpu.h | 3 +++ 3 files changed, 66 insertions(+) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 4bb2ea4bae..9fcd6b8add 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2738,6 +2738,7 @@ virCPUx86GetHost(virCPUDef *cpu, virDomainCapsCPUModels *models) { g_autoptr(virCPUData) cpuData = NULL; + unsigned int addrsz; int ret; if (virCPUx86DriverInitialize() < 0) @@ -2784,6 +2785,13 @@ virCPUx86GetHost(virCPUDef *cpu, VIR_DEBUG("Host CPU does not support invariant TSC"); } + if (virHostCPUGetPhysAddrSize(&addrsz) == 0) { + virCPUMaxPhysAddrDef *addr = g_new0(virCPUMaxPhysAddrDef, 1); + + addr->bits = addrsz; + cpu->addr = addr; + } + return ret; } #endif diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index 639dd9b51e..668e468f2a 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -570,6 +570,41 @@ virHostCPUParseFrequency(FILE *cpuinfo, } +static int +virHostCPUParsePhysAddrSize(FILE *cpuinfo, unsigned int *addrsz) +{ + char line[1024]; + + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + char *str; + char *endptr; + + if (!STRPREFIX(line, "address sizes")) + continue; + + str = line; + str += strlen("address sizes"); + + /* Skip the colon. */ + if ((str = strstr(str, ":")) == NULL) + goto error; + str++; + + /* Parse the number of physical address bits */ + if (virStrToLong_ui(str, &endptr, 10, addrsz) < 0) + goto error; + + return 0; + } + + error: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid CPU address size in %s"), + CPUINFO_PATH); + return -1; +} + + int virHostCPUGetInfoPopulateLinux(FILE *cpuinfo, virArch arch, @@ -1616,6 +1651,20 @@ virHostCPUGetSignature(char **signature) return virHostCPUReadSignature(virArchFromHost(), cpuinfo, signature); } +int +virHostCPUGetPhysAddrSize(unsigned int *size) +{ + g_autoptr(FILE) cpuinfo = NULL; + + if (!(cpuinfo = fopen(CPUINFO_PATH, "r"))) { + virReportSystemError(errno, _("Failed to open cpuinfo file '%s'"), + CPUINFO_PATH); + return -1; + } + + return virHostCPUParsePhysAddrSize(cpuinfo, size); +} + #else int @@ -1625,6 +1674,12 @@ virHostCPUGetSignature(char **signature) return 0; } +int +virHostCPUGetPhysAddrSize(unsigned int *size) +{ + return 0; +} + #endif /* __linux__ */ int diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h index b8ea7aafad..5232fee36d 100644 --- a/src/util/virhostcpu.h +++ b/src/util/virhostcpu.h @@ -58,6 +58,7 @@ int virHostCPUGetInfo(virArch hostarch, unsigned int *cores, unsigned int *threads); + int virHostCPUGetKVMMaxVCPUs(void) G_NO_INLINE; int virHostCPUStatsAssign(virNodeCPUStatsPtr param, @@ -86,6 +87,8 @@ virHostCPUTscInfo *virHostCPUGetTscInfo(void); int virHostCPUGetSignature(char **signature); +int virHostCPUGetPhysAddrSize(unsigned int *size); + int virHostCPUGetHaltPollTime(pid_t pid, unsigned long long *haltPollSuccess, unsigned long long *haltPollFail); -- 2.36.1

On 7/29/22 21:34, Jim Fehlig wrote:
Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/cpu/cpu_x86.c | 8 +++++++ src/util/virhostcpu.c | 55 +++++++++++++++++++++++++++++++++++++++++++ src/util/virhostcpu.h | 3 +++ 3 files changed, 66 insertions(+)
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 4bb2ea4bae..9fcd6b8add 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2738,6 +2738,7 @@ virCPUx86GetHost(virCPUDef *cpu, virDomainCapsCPUModels *models) { g_autoptr(virCPUData) cpuData = NULL; + unsigned int addrsz; int ret;
if (virCPUx86DriverInitialize() < 0) @@ -2784,6 +2785,13 @@ virCPUx86GetHost(virCPUDef *cpu, VIR_DEBUG("Host CPU does not support invariant TSC"); }
+ if (virHostCPUGetPhysAddrSize(&addrsz) == 0) { + virCPUMaxPhysAddrDef *addr = g_new0(virCPUMaxPhysAddrDef, 1); + + addr->bits = addrsz; + cpu->addr = addr; + } + return ret; } #endif diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index 639dd9b51e..668e468f2a 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -570,6 +570,41 @@ virHostCPUParseFrequency(FILE *cpuinfo, }
+static int +virHostCPUParsePhysAddrSize(FILE *cpuinfo, unsigned int *addrsz) +{ + char line[1024]; + + while (fgets(line, sizeof(line), cpuinfo) != NULL) { + char *str; + char *endptr; +
Starting from here ...
+ if (!STRPREFIX(line, "address sizes")) + continue; + + str = line; + str += strlen("address sizes");
... until here: this is exactly what STRSKIP() does.
+ + /* Skip the colon. */ + if ((str = strstr(str, ":")) == NULL) + goto error; + str++; + + /* Parse the number of physical address bits */ + if (virStrToLong_ui(str, &endptr, 10, addrsz) < 0) + goto error; + + return 0; + } + + error: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing or invalid CPU address size in %s"), + CPUINFO_PATH); + return -1; +} + + int virHostCPUGetInfoPopulateLinux(FILE *cpuinfo, virArch arch, @@ -1616,6 +1651,20 @@ virHostCPUGetSignature(char **signature) return virHostCPUReadSignature(virArchFromHost(), cpuinfo, signature); }
+int +virHostCPUGetPhysAddrSize(unsigned int *size)
This function should be listed in the private syms file, so that it can be used by other modules. I suggest squashing this in: diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6db04eff88..7f5c973b2b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2435,6 +2435,7 @@ virHostCPUGetMicrocodeVersion; virHostCPUGetMSR; virHostCPUGetOnline; virHostCPUGetOnlineBitmap; +virHostCPUGetPhysAddrSize; virHostCPUGetPresentBitmap; virHostCPUGetSignature; virHostCPUGetStats; diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index 668e468f2a..3a02e224e8 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -579,12 +579,9 @@ virHostCPUParsePhysAddrSize(FILE *cpuinfo, unsigned int *addrsz) char *str; char *endptr; - if (!STRPREFIX(line, "address sizes")) + if (!(str = STRSKIP(line, "address sizes"))) continue; - str = line; - str += strlen("address sizes"); - /* Skip the colon. */ if ((str = strstr(str, ":")) == NULL) goto error; Michal

From: Dario Faggioli <dfaggioli@suse.com> This patch maps /domain/cpu/maxphysaddr into -cpu parameters: - <maxphysaddr mode='passthrough'/> becomes host-phys-bits=on - <maxphysaddr mode='emualte' bits='42'/> becomes phys-bits=42 Passthrough mode can only be used if the chosen CPU model is 'host-passthrough'. Also validate that an explicitly specified bits value does not exceed the physical address bits on the host. The feature is available since QEMU 2.7.0. Signed-off-by: Dario Faggioli <dfaggioli@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/qemu/qemu_command.c | 21 +++++++++ src/qemu/qemu_domain.c | 46 +++++++++++++++++++ src/qemu/qemu_validate.c | 12 +++++ .../cpu-phys-bits-emulate.args | 32 +++++++++++++ .../cpu-phys-bits-emulate.xml | 20 ++++++++ .../cpu-phys-bits-emulate2.args | 32 +++++++++++++ .../cpu-phys-bits-emulate2.xml | 20 ++++++++ .../cpu-phys-bits-emulate3.err | 1 + .../cpu-phys-bits-emulate3.xml | 20 ++++++++ .../cpu-phys-bits-passthrough.args | 32 +++++++++++++ .../cpu-phys-bits-passthrough.xml | 20 ++++++++ .../cpu-phys-bits-passthrough2.err | 1 + .../cpu-phys-bits-passthrough2.xml | 20 ++++++++ .../cpu-phys-bits-passthrough3.err | 1 + .../cpu-phys-bits-passthrough3.xml | 20 ++++++++ tests/qemuxml2argvtest.c | 7 +++ 16 files changed, 305 insertions(+) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 30c9bbbf2e..acf214be00 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6847,6 +6847,27 @@ qemuBuildCpuCommandLine(virCommand *cmd, virBufferAddLit(&buf, ",l3-cache=off"); } + if (def->cpu && def->cpu->addr) { + virCPUMaxPhysAddrDef *addr = def->cpu->addr; + + switch (addr->mode) { + case VIR_CPU_MAX_PHYS_ADDR_MODE_PASSTHROUGH: + virBufferAddLit(&buf, ",host-phys-bits=on"); + break; + + case VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE: + if (addr->bits != -1) + virBufferAsprintf(&buf, ",phys-bits=%d", addr->bits); + else + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Physical address bits unspecified")); + break; + + case VIR_CPU_MAX_PHYS_ADDR_MODE_LAST: + break; + } + } + cpu = virBufferContentAndReset(&cpu_buf); cpu_flags = virBufferContentAndReset(&buf); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index b02ffc9a2e..0c97744b72 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -4429,6 +4429,52 @@ qemuDomainDefCPUPostParse(virDomainDef *def, } } + if (def->cpu->addr) { + virCPUMaxPhysAddrDef *addr = def->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; + } + } + for (i = 0; i < def->cpu->nfeatures; i++) { virCPUFeatureDef *feature = &def->cpu->features[i]; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 764d5b029e..b6c7d3b06a 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -380,6 +380,18 @@ qemuValidateDomainDefCpu(virQEMUDriver *driver, break; } + if (cpu->addr && + cpu->addr->mode == VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE && + driver->hostcpu && + driver->hostcpu->addr) { + if (cpu->addr->bits > driver->hostcpu->addr->bits) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("The number of virtual CPU address bits cannot " + "exceed the number supported by the host CPU")); + return -1; + } + } + return 0; } diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-emulate.args b/tests/qemuxml2argvdata/cpu-phys-bits-emulate.args new file mode 100644 index 0000000000..f612f6889b --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-emulate.args @@ -0,0 +1,32 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-foo \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-foo/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-foo/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-foo/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name guest=foo,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-foo/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel kvm \ +-cpu host,phys-bits=42 \ +-m 214 \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-emulate.xml b/tests/qemuxml2argvdata/cpu-phys-bits-emulate.xml new file mode 100644 index 0000000000..f8bd63bc68 --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-emulate.xml @@ -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='x86_64' 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> diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-emulate2.args b/tests/qemuxml2argvdata/cpu-phys-bits-emulate2.args new file mode 100644 index 0000000000..3489f44ded --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-emulate2.args @@ -0,0 +1,32 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-foo \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-foo/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-foo/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-foo/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name guest=foo,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-foo/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel kvm \ +-cpu core2duo,ds=on,acpi=on,ss=on,ht=on,tm=on,pbe=on,ds-cpl=on,vmx=on,est=on,tm2=on,cx16=on,xtpr=on,lahf-lm=on,phys-bits=42 \ +-m 214 \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-emulate2.xml b/tests/qemuxml2argvdata/cpu-phys-bits-emulate2.xml new file mode 100644 index 0000000000..188b3066ed --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-emulate2.xml @@ -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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='host-model'> + <maxphysaddr bits='42' mode='emulate'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-emulate3.err b/tests/qemuxml2argvdata/cpu-phys-bits-emulate3.err new file mode 100644 index 0000000000..5e21998259 --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-emulate3.err @@ -0,0 +1 @@ +unsupported configuration: if using CPU maximum physical address mode='emulate', bits= must be specified too diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-emulate3.xml b/tests/qemuxml2argvdata/cpu-phys-bits-emulate3.xml new file mode 100644 index 0000000000..30a14894dd --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-emulate3.xml @@ -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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='host-passthrough'> + <maxphysaddr mode='emulate'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-passthrough.args b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough.args new file mode 100644 index 0000000000..df04195d1e --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough.args @@ -0,0 +1,32 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-foo \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-foo/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-foo/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-foo/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name guest=foo,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-foo/master-key.aes \ +-machine pc,usb=off,dump-guest-core=off \ +-accel kvm \ +-cpu host,host-phys-bits=on \ +-m 214 \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-usb \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-passthrough.xml b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough.xml new file mode 100644 index 0000000000..db570beb8d --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough.xml @@ -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='x86_64' 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> diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.err b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.err new file mode 100644 index 0000000000..22009cc6e6 --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.err @@ -0,0 +1 @@ +unsupported configuration: CPU maximum physical address bits mode 'passthrough' can only be used with 'host-passthrough' CPUs diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.xml b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.xml new file mode 100644 index 0000000000..511bbf9949 --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough2.xml @@ -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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='host-model'> + <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> diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.err b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.err new file mode 100644 index 0000000000..28f2e43432 --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.err @@ -0,0 +1 @@ +unsupported configuration: CPU maximum physical address bits number specification cannot be used with mode='passthrough' diff --git a/tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.xml b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.xml new file mode 100644 index 0000000000..a94e567dcb --- /dev/null +++ b/tests/qemuxml2argvdata/cpu-phys-bits-passthrough3.xml @@ -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='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='host-passthrough'> + <maxphysaddr mode='passthrough' bits='42'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index b72d61c3bc..4fd5120b70 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -3470,6 +3470,13 @@ mymain(void) /* HVF guests should not work on Linux with KVM */ DO_TEST_CAPS_LATEST_PARSE_ERROR("hvf-x86_64-q35-headless"); + DO_TEST("cpu-phys-bits-passthrough", QEMU_CAPS_KVM); + DO_TEST("cpu-phys-bits-emulate", QEMU_CAPS_KVM); + DO_TEST("cpu-phys-bits-emulate2", QEMU_CAPS_KVM); + DO_TEST_PARSE_ERROR("cpu-phys-bits-emulate3", QEMU_CAPS_KVM); + DO_TEST_PARSE_ERROR("cpu-phys-bits-passthrough2", QEMU_CAPS_KVM); + DO_TEST_PARSE_ERROR("cpu-phys-bits-passthrough3", QEMU_CAPS_KVM); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.36.1

On 7/29/22 21:34, Jim Fehlig wrote:
From: Dario Faggioli <dfaggioli@suse.com>
This patch maps /domain/cpu/maxphysaddr into -cpu parameters:
- <maxphysaddr mode='passthrough'/> becomes host-phys-bits=on - <maxphysaddr mode='emualte' bits='42'/> becomes phys-bits=42
Passthrough mode can only be used if the chosen CPU model is 'host-passthrough'. Also validate that an explicitly specified bits value does not exceed the physical address bits on the host.
The feature is available since QEMU 2.7.0.
Signed-off-by: Dario Faggioli <dfaggioli@suse.com> Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/qemu/qemu_command.c | 21 +++++++++ src/qemu/qemu_domain.c | 46 +++++++++++++++++++ src/qemu/qemu_validate.c | 12 +++++ .../cpu-phys-bits-emulate.args | 32 +++++++++++++ .../cpu-phys-bits-emulate.xml | 20 ++++++++ .../cpu-phys-bits-emulate2.args | 32 +++++++++++++ .../cpu-phys-bits-emulate2.xml | 20 ++++++++ .../cpu-phys-bits-emulate3.err | 1 + .../cpu-phys-bits-emulate3.xml | 20 ++++++++ .../cpu-phys-bits-passthrough.args | 32 +++++++++++++ .../cpu-phys-bits-passthrough.xml | 20 ++++++++ .../cpu-phys-bits-passthrough2.err | 1 + .../cpu-phys-bits-passthrough2.xml | 20 ++++++++ .../cpu-phys-bits-passthrough3.err | 1 + .../cpu-phys-bits-passthrough3.xml | 20 ++++++++ tests/qemuxml2argvtest.c | 7 +++ 16 files changed, 305 insertions(+)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 30c9bbbf2e..acf214be00 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6847,6 +6847,27 @@ qemuBuildCpuCommandLine(virCommand *cmd, virBufferAddLit(&buf, ",l3-cache=off"); }
+ if (def->cpu && def->cpu->addr) { + virCPUMaxPhysAddrDef *addr = def->cpu->addr; + + switch (addr->mode) { + case VIR_CPU_MAX_PHYS_ADDR_MODE_PASSTHROUGH: + virBufferAddLit(&buf, ",host-phys-bits=on"); + break; + + case VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE: + if (addr->bits != -1) + virBufferAsprintf(&buf, ",phys-bits=%d", addr->bits); + else + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Physical address bits unspecified"));
Since we've checked for this case in validation step this situation can't happen really. Our XML parsing happens in three steps: 1) actual parsing, i.e. using libxml (well, our wrappers over it) to fill in internal structs according to passed XML document, 2) so called PostParse phase, where missing information is filled in, 3) validation phase, where we check whether data makes sense as whole, whether underlying hypervisor has requested features, etc. Now, steps 2) and 3) have consist of two parts each: hypervisor agnostic part and hypervisor specific part. Because some info can be filled in/validated regardless of underlying hypervisor and some require knowledge of hypervisor features. As usual, this is ideal state and if you run into older code it's likely that it does some checking during parsing. In some cases this is fine (e.g. rejecting an integer value out of range, failing parsing after invalid enum2string conversion, etc.), but in others we like to move validation into their respective functions. And for a brief moment we used to misuse PostParse for validation too. Yes, it's a mess.
+ break; + + case VIR_CPU_MAX_PHYS_ADDR_MODE_LAST: + break; + } + } + cpu = virBufferContentAndReset(&cpu_buf); cpu_flags = virBufferContentAndReset(&buf);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index b02ffc9a2e..0c97744b72 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -4429,6 +4429,52 @@ qemuDomainDefCPUPostParse(virDomainDef *def, } }
+ if (def->cpu->addr) { + virCPUMaxPhysAddrDef *addr = def->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; + } + } +
So this is the code I've mentioned earlier. Due to reasons above, this should be in qemuValidateDomainDefCpu() (or ideally in a hypervisor agnostic version, because neither of these checks are specific to QEMU, but we don't have one yet).
for (i = 0; i < def->cpu->nfeatures; i++) { virCPUFeatureDef *feature = &def->cpu->features[i];
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 764d5b029e..b6c7d3b06a 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -380,6 +380,18 @@ qemuValidateDomainDefCpu(virQEMUDriver *driver, break; }
+ if (cpu->addr && + cpu->addr->mode == VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE && + driver->hostcpu && + driver->hostcpu->addr) { + if (cpu->addr->bits > driver->hostcpu->addr->bits) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("The number of virtual CPU address bits cannot " + "exceed the number supported by the host CPU")); + return -1; + }
And after the hunk above is moved here, this can be simplified to: diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 5664241dff..5d46dd1247 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -366,6 +366,14 @@ qemuValidateDomainDefCpu(virQEMUDriver *driver, virCPUMaxPhysAddrModeTypeToString(VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE)); return -1; } + + if (driver->hostcpu && + driver->hostcpu->addr && + cpu->addr->bits > driver->hostcpu->addr->bits) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("The number of virtual CPU address bits cannot exceed the number supported by the host CPU")); + return -1; + } break; case VIR_CPU_MAX_PHYS_ADDR_MODE_LAST: @@ -470,18 +478,6 @@ qemuValidateDomainDefCpu(virQEMUDriver *driver, } } - if (cpu->addr && - cpu->addr->mode == VIR_CPU_MAX_PHYS_ADDR_MODE_EMULATE && - driver->hostcpu && - driver->hostcpu->addr) { - if (cpu->addr->bits > driver->hostcpu->addr->bits) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("The number of virtual CPU address bits cannot " - "exceed the number supported by the host CPU")); - return -1; - } - } - return 0; } Michal

Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/conf/cpu_conf.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index e31c4ab467..8e75cdbb4f 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -1127,6 +1127,15 @@ virCPUDefIsEqual(virCPUDef *src, 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) { MISMATCH(_("Target CPU feature count %zu does not match source %zu"), dst->nfeatures, src->nfeatures); -- 2.36.1

On 7/29/22 21:34, Jim Fehlig wrote:
Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/conf/cpu_conf.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index e31c4ab467..8e75cdbb4f 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -1127,6 +1127,15 @@ virCPUDefIsEqual(virCPUDef *src, 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) { MISMATCH(_("Target CPU feature count %zu does not match source %zu"), dst->nfeatures, src->nfeatures);
This could be squashed into 1/4. Michal

On 7/29/22 21:34, Jim Fehlig wrote:
Hi All,
This is a V2 of Dario's old patches adding support for specifying the virtual CPU address size in bits
https://listman.redhat.com/archives/libvir-list/2020-October/210901.html
I've rebased those patches to latest master and tweaked them a bit. E.g. I removed the qemucaps code since phys-bits and host-phys-bits have been around before the minimum qemu version supported by libvirt. I also added patches to expose the number of host address bits and ensure ABI stability as requested in the old review comments.
Dario Faggioli (2): conf: Add support for specifying CPU max physical address size qemu: Add support for max physical address size
Jim Fehlig (2): capabilities: Report number of host CPU physical address bits cpu conf: Check ABI stability of CPU maxphysaddr config
Dario, Jim, I've went through the patches and they look good. I made couple of suggestions. Proposed diffs live as a fixup commits on my local branch. So if you agree with my suggestions I can just squash them before pushing. Does that work for you? Michal

On 8/3/22 09:29, Michal Prívozník wrote:
On 7/29/22 21:34, Jim Fehlig wrote:
Hi All,
This is a V2 of Dario's old patches adding support for specifying the virtual CPU address size in bits
https://listman.redhat.com/archives/libvir-list/2020-October/210901.html
I've rebased those patches to latest master and tweaked them a bit. E.g. I removed the qemucaps code since phys-bits and host-phys-bits have been around before the minimum qemu version supported by libvirt. I also added patches to expose the number of host address bits and ensure ABI stability as requested in the old review comments.
Dario Faggioli (2): conf: Add support for specifying CPU max physical address size qemu: Add support for max physical address size
Jim Fehlig (2): capabilities: Report number of host CPU physical address bits cpu conf: Check ABI stability of CPU maxphysaddr config
Dario, Jim,
I've went through the patches and they look good. I made couple of suggestions. Proposed diffs live as a fixup commits on my local branch. So if you agree with my suggestions I can just squash them before pushing. Does that work for you?
Sure, that's fine. All the suggestions look good. And thanks for the clarification on hypervisor specific vs agnostic aspects of postparse and validation phases! Jim
participants (2)
-
Jim Fehlig
-
Michal Prívozník