提交 376261d1 编写于 作者: J Jiri Denemark 提交者: Peter Krempa

cpu: Add support for loading and storing CPU data

This patch adds cpuDataFormat and cpuDataParse APIs to be used in unit
tests for testing APIs that deal with virCPUData. In the x86 world, this
means we can now store/load arbitrary CPUID data in the test suite to
check correctness of CPU related APIs that could not be tested before.
Signed-off-by: NPeter Krempa <pkrempa@redhat.com>
上级 fe1bf917
...@@ -442,6 +442,47 @@ cpuHasFeature(const virCPUData *data, ...@@ -442,6 +442,47 @@ cpuHasFeature(const virCPUData *data,
return driver->hasFeature(data, feature); return driver->hasFeature(data, feature);
} }
char *
cpuDataFormat(const virCPUData *data)
{
struct cpuArchDriver *driver;
VIR_DEBUG("data=%p", data);
if (!(driver = cpuGetSubDriver(data->arch)))
return NULL;
if (!driver->dataFormat) {
virReportError(VIR_ERR_NO_SUPPORT,
_("cannot format %s CPU data"),
virArchToString(data->arch));
return NULL;
}
return driver->dataFormat(data);
}
virCPUDataPtr
cpuDataParse(virArch arch,
const char *xmlStr)
{
struct cpuArchDriver *driver;
VIR_DEBUG("arch=%s, xmlStr=%s", virArchToString(arch), xmlStr);
if (!(driver = cpuGetSubDriver(arch)))
return NULL;
if (!driver->dataParse) {
virReportError(VIR_ERR_NO_SUPPORT,
_("cannot parse %s CPU data"),
virArchToString(arch));
return NULL;
}
return driver->dataParse(xmlStr);
}
bool bool
cpuModelIsAllowed(const char *model, cpuModelIsAllowed(const char *model,
const char **models, const char **models,
......
...@@ -93,6 +93,11 @@ typedef int ...@@ -93,6 +93,11 @@ typedef int
(*cpuArchHasFeature) (const virCPUData *data, (*cpuArchHasFeature) (const virCPUData *data,
const char *feature); const char *feature);
typedef char *
(*cpuArchDataFormat)(const virCPUData *data);
typedef virCPUDataPtr
(*cpuArchDataParse) (const char *xmlStr);
struct cpuArchDriver { struct cpuArchDriver {
const char *name; const char *name;
...@@ -107,6 +112,8 @@ struct cpuArchDriver { ...@@ -107,6 +112,8 @@ struct cpuArchDriver {
cpuArchBaseline baseline; cpuArchBaseline baseline;
cpuArchUpdate update; cpuArchUpdate update;
cpuArchHasFeature hasFeature; cpuArchHasFeature hasFeature;
cpuArchDataFormat dataFormat;
cpuArchDataParse dataParse;
}; };
...@@ -178,4 +185,11 @@ cpuModelIsAllowed(const char *model, ...@@ -178,4 +185,11 @@ cpuModelIsAllowed(const char *model,
extern int extern int
cpuGetModels(const char *arch, char ***models); cpuGetModels(const char *arch, char ***models);
/* cpuDataFormat and cpuDataParse are implemented for unit tests only and
* have no real-life usage
*/
char *cpuDataFormat(const virCPUData *data);
virCPUDataPtr cpuDataParse(virArch arch,
const char *xmlStr);
#endif /* __VIR_CPU_H__ */ #endif /* __VIR_CPU_H__ */
...@@ -665,6 +665,35 @@ x86FeatureNames(const struct x86_map *map, ...@@ -665,6 +665,35 @@ x86FeatureNames(const struct x86_map *map,
} }
static int
x86ParseCPUID(xmlXPathContextPtr ctxt,
struct cpuX86cpuid *cpuid)
{
unsigned long fun, eax, ebx, ecx, edx;
int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
memset(cpuid, 0, sizeof(*cpuid));
fun = eax = ebx = ecx = edx = 0;
ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax);
ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx);
ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx);
if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
|| ret_ecx == -2 || ret_edx == -2)
return -1;
cpuid->function = fun;
cpuid->eax = eax;
cpuid->ebx = ebx;
cpuid->ecx = ecx;
cpuid->edx = edx;
return 0;
}
static int static int
x86FeatureLoad(xmlXPathContextPtr ctxt, x86FeatureLoad(xmlXPathContextPtr ctxt,
struct x86_map *map) struct x86_map *map)
...@@ -672,6 +701,7 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, ...@@ -672,6 +701,7 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
xmlNodePtr *nodes = NULL; xmlNodePtr *nodes = NULL;
xmlNodePtr ctxt_node = ctxt->node; xmlNodePtr ctxt_node = ctxt->node;
struct x86_feature *feature; struct x86_feature *feature;
struct cpuX86cpuid cpuid;
int ret = 0; int ret = 0;
size_t i; size_t i;
int n; int n;
...@@ -697,31 +727,13 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, ...@@ -697,31 +727,13 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
goto ignore; goto ignore;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
struct cpuX86cpuid cpuid;
unsigned long fun, eax, ebx, ecx, edx;
int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
ctxt->node = nodes[i]; ctxt->node = nodes[i];
fun = eax = ebx = ecx = edx = 0; if (x86ParseCPUID(ctxt, &cpuid) < 0) {
ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax);
ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx);
ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx);
if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
|| ret_ecx == -2 || ret_edx == -2) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid cpuid[%zu] in %s feature"), i, feature->name); _("Invalid cpuid[%zu] in %s feature"),
i, feature->name);
goto ignore; goto ignore;
} }
cpuid.function = fun;
cpuid.eax = eax;
cpuid.ebx = ebx;
cpuid.ecx = ecx;
cpuid.edx = edx;
if (x86DataAddCpuid(feature->data, &cpuid)) if (x86DataAddCpuid(feature->data, &cpuid))
goto error; goto error;
} }
...@@ -1124,6 +1136,85 @@ error: ...@@ -1124,6 +1136,85 @@ error:
} }
static char *
x86CPUDataFormat(const virCPUData *data)
{
struct data_iterator iter = DATA_ITERATOR_INIT(data->data.x86);
struct cpuX86cpuid *cpuid;
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
while ((cpuid = x86DataCpuidNext(&iter))) {
virBufferAsprintf(&buf,
" <cpuid function='0x%08x'"
" eax='0x%08x' ebx='0x%08x'"
" ecx='0x%08x' edx='0x%08x'/>\n",
cpuid->function,
cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
}
virBufferAddLit(&buf, "</cpudata>\n");
if (virBufferError(&buf)) {
virBufferFreeAndReset(&buf);
virReportOOMError();
return NULL;
}
return virBufferContentAndReset(&buf);
}
static virCPUDataPtr
x86CPUDataParse(const char *xmlStr)
{
xmlDocPtr xml = NULL;
xmlXPathContextPtr ctxt = NULL;
xmlNodePtr *nodes = NULL;
virCPUDataPtr cpuData = NULL;
struct cpuX86Data *data = NULL;
struct cpuX86cpuid cpuid;
size_t i;
int n;
if (VIR_ALLOC(data) < 0)
goto cleanup;
if (!(xml = virXMLParseStringCtxt(xmlStr, _("CPU data"), &ctxt))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot parse CPU data"));
goto cleanup;
}
ctxt->node = xmlDocGetRootElement(xml);
n = virXPathNodeSet("/cpudata[@arch='x86']/data", ctxt, &nodes);
if (n < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("no x86 CPU data found"));
goto cleanup;
}
for (i = 0; i < n; i++) {
ctxt->node = nodes[i];
if (x86ParseCPUID(ctxt, &cpuid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse cpuid[%zu]"), i);
goto cleanup;
}
if (x86DataAddCpuid(data, &cpuid) < 0)
goto cleanup;
}
cpuData = x86MakeCPUData(VIR_ARCH_X86_64, &data);
cleanup:
VIR_FREE(nodes);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml);
x86DataFree(data);
return cpuData;
}
/* A helper macro to exit the cpu computation function without writing /* A helper macro to exit the cpu computation function without writing
* redundant code: * redundant code:
* MSG: error message * MSG: error message
...@@ -1956,4 +2047,6 @@ struct cpuArchDriver cpuDriverX86 = { ...@@ -1956,4 +2047,6 @@ struct cpuArchDriver cpuDriverX86 = {
.baseline = x86Baseline, .baseline = x86Baseline,
.update = x86Update, .update = x86Update,
.hasFeature = x86HasFeature, .hasFeature = x86HasFeature,
.dataFormat = x86CPUDataFormat,
.dataParse = x86CPUDataParse,
}; };
...@@ -720,7 +720,9 @@ cpuBaseline; ...@@ -720,7 +720,9 @@ cpuBaseline;
cpuBaselineXML; cpuBaselineXML;
cpuCompare; cpuCompare;
cpuCompareXML; cpuCompareXML;
cpuDataFormat;
cpuDataFree; cpuDataFree;
cpuDataParse;
cpuDecode; cpuDecode;
cpuEncode; cpuEncode;
cpuGetModels; cpuGetModels;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册