i386: Add support for CPUID_8000_001E for AMD

Add support for cpuid leaf CPUID_8000_001E. Build the config that closely
match the underlying hardware. Please refer to the Processor Programming
Reference (PPR) for AMD Family 17h Model for more details.

Backports commit ed78467a214595a63af7800a073a03ffe37cd7db from qemu
This commit is contained in:
Babu Moger 2018-07-02 23:06:44 -04:00 committed by Lioncash
parent b27996c799
commit c07a5c06e7
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -416,6 +416,87 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs,
(cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); (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,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
struct core_topology topo = {0};
build_core_topology(cs->nr_cores, cpu->core_id, &topo);
*eax = cpu->apic_id;
/*
* CPUID_Fn8000001E_EBX
* 31:16 Reserved
* 15:8 Threads per core (The number of threads per core is
* Threads per core + 1)
* 7:0 Core id (see bit decoding below)
* SMT:
* 4:3 node id
* 2 Core complex id
* 1:0 Core id
* Non SMT:
* 5:4 node id
* 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;
}
/*
* CPUID_Fn8000001E_ECX
* 31:11 Reserved
* 10:8 Nodes per processor (Nodes per processor is number of nodes + 1)
* 7:0 Node id (see bit decoding below)
* 2 Socket id
* 1:0 Node id
*/
*ecx = ((topo.num_nodes - 1) << 8) | (cpu->socket_id << 2) | topo.node_id;
*edx = 0;
}
/* /*
* Definitions of the hardcoded cache entries we expose: * Definitions of the hardcoded cache entries we expose:
* These are legacy cache values. If there is a need to change any * These are legacy cache values. If there is a need to change any
@ -4119,6 +4200,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break; break;
} }
break; break;
case 0x8000001E:
assert(cpu->core_id <= 255);
encode_topo_cpuid8000001e(cs, cpu,
eax, ebx, ecx, edx);
break;
case 0xC0000000: case 0xC0000000:
*eax = env->cpuid_xlevel2; *eax = env->cpuid_xlevel2;
*ebx = 0; *ebx = 0;