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) -----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEWjIv1avE09usz9GqKAeTb5hNxaYFAl6GZLYUHGVoYWJrb3N0 QHJlZGhhdC5jb20ACgkQKAeTb5hNxaax6w/+KHD4spxGmKP7EhI2Kp+Jj4IGZHho jkqZAO0npJKGA30bOurHD/wYoBMavBSFPLGtU3TEPnpQunTVdBU0EMlL1wfHSSD4 VzpIaFZVgfpqg8hibvFlcqUkLBfVuZBDJnPR4yPwbcqPlUrfMp/TO0QsP5Ob6r0X 0SNNU6Rr9+XnLRGIALVKLidayjaer/I2tnL3esIxaYKs1g/qZtnQbfSEEI56dlJZ UlyOzmdKJIFWvl/X6N3nshxIS3S/RIh0oMVBlQF3aKRd99KLejaxEkpRl/zzzUJV MOANk6oXQ2XENmKsfNuMPmvMv3ytL/h3ui0/mDUM5yYm/NGFo871h5loybTXm/+F mtaZVf7yJtLtIshuMXeDNiT6McSpWfOguAJL6Vng+tKTNJYDVGPtha05jsuO0/NU 3H4zj7jonUOc7Xmx1EVupOGjwUqfBOYL1MiPQqJmqRtGOxv/C0fNlrEWYkAIKrPH UFGkAaUV2r4mMxQ9fiWeLC/rVN3F7G4iO8Z/ml1IdTt2UcHbdw1y28CNesNZFRfz n11GDW5zrGXPs6LggKvd8iANqXjSmXFbbI1zLvtrIMMX1KeyvstRZXru3WJgXAiW XgyKCCUwaVix27JBBNUQ6GEjBtriP/4ldyCmRRTUjBCSuZQWkqCX59BCP1M9QJgN B9rnT8xelsWTm2I= =o7ft -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
f2a8261110
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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] */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue