mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
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: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
parent
fe1bf917f9
commit
376261d164
@ -442,6 +442,47 @@ cpuHasFeature(const virCPUData *data,
|
||||
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
|
||||
cpuModelIsAllowed(const char *model,
|
||||
const char **models,
|
||||
|
@ -93,6 +93,11 @@ typedef int
|
||||
(*cpuArchHasFeature) (const virCPUData *data,
|
||||
const char *feature);
|
||||
|
||||
typedef char *
|
||||
(*cpuArchDataFormat)(const virCPUData *data);
|
||||
|
||||
typedef virCPUDataPtr
|
||||
(*cpuArchDataParse) (const char *xmlStr);
|
||||
|
||||
struct cpuArchDriver {
|
||||
const char *name;
|
||||
@ -107,6 +112,8 @@ struct cpuArchDriver {
|
||||
cpuArchBaseline baseline;
|
||||
cpuArchUpdate update;
|
||||
cpuArchHasFeature hasFeature;
|
||||
cpuArchDataFormat dataFormat;
|
||||
cpuArchDataParse dataParse;
|
||||
};
|
||||
|
||||
|
||||
@ -178,4 +185,11 @@ cpuModelIsAllowed(const char *model,
|
||||
extern int
|
||||
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__ */
|
||||
|
@ -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
|
||||
x86FeatureLoad(xmlXPathContextPtr ctxt,
|
||||
struct x86_map *map)
|
||||
@ -672,6 +701,7 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
|
||||
xmlNodePtr *nodes = NULL;
|
||||
xmlNodePtr ctxt_node = ctxt->node;
|
||||
struct x86_feature *feature;
|
||||
struct cpuX86cpuid cpuid;
|
||||
int ret = 0;
|
||||
size_t i;
|
||||
int n;
|
||||
@ -697,31 +727,13 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
|
||||
goto ignore;
|
||||
|
||||
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];
|
||||
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) {
|
||||
if (x86ParseCPUID(ctxt, &cpuid) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
cpuid.function = fun;
|
||||
cpuid.eax = eax;
|
||||
cpuid.ebx = ebx;
|
||||
cpuid.ecx = ecx;
|
||||
cpuid.edx = edx;
|
||||
|
||||
if (x86DataAddCpuid(feature->data, &cpuid))
|
||||
goto 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
|
||||
* redundant code:
|
||||
* MSG: error message
|
||||
@ -1956,4 +2047,6 @@ struct cpuArchDriver cpuDriverX86 = {
|
||||
.baseline = x86Baseline,
|
||||
.update = x86Update,
|
||||
.hasFeature = x86HasFeature,
|
||||
.dataFormat = x86CPUDataFormat,
|
||||
.dataParse = x86CPUDataParse,
|
||||
};
|
||||
|
@ -720,7 +720,9 @@ cpuBaseline;
|
||||
cpuBaselineXML;
|
||||
cpuCompare;
|
||||
cpuCompareXML;
|
||||
cpuDataFormat;
|
||||
cpuDataFree;
|
||||
cpuDataParse;
|
||||
cpuDecode;
|
||||
cpuEncode;
|
||||
cpuGetModels;
|
||||
|
Loading…
Reference in New Issue
Block a user