
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index def6974..c7a282e 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -424,3 +424,27 @@ cpuUpdate(virCPUDefPtr guest,
return driver->update(guest, host); } + +bool +cpuHasFeature(const char *arch, + const union cpuData *data, + const char *feature) +{ + struct cpuArchDriver *driver; + + VIR_DEBUG("arch=%s, data=%p, feature=%s", + arch, data, feature); + + if ((driver = cpuGetSubDriver(arch)) == NULL) + return -1; + + if (driver->hasFeature == NULL) { + virCPUReportError(VIR_ERR_NO_SUPPORT, + _("cannot check guest CPU data for %s architecture"), + arch); + return -1; + } + + return driver->hasFeature(arch, data, feature);
No need to pass arch down here.
+} + diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index a745917..405af48 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -82,6 +82,11 @@ typedef int (*cpuArchUpdate) (virCPUDefPtr guest, const virCPUDefPtr host);
+typedef bool +(*cpuArchHasFeature) (const char *arch, + const union cpuData *data, + const char *feature); +
The 'arch' argument is not needed here since cpuHasFeature already selected appropriate implementation according to CPU architecture.
struct cpuArchDriver { const char *name; @@ -95,6 +100,7 @@ struct cpuArchDriver { cpuArchGuestData guestData; cpuArchBaseline baseline; cpuArchUpdate update; + cpuArchHasFeature hasFeature; };
@@ -151,4 +157,10 @@ extern int cpuUpdate (virCPUDefPtr guest, const virCPUDefPtr host);
+extern bool +cpuHasFeature(const char *arch, + const union cpuData *data, + const char *feature); + + #endif /* __VIR_CPU_H__ */ diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 1937901..cc82d58 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1754,6 +1754,55 @@ cleanup: return ret; }
+static bool x86HasFeature(const char *arch ATTRIBUTE_UNUSED, + const union cpuData *data, + const char *name)
No arch argument needed here as well.
+{ + struct x86_map *map; + struct x86_feature *feature; + bool ret = false; + int i; + + if (!(map = x86LoadMap())) + return false; + + if (!(feature = x86FeatureFind(map, name))) + goto cleanup; + + for (i = 0 ; i < data->x86.basic_len ; i++) { + if (data->x86.basic[i].function == feature->cpuid->function && + ((data->x86.basic[i].eax & feature->cpuid->eax) + == feature->cpuid->eax) && + ((data->x86.basic[i].ebx & feature->cpuid->ebx) + == feature->cpuid->ebx) && + ((data->x86.basic[i].ecx & feature->cpuid->ecx) + == feature->cpuid->ecx) && + ((data->x86.basic[i].edx & feature->cpuid->edx) + == feature->cpuid->edx)) { + ret = true; + goto cleanup; + } + } + + for (i = 0 ; i < data->x86.extended_len ; i++) { + if (data->x86.extended[i].function == feature->cpuid->function && + ((data->x86.extended[i].eax & feature->cpuid->eax) + == feature->cpuid->eax) && + ((data->x86.extended[i].ebx & feature->cpuid->ebx) + == feature->cpuid->ebx) && + ((data->x86.extended[i].ecx & feature->cpuid->ecx) + == feature->cpuid->ecx) && + ((data->x86.extended[i].edx & feature->cpuid->edx) + == feature->cpuid->edx)) { + ret = true; + goto cleanup; + } + }
The two for loops should be replaced by the following single loop (which in practise will be walked through only once): for (i = 0; i < feature->ncpuid; i++) { struct cpuX86cpuid *cpuid; cpuid = x86DataCpuid(data, feature->cpuid[i].function); if (cpuid && x86cpuidMatchMasked(cpuid, feature->cpuid + i)) { ret = true; goto cleanup; } }
+ +cleanup: + x86MapFree(map); + return ret; +}
struct cpuArchDriver cpuDriverX86 = { .name = "x86", @@ -1771,4 +1820,5 @@ struct cpuArchDriver cpuDriverX86 = { .guestData = x86GuestData, .baseline = x86Baseline, .update = x86Update, + .hasFeature = x86HasFeature, };
The current code would actually work so this is not a show stopper and the changes could be done as part of a bigger cleanup patch for cpu_x86.c that I have in my git tree. However I won't send the cleanup patch before I finish unit tests for all this to check the cleanup doesn't break anything. The rest looks fine. Jirka