<commit_before>/*
 * libxl_capabilities.c: libxl capabilities generation
 *
 * Copyright (C) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include <libxl.h>

#include "internal.h"
#include "virlog.h"
#include "virerror.h"
#include "virfile.h"
#include "viralloc.h"
#include "virstring.h"
#include "domain_conf.h"
#include "capabilities.h"
#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

VIR_LOG_INIT("libxl.libxl_capabilities");

/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
#define LIBXL_X86_FEATURE_PAE_MASK (1 << 6)
#define LIBXL_X86_FEATURE_LM_MASK  (1 << 29)

struct guest_arch {
    virArch arch;
    int hvm;
    int pvh;
    int pae;
    int nonpae;
    int ia64_be;
};

#define XEN_CAP_REGEX "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(aarch64|armv7l|x86_32|x86_64|ia64|powerpc64)(p|be)?"

static int
libxlCapsAddCPUID(virCPUData *data, virCPUx86CPUID *cpuid, ssize_t ncaps)
{
    virCPUx86DataItem item = { 0 };
    size_t i;

    item.type = VIR_CPU_X86_DATA_CPUID;
    for (i = 0; i < ncaps; i++) {
        item.data.cpuid = cpuid[i];

        if (virCPUx86DataAdd(data, &item) < 0) {
            VIR_DEBUG("Failed to add CPUID(%x,%x)",
                      cpuid[i].eax_in, cpuid[i].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.
 *
 *              |       Xen >= 4.7     |
 *              ------------------------
 *       word 0 | CPUID.00000001.EDX   |
 *       word 1 | CPUID.00000001.ECX   |
 *       word 2 | CPUID.80000001.EDX   |
 *       word 3 | CPUID.80000001.ECX   |
 *       word 4 | CPUID.0000000D:1.EAX |
 *       word 5 | CPUID.00000007:0.EBX |
 *       word 6 | CPUID.00000007:0.ECX |
 *       word 7 | CPUID.80000007.EDX   |
 *       word 8 | CPUID.80000008.EBX   |
 *
 */
static virCPUData *
libxlCapsNodeData(virCPUDef *cpu, libxl_hwcap hwcap)
{
    ssize_t ncaps;
    virCPUData *cpudata = NULL;
    virCPUx86CPUID cpuid[] = {
        { .eax_in = 0x00000001, .edx = hwcap[0] },
        { .eax_in = 0x00000001, .ecx = hwcap[1] },
        { .eax_in = 0x80000001, .edx = hwcap[2] },
        { .eax_in = 0x80000001, .ecx = hwcap[3] },
        { .eax_in = 0x00000007, .ebx = hwcap[5] },
        { .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] },
    };

    if (!(cpudata = virCPUDataNew(cpu->arch)))
        goto error;

    ncaps = G_N_ELEMENTS(cpuid);
    if (libxlCapsAddCPUID(cpudata, cpuid, ncaps) < 0)
        goto error;

    return cpudata;

 error:
    virCPUDataFree(cpudata);
    return NULL;
}

/* 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(virCaps *caps, libxl_physinfo *phy_info)
{
    virCPUData *data = NULL;
    virCPUDef *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;

    cpu = virCPUDefNew();

    host_pae = phy_info->hw_cap[0] & LIBXL_X86_FEATURE_PAE_MASK;
    if (host_pae &&
        virCapabilitiesAddHostFeature(caps, "pae") < 0)
        goto error;

    host_lm = (phy_info->hw_cap[2] & 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;
    cpu->dies = 1;
    cpu->sockets = phy_info->nr_cpus / (cpu->cores * cpu->threads);

    if (!(data = libxlCapsNodeData(cpu, phy_info->hw_cap)) ||
        cpuDecode(cpu, data, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to initialize host cpu features"));
        goto error;
    }

    caps->host.cpu = cpu;
    ret = 0;

 cleanup:
    virCPUDataFree(data);

    return ret;

 error:
    virCPUDefFree(cpu);
    goto cleanup;
}

static int
libxlCapsInitHost(libxl_ctx *ctx, virCaps *caps)
{
    libxl_physinfo phy_info;
    int ret = -1;

    libxl_physinfo_init(&phy_info);
    if (libxl_get_physinfo(ctx, &phy_info) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to get node physical info from libxenlight"));
        goto cleanup;
    }

    if (libxlCapsInitCPU(caps, &phy_info) < 0)
        goto cleanup;

    if (virCapabilitiesSetNetPrefix(caps, LIBXL_GENERATED_PREFIX_XEN) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    libxl_physinfo_dispose(&phy_info);
    return ret;
}<commit_msg>libxl: refactor libxlCapsInitCPU<commit_after>/*
 * libxl_capabilities.c: libxl capabilities generation
 *
 * Copyright (C) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include <libxl.h>

#include "internal.h"
#include "virlog.h"
#include "virerror.h"
#include "virfile.h"
#include "viralloc.h"
#include "virstring.h"
#include "domain_conf.h"
#include "capabilities.h"
#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

VIR_LOG_INIT("libxl.libxl_capabilities");

/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
#define LIBXL_X86_FEATURE_PAE_MASK (1 << 6)
#define LIBXL_X86_FEATURE_LM_MASK  (1 << 29)

struct guest_arch {
    virArch arch;
    int hvm;
    int pvh;
    int pae;
    int nonpae;
    int ia64_be;
};

#define XEN_CAP_REGEX "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(aarch64|armv7l|x86_32|x86_64|ia64|powerpc64)(p|be)?"

static int
libxlCapsAddCPUID(virCPUData *data, virCPUx86CPUID *cpuid, ssize_t ncaps)
{
    virCPUx86DataItem item = { 0 };
    size_t i;

    item.type = VIR_CPU_X86_DATA_CPUID;
    for (i = 0; i < ncaps; i++) {
        item.data.cpuid = cpuid[i];

        if (virCPUx86DataAdd(data, &item) < 0) {
            VIR_DEBUG("Failed to add CPUID(%x,%x)",
                      cpuid[i].eax_in, cpuid[i].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.
 *
 *              |       Xen >= 4.7     |
 *              ------------------------
 *       word 0 | CPUID.00000001.EDX   |
 *       word 1 | CPUID.00000001.ECX   |
 *       word 2 | CPUID.80000001.EDX   |
 *       word 3 | CPUID.80000001.ECX   |
 *       word 4 | CPUID.0000000D:1.EAX |
 *       word 5 | CPUID.00000007:0.EBX |
 *       word 6 | CPUID.00000007:0.ECX |
 *       word 7 | CPUID.80000007.EDX   |
 *       word 8 | CPUID.80000008.EBX   |
 *
 */
static virCPUData *
libxlCapsNodeData(virCPUDef *cpu, libxl_hwcap hwcap)
{
    ssize_t ncaps;
    virCPUData *cpudata = NULL;
    virCPUx86CPUID cpuid[] = {
        { .eax_in = 0x00000001, .edx = hwcap[0] },
        { .eax_in = 0x00000001, .ecx = hwcap[1] },
        { .eax_in = 0x80000001, .edx = hwcap[2] },
        { .eax_in = 0x80000001, .ecx = hwcap[3] },
        { .eax_in = 0x00000007, .ebx = hwcap[5] },
        { .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] },
    };

    if (!(cpudata = virCPUDataNew(cpu->arch)))
        goto error;

    ncaps = G_N_ELEMENTS(cpuid);
    if (libxlCapsAddCPUID(cpudata, cpuid, ncaps) < 0)
        goto error;

    return cpudata;

 error:
    virCPUDataFree(cpudata);
    return NULL;
}

/* 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(virCaps *caps, libxl_physinfo *phy_info)
{
    g_autoptr(virCPUData) data = NULL;
    g_autoptr(virCPUDef) cpu = NULL;
    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;

    cpu = virCPUDefNew();

    host_pae = phy_info->hw_cap[0] & LIBXL_X86_FEATURE_PAE_MASK;
    if (host_pae &&
        virCapabilitiesAddHostFeature(caps, "pae") < 0)
        return -1;

    host_lm = (phy_info->hw_cap[2] & 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;
    cpu->dies = 1;
    cpu->sockets = phy_info->nr_cpus / (cpu->cores * cpu->threads);

    if (!(data = libxlCapsNodeData(cpu, phy_info->hw_cap)) ||
        cpuDecode(cpu, data, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to initialize host cpu features"));
        return -1;
    }

    caps->host.cpu = g_steal_pointer(&cpu);
    return 0;
}

static int
libxlCapsInitHost(libxl_ctx *ctx, virCaps *caps)
{
    libxl_physinfo phy_info;
    int ret = -1;

    libxl_physinfo_init(&phy_info);
    if (libxl_get_physinfo(ctx, &phy_info) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to get node physical info from libxenlight"));
        goto cleanup;
    }

    if (libxlCapsInitCPU(caps, &phy_info) < 0)
        goto cleanup;

    if (virCapabilitiesSetNetPrefix(caps, LIBXL_GENERATED_PREFIX_XEN) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    libxl_physinfo_dispose(&phy_info);
    return ret;
}
{'fraction_non_alphanumeric': 0.11864818867007051, 'fraction_numerical': 0.04189966772023665, 'mean_word_length': 2.7945879458794587, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 20, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5977563', 'n_tokens_mistral': 4914, 'n_tokens_neox': 4413, 'n_words': 1175}