Commit f2a82611 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/ehabkost/tags/x86-next-pull-request' into staging



x86 queue for -rc2

Fixes:
* EPYC CPU model APIC ID topology fixes (Babu Moger)
* Fix crash when enabling intel-pt on older machine types
  (Luwei Kang)
* Add missing ARCH_CAPABILITIES bits to Icelake-Server CPU model
  (Xiaoyao Li)

# gpg: Signature made Thu 02 Apr 2020 23:18:30 BST
# gpg:                using RSA key 5A322FD5ABC4D3DBACCFD1AA2807936F984DC5A6
# gpg:                issuer "ehabkost@redhat.com"
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" [full]
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* remotes/ehabkost/tags/x86-next-pull-request:
  target/i386: Add ARCH_CAPABILITIES related bits into Icelake-Server CPU model
  target/i386: set the CPUID level to 0x14 on old machine-type
  i386: Fix pkg_id offset for EPYC cpu models
  target/i386: Enable new apic id encoding for EPYC based cpus models
  hw/i386: Move arch_id decode inside x86_cpus_init
  i386: Introduce use_epyc_apic_id_encoding in X86CPUDefinition
  hw/i386: Introduce apicid functions inside X86MachineState
  target/i386: Cleanup and use the EPYC mode topology functions
  hw/386: Add EPYC mode topology decoding functions

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 5142ca07 d965dc35
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -1526,6 +1526,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,

    env->nr_dies = x86ms->smp_dies;
    env->nr_nodes = topo_info.nodes_per_pkg;
    env->pkg_offset = x86ms->apicid_pkg_offset(&topo_info);

    /*
     * If APIC ID is not set,
@@ -1580,14 +1581,14 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
        topo_ids.die_id = cpu->die_id;
        topo_ids.core_id = cpu->core_id;
        topo_ids.smt_id = cpu->thread_id;
        cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
        cpu->apic_id = x86ms->apicid_from_topo_ids(&topo_info, &topo_ids);
    }

    cpu_slot = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
    if (!cpu_slot) {
        MachineState *ms = MACHINE(pcms);

        x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
        x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
        error_setg(errp,
            "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
            " APIC ID %" PRIu32 ", valid index range 0:%d",
@@ -1608,7 +1609,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
    /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
     * once -smp refactoring is complete and there will be CPU private
     * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
    x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
    x86ms->topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
    if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
        error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
            " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
+35 −7
Original line number Diff line number Diff line
@@ -68,6 +68,22 @@ inline void init_topo_info(X86CPUTopoInfo *topo_info,
    topo_info->threads_per_core = ms->smp.threads;
}

/*
 * Set up with the new EPYC topology handlers
 *
 * AMD uses different apic id encoding for EPYC based cpus. Override
 * the default topo handlers with EPYC encoding handlers.
 */
static void x86_set_epyc_topo_handlers(MachineState *machine)
{
    X86MachineState *x86ms = X86_MACHINE(machine);

    x86ms->apicid_from_cpu_idx = x86_apicid_from_cpu_idx_epyc;
    x86ms->topo_ids_from_apicid = x86_topo_ids_from_apicid_epyc;
    x86ms->apicid_from_topo_ids = x86_apicid_from_topo_ids_epyc;
    x86ms->apicid_pkg_offset = apicid_pkg_offset_epyc;
}

/*
 * Calculates initial APIC ID for a specific CPU index
 *
@@ -86,7 +102,7 @@ uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms,

    init_topo_info(&topo_info, x86ms);

    correct_id = x86_apicid_from_cpu_idx(&topo_info, cpu_index);
    correct_id = x86ms->apicid_from_cpu_idx(&topo_info, cpu_index);
    if (x86mc->compat_apic_id_mode) {
        if (cpu_index != correct_id && !warned && !qtest_enabled()) {
            error_report("APIC IDs set in compatibility mode, "
@@ -121,6 +137,11 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
    MachineState *ms = MACHINE(x86ms);
    MachineClass *mc = MACHINE_GET_CLASS(x86ms);

    /* Check for apicid encoding */
    if (cpu_x86_use_epyc_apic_id_encoding(ms->cpu_type)) {
        x86_set_epyc_topo_handlers(ms);
    }

    x86_cpu_set_default_version(default_cpu_version);

    /*
@@ -134,6 +155,12 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
    x86ms->apic_id_limit = x86_cpu_apic_id_from_index(x86ms,
                                                      ms->smp.max_cpus - 1) + 1;
    possible_cpus = mc->possible_cpu_arch_ids(ms);

    for (i = 0; i < ms->possible_cpus->len; i++) {
        ms->possible_cpus->cpus[i].arch_id =
            x86_cpu_apic_id_from_index(x86ms, i);
    }

    for (i = 0; i < ms->smp.cpus; i++) {
        x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal);
    }
@@ -158,8 +185,7 @@ int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx)
   init_topo_info(&topo_info, x86ms);

   assert(idx < ms->possible_cpus->len);
   x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id,
                            &topo_info, &topo_ids);
   x86_topo_ids_from_idx(&topo_info, idx, &topo_ids);
   return topo_ids.pkg_id % ms->numa_state->num_nodes;
}

@@ -190,10 +216,7 @@ const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms)

        ms->possible_cpus->cpus[i].type = ms->cpu_type;
        ms->possible_cpus->cpus[i].vcpus_count = 1;
        ms->possible_cpus->cpus[i].arch_id =
            x86_cpu_apic_id_from_index(x86ms, i);
        x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id,
                                 &topo_info, &topo_ids);
        x86_topo_ids_from_idx(&topo_info, i, &topo_ids);
        ms->possible_cpus->cpus[i].props.has_socket_id = true;
        ms->possible_cpus->cpus[i].props.socket_id = topo_ids.pkg_id;
        if (x86ms->smp_dies > 1) {
@@ -937,6 +960,11 @@ static void x86_machine_initfn(Object *obj)
    x86ms->acpi = ON_OFF_AUTO_AUTO;
    x86ms->max_ram_below_4g = 0; /* use default */
    x86ms->smp_dies = 1;

    x86ms->apicid_from_cpu_idx = x86_apicid_from_cpu_idx;
    x86ms->topo_ids_from_apicid = x86_topo_ids_from_apicid;
    x86ms->apicid_from_topo_ids = x86_apicid_from_topo_ids;
    x86ms->apicid_pkg_offset = apicid_pkg_offset;
}

static void x86_machine_class_init(ObjectClass *oc, void *data)
+100 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ typedef uint32_t apic_id_t;

typedef struct X86CPUTopoIDs {
    unsigned pkg_id;
    unsigned node_id;
    unsigned die_id;
    unsigned core_id;
    unsigned smt_id;
@@ -88,6 +89,11 @@ static inline unsigned apicid_die_width(X86CPUTopoInfo *topo_info)
    return apicid_bitwidth_for_count(topo_info->dies_per_pkg);
}

/* Bit width of the node_id field per socket */
static inline unsigned apicid_node_width_epyc(X86CPUTopoInfo *topo_info)
{
    return apicid_bitwidth_for_count(MAX(topo_info->nodes_per_pkg, 1));
}
/* Bit offset of the Core_ID field
 */
static inline unsigned apicid_core_offset(X86CPUTopoInfo *topo_info)
@@ -108,6 +114,100 @@ static inline unsigned apicid_pkg_offset(X86CPUTopoInfo *topo_info)
    return apicid_die_offset(topo_info) + apicid_die_width(topo_info);
}

#define NODE_ID_OFFSET 3 /* Minimum node_id offset if numa configured */

/*
 * Bit offset of the node_id field
 *
 * Make sure nodes_per_pkg >  0 if numa configured else zero.
 */
static inline unsigned apicid_node_offset_epyc(X86CPUTopoInfo *topo_info)
{
    unsigned offset = apicid_die_offset(topo_info) +
                      apicid_die_width(topo_info);

    if (topo_info->nodes_per_pkg) {
        return MAX(NODE_ID_OFFSET, offset);
    } else {
        return offset;
    }
}

/* Bit offset of the Pkg_ID (socket ID) field */
static inline unsigned apicid_pkg_offset_epyc(X86CPUTopoInfo *topo_info)
{
    return apicid_node_offset_epyc(topo_info) +
           apicid_node_width_epyc(topo_info);
}

/*
 * Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID
 *
 * The caller must make sure core_id < nr_cores and smt_id < nr_threads.
 */
static inline apic_id_t
x86_apicid_from_topo_ids_epyc(X86CPUTopoInfo *topo_info,
                              const X86CPUTopoIDs *topo_ids)
{
    return (topo_ids->pkg_id  << apicid_pkg_offset_epyc(topo_info)) |
           (topo_ids->node_id << apicid_node_offset_epyc(topo_info)) |
           (topo_ids->die_id  << apicid_die_offset(topo_info)) |
           (topo_ids->core_id << apicid_core_offset(topo_info)) |
           topo_ids->smt_id;
}

static inline void x86_topo_ids_from_idx_epyc(X86CPUTopoInfo *topo_info,
                                              unsigned cpu_index,
                                              X86CPUTopoIDs *topo_ids)
{
    unsigned nr_nodes = MAX(topo_info->nodes_per_pkg, 1);
    unsigned nr_dies = topo_info->dies_per_pkg;
    unsigned nr_cores = topo_info->cores_per_die;
    unsigned nr_threads = topo_info->threads_per_core;
    unsigned cores_per_node = DIV_ROUND_UP((nr_dies * nr_cores * nr_threads),
                                            nr_nodes);

    topo_ids->pkg_id = cpu_index / (nr_dies * nr_cores * nr_threads);
    topo_ids->node_id = (cpu_index / cores_per_node) % nr_nodes;
    topo_ids->die_id = cpu_index / (nr_cores * nr_threads) % nr_dies;
    topo_ids->core_id = cpu_index / nr_threads % nr_cores;
    topo_ids->smt_id = cpu_index % nr_threads;
}

/*
 * Calculate thread/core/package IDs for a specific topology,
 * based on APIC ID
 */
static inline void x86_topo_ids_from_apicid_epyc(apic_id_t apicid,
                                            X86CPUTopoInfo *topo_info,
                                            X86CPUTopoIDs *topo_ids)
{
    topo_ids->smt_id = apicid &
            ~(0xFFFFFFFFUL << apicid_smt_width(topo_info));
    topo_ids->core_id =
            (apicid >> apicid_core_offset(topo_info)) &
            ~(0xFFFFFFFFUL << apicid_core_width(topo_info));
    topo_ids->die_id =
            (apicid >> apicid_die_offset(topo_info)) &
            ~(0xFFFFFFFFUL << apicid_die_width(topo_info));
    topo_ids->node_id =
            (apicid >> apicid_node_offset_epyc(topo_info)) &
            ~(0xFFFFFFFFUL << apicid_node_width_epyc(topo_info));
    topo_ids->pkg_id = apicid >> apicid_pkg_offset_epyc(topo_info);
}

/*
 * Make APIC ID for the CPU 'cpu_index'
 *
 * 'cpu_index' is a sequential, contiguous ID for the CPU.
 */
static inline apic_id_t x86_apicid_from_cpu_idx_epyc(X86CPUTopoInfo *topo_info,
                                                     unsigned cpu_index)
{
    X86CPUTopoIDs topo_ids;
    x86_topo_ids_from_idx_epyc(topo_info, cpu_index, &topo_ids);
    return x86_apicid_from_topo_ids_epyc(topo_info, &topo_ids);
}
/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID
 *
 * The caller must make sure core_id < nr_cores and smt_id < nr_threads.
+9 −0
Original line number Diff line number Diff line
@@ -66,6 +66,15 @@ typedef struct {
    OnOffAuto smm;
    OnOffAuto acpi;

    /* Apic id specific handlers */
    uint32_t (*apicid_from_cpu_idx)(X86CPUTopoInfo *topo_info,
                                    unsigned cpu_index);
    void (*topo_ids_from_apicid)(apic_id_t apicid, X86CPUTopoInfo *topo_info,
                                 X86CPUTopoIDs *topo_ids);
    apic_id_t (*apicid_from_topo_ids)(X86CPUTopoInfo *topo_info,
                                      const X86CPUTopoIDs *topo_ids);
    uint32_t (*apicid_pkg_offset)(X86CPUTopoInfo *topo_info);

    /*
     * Address space used by IOAPIC device. All IOAPIC interrupts
     * will be translated to MSI messages in the address space.
+75 −132
Original line number Diff line number Diff line
@@ -338,68 +338,15 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2,
    }
}

/*
 * Definitions used for building CPUID Leaf 0x8000001D and 0x8000001E
 * Please refer to the AMD64 Architecture Programmer’s Manual Volume 3.
 * Define the constants to build the cpu topology. Right now, TOPOEXT
 * feature is enabled only on EPYC. So, these constants are based on
 * EPYC supported configurations. We may need to handle the cases if
 * these values change in future.
 */
/* Maximum core complexes in a node */
#define MAX_CCX 2
/* Maximum cores in a core complex */
#define MAX_CORES_IN_CCX 4
/* Maximum cores in a node */
#define MAX_CORES_IN_NODE 8
/* Maximum nodes in a socket */
#define MAX_NODES_PER_SOCKET 4

/*
 * Figure out the number of nodes required to build this config.
 * Max cores in a node is 8
 */
static int nodes_in_socket(int nr_cores)
{
    int nodes;

    nodes = DIV_ROUND_UP(nr_cores, MAX_CORES_IN_NODE);

   /* Hardware does not support config with 3 nodes, return 4 in that case */
    return (nodes == 3) ? 4 : nodes;
}

/*
 * Decide the number of cores in a core complex with the given nr_cores using
 * following set constants MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE and
 * MAX_NODES_PER_SOCKET. Maintain symmetry as much as possible
 * L3 cache is shared across all cores in a core complex. So, this will also
 * tell us how many cores are sharing the L3 cache.
 */
static int cores_in_core_complex(int nr_cores)
{
    int nodes;

    /* Check if we can fit all the cores in one core complex */
    if (nr_cores <= MAX_CORES_IN_CCX) {
        return nr_cores;
    }
    /* Get the number of nodes required to build this config */
    nodes = nodes_in_socket(nr_cores);

    /*
     * Divide the cores accros all the core complexes
     * Return rounded up value
     */
    return DIV_ROUND_UP(nr_cores, nodes * MAX_CCX);
}

/* Encode cache info for CPUID[8000001D] */
static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs,
static void encode_cache_cpuid8000001d(CPUCacheInfo *cache,
                                       X86CPUTopoInfo *topo_info,
                                       uint32_t *eax, uint32_t *ebx,
                                       uint32_t *ecx, uint32_t *edx)
{
    uint32_t l3_cores;
    unsigned nodes = MAX(topo_info->nodes_per_pkg, 1);

    assert(cache->size == cache->line_size * cache->associativity *
                          cache->partitions * cache->sets);

@@ -408,10 +355,13 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs,

    /* L3 is shared among multiple cores */
    if (cache->level == 3) {
        l3_cores = cores_in_core_complex(cs->nr_cores);
        *eax |= ((l3_cores * cs->nr_threads) - 1) << 14;
        l3_cores = DIV_ROUND_UP((topo_info->dies_per_pkg *
                                 topo_info->cores_per_die *
                                 topo_info->threads_per_core),
                                 nodes);
        *eax |= (l3_cores - 1) << 14;
    } else {
        *eax |= ((cs->nr_threads - 1) << 14);
        *eax |= ((topo_info->threads_per_core - 1) << 14);
    }

    assert(cache->line_size > 0);
@@ -431,55 +381,17 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs,
           (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0);
}

/* Data structure to hold the configuration info for a given core index */
struct core_topology {
    /* core complex id of the current core index */
    int ccx_id;
    /*
     * Adjusted core index for this core in the topology
     * This can be 0,1,2,3 with max 4 cores in a core complex
     */
    int core_id;
    /* Node id for this core index */
    int node_id;
    /* Number of nodes in this config */
    int num_nodes;
};

/*
 * Build the configuration closely match the EPYC hardware. Using the EPYC
 * hardware configuration values (MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE)
 * right now. This could change in future.
 * nr_cores : Total number of cores in the config
 * core_id  : Core index of the current CPU
 * topo     : Data structure to hold all the config info for this core index
 */
static void build_core_topology(int nr_cores, int core_id,
                                struct core_topology *topo)
{
    int nodes, cores_in_ccx;

    /* First get the number of nodes required */
    nodes = nodes_in_socket(nr_cores);

    cores_in_ccx = cores_in_core_complex(nr_cores);

    topo->node_id = core_id / (cores_in_ccx * MAX_CCX);
    topo->ccx_id = (core_id % (cores_in_ccx * MAX_CCX)) / cores_in_ccx;
    topo->core_id = core_id % cores_in_ccx;
    topo->num_nodes = nodes;
}

/* Encode cache info for CPUID[8000001E] */
static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu,
static void encode_topo_cpuid8000001e(X86CPUTopoInfo *topo_info, X86CPU *cpu,
                                       uint32_t *eax, uint32_t *ebx,
                                       uint32_t *ecx, uint32_t *edx)
{
    struct core_topology topo = {0};
    unsigned long nodes;
    X86CPUTopoIDs topo_ids = {0};
    unsigned long nodes = MAX(topo_info->nodes_per_pkg, 1);
    int shift;

    build_core_topology(cs->nr_cores, cpu->core_id, &topo);
    x86_topo_ids_from_apicid_epyc(cpu->apic_id, topo_info, &topo_ids);

    *eax = cpu->apic_id;
    /*
     * CPUID_Fn8000001E_EBX
@@ -496,12 +408,8 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu,
     *             3 Core complex id
     *           1:0 Core id
     */
    if (cs->nr_threads - 1) {
        *ebx = ((cs->nr_threads - 1) << 8) | (topo.node_id << 3) |
                (topo.ccx_id << 2) | topo.core_id;
    } else {
        *ebx = (topo.node_id << 4) | (topo.ccx_id << 3) | topo.core_id;
    }
    *ebx = ((topo_info->threads_per_core - 1) << 8) | (topo_ids.node_id << 3) |
            (topo_ids.core_id);
    /*
     * CPUID_Fn8000001E_ECX
     * 31:11 Reserved
@@ -510,9 +418,8 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu,
     *         2  Socket id
     *       1:0  Node id
     */
    if (topo.num_nodes <= 4) {
        *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) |
                topo.node_id;
    if (nodes <= 4) {
        *ecx = ((nodes - 1) << 8) | (topo_ids.pkg_id << 2) | topo_ids.node_id;
    } else {
        /*
         * Node id fix up. Actual hardware supports up to 4 nodes. But with
@@ -527,10 +434,10 @@ static void encode_topo_cpuid8000001e(CPUState *cs, X86CPU *cpu,
         * number of nodes. find_last_bit returns last set bit(0 based). Left
         * shift(+1) the socket id to represent all the nodes.
         */
        nodes = topo.num_nodes - 1;
        nodes -= 1;
        shift = find_last_bit(&nodes, 8);
        *ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << (shift + 1)) |
                topo.node_id;
        *ecx = (nodes << 8) | (topo_ids.pkg_id << (shift + 1)) |
               topo_ids.node_id;
    }
    *edx = 0;
}
@@ -1707,6 +1614,10 @@ typedef struct X86CPUDefinition {
    FeatureWordArray features;
    const char *model_id;
    CPUCaches *cache_info;

    /* Use AMD EPYC encoding for apic id */
    bool use_epyc_apic_id_encoding;

    /*
     * Definitions for alternative versions of CPU model.
     * List is terminated by item with version == 0.
@@ -1748,6 +1659,18 @@ static const X86CPUVersionDefinition *x86_cpu_def_get_versions(X86CPUDefinition
    return def->versions ?: default_version_list;
}

bool cpu_x86_use_epyc_apic_id_encoding(const char *cpu_type)
{
    X86CPUClass *xcc = X86_CPU_CLASS(object_class_by_name(cpu_type));

    assert(xcc);
    if (xcc->model && xcc->model->cpudef) {
        return xcc->model->cpudef->use_epyc_apic_id_encoding;
    } else {
        return false;
    }
}

static CPUCaches epyc_cache_info = {
    .l1d_cache = &(CPUCacheInfo) {
        .type = DATA_CACHE,
@@ -3548,6 +3471,19 @@ static X86CPUDefinition builtin_x86_defs[] = {
                    { /* end of list */ }
                },
            },
            {
                .version = 3,
                .props = (PropValue[]) {
                    { "arch-capabilities", "on" },
                    { "rdctl-no", "on" },
                    { "ibrs-all", "on" },
                    { "skip-l1dfl-vmentry", "on" },
                    { "mds-no", "on" },
                    { "pschange-mc-no", "on" },
                    { "taa-no", "on" },
                    { /* end of list */ }
                },
            },
            { /* end of list */ }
        }
    },
@@ -4002,6 +3938,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
        .xlevel = 0x8000001E,
        .model_id = "AMD EPYC Processor",
        .cache_info = &epyc_cache_info,
        .use_epyc_apic_id_encoding = 1,
        .versions = (X86CPUVersionDefinition[]) {
            { .version = 1 },
            {
@@ -4129,6 +4066,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
        .xlevel = 0x8000001E,
        .model_id = "AMD EPYC-Rome Processor",
        .cache_info = &epyc_rome_cache_info,
        .use_epyc_apic_id_encoding = 1,
    },
};

@@ -5499,6 +5437,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
    uint32_t signature[3];
    X86CPUTopoInfo topo_info;

    topo_info.nodes_per_pkg = env->nr_nodes;
    topo_info.dies_per_pkg = env->nr_dies;
    topo_info.cores_per_die = cs->nr_cores;
    topo_info.threads_per_core = cs->nr_threads;
@@ -5684,7 +5623,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
            *ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
            break;
        case 1:
            *eax = apicid_pkg_offset(&topo_info);
            *eax = env->pkg_offset;
            *ebx = cs->nr_cores * cs->nr_threads;
            *ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
            break;
@@ -5718,7 +5657,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
            *ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
            break;
        case 2:
            *eax = apicid_pkg_offset(&topo_info);
            *eax = env->pkg_offset;
            *ebx = env->nr_dies * cs->nr_cores * cs->nr_threads;
            *ecx |= CPUID_TOPOLOGY_LEVEL_DIE;
            break;
@@ -5918,20 +5857,20 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
        }
        switch (count) {
        case 0: /* L1 dcache info */
            encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, cs,
                                       eax, ebx, ecx, edx);
            encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache,
                                       &topo_info, eax, ebx, ecx, edx);
            break;
        case 1: /* L1 icache info */
            encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache, cs,
                                       eax, ebx, ecx, edx);
            encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache,
                                       &topo_info, eax, ebx, ecx, edx);
            break;
        case 2: /* L2 cache info */
            encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache, cs,
                                       eax, ebx, ecx, edx);
            encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache,
                                       &topo_info, eax, ebx, ecx, edx);
            break;
        case 3: /* L3 cache info */
            encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache, cs,
                                       eax, ebx, ecx, edx);
            encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache,
                                       &topo_info, eax, ebx, ecx, edx);
            break;
        default: /* end of info */
            *eax = *ebx = *ecx = *edx = 0;
@@ -5940,8 +5879,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
        break;
    case 0x8000001E:
        assert(cpu->core_id <= 255);
        encode_topo_cpuid8000001e(cs, cpu,
                                  eax, ebx, ecx, edx);
        encode_topo_cpuid8000001e(&topo_info, cpu, eax, ebx, ecx, edx);
        break;
    case 0xC0000000:
        *eax = env->cpuid_xlevel2;
@@ -6431,9 +6369,14 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
        x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE);

        /* Intel Processor Trace requires CPUID[0x14] */
        if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
             kvm_enabled() && cpu->intel_pt_auto_level) {
        if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT)) {
            if (cpu->intel_pt_auto_level) {
                x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14);
            } else if (cpu->env.cpuid_min_level < 0x14) {
                mark_unavailable_features(cpu, FEAT_7_0_EBX,
                    CPUID_7_0_EBX_INTEL_PT,
                    "Intel PT need CPUID leaf 0x14, please set by \"-cpu ...,+intel-pt,level=0x14\"");
            }
        }

        /* CPU topology with multi-dies support requires CPUID[0x1F] */
Loading