libxl: describe host cpu features based on hwcaps

Parse libxl_hwcap accounting for versions since Xen 4.4 - Xen 4.7.
libxl_hwcaps is a set of cpuid leaves output that is described in [0] or
[1] in Xen 4.7. This is a collection of CPUID leaves that we version
in libvirt whenever feature words are reordered or added. Thus we keep the
common ones in one struct and others for each version. Since
libxl_hwcaps doesn't appear to have a stable format across all supported
versions thus we need to keep track of changes as a compromise until it's
exported in xen libxl API. We don't fail in initializing the driver in case
parsing of hwcaps failed for that reason. In addition, change the notation
on PAE feature such that is easier to read which bit it corresponds.

[0] xen/include/asm-x86/cpufeature.h
[1] xen/include/public/arch-x86/cpufeatureset.h

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
This commit is contained in:
Joao Martins 2016-07-20 20:08:47 +01:00 committed by Michal Privoznik
parent 3d54305e1c
commit 17322e5518

View File

@ -36,6 +36,8 @@
#include "domain_capabilities.h"
#include "vircommand.h"
#include "libxl_capabilities.h"
#include "cpu/cpu_x86.h"
#include "cpu/cpu_x86_data.h"
#define VIR_FROM_THIS VIR_FROM_LIBXL
@ -43,8 +45,13 @@
VIR_LOG_INIT("libxl.libxl_capabilities");
/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
#define LIBXL_X86_FEATURE_PAE_MASK 0x40
#define LIBXL_X86_FEATURE_PAE_MASK (1 << 6)
#define LIBXL_X86_FEATURE_LM_MASK (1 << 29)
enum libxlHwcapVersion {
LIBXL_HWCAP_V0 = 0, /* for Xen 4.4 .. 4.6 */
LIBXL_HWCAP_V1, /* for Xen 4.7 and up */
};
struct guest_arch {
virArch arch;
@ -57,17 +64,107 @@ struct guest_arch {
#define XEN_CAP_REGEX "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(aarch64|armv7l|x86_32|x86_64|ia64|powerpc64)(p|be)?"
static int
libxlCapsAddCPUID(virCPUx86Data *data, virCPUx86CPUID *cpuid, ssize_t ncaps)
{
size_t i;
for (i = 0; i < ncaps; i++) {
virCPUx86CPUID *c = &cpuid[i];
if (virCPUx86DataAddCPUID(data, c) < 0) {
VIR_DEBUG("Failed to add CPUID(%x,%x)", c->eax_in, c->ecx_in);
return -1;
}
}
return 0;
}
/*
* The words represented in physinfo.hw_cap are host CPUID (sub) leafs.
* Position of these hasn't changed much up until Xen 4.7 with a rework
* on how CPUID is handled internally. As a side-effect it got normalized
* and also added more feature words. Although cannot be relied upon as
* stable interface, and hence we version changes in position of the features
* across all supported versions of the libxl driver until libxl exposes a
* stable representation of these capabilities. Fortunately not a lot of
* variation happened so it's still trivial to keep track of these leafs
* to describe host CPU in libvirt capabilities. v0 stands for Xen 4.4
* up to 4.6, while v1 is meant for Xen 4.7, as depicted in the table below:
*
* | v0 (Xen 4.4 - 4.6) | v1 (Xen >= 4.7) |
* ---------------------------------------------
* word 0 | CPUID.00000001.EDX | CPUID.00000001.EDX |
* word 1 | CPUID.80000001.EDX | CPUID.00000001.ECX |
* word 2 | CPUID.80860001 | CPUID.80000001.EDX |
* word 3 | - Linux - | CPUID.80000001.ECX |
* word 4 | CPUID.00000001.ECX | CPUID.0000000D:1.EAX |
* word 5 | CPUID.C0000001 | CPUID.00000007:0.EBX |
* word 6 | CPUID.80000001.ECX | CPUID.00000007:0.ECX |
* word 7 | CPUID.00000007.EBX | CPUID.80000007.EDX |
* word 8 | - Non existent - | CPUID.80000008.EBX |
*
*/
static virCPUDataPtr
libxlCapsNodeData(virCPUDefPtr cpu, libxl_hwcap hwcap,
enum libxlHwcapVersion version)
{
ssize_t ncaps;
virCPUDataPtr cpudata = NULL;
virCPUx86Data data = VIR_CPU_X86_DATA_INIT;
virCPUx86CPUID cpuid[] = {
{ .eax_in = 0x00000001,
.edx = hwcap[0] },
{ .eax_in = 0x00000001,
.ecx = (version > LIBXL_HWCAP_V0 ? hwcap[1] : hwcap[4]) },
{ .eax_in = 0x80000001,
.edx = (version > LIBXL_HWCAP_V0 ? hwcap[2] : hwcap[1]) },
{ .eax_in = 0x80000001,
.ecx = (version > LIBXL_HWCAP_V0 ? hwcap[3] : hwcap[6]) },
{ .eax_in = 0x00000007,
.ebx = (version > LIBXL_HWCAP_V0 ? hwcap[5] : hwcap[7]) },
};
virCPUx86CPUID cpuid_ver1[] = {
{ .eax_in = 0x0000000D, .ecx_in = 1U, .eax = hwcap[4] },
{ .eax_in = 0x00000007, .ecx_in = 0U, .ecx = hwcap[6] },
{ .eax_in = 0x80000007, .ecx_in = 0U, .edx = hwcap[7] },
};
ncaps = ARRAY_CARDINALITY(cpuid);
if (libxlCapsAddCPUID(&data, cpuid, ncaps) < 0)
goto error;
ncaps = ARRAY_CARDINALITY(cpuid_ver1);
if (version > LIBXL_HWCAP_V0 &&
libxlCapsAddCPUID(&data, cpuid_ver1, ncaps) < 0)
goto error;
cpudata = virCPUx86MakeData(cpu->arch, &data);
error:
virCPUx86DataClear(&data);
return cpudata;
}
/* hw_caps is an array of 32-bit words whose meaning is listed in
* xen-unstable.hg/xen/include/asm-x86/cpufeature.h. Each feature
* is defined in the form X*32+Y, corresponding to the Y'th bit in
* the X'th 32-bit word of hw_cap.
*/
static int
libxlCapsInitCPU(virCapsPtr caps, libxl_physinfo *phy_info)
libxlCapsInitCPU(virCapsPtr caps, libxl_physinfo *phy_info,
enum libxlHwcapVersion version)
{
virCPUDataPtr data = NULL;
virCPUDefPtr cpu = NULL;
int ret = -1;
int host_pae;
int host_lm;
/* On ARM hw_cap vector is zeroed out but not on x86 */
if (!phy_info->hw_cap[0])
return 0;
if (VIR_ALLOC(cpu) < 0)
goto error;
@ -77,6 +174,13 @@ libxlCapsInitCPU(virCapsPtr caps, libxl_physinfo *phy_info)
virCapabilitiesAddHostFeature(caps, "pae") < 0)
goto error;
host_lm = (phy_info->hw_cap[version > LIBXL_HWCAP_V0 ? 2 : 1]
& LIBXL_X86_FEATURE_LM_MASK);
if (host_lm)
cpu->arch = VIR_ARCH_X86_64;
else
cpu->arch = VIR_ARCH_I686;
cpu->type = VIR_CPU_TYPE_HOST;
cpu->cores = phy_info->cores_per_socket;
cpu->threads = phy_info->threads_per_core;
@ -85,7 +189,14 @@ libxlCapsInitCPU(virCapsPtr caps, libxl_physinfo *phy_info)
ret = 0;
if (!(data = libxlCapsNodeData(cpu, phy_info->hw_cap, version)) ||
cpuDecode(cpu, data, NULL, 0, NULL) < 0) {
VIR_WARN("Failed to initialize host cpu features");
goto error;
}
cleanup:
cpuDataFree(data);
return ret;
@ -97,6 +208,8 @@ libxlCapsInitCPU(virCapsPtr caps, libxl_physinfo *phy_info)
static int
libxlCapsInitHost(libxl_ctx *ctx, virCapsPtr caps)
{
const libxl_version_info *ver_info;
enum libxlHwcapVersion version;
libxl_physinfo phy_info;
if (libxl_get_physinfo(ctx, &phy_info) != 0) {
@ -105,7 +218,14 @@ libxlCapsInitHost(libxl_ctx *ctx, virCapsPtr caps)
return -1;
}
if (libxlCapsInitCPU(caps, &phy_info) < 0)
if ((ver_info = libxl_get_version_info(ctx)) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to get version info from libxenlight"));
return -1;
}
version = (ver_info->xen_version_minor >= 7);
if (libxlCapsInitCPU(caps, &phy_info, version) < 0)
return -1;
if (virCapabilitiesSetNetPrefix(caps, LIBXL_GENERATED_PREFIX_XEN) < 0)