Add parsing of LoongArch CPU models from the CPU map XML files. A model references a vendor and a list of features. Each feature may either reference a predefined feature or specify its own CPUCFG index and value. Model lookup by name and the model free function are also added. The model parsing callback is now passed to cpuMapLoad(). Signed-off-by: Xianglai Li <lixianglai@loongson.cn> --- Cc: Bibo Mao <maobibo@loongson.cn> src/cpu/cpu_loongarch.c | 147 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_loongarch.c b/src/cpu/cpu_loongarch.c index 7d63630615..3cce682349 100644 --- a/src/cpu/cpu_loongarch.c +++ b/src/cpu/cpu_loongarch.c @@ -34,10 +34,19 @@ struct _virCPULoongArchVendor { uint32_t value; }; +typedef struct _virCPULoongArchModel virCPULoongArchModel; +struct _virCPULoongArchModel { + char *name; + virCPULoongArchVendor *vendor; + virCPULoongArchData data; +}; + typedef struct _virCPULoongArchMap virCPULoongArchMap; struct _virCPULoongArchMap { size_t nvendors; virCPULoongArchVendor **vendors; + size_t nmodels; + virCPULoongArchModel **models; virCPULoongArchData data; }; @@ -55,6 +64,25 @@ virCPULoongArchCompare(virCPUDef *host G_GNUC_UNUSED, return VIR_CPU_COMPARE_IDENTICAL; } +static void +virCPULoongArchDataClear(virCPULoongArchData *data) +{ + if (!data) + return; + + g_clear_pointer(&data->features, g_ptr_array_unref); +} + +static void +virCPULoongArchDataFree(virCPUData *data) +{ + if (!data) + return; + + virCPULoongArchDataClear(&data->data.loongarch); + g_free(data); +} + static virCPULoongArchFeature * virCPULoongArchFeatureNew(void) { @@ -86,6 +114,18 @@ virCPULoongArchVendorFree(virCPULoongArchVendor *vendor) G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPULoongArchVendor, virCPULoongArchVendorFree); +static void +virCPULoongArchModelFree(virCPULoongArchModel *model) +{ + if (!model) + return; + + virCPULoongArchDataClear(&model->data); + g_free(model->name); + g_free(model); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPULoongArchModel, virCPULoongArchModelFree); + static virCPULoongArchMap * virCPULoongArchMapNew(void) { @@ -106,6 +146,10 @@ virCPULoongArchMapFree(virCPULoongArchMap *map) if (!map) return; + for (i = 0; i < map->nmodels; i++) + virCPULoongArchModelFree(map->models[i]); + g_free(map->models); + for (i = 0; i < map->nvendors; i++) virCPULoongArchVendorFree(map->vendors[i]); g_free(map->vendors); @@ -130,6 +174,19 @@ virCPULoongArchMapFeatureFindByName(virCPULoongArchMap *map, return NULL; } +static virCPULoongArchModel * +virCPULoongArchModelFindByName(virCPULoongArchMap *map, + const char *name) +{ + size_t i; + + for (i = 0; i < map->nmodels; i++) { + if (STREQ(map->models[i]->name, name)) + return map->models[i]; + } + + return NULL; +} static virCPULoongArchVendor * virCPULoongArchVendorFindByName(virCPULoongArchMap *map, @@ -206,6 +263,92 @@ virCPULoongArchMapFeatureParse(xmlXPathContextPtr ctxt, return 0; } +static int +virCPULoongArchMapModelParse(xmlXPathContextPtr ctxt, + const char *name, + void *data) +{ + virCPULoongArchMap *map = data; + g_autoptr(virCPULoongArchModel) model = NULL; + xmlNodePtr vendorNode = NULL; + g_autofree xmlNodePtr *nodes = NULL; + size_t i; + int n; + + model = g_new0(virCPULoongArchModel, 1); + model->name = g_strdup(name); + + if (virCPULoongArchModelFindByName(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %1$s already defined"), + model->name); + return -1; + } + + if ((vendorNode = virXPathNode("./vendor", ctxt))) { + g_autofree char *vendor = NULL; + + if (!(vendor = virXMLPropStringRequired(vendorNode, "name"))) + return -1; + + if (!(model->vendor = virCPULoongArchVendorFindByName(map, vendor))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown vendor %1$s referenced by CPU model %2$s"), + vendor, model->name); + return -1; + } + } + + if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0) + return -1; + + if (n == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing feature information for CPU model %1$s"), + model->name); + return -1; + } + + model->data.features = g_ptr_array_new(); + g_ptr_array_set_free_func(model->data.features, + (GDestroyNotify) virCPULoongArchFeatureFree); + + for (i = 0; i < n; i++) { + g_autoptr(virCPULoongArchFeature) feature = NULL; + virCPULoongArchFeature *found; + g_autofree char *ftname = NULL; + xmlNodePtr node = nodes[i]; + xmlNodePtr child; + + if (!(ftname = virXMLPropString(node, "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing feature name for CPU model %1$s"), + model->name); + return -1; + } + + feature = virCPULoongArchFeatureNew(); + feature->name = g_strdup(ftname); + + if ((found = virCPULoongArchMapFeatureFindByName(map, ftname))) { + feature->index = found->index; + feature->value = found->value; + } else if ((child = xmlFirstElementChild(node))) { + virCPULoongArchFeature cpucfg; + if (virXMLNodeNameEqual(child, "cpucfg")) { + if (virCPULoongArchMapCpucfgParse(child, &cpucfg) >= 0) { + feature->index = cpucfg.index; + feature->value = cpucfg.value; + } + } + } + g_ptr_array_add(model->data.features, g_steal_pointer(&feature)); + } + + VIR_APPEND_ELEMENT(map->models, map->nmodels, model); + return 0; +} + static int virCPULoongArchMapVendorParse(xmlXPathContextPtr ctxt, const char *name, @@ -248,7 +391,7 @@ virCPULoongArchLoadMap(void) if (cpuMapLoad("loongarch", virCPULoongArchMapVendorParse, virCPULoongArchMapFeatureParse, - NULL, map) < 0) + virCPULoongArchMapModelParse, map) < 0) return NULL; return g_steal_pointer(&map); @@ -301,7 +444,7 @@ struct cpuArchDriver cpuDriverLoongArch = { .compare = virCPULoongArchCompare, .decode = virCPULoongArchDriverDecode, .encode = NULL, - .dataFree = NULL, + .dataFree = virCPULoongArchDataFree, .baseline = NULL, .update = virCPULoongArchUpdate, .getModels = NULL, -- 2.39.1