[libvirt] [PATCH 1/3] CPU: Implement guestData for PPC CPU driver

From: Li Zhang <zhlcindy@linux.vnet.ibm.com> On Power platform, Power7+ can support Power7 guest. It needs to define XML configuration to specify guest's CPU model. For exmaple: <cpu match='exact'> <model>POWER7+_v2.1</model> <vendor>IBM</vendor> </cpu> Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com> --- src/cpu/cpu_powerpc.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 647a8a1..84fa3f7 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -99,6 +99,23 @@ ppcModelFindPVR(const struct ppc_map *map, return NULL; } +static struct ppc_model * +ppcModelCopy(const struct ppc_model *model) +{ + struct ppc_model *copy; + + if (VIR_ALLOC(copy) < 0 || + VIR_STRDUP(copy->name, model->name) < 0) { + ppcModelFree(copy); + return NULL; + } + + copy->data.pvr = model->data.pvr; + copy->vendor = model->vendor; + + return copy; +} + static struct ppc_vendor * ppcVendorFind(const struct ppc_map *map, const char *name) @@ -126,6 +143,29 @@ ppcVendorFree(struct ppc_vendor *vendor) VIR_FREE(vendor); } +static struct ppc_model * +ppcModelFromCPU(const virCPUDefPtr cpu, + const struct ppc_map *map) +{ + struct ppc_model *model = NULL; + + if ((model = ppcModelFind(map, cpu->model)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %s"), cpu->model); + goto error; + } + + if ((model = ppcModelCopy(model)) == NULL) + goto error; + + return model; + +error: + ppcModelFree(model); + return NULL; +} + + static int ppcVendorLoad(xmlXPathContextPtr ctxt, struct ppc_map *map) @@ -288,6 +328,112 @@ error: return NULL; } +static virCPUDataPtr +ppcMakeCPUData(virArch arch, struct cpuPPCData *data) +{ + virCPUDataPtr cpuData; + + if (VIR_ALLOC(cpuData) < 0) + return NULL; + + cpuData->arch = arch; + cpuData->data.ppc = *data; + data = NULL; + + return cpuData; +} + +static virCPUCompareResult +ppcCompute(virCPUDefPtr host, + const virCPUDefPtr cpu, + virCPUDataPtr *guestData, + char **message) + +{ + struct ppc_map *map = NULL; + struct ppc_model *host_model = NULL; + struct ppc_model *guest_model = NULL; + + int ret = 0; + virArch arch; + size_t i; + + if (cpu->arch != VIR_ARCH_NONE) { + bool found = false; + + for (i = 0; i < ARRAY_CARDINALITY(archs); i++) { + if (archs[i] == cpu->arch) { + found = true; + break; + } + } + + if (!found) { + VIR_DEBUG("CPU arch %s does not match host arch", + virArchToString(cpu->arch)); + if (message && + virAsprintf(message, + _("CPU arch %s does not match host arch"), + virArchToString(cpu->arch)) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + arch = cpu->arch; + } else { + arch = host->arch; + } + + if (cpu->vendor && + (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) { + VIR_DEBUG("host CPU vendor does not match required CPU vendor %s", + cpu->vendor); + if (message && + virAsprintf(message, + _("host CPU vendor does not match required " + "CPU vendor %s"), + cpu->vendor) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + if (!(map = ppcLoadMap()) || + !(host_model = ppcModelFromCPU(host, map)) || + !(guest_model = ppcModelFromCPU(cpu, map))) + goto error; + + if (guestData != NULL) { + if (cpu->type == VIR_CPU_TYPE_GUEST && + cpu->match == VIR_CPU_MATCH_STRICT && + STRNEQ(guest_model->name, host_model->name)) { + VIR_DEBUG("host CPU model does not match required CPU model %s", + guest_model->name); + if (message && + virAsprintf(message, + _("host CPU model does not match required " + "CPU model %s"), + guest_model->name) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data))) + goto error; + } + + ret = VIR_CPU_COMPARE_IDENTICAL; + +out: + ppcMapFree(map); + ppcModelFree(host_model); + ppcModelFree(guest_model); + return ret; + +error: + ret = VIR_CPU_COMPARE_ERROR; + goto out; + +} + static virCPUCompareResult ppcCompare(virCPUDefPtr host, virCPUDefPtr cpu) @@ -369,6 +515,15 @@ ppcNodeData(void) } #endif +static virCPUCompareResult +ppcGuestData(virCPUDefPtr host, + virCPUDefPtr guest, + virCPUDataPtr *data, + char **message) +{ + return ppcCompute(host, guest, data, message); +} + static int ppcUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED, const virCPUDefPtr host ATTRIBUTE_UNUSED) @@ -466,6 +621,13 @@ error: goto cleanup; } +static int +ppcHasFeature(const virCPUDataPtr data ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ + return 0; +} + struct cpuArchDriver cpuDriverPowerPC = { .name = "ppc64", .arch = archs, @@ -479,8 +641,8 @@ struct cpuArchDriver cpuDriverPowerPC = { #else .nodeData = NULL, #endif - .guestData = NULL, + .guestData = ppcGuestData, .baseline = ppcBaseline, .update = ppcUpdate, - .hasFeature = NULL, + .hasFeature = ppcHasFeature, }; -- 1.8.1.4

From: Li Zhang <zhlcindy@linux.vnet.ibm.com> This patch is to add test cases for PPC CPU driver. Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com> --- tests/cputest.c | 9 +++++++++ tests/cputestdata/ppc64-baseline-1-result.xml | 3 +++ .../ppc64-baseline-incompatible-vendors.xml | 14 ++++++++++++++ .../cputestdata/ppc64-baseline-no-vendor-result.xml | 3 +++ tests/cputestdata/ppc64-baseline-no-vendor.xml | 7 +++++++ tests/cputestdata/ppc64-exact.xml | 3 +++ tests/cputestdata/ppc64-guest-nofallback.xml | 4 ++++ tests/cputestdata/ppc64-guest.xml | 4 ++++ .../ppc64-host+guest,ppc_models-result.xml | 5 +++++ ...est-nofallback,ppc_models,POWER7_v2.1-result.xml | 5 +++++ tests/cputestdata/ppc64-host.xml | 6 ++++++ tests/cputestdata/ppc64-strict.xml | 3 +++ .../qemuxml2argv-pseries-cpu-exact.args | 7 +++++++ .../qemuxml2argv-pseries-cpu-exact.xml | 21 +++++++++++++++++++++ tests/qemuxml2argvtest.c | 1 + 15 files changed, 95 insertions(+) create mode 100644 tests/cputestdata/ppc64-baseline-1-result.xml create mode 100644 tests/cputestdata/ppc64-baseline-incompatible-vendors.xml create mode 100644 tests/cputestdata/ppc64-baseline-no-vendor-result.xml create mode 100644 tests/cputestdata/ppc64-baseline-no-vendor.xml create mode 100644 tests/cputestdata/ppc64-exact.xml create mode 100644 tests/cputestdata/ppc64-guest-nofallback.xml create mode 100644 tests/cputestdata/ppc64-guest.xml create mode 100644 tests/cputestdata/ppc64-host+guest,ppc_models-result.xml create mode 100644 tests/cputestdata/ppc64-host+guest-nofallback,ppc_models,POWER7_v2.1-result.xml create mode 100644 tests/cputestdata/ppc64-host.xml create mode 100644 tests/cputestdata/ppc64-strict.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml diff --git a/tests/cputest.c b/tests/cputest.c index 959cb9f..408a510 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -493,6 +493,7 @@ cpuTestRun(const char *name, const struct data *data) static const char *model486[] = { "486" }; static const char *nomodel[] = { "nomodel" }; static const char *models[] = { "qemu64", "core2duo", "Nehalem" }; +static const char *ppc_models[] = { "POWER7", "POWER7_v2.1", "POWER8_v1.0"}; static int mymain(void) @@ -584,6 +585,9 @@ mymain(void) DO_TEST_COMPARE("x86", "host-worse", "nehalem-force", VIR_CPU_COMPARE_IDENTICAL); DO_TEST_COMPARE("x86", "host-SandyBridge", "exact-force-Haswell", VIR_CPU_COMPARE_IDENTICAL); + DO_TEST_COMPARE("ppc64", "host", "strict", VIR_CPU_COMPARE_IDENTICAL); + DO_TEST_COMPARE("ppc64", "host", "exact", VIR_CPU_COMPARE_INCOMPATIBLE); + /* guest updates for migration * automatically compares host CPU with the result */ DO_TEST_UPDATE("x86", "host", "min", VIR_CPU_COMPARE_IDENTICAL); @@ -601,6 +605,8 @@ mymain(void) DO_TEST_BASELINE("x86", "2", 0, 0); DO_TEST_BASELINE("x86", "3", VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, 0); + DO_TEST_BASELINE("ppc64", "incompatible-vendors", 0, -1); + DO_TEST_BASELINE("ppc64", "no-vendor", 0, 0); /* CPU features */ DO_TEST_HASFEATURE("x86", "host", "vmx", YES); DO_TEST_HASFEATURE("x86", "host", "lm", YES); @@ -627,6 +633,9 @@ mymain(void) DO_TEST_GUESTDATA("x86", "host", "host+host-model-nofallback", models, "Penryn", -1); + DO_TEST_GUESTDATA("ppc64", "host", "guest", ppc_models, NULL, 0); + DO_TEST_GUESTDATA("ppc64", "host", "guest-nofallback", ppc_models, "POWER7_v2.1", -1); + VIR_FREE(map); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/cputestdata/ppc64-baseline-1-result.xml b/tests/cputestdata/ppc64-baseline-1-result.xml new file mode 100644 index 0000000..cbdd9bc --- /dev/null +++ b/tests/cputestdata/ppc64-baseline-1-result.xml @@ -0,0 +1,3 @@ +<cpu mode='custom' match='exact'> + <model fallback='allow'>POWER7+_v2.1</model> +</cpu> diff --git a/tests/cputestdata/ppc64-baseline-incompatible-vendors.xml b/tests/cputestdata/ppc64-baseline-incompatible-vendors.xml new file mode 100644 index 0000000..97d3c9c --- /dev/null +++ b/tests/cputestdata/ppc64-baseline-incompatible-vendors.xml @@ -0,0 +1,14 @@ +<cpuTest> +<cpu> + <arch>ppc64</arch> + <model>POWER7+_v2.1</model> + <vendor>Intel</vendor> + <topology sockets='2' cores='4' threads='1'/> +</cpu> +<cpu> + <arch>ppc64</arch> + <model>POWER8_v1.0</model> + <vendor>Intel</vendor> + <topology sockets='1' cores='1' threads='1'/> +</cpu> +</cpuTest> diff --git a/tests/cputestdata/ppc64-baseline-no-vendor-result.xml b/tests/cputestdata/ppc64-baseline-no-vendor-result.xml new file mode 100644 index 0000000..36bae52 --- /dev/null +++ b/tests/cputestdata/ppc64-baseline-no-vendor-result.xml @@ -0,0 +1,3 @@ +<cpu mode='custom' match='exact'> + <model fallback='allow'>POWER7_v2.3</model> +</cpu> diff --git a/tests/cputestdata/ppc64-baseline-no-vendor.xml b/tests/cputestdata/ppc64-baseline-no-vendor.xml new file mode 100644 index 0000000..5e69a62 --- /dev/null +++ b/tests/cputestdata/ppc64-baseline-no-vendor.xml @@ -0,0 +1,7 @@ +<cpuTest> +<cpu> + <arch>ppc64</arch> + <model>POWER7_v2.3</model> + <topology sockets='2' cores='4' threads='1'/> +</cpu> +</cpuTest> diff --git a/tests/cputestdata/ppc64-exact.xml b/tests/cputestdata/ppc64-exact.xml new file mode 100644 index 0000000..c84f16a --- /dev/null +++ b/tests/cputestdata/ppc64-exact.xml @@ -0,0 +1,3 @@ +<cpu match='exact'> + <model>POWER8_v1.0</model> +</cpu> diff --git a/tests/cputestdata/ppc64-guest-nofallback.xml b/tests/cputestdata/ppc64-guest-nofallback.xml new file mode 100644 index 0000000..42026b4 --- /dev/null +++ b/tests/cputestdata/ppc64-guest-nofallback.xml @@ -0,0 +1,4 @@ +<cpu match='exact'> + <model fallback='forbid'>POWER7_v2.1</model> + <topology sockets='2' cores='4' threads='1'/> +</cpu> diff --git a/tests/cputestdata/ppc64-guest.xml b/tests/cputestdata/ppc64-guest.xml new file mode 100644 index 0000000..ac81ec0 --- /dev/null +++ b/tests/cputestdata/ppc64-guest.xml @@ -0,0 +1,4 @@ +<cpu match='exact'> + <model>POWER8_v1.0</model> + <topology sockets='2' cores='4' threads='1'/> +</cpu> diff --git a/tests/cputestdata/ppc64-host+guest,ppc_models-result.xml b/tests/cputestdata/ppc64-host+guest,ppc_models-result.xml new file mode 100644 index 0000000..0cb0830 --- /dev/null +++ b/tests/cputestdata/ppc64-host+guest,ppc_models-result.xml @@ -0,0 +1,5 @@ +<cpu mode='custom' match='exact'> + <arch>ppc64</arch> + <model fallback='allow'>POWER8_v1.0</model> + <vendor>IBM</vendor> +</cpu> diff --git a/tests/cputestdata/ppc64-host+guest-nofallback,ppc_models,POWER7_v2.1-result.xml b/tests/cputestdata/ppc64-host+guest-nofallback,ppc_models,POWER7_v2.1-result.xml new file mode 100644 index 0000000..7e58361 --- /dev/null +++ b/tests/cputestdata/ppc64-host+guest-nofallback,ppc_models,POWER7_v2.1-result.xml @@ -0,0 +1,5 @@ +<cpu mode='custom' match='exact'> + <arch>ppc64</arch> + <model fallback='forbid'>POWER7_v2.1</model> + <vendor>IBM</vendor> +</cpu> diff --git a/tests/cputestdata/ppc64-host.xml b/tests/cputestdata/ppc64-host.xml new file mode 100644 index 0000000..39cb741 --- /dev/null +++ b/tests/cputestdata/ppc64-host.xml @@ -0,0 +1,6 @@ +<cpu> + <arch>ppc64</arch> + <model>POWER7_v2.3</model> + <vendor>IBM</vendor> + <topology sockets='1' cores='64' threads='1'/> +</cpu> diff --git a/tests/cputestdata/ppc64-strict.xml b/tests/cputestdata/ppc64-strict.xml new file mode 100644 index 0000000..e91c6e7 --- /dev/null +++ b/tests/cputestdata/ppc64-strict.xml @@ -0,0 +1,3 @@ +<cpu match='exact'> + <model>POWER7_v2.3</model> +</cpu> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args new file mode 100644 index 0000000..1e09680 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args @@ -0,0 +1,7 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu-system-ppc64 -S -M pseries -cpu POWER7_v2.3 -m 512 -smp 1 -nographic \ +-nodefconfig -nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c -usb \ +-chardev pty,id=charserial0 \ +-device spapr-vty,chardev=charserial0,reg=0x30000000 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml new file mode 100644 index 0000000..b54dae2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml @@ -0,0 +1,21 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <cpu match='exact'> + <model>POWER7_v2.3</model> + <vendor>IBM</vendor> + </cpu> + <clock offset='utc'/> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <console type='pty'> + <address type="spapr-vio"/> + </console> + <memballoon model="none"/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 99406b6..e90c914 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -946,6 +946,7 @@ mymain(void) DO_TEST_ERROR("pseries-vio-address-clash", QEMU_CAPS_DRIVE, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("pseries-nvram", QEMU_CAPS_DEVICE_NVRAM); + DO_TEST_FAILURE("pseries-cpu-exact", QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("disk-ide-drive-split", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_IDE_CD); -- 1.8.1.4

From: Li Zhang <zhlcindy@linux.vnet.ibm.com> Applications on PPC platform wants to support host-model for users Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com> --- src/cpu/cpu_powerpc.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 84fa3f7..e0dffde 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -525,10 +525,39 @@ ppcGuestData(virCPUDefPtr host, } static int -ppcUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED, - const virCPUDefPtr host ATTRIBUTE_UNUSED) +ppcUpdateHostModel(virCPUDefPtr guest, + const virCPUDefPtr host) { - return 0; + guest->match = VIR_CPU_MATCH_EXACT; + + virCPUDefFreeModel(guest); + if (virCPUDefCopyModel(guest, host, true) < 0) + return -1; + + return 0; +} + +static int +ppcUpdate(virCPUDefPtr guest, + const virCPUDefPtr host) +{ + switch ((enum virCPUMode) guest->mode) { + case VIR_CPU_MODE_HOST_MODEL: + return ppcUpdateHostModel(guest, host); + + case VIR_CPU_MODE_HOST_PASSTHROUGH: + guest->match = VIR_CPU_MATCH_MINIMUM; + virCPUDefFreeModel(guest); + return virCPUDefCopyModel(guest, host, true); + + case VIR_CPU_MODE_CUSTOM: + case VIR_CPU_MODE_LAST: + break; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU mode: %d"), guest->mode); + return -1; } static virCPUDefPtr -- 1.8.1.4

Any comments about my CPU patches? On 2013年08月29日 16:46, Li Zhang wrote:
From: Li Zhang <zhlcindy@linux.vnet.ibm.com>
On Power platform, Power7+ can support Power7 guest. It needs to define XML configuration to specify guest's CPU model.
For exmaple: <cpu match='exact'> <model>POWER7+_v2.1</model> <vendor>IBM</vendor> </cpu>
Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com> --- src/cpu/cpu_powerpc.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-)
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 647a8a1..84fa3f7 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -99,6 +99,23 @@ ppcModelFindPVR(const struct ppc_map *map, return NULL; }
+static struct ppc_model * +ppcModelCopy(const struct ppc_model *model) +{ + struct ppc_model *copy; + + if (VIR_ALLOC(copy) < 0 || + VIR_STRDUP(copy->name, model->name) < 0) { + ppcModelFree(copy); + return NULL; + } + + copy->data.pvr = model->data.pvr; + copy->vendor = model->vendor; + + return copy; +} + static struct ppc_vendor * ppcVendorFind(const struct ppc_map *map, const char *name) @@ -126,6 +143,29 @@ ppcVendorFree(struct ppc_vendor *vendor) VIR_FREE(vendor); }
+static struct ppc_model * +ppcModelFromCPU(const virCPUDefPtr cpu, + const struct ppc_map *map) +{ + struct ppc_model *model = NULL; + + if ((model = ppcModelFind(map, cpu->model)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %s"), cpu->model); + goto error; + } + + if ((model = ppcModelCopy(model)) == NULL) + goto error; + + return model; + +error: + ppcModelFree(model); + return NULL; +} + + static int ppcVendorLoad(xmlXPathContextPtr ctxt, struct ppc_map *map) @@ -288,6 +328,112 @@ error: return NULL; }
+static virCPUDataPtr +ppcMakeCPUData(virArch arch, struct cpuPPCData *data) +{ + virCPUDataPtr cpuData; + + if (VIR_ALLOC(cpuData) < 0) + return NULL; + + cpuData->arch = arch; + cpuData->data.ppc = *data; + data = NULL; + + return cpuData; +} + +static virCPUCompareResult +ppcCompute(virCPUDefPtr host, + const virCPUDefPtr cpu, + virCPUDataPtr *guestData, + char **message) + +{ + struct ppc_map *map = NULL; + struct ppc_model *host_model = NULL; + struct ppc_model *guest_model = NULL; + + int ret = 0; + virArch arch; + size_t i; + + if (cpu->arch != VIR_ARCH_NONE) { + bool found = false; + + for (i = 0; i < ARRAY_CARDINALITY(archs); i++) { + if (archs[i] == cpu->arch) { + found = true; + break; + } + } + + if (!found) { + VIR_DEBUG("CPU arch %s does not match host arch", + virArchToString(cpu->arch)); + if (message && + virAsprintf(message, + _("CPU arch %s does not match host arch"), + virArchToString(cpu->arch)) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + arch = cpu->arch; + } else { + arch = host->arch; + } + + if (cpu->vendor && + (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) { + VIR_DEBUG("host CPU vendor does not match required CPU vendor %s", + cpu->vendor); + if (message && + virAsprintf(message, + _("host CPU vendor does not match required " + "CPU vendor %s"), + cpu->vendor) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + if (!(map = ppcLoadMap()) || + !(host_model = ppcModelFromCPU(host, map)) || + !(guest_model = ppcModelFromCPU(cpu, map))) + goto error; + + if (guestData != NULL) { + if (cpu->type == VIR_CPU_TYPE_GUEST && + cpu->match == VIR_CPU_MATCH_STRICT && + STRNEQ(guest_model->name, host_model->name)) { + VIR_DEBUG("host CPU model does not match required CPU model %s", + guest_model->name); + if (message && + virAsprintf(message, + _("host CPU model does not match required " + "CPU model %s"), + guest_model->name) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data))) + goto error; + } + + ret = VIR_CPU_COMPARE_IDENTICAL; + +out: + ppcMapFree(map); + ppcModelFree(host_model); + ppcModelFree(guest_model); + return ret; + +error: + ret = VIR_CPU_COMPARE_ERROR; + goto out; + +} + static virCPUCompareResult ppcCompare(virCPUDefPtr host, virCPUDefPtr cpu) @@ -369,6 +515,15 @@ ppcNodeData(void) } #endif
+static virCPUCompareResult +ppcGuestData(virCPUDefPtr host, + virCPUDefPtr guest, + virCPUDataPtr *data, + char **message) +{ + return ppcCompute(host, guest, data, message); +} + static int ppcUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED, const virCPUDefPtr host ATTRIBUTE_UNUSED) @@ -466,6 +621,13 @@ error: goto cleanup; }
+static int +ppcHasFeature(const virCPUDataPtr data ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ + return 0; +} + struct cpuArchDriver cpuDriverPowerPC = { .name = "ppc64", .arch = archs, @@ -479,8 +641,8 @@ struct cpuArchDriver cpuDriverPowerPC = { #else .nodeData = NULL, #endif - .guestData = NULL, + .guestData = ppcGuestData, .baseline = ppcBaseline, .update = ppcUpdate, - .hasFeature = NULL, + .hasFeature = ppcHasFeature, };

On Thu, Aug 29, 2013 at 3:46 AM, Li Zhang <zhlcindy@gmail.com> wrote:
From: Li Zhang <zhlcindy@linux.vnet.ibm.com>
On Power platform, Power7+ can support Power7 guest. It needs to define XML configuration to specify guest's CPU model.
For exmaple: <cpu match='exact'> <model>POWER7+_v2.1</model> <vendor>IBM</vendor> </cpu>
Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com> --- src/cpu/cpu_powerpc.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-)
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 647a8a1..84fa3f7 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -99,6 +99,23 @@ ppcModelFindPVR(const struct ppc_map *map, return NULL; }
+static struct ppc_model * +ppcModelCopy(const struct ppc_model *model) +{ + struct ppc_model *copy; + + if (VIR_ALLOC(copy) < 0 || + VIR_STRDUP(copy->name, model->name) < 0) { + ppcModelFree(copy); + return NULL; + } + + copy->data.pvr = model->data.pvr; + copy->vendor = model->vendor; + + return copy; +} + static struct ppc_vendor * ppcVendorFind(const struct ppc_map *map, const char *name) @@ -126,6 +143,29 @@ ppcVendorFree(struct ppc_vendor *vendor) VIR_FREE(vendor); }
+static struct ppc_model * +ppcModelFromCPU(const virCPUDefPtr cpu, + const struct ppc_map *map) +{ + struct ppc_model *model = NULL; + + if ((model = ppcModelFind(map, cpu->model)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %s"), cpu->model); + goto error; + } + + if ((model = ppcModelCopy(model)) == NULL) + goto error; + + return model; + +error: + ppcModelFree(model); + return NULL; +} + + static int ppcVendorLoad(xmlXPathContextPtr ctxt, struct ppc_map *map) @@ -288,6 +328,112 @@ error: return NULL; }
+static virCPUDataPtr +ppcMakeCPUData(virArch arch, struct cpuPPCData *data) +{ + virCPUDataPtr cpuData; + + if (VIR_ALLOC(cpuData) < 0) + return NULL; + + cpuData->arch = arch; + cpuData->data.ppc = *data; + data = NULL; + + return cpuData; +} + +static virCPUCompareResult +ppcCompute(virCPUDefPtr host, + const virCPUDefPtr cpu, + virCPUDataPtr *guestData, + char **message) + +{ + struct ppc_map *map = NULL; + struct ppc_model *host_model = NULL; + struct ppc_model *guest_model = NULL; + + int ret = 0; + virArch arch; + size_t i; + + if (cpu->arch != VIR_ARCH_NONE) { + bool found = false; + + for (i = 0; i < ARRAY_CARDINALITY(archs); i++) { + if (archs[i] == cpu->arch) { + found = true; + break; + } + } + + if (!found) { + VIR_DEBUG("CPU arch %s does not match host arch", + virArchToString(cpu->arch)); + if (message && + virAsprintf(message, + _("CPU arch %s does not match host arch"), + virArchToString(cpu->arch)) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + arch = cpu->arch; + } else { + arch = host->arch; + } + + if (cpu->vendor && + (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) { + VIR_DEBUG("host CPU vendor does not match required CPU vendor %s", + cpu->vendor); + if (message && + virAsprintf(message, + _("host CPU vendor does not match required " + "CPU vendor %s"), + cpu->vendor) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + }
Could this beginning part of ppcCompute() not go into some common function in cpu_generic.c? It just looks entirely copied and pasted from cpu_x86.c from x86Compute()
+ + if (!(map = ppcLoadMap()) || + !(host_model = ppcModelFromCPU(host, map)) || + !(guest_model = ppcModelFromCPU(cpu, map))) + goto error; + + if (guestData != NULL) { + if (cpu->type == VIR_CPU_TYPE_GUEST && + cpu->match == VIR_CPU_MATCH_STRICT && + STRNEQ(guest_model->name, host_model->name)) { + VIR_DEBUG("host CPU model does not match required CPU model %s", + guest_model->name); + if (message && + virAsprintf(message, + _("host CPU model does not match required " + "CPU model %s"), + guest_model->name) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data))) + goto error; + } + + ret = VIR_CPU_COMPARE_IDENTICAL; + +out:
I don't see this label used anywhere.
+ ppcMapFree(map); + ppcModelFree(host_model); + ppcModelFree(guest_model); + return ret; + +error: + ret = VIR_CPU_COMPARE_ERROR; + goto out; + +} + static virCPUCompareResult ppcCompare(virCPUDefPtr host, virCPUDefPtr cpu) @@ -369,6 +515,15 @@ ppcNodeData(void) } #endif
+static virCPUCompareResult +ppcGuestData(virCPUDefPtr host, + virCPUDefPtr guest, + virCPUDataPtr *data, + char **message) +{ + return ppcCompute(host, guest, data, message); +} + static int ppcUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED, const virCPUDefPtr host ATTRIBUTE_UNUSED) @@ -466,6 +621,13 @@ error: goto cleanup; }
+static int +ppcHasFeature(const virCPUDataPtr data ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ + return 0; +} +
I'm really curious about this addition. I'm assuming you are hitting a check from qemu_command.c and I'm wondering which one because it likely seems that we need to fix that rather than just providing this dummy stub. That or this was left in and isn't really necessary.
struct cpuArchDriver cpuDriverPowerPC = { .name = "ppc64", .arch = archs, @@ -479,8 +641,8 @@ struct cpuArchDriver cpuDriverPowerPC = { #else .nodeData = NULL, #endif - .guestData = NULL, + .guestData = ppcGuestData, .baseline = ppcBaseline, .update = ppcUpdate, - .hasFeature = NULL, + .hasFeature = ppcHasFeature, }; -- 1.8.1.4
I don't have PPC however so I can't actually test the code. But I did add a few comments above. -- Doug Goldstein

On 2013年09月02日 12:08, Doug Goldstein wrote:
On Thu, Aug 29, 2013 at 3:46 AM, Li Zhang <zhlcindy@gmail.com <mailto:zhlcindy@gmail.com>> wrote:
From: Li Zhang <zhlcindy@linux.vnet.ibm.com <mailto:zhlcindy@linux.vnet.ibm.com>>
On Power platform, Power7+ can support Power7 guest. It needs to define XML configuration to specify guest's CPU model.
For exmaple: <cpu match='exact'> <model>POWER7+_v2.1</model> <vendor>IBM</vendor> </cpu>
Signed-off-by: Li Zhang <zhlcindy@linux.vnet.ibm.com <mailto:zhlcindy@linux.vnet.ibm.com>> --- src/cpu/cpu_powerpc.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-)
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 647a8a1..84fa3f7 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -99,6 +99,23 @@ ppcModelFindPVR(const struct ppc_map *map, return NULL; }
+static struct ppc_model * +ppcModelCopy(const struct ppc_model *model) +{ + struct ppc_model *copy; + + if (VIR_ALLOC(copy) < 0 || + VIR_STRDUP(copy->name, model->name) < 0) { + ppcModelFree(copy); + return NULL; + } + + copy->data.pvr = model->data.pvr; + copy->vendor = model->vendor; + + return copy; +} + static struct ppc_vendor * ppcVendorFind(const struct ppc_map *map, const char *name) @@ -126,6 +143,29 @@ ppcVendorFree(struct ppc_vendor *vendor) VIR_FREE(vendor); }
+static struct ppc_model * +ppcModelFromCPU(const virCPUDefPtr cpu, + const struct ppc_map *map) +{ + struct ppc_model *model = NULL; + + if ((model = ppcModelFind(map, cpu->model)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %s"), cpu->model); + goto error; + } + + if ((model = ppcModelCopy(model)) == NULL) + goto error; + + return model; + +error: + ppcModelFree(model); + return NULL; +} + + static int ppcVendorLoad(xmlXPathContextPtr ctxt, struct ppc_map *map) @@ -288,6 +328,112 @@ error: return NULL; }
+static virCPUDataPtr +ppcMakeCPUData(virArch arch, struct cpuPPCData *data) +{ + virCPUDataPtr cpuData; + + if (VIR_ALLOC(cpuData) < 0) + return NULL; + + cpuData->arch = arch; + cpuData->data.ppc = *data; + data = NULL; + + return cpuData; +} + +static virCPUCompareResult +ppcCompute(virCPUDefPtr host, + const virCPUDefPtr cpu, + virCPUDataPtr *guestData, + char **message) + +{ + struct ppc_map *map = NULL; + struct ppc_model *host_model = NULL; + struct ppc_model *guest_model = NULL; + + int ret = 0; + virArch arch; + size_t i; + + if (cpu->arch != VIR_ARCH_NONE) { + bool found = false; + + for (i = 0; i < ARRAY_CARDINALITY(archs); i++) { + if (archs[i] == cpu->arch) { + found = true; + break; + } + } + + if (!found) { + VIR_DEBUG("CPU arch %s does not match host arch", + virArchToString(cpu->arch)); + if (message && + virAsprintf(message, + _("CPU arch %s does not match host arch"), + virArchToString(cpu->arch)) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + arch = cpu->arch; + } else { + arch = host->arch; + } + + if (cpu->vendor && + (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) { + VIR_DEBUG("host CPU vendor does not match required CPU vendor %s", + cpu->vendor); + if (message && + virAsprintf(message, + _("host CPU vendor does not match required " + "CPU vendor %s"), + cpu->vendor) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + }
Could this beginning part of ppcCompute() not go into some common function in cpu_generic.c? It just looks entirely copied and pasted from cpu_x86.c from x86Compute()
CPU driver's functions can be called separately for different architectures. Doesn't it break the structure to let PPC driver go into some functions in cpu_generic.c? PPC's CPU logic is the same as X86. The difference is that CPUID is not supported on PPC and it is removed.
+ + if (!(map = ppcLoadMap()) || + !(host_model = ppcModelFromCPU(host, map)) || + !(guest_model = ppcModelFromCPU(cpu, map))) + goto error; + + if (guestData != NULL) { + if (cpu->type == VIR_CPU_TYPE_GUEST && + cpu->match == VIR_CPU_MATCH_STRICT && + STRNEQ(guest_model->name, host_model->name)) { + VIR_DEBUG("host CPU model does not match required CPU model %s", + guest_model->name); + if (message && + virAsprintf(message, + _("host CPU model does not match required " + "CPU model %s"), + guest_model->name) < 0) + goto error; + return VIR_CPU_COMPARE_INCOMPATIBLE; + } + + if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data))) + goto error; + } + + ret = VIR_CPU_COMPARE_IDENTICAL; + +out:
I don't see this label used anywhere.
It is in the following code:
+ ppcMapFree(map); + ppcModelFree(host_model); + ppcModelFree(guest_model); + return ret; + +error: + ret = VIR_CPU_COMPARE_ERROR; + goto out;
^^^
+ +} + static virCPUCompareResult ppcCompare(virCPUDefPtr host, virCPUDefPtr cpu) @@ -369,6 +515,15 @@ ppcNodeData(void) } #endif
+static virCPUCompareResult +ppcGuestData(virCPUDefPtr host, + virCPUDefPtr guest, + virCPUDataPtr *data, + char **message) +{ + return ppcCompute(host, guest, data, message); +} + static int ppcUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED, const virCPUDefPtr host ATTRIBUTE_UNUSED) @@ -466,6 +621,13 @@ error: goto cleanup; }
+static int +ppcHasFeature(const virCPUDataPtr data ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED) +{ + return 0; +} +
I'm really curious about this addition. I'm assuming you are hitting a check from qemu_command.c and I'm wondering which one because it likely seems that we need to fix that rather than just providing this dummy stub. That or this was left in and isn't really necessary.
Yes, you are right. In the qemuBuildCpuArgStr, it calls this function. hasSVM = cpuHasFeature(data, "svm"); That is X86 specific. I will remove it for PPC.
struct cpuArchDriver cpuDriverPowerPC = { .name = "ppc64", .arch = archs, @@ -479,8 +641,8 @@ struct cpuArchDriver cpuDriverPowerPC = { #else .nodeData = NULL, #endif - .guestData = NULL, + .guestData = ppcGuestData, .baseline = ppcBaseline, .update = ppcUpdate, - .hasFeature = NULL, + .hasFeature = ppcHasFeature, }; -- 1.8.1.4
I don't have PPC however so I can't actually test the code. But I did add a few comments above.
Thanks very much for your comments.
-- Doug Goldstein
participants (2)
-
Doug Goldstein
-
Li Zhang