diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-04-03 10:07:27 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-04-03 10:07:27 +0100 |
commit | f2a8261110c32c4dccd84e774d8dd7a0524e00fb (patch) | |
tree | 88c62d86316132f701dc2f181cae437fa90e2e40 /target | |
parent | 5142ca078d1cbc0f77b0f385d28cdb3e504e62bd (diff) | |
parent | d965dc35592d24c0c1519f1c566223c6277cb80e (diff) | |
download | qemu-f2a8261110c32c4dccd84e774d8dd7a0524e00fb.zip qemu-f2a8261110c32c4dccd84e774d8dd7a0524e00fb.tar.gz qemu-f2a8261110c32c4dccd84e774d8dd7a0524e00fb.tar.bz2 |
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: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/i386/cpu.c | 207 | ||||
-rw-r--r-- | target/i386/cpu.h | 2 |
2 files changed, 77 insertions, 132 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 34b511f..90ffc5f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -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, - uint32_t *eax, uint32_t *ebx, - uint32_t *ecx, uint32_t *edx) +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) { - x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14); + 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] */ diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9af1b0c..e818fc7 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1610,6 +1610,7 @@ typedef struct CPUX86State { unsigned nr_dies; unsigned nr_nodes; + unsigned pkg_offset; } CPUX86State; struct kvm_msrs; @@ -1897,6 +1898,7 @@ void cpu_clear_apic_feature(CPUX86State *env); void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); void host_vendor_fms(char *vendor, int *family, int *model, int *stepping); +bool cpu_x86_use_epyc_apic_id_encoding(const char *cpu_type); /* helper.c */ bool x86_cpu_tlb_fill(CPUState *cs, vaddr address, int size, |