提交 3afde075 编写于 作者: J Jiri Denemark 提交者: Peter Krempa

qemu: Add monitor APIs to fetch CPUID data from QEMU

The qemu monitor supports retrieval of actual CPUID bits presented to
the guest using QMP monitor. Add APIs to extract these information and
tests for them.
Signed-off-by: NPeter Krempa <pkrempa@redhat.com>
上级 f80a11c9
......@@ -3927,3 +3927,34 @@ qemuMonitorSetDomainLog(qemuMonitorPtr mon, int logfd)
return 0;
}
/**
* qemuMonitorJSONGetGuestCPU:
* @mon: Pointer to the monitor
* @arch: arch of the guest
*
* Retrieve the definition of the guest CPU from a running qemu instance.
*
* Returns the cpu definition object. On error returns NULL.
*/
virCPUDataPtr
qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
virArch arch)
{
VIR_DEBUG("mon=%p, arch='%s'", mon, virArchToString(arch));
if (!mon) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("monitor must not be NULL"));
return NULL;
}
if (!mon->json) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("JSON monitor is required"));
return NULL;
}
return qemuMonitorJSONGetGuestCPU(mon, arch);
}
......@@ -32,6 +32,7 @@
# include "virhash.h"
# include "virjson.h"
# include "device_conf.h"
# include "cpu/cpu.h"
typedef struct _qemuMonitor qemuMonitor;
typedef qemuMonitor *qemuMonitorPtr;
......@@ -763,6 +764,9 @@ int qemuMonitorGetDeviceAliases(qemuMonitorPtr mon,
int qemuMonitorSetDomainLog(qemuMonitorPtr mon, int logfd);
virCPUDataPtr qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
virArch arch);
/**
* When running two dd process and using <> redirection, we need a
* shell that will not truncate files. These two strings serve that
......
......@@ -42,6 +42,7 @@
#include "virerror.h"
#include "virjson.h"
#include "virstring.h"
#include "cpu/cpu_x86.h"
#ifdef WITH_DTRACE_PROBES
# include "libvirt_qemu_probes.h"
......@@ -49,6 +50,7 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
#define QOM_CPU_PATH "/machine/unattached/device[0]"
#define LINE_ENDING "\r\n"
......@@ -5454,3 +5456,134 @@ cleanup:
VIR_FREE(paths);
return ret;
}
static int
qemuMonitorJSONParseCPUx86FeatureWord(virJSONValuePtr data,
virCPUx86CPUID *cpuid)
{
const char *reg;
unsigned long long fun;
unsigned long long features;
memset(cpuid, 0, sizeof(*cpuid));
if (!(reg = virJSONValueObjectGetString(data, "cpuid-register"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing cpuid-register in CPU data"));
return -1;
}
if (virJSONValueObjectGetNumberUlong(data, "cpuid-input-eax", &fun) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing or invalid cpuid-input-eax in CPU data"));
return -1;
}
if (virJSONValueObjectGetNumberUlong(data, "features", &features) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing or invalid features in CPU data"));
return -1;
}
cpuid->function = fun;
if (STREQ(reg, "EAX")) {
cpuid->eax = features;
} else if (STREQ(reg, "EBX")) {
cpuid->ebx = features;
} else if (STREQ(reg, "ECX")) {
cpuid->ecx = features;
} else if (STREQ(reg, "EDX")) {
cpuid->edx = features;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown CPU register '%s'"), reg);
return -1;
}
return 0;
}
static virCPUDataPtr
qemuMonitorJSONGetCPUx86Data(qemuMonitorPtr mon,
const char *property)
{
virJSONValuePtr cmd;
virJSONValuePtr reply = NULL;
virJSONValuePtr data;
virCPUx86Data *x86Data = NULL;
virCPUx86CPUID cpuid;
size_t i;
virCPUDataPtr ret = NULL;
int n;
if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
"s:path", QOM_CPU_PATH,
"s:property", property,
NULL)))
return NULL;
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
goto cleanup;
if (qemuMonitorJSONCheckError(cmd, reply))
goto cleanup;
if (!(data = virJSONValueObjectGet(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("qom-get reply was missing return data"));
goto cleanup;
}
if ((n = virJSONValueArraySize(data)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s CPU property did not return an array"),
property);
goto cleanup;
}
if (VIR_ALLOC(x86Data) < 0)
goto cleanup;
for (i = 0; i < n; i++) {
if (qemuMonitorJSONParseCPUx86FeatureWord(virJSONValueArrayGet(data, i),
&cpuid) < 0 ||
virCPUx86DataAddCPUID(x86Data, &cpuid) < 0)
goto cleanup;
}
if (!(ret = virCPUx86MakeData(VIR_ARCH_X86_64, &x86Data)))
goto cleanup;
cleanup:
virJSONValueFree(cmd);
virJSONValueFree(reply);
virCPUx86DataFree(x86Data);
return ret;
}
/**
* qemuMonitorJSONGetGuestCPU:
* @mon: Pointer to the monitor
* @arch: arch of the guest
*
* Retrieve the definition of the guest CPU from a running qemu instance.
*
* Returns the cpu definition object. On error returns NULL.
*/
virCPUDataPtr
qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon,
virArch arch)
{
switch (arch) {
case VIR_ARCH_X86_64:
case VIR_ARCH_I686:
return qemuMonitorJSONGetCPUx86Data(mon, "feature-words");
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("CPU definition retrieval isn't supported for '%s'"),
virArchToString(arch));
return NULL;
}
}
......@@ -29,6 +29,7 @@
# include "qemu_monitor.h"
# include "virbitmap.h"
# include "cpu/cpu.h"
int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
const char *data,
......@@ -426,4 +427,5 @@ int qemuMonitorJSONDetachCharDev(qemuMonitorPtr mon,
int qemuMonitorJSONGetDeviceAliases(qemuMonitorPtr mon,
char ***aliases);
virCPUDataPtr qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon, virArch arch);
#endif /* QEMU_MONITOR_JSON_H */
......@@ -89,6 +89,7 @@ EXTRA_DIST = \
qemucapabilitiesdata \
qemuhelpdata \
qemuhotplugtestdata \
qemumonitorjsondata \
qemuxml2argvdata \
qemuxml2xmloutdata \
qemuxmlnsdata \
......
<cpudata arch='x86'>
<cpuid function='0x00000001' eax='0x00000000' ebx='0x00000000' ecx='0x97ba2223' edx='0x078bfbfd'/>
<cpuid function='0x40000001' eax='0x0100003b' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
<cpuid function='0x80000001' eax='0x00000000' ebx='0x00000000' ecx='0x00000001' edx='0x28100800'/>
</cpudata>
{
"return": [
{
"cpuid-register": "EDX",
"cpuid-input-eax": 2147483658,
"features": 0
},
{
"cpuid-register": "EAX",
"cpuid-input-eax": 1073741825,
"features": 16777275
},
{
"cpuid-register": "EDX",
"cpuid-input-eax": 3221225473,
"features": 0
},
{
"cpuid-register": "ECX",
"cpuid-input-eax": 2147483649,
"features": 1
},
{
"cpuid-register": "EDX",
"cpuid-input-eax": 2147483649,
"features": 672139264
},
{
"cpuid-register": "EBX",
"cpuid-input-ecx": 0,
"cpuid-input-eax": 7,
"features": 0
},
{
"cpuid-register": "ECX",
"cpuid-input-eax": 1,
"features": 2545558051
},
{
"cpuid-register": "EDX",
"cpuid-input-eax": 1,
"features": 126614525
}
],
"id": "libvirt-6"
}
<cpudata arch='x86'>
<cpuid function='0x00000001' eax='0x00000000' ebx='0x00000000' ecx='0x97ba2223' edx='0x0f8bfbff'/>
<cpuid function='0x00000007' eax='0x00000000' ebx='0x00000002' ecx='0x00000000' edx='0x00000000'/>
<cpuid function='0x40000001' eax='0x0100007b' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
<cpuid function='0x80000001' eax='0x00000000' ebx='0x00000000' ecx='0x00000001' edx='0x2993fbff'/>
</cpudata>
{
"return": [
{
"cpuid-register": "EDX",
"cpuid-input-eax": 2147483658,
"features": 0
},
{
"cpuid-register": "EAX",
"cpuid-input-eax": 1073741825,
"features": 16777339
},
{
"cpuid-register": "EDX",
"cpuid-input-eax": 3221225473,
"features": 0
},
{
"cpuid-register": "ECX",
"cpuid-input-eax": 2147483649,
"features": 1
},
{
"cpuid-register": "EDX",
"cpuid-input-eax": 2147483649,
"features": 697564159
},
{
"cpuid-register": "EBX",
"cpuid-input-ecx": 0,
"cpuid-input-eax": 7,
"features": 2
},
{
"cpuid-register": "ECX",
"cpuid-input-eax": 1,
"features": 2545558051
},
{
"cpuid-register": "EDX",
"cpuid-input-eax": 1,
"features": 260832255
}
]
}
......@@ -27,6 +27,7 @@
#include "virthread.h"
#include "virerror.h"
#include "virstring.h"
#include "cpu/cpu.h"
#define VIR_FROM_THIS VIR_FROM_NONE
......@@ -1958,6 +1959,69 @@ cleanup:
return ret;
}
struct testCPUData {
const char *name;
virDomainXMLOptionPtr xmlopt;
};
static int
testQemuMonitorJSONGetCPUData(const void *opaque)
{
const struct testCPUData *data = opaque;
qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, data->xmlopt);
virCPUDataPtr cpuData = NULL;
char *jsonFile = NULL;
char *dataFile = NULL;
char *jsonStr = NULL;
char *expected = NULL;
char *actual = NULL;
int ret = -1;
if (!test)
return -1;
if (virAsprintf(&jsonFile,
"%s/qemumonitorjsondata/qemumonitorjson-getcpu-%s.json",
abs_srcdir, data->name) < 0 ||
virAsprintf(&dataFile,
"%s/qemumonitorjsondata/qemumonitorjson-getcpu-%s.data",
abs_srcdir, data->name) < 0)
goto cleanup;
if (virtTestLoadFile(jsonFile, &jsonStr) < 0 ||
virtTestLoadFile(dataFile, &expected) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "qom-get", jsonStr) < 0)
goto cleanup;
if (!(cpuData = qemuMonitorJSONGetGuestCPU(qemuMonitorTestGetMonitor(test),
VIR_ARCH_X86_64)))
goto cleanup;
if (!(actual = cpuDataFormat(cpuData)))
goto cleanup;
if (STRNEQ(expected, actual)) {
virtTestDifference(stderr, expected, actual);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(jsonFile);
VIR_FREE(dataFile);
VIR_FREE(jsonStr);
VIR_FREE(expected);
VIR_FREE(actual);
cpuDataFree(cpuData);
qemuMonitorTestFree(test);
return ret;
}
static int
mymain(void)
{
......@@ -1991,6 +2055,14 @@ mymain(void)
if (virtTestRun(# name, testQemuMonitorJSON ## name, &simpleFunc) < 0) \
ret = -1
#define DO_TEST_CPU_DATA(name) \
do { \
struct testCPUData data = { name, xmlopt }; \
const char *label = "GetCPUData(" name ")"; \
if (virtTestRun(label, testQemuMonitorJSONGetCPUData, &data) < 0) \
ret = -1; \
} while (0)
DO_TEST(GetStatus);
DO_TEST(GetVersion);
DO_TEST(GetMachines);
......@@ -2055,6 +2127,9 @@ mymain(void)
DO_TEST(qemuMonitorJSONGetVirtType);
DO_TEST(qemuMonitorJSONSendKey);
DO_TEST_CPU_DATA("host");
DO_TEST_CPU_DATA("full");
virObjectUnref(xmlopt);
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册