* hw/i386/pc_sysfw: Alias rather than copy isa-bios region
* target/i386: add control bits support for LAM * target/i386: tweaks to new translator * target/i386: add support for LAM in CPUID enumeration * hw/i386/pc: Support smp.modules for x86 PC machine * target-i386: hyper-v: Correct kvm_hv_handle_exit return value -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmZOMlAUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroNTSwf8DOPgipepNcsxUQoV9nOBfNXqEWa6 DilQGwuu/3eMSPITUCGKVrtLR5azwCwvNfYYErVBPVIhjImnk3XHwfKpH1csadgq 7Np8WGjAyKEIP/yC/K1VwsanFHv3hmC6jfcO3ZnsnlmbHsRINbvU9uMlFuiQkKJG lP/dSUcTVhwLT6eFr9DVDUnq4Nh7j3saY85pZUoDclobpeRLaEAYrawha1/0uQpc g7MZYsxT3sg9PIHlM+flpRvJNPz/ZDBdj4raN1xo4q0ET0KRLni6oEOVs5GpTY1R t4O8a/IYkxeI15K9U7i0HwYI2wVwKZbHgp9XPMYVZFJdKBGT8bnF56pV9A== =lp7q -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * hw/i386/pc_sysfw: Alias rather than copy isa-bios region * target/i386: add control bits support for LAM * target/i386: tweaks to new translator * target/i386: add support for LAM in CPUID enumeration * hw/i386/pc: Support smp.modules for x86 PC machine * target-i386: hyper-v: Correct kvm_hv_handle_exit return value # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmZOMlAUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroNTSwf8DOPgipepNcsxUQoV9nOBfNXqEWa6 # DilQGwuu/3eMSPITUCGKVrtLR5azwCwvNfYYErVBPVIhjImnk3XHwfKpH1csadgq # 7Np8WGjAyKEIP/yC/K1VwsanFHv3hmC6jfcO3ZnsnlmbHsRINbvU9uMlFuiQkKJG # lP/dSUcTVhwLT6eFr9DVDUnq4Nh7j3saY85pZUoDclobpeRLaEAYrawha1/0uQpc # g7MZYsxT3sg9PIHlM+flpRvJNPz/ZDBdj4raN1xo4q0ET0KRLni6oEOVs5GpTY1R # t4O8a/IYkxeI15K9U7i0HwYI2wVwKZbHgp9XPMYVZFJdKBGT8bnF56pV9A== # =lp7q # -----END PGP SIGNATURE----- # gpg: Signature made Wed 22 May 2024 10:58:40 AM PDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (23 commits) target-i386: hyper-v: Correct kvm_hv_handle_exit return value i386/cpu: Use CPUCacheInfo.share_level to encode CPUID[0x8000001D].EAX[bits 25:14] i386/cpu: Use CPUCacheInfo.share_level to encode CPUID[4] i386: Add cache topology info in CPUCacheInfo hw/i386/pc: Support smp.modules for x86 PC machine tests: Add test case of APIC ID for module level parsing i386/cpu: Introduce module-id to X86CPU i386: Support module_id in X86CPUTopoIDs i386: Expose module level in CPUID[0x1F] i386: Support modules_per_die in X86CPUTopoInfo i386: Introduce module level cpu topology to CPUX86State i386/cpu: Decouple CPUID[0x1F] subleaf with specific topology level i386: Split topology types of CPUID[0x1F] from the definitions of CPUID[0xB] i386/cpu: Introduce bitmap to cache available CPU topology levels i386/cpu: Consolidate the use of topo_info in cpu_x86_cpuid() i386/cpu: Use APIC ID info get NumSharingCache for CPUID[0x8000001D].EAX[bits 25:14] i386/cpu: Use APIC ID info to encode cache topo in CPUID[4] i386/cpu: Fix i/d-cache topology to core level for Intel CPU target/i386: add control bits support for LAM target/i386: add support for LAM in CPUID enumeration ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
7b68a5fe2f
@ -79,6 +79,7 @@
|
||||
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
|
||||
|
||||
GlobalProperty pc_compat_9_0[] = {
|
||||
{ TYPE_X86_CPU, "x-l1-cache-per-thread", "false" },
|
||||
{ TYPE_X86_CPU, "guest-phys-bits", "0" },
|
||||
{ "sev-guest", "legacy-vm-type", "true" },
|
||||
{ TYPE_X86_CPU, "legacy-multi-node", "on" },
|
||||
@ -1816,6 +1817,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||
pcmc->has_reserved_memory = true;
|
||||
pcmc->enforce_aligned_dimm = true;
|
||||
pcmc->enforce_amd_1tb_hole = true;
|
||||
pcmc->isa_bios_alias = true;
|
||||
/* BIOS ACPI tables: 128K. Other BIOS datastructures: less than 4K reported
|
||||
* to be used at the moment, 32K should be enough for a while. */
|
||||
pcmc->acpi_data_size = 0x20000 + 0x8000;
|
||||
@ -1841,6 +1843,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
|
||||
mc->nvdimm_supported = true;
|
||||
mc->smp_props.dies_supported = true;
|
||||
mc->smp_props.modules_supported = true;
|
||||
mc->default_ram_id = "pc.ram";
|
||||
pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_AUTO;
|
||||
|
||||
|
@ -526,12 +526,15 @@ DEFINE_I440FX_MACHINE(v9_1, "pc-i440fx-9.1", NULL,
|
||||
|
||||
static void pc_i440fx_9_0_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
|
||||
pc_i440fx_9_1_machine_options(m);
|
||||
m->alias = NULL;
|
||||
m->is_default = false;
|
||||
|
||||
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
|
||||
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
|
||||
pcmc->isa_bios_alias = false;
|
||||
}
|
||||
|
||||
DEFINE_I440FX_MACHINE(v9_0, "pc-i440fx-9.0", NULL,
|
||||
|
@ -378,10 +378,12 @@ DEFINE_Q35_MACHINE(v9_1, "pc-q35-9.1", NULL,
|
||||
|
||||
static void pc_q35_9_0_machine_options(MachineClass *m)
|
||||
{
|
||||
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
|
||||
pc_q35_9_1_machine_options(m);
|
||||
m->alias = NULL;
|
||||
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
|
||||
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
|
||||
pcmc->isa_bios_alias = false;
|
||||
}
|
||||
|
||||
DEFINE_Q35_MACHINE(v9_0, "pc-q35-9.0", NULL,
|
||||
|
@ -135,6 +135,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
|
||||
MemoryRegion *rom_memory)
|
||||
{
|
||||
X86MachineState *x86ms = X86_MACHINE(pcms);
|
||||
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
||||
hwaddr total_size = 0;
|
||||
int i;
|
||||
BlockBackend *blk;
|
||||
@ -184,7 +185,12 @@ static void pc_system_flash_map(PCMachineState *pcms,
|
||||
|
||||
if (i == 0) {
|
||||
flash_mem = pflash_cfi01_get_memory(system_flash);
|
||||
pc_isa_bios_init(&x86ms->isa_bios, rom_memory, flash_mem);
|
||||
if (pcmc->isa_bios_alias) {
|
||||
x86_isa_bios_init(&x86ms->isa_bios, rom_memory, flash_mem,
|
||||
true);
|
||||
} else {
|
||||
pc_isa_bios_init(&x86ms->isa_bios, rom_memory, flash_mem);
|
||||
}
|
||||
|
||||
/* Encrypt the pflash boot ROM */
|
||||
if (sev_enabled()) {
|
||||
|
@ -271,16 +271,21 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
|
||||
init_topo_info(&topo_info, x86ms);
|
||||
|
||||
env->nr_dies = ms->smp.dies;
|
||||
if (ms->smp.modules > 1) {
|
||||
env->nr_modules = ms->smp.modules;
|
||||
set_bit(CPU_TOPO_LEVEL_MODULE, env->avail_cpu_topo);
|
||||
}
|
||||
|
||||
if (ms->smp.dies > 1) {
|
||||
env->nr_dies = ms->smp.dies;
|
||||
set_bit(CPU_TOPO_LEVEL_DIE, env->avail_cpu_topo);
|
||||
}
|
||||
|
||||
/*
|
||||
* If APIC ID is not set,
|
||||
* set it based on socket/die/core/thread properties.
|
||||
* set it based on socket/die/module/core/thread properties.
|
||||
*/
|
||||
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
|
||||
int max_socket = (ms->smp.max_cpus - 1) /
|
||||
smp_threads / smp_cores / ms->smp.dies;
|
||||
|
||||
/*
|
||||
* die-id was optional in QEMU 4.0 and older, so keep it optional
|
||||
* if there's only one die per socket.
|
||||
@ -289,12 +294,20 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
cpu->die_id = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* module-id was optional in QEMU 9.0 and older, so keep it optional
|
||||
* if there's only one module per die.
|
||||
*/
|
||||
if (cpu->module_id < 0 && ms->smp.modules == 1) {
|
||||
cpu->module_id = 0;
|
||||
}
|
||||
|
||||
if (cpu->socket_id < 0) {
|
||||
error_setg(errp, "CPU socket-id is not set");
|
||||
return;
|
||||
} else if (cpu->socket_id > max_socket) {
|
||||
} else if (cpu->socket_id > ms->smp.sockets - 1) {
|
||||
error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
|
||||
cpu->socket_id, max_socket);
|
||||
cpu->socket_id, ms->smp.sockets - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->die_id < 0) {
|
||||
@ -305,6 +318,14 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
cpu->die_id, ms->smp.dies - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->module_id < 0) {
|
||||
error_setg(errp, "CPU module-id is not set");
|
||||
return;
|
||||
} else if (cpu->module_id > ms->smp.modules - 1) {
|
||||
error_setg(errp, "Invalid CPU module-id: %u must be in range 0:%u",
|
||||
cpu->module_id, ms->smp.modules - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->core_id < 0) {
|
||||
error_setg(errp, "CPU core-id is not set");
|
||||
return;
|
||||
@ -324,6 +345,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
|
||||
topo_ids.pkg_id = cpu->socket_id;
|
||||
topo_ids.die_id = cpu->die_id;
|
||||
topo_ids.module_id = cpu->module_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);
|
||||
@ -332,11 +354,13 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
|
||||
if (!cpu_slot) {
|
||||
x86_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",
|
||||
topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
|
||||
cpu->apic_id, ms->possible_cpus->len - 1);
|
||||
"Invalid CPU [socket: %u, die: %u, module: %u, core: %u, thread: %u]"
|
||||
" with APIC ID %" PRIu32 ", valid index range 0:%d",
|
||||
topo_ids.pkg_id, topo_ids.die_id, topo_ids.module_id,
|
||||
topo_ids.core_id, topo_ids.smt_id, cpu->apic_id,
|
||||
ms->possible_cpus->len - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -368,6 +392,14 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
}
|
||||
cpu->die_id = topo_ids.die_id;
|
||||
|
||||
if (cpu->module_id != -1 && cpu->module_id != topo_ids.module_id) {
|
||||
error_setg(errp, "property module-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (module-id: %u)", cpu->module_id, cpu->apic_id,
|
||||
topo_ids.module_id);
|
||||
return;
|
||||
}
|
||||
cpu->module_id = topo_ids.module_id;
|
||||
|
||||
if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
|
||||
error_setg(errp, "property core-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
|
||||
|
@ -45,7 +45,14 @@ void init_topo_info(X86CPUTopoInfo *topo_info,
|
||||
MachineState *ms = MACHINE(x86ms);
|
||||
|
||||
topo_info->dies_per_pkg = ms->smp.dies;
|
||||
topo_info->cores_per_die = ms->smp.cores;
|
||||
/*
|
||||
* Though smp.modules means the number of modules in one cluster,
|
||||
* i386 doesn't support cluster level so that the smp.clusters
|
||||
* always defaults to 1, therefore using smp.modules directly is
|
||||
* fine here.
|
||||
*/
|
||||
topo_info->modules_per_die = ms->smp.modules;
|
||||
topo_info->cores_per_module = ms->smp.cores;
|
||||
topo_info->threads_per_core = ms->smp.threads;
|
||||
}
|
||||
|
||||
@ -128,6 +135,10 @@ static const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms)
|
||||
ms->possible_cpus->cpus[i].props.has_die_id = true;
|
||||
ms->possible_cpus->cpus[i].props.die_id = topo_ids.die_id;
|
||||
}
|
||||
if (ms->smp.modules > 1) {
|
||||
ms->possible_cpus->cpus[i].props.has_module_id = true;
|
||||
ms->possible_cpus->cpus[i].props.module_id = topo_ids.module_id;
|
||||
}
|
||||
ms->possible_cpus->cpus[i].props.has_core_id = true;
|
||||
ms->possible_cpus->cpus[i].props.core_id = topo_ids.core_id;
|
||||
ms->possible_cpus->cpus[i].props.has_thread_id = true;
|
||||
|
@ -119,6 +119,7 @@ struct PCMachineClass {
|
||||
bool enforce_aligned_dimm;
|
||||
bool broken_reserved_end;
|
||||
bool enforce_amd_1tb_hole;
|
||||
bool isa_bios_alias;
|
||||
|
||||
/* generate legacy CPU hotplug AML */
|
||||
bool legacy_cpu_hotplug;
|
||||
|
@ -50,16 +50,34 @@ typedef uint32_t apic_id_t;
|
||||
typedef struct X86CPUTopoIDs {
|
||||
unsigned pkg_id;
|
||||
unsigned die_id;
|
||||
unsigned module_id;
|
||||
unsigned core_id;
|
||||
unsigned smt_id;
|
||||
} X86CPUTopoIDs;
|
||||
|
||||
typedef struct X86CPUTopoInfo {
|
||||
unsigned dies_per_pkg;
|
||||
unsigned cores_per_die;
|
||||
unsigned modules_per_die;
|
||||
unsigned cores_per_module;
|
||||
unsigned threads_per_core;
|
||||
} X86CPUTopoInfo;
|
||||
|
||||
/*
|
||||
* CPUTopoLevel is the general i386 topology hierarchical representation,
|
||||
* ordered by increasing hierarchical relationship.
|
||||
* Its enumeration value is not bound to the type value of Intel (CPUID[0x1F])
|
||||
* or AMD (CPUID[0x80000026]).
|
||||
*/
|
||||
enum CPUTopoLevel {
|
||||
CPU_TOPO_LEVEL_INVALID,
|
||||
CPU_TOPO_LEVEL_SMT,
|
||||
CPU_TOPO_LEVEL_CORE,
|
||||
CPU_TOPO_LEVEL_MODULE,
|
||||
CPU_TOPO_LEVEL_DIE,
|
||||
CPU_TOPO_LEVEL_PACKAGE,
|
||||
CPU_TOPO_LEVEL_MAX,
|
||||
};
|
||||
|
||||
/* Return the bit width needed for 'count' IDs */
|
||||
static unsigned apicid_bitwidth_for_count(unsigned count)
|
||||
{
|
||||
@ -77,7 +95,13 @@ static inline unsigned apicid_smt_width(X86CPUTopoInfo *topo_info)
|
||||
/* Bit width of the Core_ID field */
|
||||
static inline unsigned apicid_core_width(X86CPUTopoInfo *topo_info)
|
||||
{
|
||||
return apicid_bitwidth_for_count(topo_info->cores_per_die);
|
||||
return apicid_bitwidth_for_count(topo_info->cores_per_module);
|
||||
}
|
||||
|
||||
/* Bit width of the Module_ID field */
|
||||
static inline unsigned apicid_module_width(X86CPUTopoInfo *topo_info)
|
||||
{
|
||||
return apicid_bitwidth_for_count(topo_info->modules_per_die);
|
||||
}
|
||||
|
||||
/* Bit width of the Die_ID field */
|
||||
@ -92,10 +116,16 @@ static inline unsigned apicid_core_offset(X86CPUTopoInfo *topo_info)
|
||||
return apicid_smt_width(topo_info);
|
||||
}
|
||||
|
||||
/* Bit offset of the Module_ID field */
|
||||
static inline unsigned apicid_module_offset(X86CPUTopoInfo *topo_info)
|
||||
{
|
||||
return apicid_core_offset(topo_info) + apicid_core_width(topo_info);
|
||||
}
|
||||
|
||||
/* Bit offset of the Die_ID field */
|
||||
static inline unsigned apicid_die_offset(X86CPUTopoInfo *topo_info)
|
||||
{
|
||||
return apicid_core_offset(topo_info) + apicid_core_width(topo_info);
|
||||
return apicid_module_offset(topo_info) + apicid_module_width(topo_info);
|
||||
}
|
||||
|
||||
/* Bit offset of the Pkg_ID (socket ID) field */
|
||||
@ -114,6 +144,7 @@ static inline apic_id_t x86_apicid_from_topo_ids(X86CPUTopoInfo *topo_info,
|
||||
{
|
||||
return (topo_ids->pkg_id << apicid_pkg_offset(topo_info)) |
|
||||
(topo_ids->die_id << apicid_die_offset(topo_info)) |
|
||||
(topo_ids->module_id << apicid_module_offset(topo_info)) |
|
||||
(topo_ids->core_id << apicid_core_offset(topo_info)) |
|
||||
topo_ids->smt_id;
|
||||
}
|
||||
@ -127,11 +158,16 @@ static inline void x86_topo_ids_from_idx(X86CPUTopoInfo *topo_info,
|
||||
X86CPUTopoIDs *topo_ids)
|
||||
{
|
||||
unsigned nr_dies = topo_info->dies_per_pkg;
|
||||
unsigned nr_cores = topo_info->cores_per_die;
|
||||
unsigned nr_modules = topo_info->modules_per_die;
|
||||
unsigned nr_cores = topo_info->cores_per_module;
|
||||
unsigned nr_threads = topo_info->threads_per_core;
|
||||
|
||||
topo_ids->pkg_id = cpu_index / (nr_dies * nr_cores * nr_threads);
|
||||
topo_ids->die_id = cpu_index / (nr_cores * nr_threads) % nr_dies;
|
||||
topo_ids->pkg_id = cpu_index / (nr_dies * nr_modules *
|
||||
nr_cores * nr_threads);
|
||||
topo_ids->die_id = cpu_index / (nr_modules * nr_cores *
|
||||
nr_threads) % nr_dies;
|
||||
topo_ids->module_id = cpu_index / (nr_cores * nr_threads) %
|
||||
nr_modules;
|
||||
topo_ids->core_id = cpu_index / nr_threads % nr_cores;
|
||||
topo_ids->smt_id = cpu_index % nr_threads;
|
||||
}
|
||||
@ -149,6 +185,9 @@ static inline void x86_topo_ids_from_apicid(apic_id_t apicid,
|
||||
topo_ids->core_id =
|
||||
(apicid >> apicid_core_offset(topo_info)) &
|
||||
~(0xFFFFFFFFUL << apicid_core_width(topo_info));
|
||||
topo_ids->module_id =
|
||||
(apicid >> apicid_module_offset(topo_info)) &
|
||||
~(0xFFFFFFFFUL << apicid_module_width(topo_info));
|
||||
topo_ids->die_id =
|
||||
(apicid >> apicid_die_offset(topo_info)) &
|
||||
~(0xFFFFFFFFUL << apicid_die_width(topo_info));
|
||||
@ -168,4 +207,13 @@ static inline apic_id_t x86_apicid_from_cpu_idx(X86CPUTopoInfo *topo_info,
|
||||
return x86_apicid_from_topo_ids(topo_info, &topo_ids);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether there's extended topology level (module or die)?
|
||||
*/
|
||||
static inline bool x86_has_extended_topo(unsigned long *topo_bitmap)
|
||||
{
|
||||
return test_bit(CPU_TOPO_LEVEL_MODULE, topo_bitmap) ||
|
||||
test_bit(CPU_TOPO_LEVEL_DIE, topo_bitmap);
|
||||
}
|
||||
|
||||
#endif /* HW_I386_TOPOLOGY_H */
|
||||
|
@ -281,7 +281,8 @@ ERST
|
||||
|
||||
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
|
||||
"-smp [[cpus=]n][,maxcpus=maxcpus][,drawers=drawers][,books=books][,sockets=sockets]\n"
|
||||
" [,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n"
|
||||
" [,dies=dies][,clusters=clusters][,modules=modules][,cores=cores]\n"
|
||||
" [,threads=threads]\n"
|
||||
" set the number of initial CPUs to 'n' [default=1]\n"
|
||||
" maxcpus= maximum number of total CPUs, including\n"
|
||||
" offline CPUs for hotplug, etc\n"
|
||||
@ -290,7 +291,8 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp,
|
||||
" sockets= number of sockets in one book\n"
|
||||
" dies= number of dies in one socket\n"
|
||||
" clusters= number of clusters in one die\n"
|
||||
" cores= number of cores in one cluster\n"
|
||||
" modules= number of modules in one cluster\n"
|
||||
" cores= number of cores in one module\n"
|
||||
" threads= number of threads in one core\n"
|
||||
"Note: Different machines may have different subsets of the CPU topology\n"
|
||||
" parameters supported, so the actual meaning of the supported parameters\n"
|
||||
@ -306,7 +308,7 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp,
|
||||
" must be set as 1 in the purpose of correct parsing.\n",
|
||||
QEMU_ARCH_ALL)
|
||||
SRST
|
||||
``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]``
|
||||
``-smp [[cpus=]n][,maxcpus=maxcpus][,drawers=drawers][,books=books][,sockets=sockets][,dies=dies][,clusters=clusters][,modules=modules][,cores=cores][,threads=threads]``
|
||||
Simulate a SMP system with '\ ``n``\ ' CPUs initially present on
|
||||
the machine type board. On boards supporting CPU hotplug, the optional
|
||||
'\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be
|
||||
@ -345,14 +347,14 @@ SRST
|
||||
-smp 8,sockets=2,cores=2,threads=2,maxcpus=8
|
||||
|
||||
The following sub-option defines a CPU topology hierarchy (2 sockets
|
||||
totally on the machine, 2 dies per socket, 2 cores per die, 2 threads
|
||||
per core) for PC machines which support sockets/dies/cores/threads.
|
||||
Some members of the option can be omitted but their values will be
|
||||
automatically computed:
|
||||
totally on the machine, 2 dies per socket, 2 modules per die, 2 cores per
|
||||
module, 2 threads per core) for PC machines which support sockets/dies
|
||||
/modules/cores/threads. Some members of the option can be omitted but
|
||||
their values will be automatically computed:
|
||||
|
||||
::
|
||||
|
||||
-smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16
|
||||
-smp 32,sockets=2,dies=2,modules=2,cores=2,threads=2,maxcpus=32
|
||||
|
||||
The following sub-option defines a CPU topology hierarchy (2 sockets
|
||||
totally on the machine, 2 clusters per socket, 2 cores per cluster,
|
||||
|
@ -235,22 +235,53 @@ static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache)
|
||||
((t) == UNIFIED_CACHE) ? CACHE_TYPE_UNIFIED : \
|
||||
0 /* Invalid value */)
|
||||
|
||||
static uint32_t max_thread_ids_for_cache(X86CPUTopoInfo *topo_info,
|
||||
enum CPUTopoLevel share_level)
|
||||
{
|
||||
uint32_t num_ids = 0;
|
||||
|
||||
switch (share_level) {
|
||||
case CPU_TOPO_LEVEL_CORE:
|
||||
num_ids = 1 << apicid_core_offset(topo_info);
|
||||
break;
|
||||
case CPU_TOPO_LEVEL_DIE:
|
||||
num_ids = 1 << apicid_die_offset(topo_info);
|
||||
break;
|
||||
case CPU_TOPO_LEVEL_PACKAGE:
|
||||
num_ids = 1 << apicid_pkg_offset(topo_info);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Currently there is no use case for SMT and MODULE, so use
|
||||
* assert directly to facilitate debugging.
|
||||
*/
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return num_ids - 1;
|
||||
}
|
||||
|
||||
static uint32_t max_core_ids_in_package(X86CPUTopoInfo *topo_info)
|
||||
{
|
||||
uint32_t num_cores = 1 << (apicid_pkg_offset(topo_info) -
|
||||
apicid_core_offset(topo_info));
|
||||
return num_cores - 1;
|
||||
}
|
||||
|
||||
/* Encode cache info for CPUID[4] */
|
||||
static void encode_cache_cpuid4(CPUCacheInfo *cache,
|
||||
int num_apic_ids, int num_cores,
|
||||
X86CPUTopoInfo *topo_info,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx)
|
||||
{
|
||||
assert(cache->size == cache->line_size * cache->associativity *
|
||||
cache->partitions * cache->sets);
|
||||
|
||||
assert(num_apic_ids > 0);
|
||||
*eax = CACHE_TYPE(cache->type) |
|
||||
CACHE_LEVEL(cache->level) |
|
||||
(cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) |
|
||||
((num_cores - 1) << 26) |
|
||||
((num_apic_ids - 1) << 14);
|
||||
(max_core_ids_in_package(topo_info) << 26) |
|
||||
(max_thread_ids_for_cache(topo_info, cache->share_level) << 14);
|
||||
|
||||
assert(cache->line_size > 0);
|
||||
assert(cache->partitions > 0);
|
||||
@ -269,6 +300,122 @@ static void encode_cache_cpuid4(CPUCacheInfo *cache,
|
||||
(cache->complex_indexing ? CACHE_COMPLEX_IDX : 0);
|
||||
}
|
||||
|
||||
static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info,
|
||||
enum CPUTopoLevel topo_level)
|
||||
{
|
||||
switch (topo_level) {
|
||||
case CPU_TOPO_LEVEL_SMT:
|
||||
return 1;
|
||||
case CPU_TOPO_LEVEL_CORE:
|
||||
return topo_info->threads_per_core;
|
||||
case CPU_TOPO_LEVEL_MODULE:
|
||||
return topo_info->threads_per_core * topo_info->cores_per_module;
|
||||
case CPU_TOPO_LEVEL_DIE:
|
||||
return topo_info->threads_per_core * topo_info->cores_per_module *
|
||||
topo_info->modules_per_die;
|
||||
case CPU_TOPO_LEVEL_PACKAGE:
|
||||
return topo_info->threads_per_core * topo_info->cores_per_module *
|
||||
topo_info->modules_per_die * topo_info->dies_per_pkg;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info,
|
||||
enum CPUTopoLevel topo_level)
|
||||
{
|
||||
switch (topo_level) {
|
||||
case CPU_TOPO_LEVEL_SMT:
|
||||
return 0;
|
||||
case CPU_TOPO_LEVEL_CORE:
|
||||
return apicid_core_offset(topo_info);
|
||||
case CPU_TOPO_LEVEL_MODULE:
|
||||
return apicid_module_offset(topo_info);
|
||||
case CPU_TOPO_LEVEL_DIE:
|
||||
return apicid_die_offset(topo_info);
|
||||
case CPU_TOPO_LEVEL_PACKAGE:
|
||||
return apicid_pkg_offset(topo_info);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t cpuid1f_topo_type(enum CPUTopoLevel topo_level)
|
||||
{
|
||||
switch (topo_level) {
|
||||
case CPU_TOPO_LEVEL_INVALID:
|
||||
return CPUID_1F_ECX_TOPO_LEVEL_INVALID;
|
||||
case CPU_TOPO_LEVEL_SMT:
|
||||
return CPUID_1F_ECX_TOPO_LEVEL_SMT;
|
||||
case CPU_TOPO_LEVEL_CORE:
|
||||
return CPUID_1F_ECX_TOPO_LEVEL_CORE;
|
||||
case CPU_TOPO_LEVEL_MODULE:
|
||||
return CPUID_1F_ECX_TOPO_LEVEL_MODULE;
|
||||
case CPU_TOPO_LEVEL_DIE:
|
||||
return CPUID_1F_ECX_TOPO_LEVEL_DIE;
|
||||
default:
|
||||
/* Other types are not supported in QEMU. */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count,
|
||||
X86CPUTopoInfo *topo_info,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx)
|
||||
{
|
||||
X86CPU *cpu = env_archcpu(env);
|
||||
unsigned long level, next_level;
|
||||
uint32_t num_threads_next_level, offset_next_level;
|
||||
|
||||
assert(count + 1 < CPU_TOPO_LEVEL_MAX);
|
||||
|
||||
/*
|
||||
* Find the No.(count + 1) topology level in avail_cpu_topo bitmap.
|
||||
* The search starts from bit 1 (CPU_TOPO_LEVEL_INVALID + 1).
|
||||
*/
|
||||
level = CPU_TOPO_LEVEL_INVALID;
|
||||
for (int i = 0; i <= count; i++) {
|
||||
level = find_next_bit(env->avail_cpu_topo,
|
||||
CPU_TOPO_LEVEL_PACKAGE,
|
||||
level + 1);
|
||||
|
||||
/*
|
||||
* CPUID[0x1f] doesn't explicitly encode the package level,
|
||||
* and it just encodes the invalid level (all fields are 0)
|
||||
* into the last subleaf of 0x1f.
|
||||
*/
|
||||
if (level == CPU_TOPO_LEVEL_PACKAGE) {
|
||||
level = CPU_TOPO_LEVEL_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (level == CPU_TOPO_LEVEL_INVALID) {
|
||||
num_threads_next_level = 0;
|
||||
offset_next_level = 0;
|
||||
} else {
|
||||
next_level = find_next_bit(env->avail_cpu_topo,
|
||||
CPU_TOPO_LEVEL_PACKAGE,
|
||||
level + 1);
|
||||
num_threads_next_level = num_threads_by_topo_level(topo_info,
|
||||
next_level);
|
||||
offset_next_level = apicid_offset_by_topo_level(topo_info,
|
||||
next_level);
|
||||
}
|
||||
|
||||
*eax = offset_next_level;
|
||||
/* The count (bits 15-00) doesn't need to be reliable. */
|
||||
*ebx = num_threads_next_level & 0xffff;
|
||||
*ecx = (count & 0xff) | (cpuid1f_topo_type(level) << 8);
|
||||
*edx = cpu->apic_id;
|
||||
|
||||
assert(!(*eax & ~0x1f));
|
||||
}
|
||||
|
||||
/* Encode cache info for CPUID[0x80000005].ECX or CPUID[0x80000005].EDX */
|
||||
static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache)
|
||||
{
|
||||
@ -331,20 +478,12 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx)
|
||||
{
|
||||
uint32_t l3_threads;
|
||||
assert(cache->size == cache->line_size * cache->associativity *
|
||||
cache->partitions * cache->sets);
|
||||
|
||||
*eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) |
|
||||
(cache->self_init ? CACHE_SELF_INIT_LEVEL : 0);
|
||||
|
||||
/* L3 is shared among multiple cores */
|
||||
if (cache->level == 3) {
|
||||
l3_threads = topo_info->cores_per_die * topo_info->threads_per_core;
|
||||
*eax |= (l3_threads - 1) << 14;
|
||||
} else {
|
||||
*eax |= ((topo_info->threads_per_core - 1) << 14);
|
||||
}
|
||||
*eax |= max_thread_ids_for_cache(topo_info, cache->share_level) << 14;
|
||||
|
||||
assert(cache->line_size > 0);
|
||||
assert(cache->partitions > 0);
|
||||
@ -436,6 +575,7 @@ static CPUCacheInfo legacy_l1d_cache = {
|
||||
.sets = 64,
|
||||
.partitions = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
};
|
||||
|
||||
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
|
||||
@ -450,6 +590,7 @@ static CPUCacheInfo legacy_l1d_cache_amd = {
|
||||
.partitions = 1,
|
||||
.lines_per_tag = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
};
|
||||
|
||||
/* L1 instruction cache: */
|
||||
@ -463,6 +604,7 @@ static CPUCacheInfo legacy_l1i_cache = {
|
||||
.sets = 64,
|
||||
.partitions = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
};
|
||||
|
||||
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
|
||||
@ -477,6 +619,7 @@ static CPUCacheInfo legacy_l1i_cache_amd = {
|
||||
.partitions = 1,
|
||||
.lines_per_tag = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
};
|
||||
|
||||
/* Level 2 unified cache: */
|
||||
@ -490,6 +633,7 @@ static CPUCacheInfo legacy_l2_cache = {
|
||||
.sets = 4096,
|
||||
.partitions = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
};
|
||||
|
||||
/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */
|
||||
@ -499,6 +643,7 @@ static CPUCacheInfo legacy_l2_cache_cpuid2 = {
|
||||
.size = 2 * MiB,
|
||||
.line_size = 64,
|
||||
.associativity = 8,
|
||||
.share_level = CPU_TOPO_LEVEL_INVALID,
|
||||
};
|
||||
|
||||
|
||||
@ -512,6 +657,7 @@ static CPUCacheInfo legacy_l2_cache_amd = {
|
||||
.associativity = 16,
|
||||
.sets = 512,
|
||||
.partitions = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
};
|
||||
|
||||
/* Level 3 unified cache: */
|
||||
@ -527,6 +673,7 @@ static CPUCacheInfo legacy_l3_cache = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
};
|
||||
|
||||
/* TLB definitions: */
|
||||
@ -969,7 +1116,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
|
||||
"fsrc", NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, "amx-fp16", NULL, "avx-ifma",
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, "lam", NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
},
|
||||
.cpuid = {
|
||||
@ -1825,6 +1972,7 @@ static const CPUCaches epyc_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -1837,6 +1985,7 @@ static const CPUCaches epyc_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1847,6 +1996,7 @@ static const CPUCaches epyc_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1860,6 +2010,7 @@ static const CPUCaches epyc_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1875,6 +2026,7 @@ static CPUCaches epyc_v4_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -1887,6 +2039,7 @@ static CPUCaches epyc_v4_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1897,6 +2050,7 @@ static CPUCaches epyc_v4_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1910,6 +2064,7 @@ static CPUCaches epyc_v4_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1925,6 +2080,7 @@ static const CPUCaches epyc_rome_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -1937,6 +2093,7 @@ static const CPUCaches epyc_rome_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1947,6 +2104,7 @@ static const CPUCaches epyc_rome_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1960,6 +2118,7 @@ static const CPUCaches epyc_rome_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1975,6 +2134,7 @@ static const CPUCaches epyc_rome_v3_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -1987,6 +2147,7 @@ static const CPUCaches epyc_rome_v3_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -1997,6 +2158,7 @@ static const CPUCaches epyc_rome_v3_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2010,6 +2172,7 @@ static const CPUCaches epyc_rome_v3_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2025,6 +2188,7 @@ static const CPUCaches epyc_milan_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -2037,6 +2201,7 @@ static const CPUCaches epyc_milan_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2047,6 +2212,7 @@ static const CPUCaches epyc_milan_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2060,6 +2226,7 @@ static const CPUCaches epyc_milan_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2075,6 +2242,7 @@ static const CPUCaches epyc_milan_v2_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -2087,6 +2255,7 @@ static const CPUCaches epyc_milan_v2_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2097,6 +2266,7 @@ static const CPUCaches epyc_milan_v2_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 1024,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2110,6 +2280,7 @@ static const CPUCaches epyc_milan_v2_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2125,6 +2296,7 @@ static const CPUCaches epyc_genoa_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l1i_cache = &(CPUCacheInfo) {
|
||||
.type = INSTRUCTION_CACHE,
|
||||
@ -2137,6 +2309,7 @@ static const CPUCaches epyc_genoa_cache_info = {
|
||||
.lines_per_tag = 1,
|
||||
.self_init = 1,
|
||||
.no_invd_sharing = true,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l2_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2147,6 +2320,7 @@ static const CPUCaches epyc_genoa_cache_info = {
|
||||
.partitions = 1,
|
||||
.sets = 2048,
|
||||
.lines_per_tag = 1,
|
||||
.share_level = CPU_TOPO_LEVEL_CORE,
|
||||
},
|
||||
.l3_cache = &(CPUCacheInfo) {
|
||||
.type = UNIFIED_CACHE,
|
||||
@ -2160,6 +2334,7 @@ static const CPUCaches epyc_genoa_cache_info = {
|
||||
.self_init = true,
|
||||
.inclusive = true,
|
||||
.complex_indexing = false,
|
||||
.share_level = CPU_TOPO_LEVEL_DIE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -6162,15 +6337,21 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
{
|
||||
X86CPU *cpu = env_archcpu(env);
|
||||
CPUState *cs = env_cpu(env);
|
||||
uint32_t die_offset;
|
||||
uint32_t limit;
|
||||
uint32_t signature[3];
|
||||
X86CPUTopoInfo topo_info;
|
||||
uint32_t cores_per_pkg;
|
||||
uint32_t threads_per_pkg;
|
||||
|
||||
topo_info.dies_per_pkg = env->nr_dies;
|
||||
topo_info.cores_per_die = cs->nr_cores / env->nr_dies;
|
||||
topo_info.modules_per_die = env->nr_modules;
|
||||
topo_info.cores_per_module = cs->nr_cores / env->nr_dies / env->nr_modules;
|
||||
topo_info.threads_per_core = cs->nr_threads;
|
||||
|
||||
cores_per_pkg = topo_info.cores_per_module * topo_info.modules_per_die *
|
||||
topo_info.dies_per_pkg;
|
||||
threads_per_pkg = cores_per_pkg * topo_info.threads_per_core;
|
||||
|
||||
/* Calculate & apply limits for different index ranges */
|
||||
if (index >= 0xC0000000) {
|
||||
limit = env->cpuid_xlevel2;
|
||||
@ -6206,8 +6387,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
*ecx |= CPUID_EXT_OSXSAVE;
|
||||
}
|
||||
*edx = env->features[FEAT_1_EDX];
|
||||
if (cs->nr_cores * cs->nr_threads > 1) {
|
||||
*ebx |= (cs->nr_cores * cs->nr_threads) << 16;
|
||||
if (threads_per_pkg > 1) {
|
||||
*ebx |= threads_per_pkg << 16;
|
||||
*edx |= CPUID_HT;
|
||||
}
|
||||
if (!cpu->enable_pmu) {
|
||||
@ -6244,41 +6425,50 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
*/
|
||||
if (*eax & 31) {
|
||||
int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14);
|
||||
int vcpus_per_socket = cs->nr_cores * cs->nr_threads;
|
||||
if (cs->nr_cores > 1) {
|
||||
|
||||
if (cores_per_pkg > 1) {
|
||||
*eax &= ~0xFC000000;
|
||||
*eax |= (pow2ceil(cs->nr_cores) - 1) << 26;
|
||||
*eax |= max_core_ids_in_package(&topo_info) << 26;
|
||||
}
|
||||
if (host_vcpus_per_cache > vcpus_per_socket) {
|
||||
if (host_vcpus_per_cache > threads_per_pkg) {
|
||||
*eax &= ~0x3FFC000;
|
||||
*eax |= (pow2ceil(vcpus_per_socket) - 1) << 14;
|
||||
|
||||
/* Share the cache at package level. */
|
||||
*eax |= max_thread_ids_for_cache(&topo_info,
|
||||
CPU_TOPO_LEVEL_PACKAGE) << 14;
|
||||
}
|
||||
}
|
||||
} else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) {
|
||||
*eax = *ebx = *ecx = *edx = 0;
|
||||
} else {
|
||||
*eax = 0;
|
||||
|
||||
switch (count) {
|
||||
case 0: /* L1 dcache info */
|
||||
encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache,
|
||||
1, cs->nr_cores,
|
||||
&topo_info,
|
||||
eax, ebx, ecx, edx);
|
||||
if (!cpu->l1_cache_per_core) {
|
||||
*eax &= ~MAKE_64BIT_MASK(14, 12);
|
||||
}
|
||||
break;
|
||||
case 1: /* L1 icache info */
|
||||
encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache,
|
||||
1, cs->nr_cores,
|
||||
&topo_info,
|
||||
eax, ebx, ecx, edx);
|
||||
if (!cpu->l1_cache_per_core) {
|
||||
*eax &= ~MAKE_64BIT_MASK(14, 12);
|
||||
}
|
||||
break;
|
||||
case 2: /* L2 cache info */
|
||||
encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache,
|
||||
cs->nr_threads, cs->nr_cores,
|
||||
&topo_info,
|
||||
eax, ebx, ecx, edx);
|
||||
break;
|
||||
case 3: /* L3 cache info */
|
||||
die_offset = apicid_die_offset(&topo_info);
|
||||
if (cpu->enable_l3_cache) {
|
||||
encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache,
|
||||
(1 << die_offset), cs->nr_cores,
|
||||
&topo_info,
|
||||
eax, ebx, ecx, edx);
|
||||
break;
|
||||
}
|
||||
@ -6381,18 +6571,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
switch (count) {
|
||||
case 0:
|
||||
*eax = apicid_core_offset(&topo_info);
|
||||
*ebx = cs->nr_threads;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
|
||||
*ebx = topo_info.threads_per_core;
|
||||
*ecx |= CPUID_B_ECX_TOPO_LEVEL_SMT << 8;
|
||||
break;
|
||||
case 1:
|
||||
*eax = apicid_pkg_offset(&topo_info);
|
||||
*ebx = cs->nr_cores * cs->nr_threads;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
|
||||
*ebx = threads_per_pkg;
|
||||
*ecx |= CPUID_B_ECX_TOPO_LEVEL_CORE << 8;
|
||||
break;
|
||||
default:
|
||||
*eax = 0;
|
||||
*ebx = 0;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_INVALID;
|
||||
*ecx |= CPUID_B_ECX_TOPO_LEVEL_INVALID << 8;
|
||||
}
|
||||
|
||||
assert(!(*eax & ~0x1f));
|
||||
@ -6406,36 +6596,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
break;
|
||||
case 0x1F:
|
||||
/* V2 Extended Topology Enumeration Leaf */
|
||||
if (env->nr_dies < 2) {
|
||||
if (!x86_has_extended_topo(env->avail_cpu_topo)) {
|
||||
*eax = *ebx = *ecx = *edx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*ecx = count & 0xff;
|
||||
*edx = cpu->apic_id;
|
||||
switch (count) {
|
||||
case 0:
|
||||
*eax = apicid_core_offset(&topo_info);
|
||||
*ebx = cs->nr_threads;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
|
||||
break;
|
||||
case 1:
|
||||
*eax = apicid_die_offset(&topo_info);
|
||||
*ebx = topo_info.cores_per_die * topo_info.threads_per_core;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
|
||||
break;
|
||||
case 2:
|
||||
*eax = apicid_pkg_offset(&topo_info);
|
||||
*ebx = cs->nr_cores * cs->nr_threads;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_DIE;
|
||||
break;
|
||||
default:
|
||||
*eax = 0;
|
||||
*ebx = 0;
|
||||
*ecx |= CPUID_TOPOLOGY_LEVEL_INVALID;
|
||||
}
|
||||
assert(!(*eax & ~0x1f));
|
||||
*ebx &= 0xffff; /* The count doesn't need to be reliable. */
|
||||
encode_topo_cpuid1f(env, count, &topo_info, eax, ebx, ecx, edx);
|
||||
break;
|
||||
case 0xD: {
|
||||
/* Processor Extended State */
|
||||
@ -6654,7 +6820,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
* discards multiple thread information if it is set.
|
||||
* So don't set it here for Intel to make Linux guests happy.
|
||||
*/
|
||||
if (cs->nr_cores * cs->nr_threads > 1) {
|
||||
if (threads_per_pkg > 1) {
|
||||
if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 ||
|
||||
env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 ||
|
||||
env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) {
|
||||
@ -6721,7 +6887,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
*eax |= (cpu->guest_phys_bits << 16);
|
||||
}
|
||||
*ebx = env->features[FEAT_8000_0008_EBX];
|
||||
if (cs->nr_cores * cs->nr_threads > 1) {
|
||||
if (threads_per_pkg > 1) {
|
||||
/*
|
||||
* Bits 15:12 is "The number of bits in the initial
|
||||
* Core::X86::Apic::ApicId[ApicId] value that indicate
|
||||
@ -6729,7 +6895,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
* Bits 7:0 is "The number of threads in the package is NC+1"
|
||||
*/
|
||||
*ecx = (apicid_pkg_offset(&topo_info) << 12) |
|
||||
((cs->nr_cores * cs->nr_threads) - 1);
|
||||
(threads_per_pkg - 1);
|
||||
} else {
|
||||
*ecx = 0;
|
||||
}
|
||||
@ -7239,7 +7405,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
|
||||
* cpu->vendor_cpuid_only has been unset for compatibility with older
|
||||
* machine types.
|
||||
*/
|
||||
if ((env->nr_dies > 1) &&
|
||||
if (x86_has_extended_topo(env->avail_cpu_topo) &&
|
||||
(IS_INTEL_CPU(env) || !cpu->vendor_cpuid_only)) {
|
||||
x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F);
|
||||
}
|
||||
@ -7762,13 +7928,26 @@ static void x86_cpu_post_initfn(Object *obj)
|
||||
accel_cpu_instance_init(CPU(obj));
|
||||
}
|
||||
|
||||
static void x86_cpu_init_default_topo(X86CPU *cpu)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
|
||||
env->nr_modules = 1;
|
||||
env->nr_dies = 1;
|
||||
|
||||
/* SMT, core and package levels are set by default. */
|
||||
set_bit(CPU_TOPO_LEVEL_SMT, env->avail_cpu_topo);
|
||||
set_bit(CPU_TOPO_LEVEL_CORE, env->avail_cpu_topo);
|
||||
set_bit(CPU_TOPO_LEVEL_PACKAGE, env->avail_cpu_topo);
|
||||
}
|
||||
|
||||
static void x86_cpu_initfn(Object *obj)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(obj);
|
||||
X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
|
||||
CPUX86State *env = &cpu->env;
|
||||
|
||||
env->nr_dies = 1;
|
||||
x86_cpu_init_default_topo(cpu);
|
||||
|
||||
object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo",
|
||||
x86_cpu_get_feature_words,
|
||||
@ -7975,12 +8154,14 @@ static Property x86_cpu_properties[] = {
|
||||
DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, 0),
|
||||
DEFINE_PROP_INT32("thread-id", X86CPU, thread_id, 0),
|
||||
DEFINE_PROP_INT32("core-id", X86CPU, core_id, 0),
|
||||
DEFINE_PROP_INT32("module-id", X86CPU, module_id, 0),
|
||||
DEFINE_PROP_INT32("die-id", X86CPU, die_id, 0),
|
||||
DEFINE_PROP_INT32("socket-id", X86CPU, socket_id, 0),
|
||||
#else
|
||||
DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, UNASSIGNED_APIC_ID),
|
||||
DEFINE_PROP_INT32("thread-id", X86CPU, thread_id, -1),
|
||||
DEFINE_PROP_INT32("core-id", X86CPU, core_id, -1),
|
||||
DEFINE_PROP_INT32("module-id", X86CPU, module_id, -1),
|
||||
DEFINE_PROP_INT32("die-id", X86CPU, die_id, -1),
|
||||
DEFINE_PROP_INT32("socket-id", X86CPU, socket_id, -1),
|
||||
#endif
|
||||
@ -8105,6 +8286,7 @@ static Property x86_cpu_properties[] = {
|
||||
false),
|
||||
DEFINE_PROP_BOOL("x-intel-pt-auto-level", X86CPU, intel_pt_auto_level,
|
||||
true),
|
||||
DEFINE_PROP_BOOL("x-l1-cache-per-thread", X86CPU, l1_cache_per_core, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "cpu-qom.h"
|
||||
#include "kvm/hyperv-proto.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "hw/i386/topology.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "qemu/cpu-float.h"
|
||||
#include "qemu/timer.h"
|
||||
@ -258,6 +259,7 @@ typedef enum X86Seg {
|
||||
#define CR4_SMAP_MASK (1U << 21)
|
||||
#define CR4_PKE_MASK (1U << 22)
|
||||
#define CR4_PKS_MASK (1U << 24)
|
||||
#define CR4_LAM_SUP_MASK (1U << 28)
|
||||
|
||||
#define CR4_RESERVED_MASK \
|
||||
(~(target_ulong)(CR4_VME_MASK | CR4_PVI_MASK | CR4_TSD_MASK \
|
||||
@ -266,7 +268,8 @@ typedef enum X86Seg {
|
||||
| CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK | CR4_UMIP_MASK \
|
||||
| CR4_LA57_MASK \
|
||||
| CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \
|
||||
| CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK))
|
||||
| CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK \
|
||||
| CR4_LAM_SUP_MASK))
|
||||
|
||||
#define DR6_BD (1 << 13)
|
||||
#define DR6_BS (1 << 14)
|
||||
@ -927,6 +930,8 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||
#define CPUID_7_1_EAX_AMX_FP16 (1U << 21)
|
||||
/* Support for VPMADD52[H,L]UQ */
|
||||
#define CPUID_7_1_EAX_AVX_IFMA (1U << 23)
|
||||
/* Linear Address Masking */
|
||||
#define CPUID_7_1_EAX_LAM (1U << 26)
|
||||
|
||||
/* Support for VPDPB[SU,UU,SS]D[,S] */
|
||||
#define CPUID_7_1_EDX_AVX_VNNI_INT8 (1U << 4)
|
||||
@ -1011,10 +1016,16 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||
#define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */
|
||||
|
||||
/* CPUID[0xB].ECX level types */
|
||||
#define CPUID_TOPOLOGY_LEVEL_INVALID (0U << 8)
|
||||
#define CPUID_TOPOLOGY_LEVEL_SMT (1U << 8)
|
||||
#define CPUID_TOPOLOGY_LEVEL_CORE (2U << 8)
|
||||
#define CPUID_TOPOLOGY_LEVEL_DIE (5U << 8)
|
||||
#define CPUID_B_ECX_TOPO_LEVEL_INVALID 0
|
||||
#define CPUID_B_ECX_TOPO_LEVEL_SMT 1
|
||||
#define CPUID_B_ECX_TOPO_LEVEL_CORE 2
|
||||
|
||||
/* COUID[0x1F].ECX level types */
|
||||
#define CPUID_1F_ECX_TOPO_LEVEL_INVALID CPUID_B_ECX_TOPO_LEVEL_INVALID
|
||||
#define CPUID_1F_ECX_TOPO_LEVEL_SMT CPUID_B_ECX_TOPO_LEVEL_SMT
|
||||
#define CPUID_1F_ECX_TOPO_LEVEL_CORE CPUID_B_ECX_TOPO_LEVEL_CORE
|
||||
#define CPUID_1F_ECX_TOPO_LEVEL_MODULE 3
|
||||
#define CPUID_1F_ECX_TOPO_LEVEL_DIE 5
|
||||
|
||||
/* MSR Feature Bits */
|
||||
#define MSR_ARCH_CAP_RDCL_NO (1U << 0)
|
||||
@ -1578,6 +1589,13 @@ typedef struct CPUCacheInfo {
|
||||
* address bits. CPUID[4].EDX[bit 2].
|
||||
*/
|
||||
bool complex_indexing;
|
||||
|
||||
/*
|
||||
* Cache Topology. The level that cache is shared in.
|
||||
* Used to encode CPUID[4].EAX[bits 25:14] or
|
||||
* CPUID[0x8000001D].EAX[bits 25:14].
|
||||
*/
|
||||
enum CPUTopoLevel share_level;
|
||||
} CPUCacheInfo;
|
||||
|
||||
|
||||
@ -1887,6 +1905,12 @@ typedef struct CPUArchState {
|
||||
|
||||
/* Number of dies within this CPU package. */
|
||||
unsigned nr_dies;
|
||||
|
||||
/* Number of modules within one die. */
|
||||
unsigned nr_modules;
|
||||
|
||||
/* Bitmap of available CPU topology levels for this CPU. */
|
||||
DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL_MAX);
|
||||
} CPUX86State;
|
||||
|
||||
struct kvm_msrs;
|
||||
@ -1987,6 +2011,11 @@ struct ArchCPU {
|
||||
*/
|
||||
bool enable_l3_cache;
|
||||
|
||||
/* Compatibility bits for old machine types.
|
||||
* If true present L1 cache as per-thread, not per-core.
|
||||
*/
|
||||
bool l1_cache_per_core;
|
||||
|
||||
/* Compatibility bits for old machine types.
|
||||
* If true present the old cache topology information
|
||||
*/
|
||||
@ -2047,6 +2076,7 @@ struct ArchCPU {
|
||||
int32_t node_id; /* NUMA node this CPU belongs to */
|
||||
int32_t socket_id;
|
||||
int32_t die_id;
|
||||
int32_t module_id;
|
||||
int32_t core_id;
|
||||
int32_t thread_id;
|
||||
|
||||
@ -2561,6 +2591,9 @@ static inline uint64_t cr4_reserved_bits(CPUX86State *env)
|
||||
if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKS)) {
|
||||
reserved_bits |= CR4_PKS_MASK;
|
||||
}
|
||||
if (!(env->features[FEAT_7_1_EAX] & CPUID_7_1_EAX_LAM)) {
|
||||
reserved_bits |= CR4_LAM_SUP_MASK;
|
||||
}
|
||||
return reserved_bits;
|
||||
}
|
||||
|
||||
|
@ -219,6 +219,10 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
|
||||
new_cr4 &= ~CR4_PKS_MASK;
|
||||
}
|
||||
|
||||
if (!(env->features[FEAT_7_1_EAX] & CPUID_7_1_EAX_LAM)) {
|
||||
new_cr4 &= ~CR4_LAM_SUP_MASK;
|
||||
}
|
||||
|
||||
env->cr[4] = new_cr4;
|
||||
env->hflags = hflags;
|
||||
|
||||
|
@ -22,8 +22,8 @@ DEF_HELPER_FLAGS_5(bndstx32, TCG_CALL_NO_WG, void, env, tl, tl, i64, i64)
|
||||
DEF_HELPER_FLAGS_5(bndstx64, TCG_CALL_NO_WG, void, env, tl, tl, i64, i64)
|
||||
DEF_HELPER_1(bnd_jmp, void, env)
|
||||
|
||||
DEF_HELPER_2(aam, void, env, int)
|
||||
DEF_HELPER_2(aad, void, env, int)
|
||||
DEF_HELPER_FLAGS_2(aam, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_FLAGS_2(aad, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
DEF_HELPER_1(aaa, void, env)
|
||||
DEF_HELPER_1(aas, void, env)
|
||||
DEF_HELPER_1(daa, void, env)
|
||||
|
@ -81,7 +81,7 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
|
||||
*/
|
||||
async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL);
|
||||
|
||||
return 0;
|
||||
return EXCP_INTERRUPT;
|
||||
case KVM_EXIT_HYPERV_HCALL: {
|
||||
uint16_t code = exit->u.hcall.input & 0xffff;
|
||||
bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST;
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "hw/i386/apic_internal.h"
|
||||
#include "hw/i386/apic-msidef.h"
|
||||
#include "hw/i386/intel_iommu.h"
|
||||
#include "hw/i386/topology.h"
|
||||
#include "hw/i386/x86-iommu.h"
|
||||
#include "hw/i386/e820_memory_layout.h"
|
||||
|
||||
@ -1791,7 +1792,7 @@ static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
|
||||
break;
|
||||
}
|
||||
case 0x1f:
|
||||
if (env->nr_dies < 2) {
|
||||
if (!x86_has_extended_topo(env->avail_cpu_topo)) {
|
||||
cpuid_i--;
|
||||
break;
|
||||
}
|
||||
|
@ -1480,8 +1480,8 @@ static const X86OpEntry opcodes_root[256] = {
|
||||
[0xD1] = X86_OP_GROUP1(group2, E,v),
|
||||
[0xD2] = X86_OP_GROUP2(group2, E,b, 1,b), /* CL */
|
||||
[0xD3] = X86_OP_GROUP2(group2, E,v, 1,b), /* CL */
|
||||
[0xD4] = X86_OP_ENTRYr(AAM, I,b),
|
||||
[0xD5] = X86_OP_ENTRYr(AAD, I,b),
|
||||
[0xD4] = X86_OP_ENTRY2(AAM, 0,w, I,b),
|
||||
[0xD5] = X86_OP_ENTRY2(AAD, 0,w, I,b),
|
||||
[0xD6] = X86_OP_ENTRYw(SALC, 0,b),
|
||||
[0xD7] = X86_OP_ENTRY1(XLAT, 0,b, zextT0), /* AL read/written */
|
||||
|
||||
|
@ -1084,8 +1084,8 @@ static void gen_AAA(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
|
||||
static void gen_AAD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
{
|
||||
gen_helper_aad(tcg_env, tcg_constant_i32(decode->immediate));
|
||||
set_cc_op(s, CC_OP_LOGICB);
|
||||
gen_helper_aad(s->T0, s->T0, s->T1);
|
||||
prepare_update1_cc(decode, s, CC_OP_LOGICB);
|
||||
}
|
||||
|
||||
static void gen_AAM(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
@ -1093,8 +1093,8 @@ static void gen_AAM(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
if (decode->immediate == 0) {
|
||||
gen_exception(s, EXCP00_DIVZ);
|
||||
} else {
|
||||
gen_helper_aam(tcg_env, tcg_constant_i32(decode->immediate));
|
||||
set_cc_op(s, CC_OP_LOGICB);
|
||||
gen_helper_aam(s->T0, s->T0, s->T1);
|
||||
prepare_update1_cc(decode, s, CC_OP_LOGICB);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2901,14 +2901,15 @@ static bool gen_eflags_adcox(DisasContext *s, X86DecodedInsn *decode, bool want_
|
||||
return got_cf;
|
||||
}
|
||||
|
||||
static void gen_rot_overflow(X86DecodedInsn *decode, TCGv result, TCGv old, TCGv count)
|
||||
static void gen_rot_overflow(X86DecodedInsn *decode, TCGv result, TCGv old,
|
||||
bool can_be_zero, TCGv count)
|
||||
{
|
||||
MemOp ot = decode->op[0].ot;
|
||||
TCGv temp = count ? tcg_temp_new() : decode->cc_src2;
|
||||
TCGv temp = can_be_zero ? tcg_temp_new() : decode->cc_src2;
|
||||
|
||||
tcg_gen_xor_tl(temp, old, result);
|
||||
tcg_gen_extract_tl(temp, temp, (8 << ot) - 1, 1);
|
||||
if (count) {
|
||||
if (can_be_zero) {
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, decode->cc_src2, count, tcg_constant_tl(0),
|
||||
decode->cc_src2, temp);
|
||||
}
|
||||
@ -3000,7 +3001,7 @@ static void gen_RCL(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
/* Compute result and outgoing overflow */
|
||||
tcg_gen_mov_tl(decode->cc_src2, s->T0);
|
||||
tcg_gen_or_tl(s->T0, low, high);
|
||||
gen_rot_overflow(decode, s->T0, decode->cc_src2, NULL);
|
||||
gen_rot_overflow(decode, s->T0, decode->cc_src2, false, NULL);
|
||||
|
||||
if (zero_label) {
|
||||
gen_set_label(zero_label);
|
||||
@ -3053,7 +3054,7 @@ static void gen_RCR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
/* Compute result and outgoing overflow */
|
||||
tcg_gen_mov_tl(decode->cc_src2, s->T0);
|
||||
tcg_gen_or_tl(s->T0, low, high);
|
||||
gen_rot_overflow(decode, s->T0, decode->cc_src2, NULL);
|
||||
gen_rot_overflow(decode, s->T0, decode->cc_src2, false, NULL);
|
||||
|
||||
if (zero_label) {
|
||||
gen_set_label(zero_label);
|
||||
@ -3129,9 +3130,10 @@ static TCGv_i32 gen_rot_replicate(MemOp ot, TCGv in)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_rot_carry(X86DecodedInsn *decode, TCGv result, TCGv count, int bit)
|
||||
static void gen_rot_carry(X86DecodedInsn *decode, TCGv result,
|
||||
bool can_be_zero, TCGv count, int bit)
|
||||
{
|
||||
if (count == NULL) {
|
||||
if (!can_be_zero) {
|
||||
tcg_gen_extract_tl(decode->cc_dst, result, bit, 1);
|
||||
} else {
|
||||
TCGv temp = tcg_temp_new();
|
||||
@ -3165,8 +3167,8 @@ static void gen_ROL(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
} else {
|
||||
tcg_gen_rotl_tl(s->T0, s->T0, count);
|
||||
}
|
||||
gen_rot_carry(decode, s->T0, count, 0);
|
||||
gen_rot_overflow(decode, s->T0, old, count);
|
||||
gen_rot_carry(decode, s->T0, can_be_zero, count, 0);
|
||||
gen_rot_overflow(decode, s->T0, old, can_be_zero, count);
|
||||
}
|
||||
|
||||
static void gen_ROR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
@ -3190,12 +3192,12 @@ static void gen_ROR(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
tcg_gen_rotr_i32(temp32, temp32, count32);
|
||||
/* Zero extend to facilitate later optimization. */
|
||||
tcg_gen_extu_i32_tl(s->T0, temp32);
|
||||
gen_rot_carry(decode, s->T0, count, 31);
|
||||
gen_rot_carry(decode, s->T0, can_be_zero, count, 31);
|
||||
} else {
|
||||
tcg_gen_rotr_tl(s->T0, s->T0, count);
|
||||
gen_rot_carry(decode, s->T0, count, TARGET_LONG_BITS - 1);
|
||||
gen_rot_carry(decode, s->T0, can_be_zero, count, TARGET_LONG_BITS - 1);
|
||||
}
|
||||
gen_rot_overflow(decode, s->T0, old, count);
|
||||
gen_rot_overflow(decode, s->T0, old, can_be_zero, count);
|
||||
}
|
||||
|
||||
static void gen_RORX(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
|
||||
|
@ -145,27 +145,24 @@ void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
|
||||
|
||||
/* bcd */
|
||||
|
||||
/* XXX: exception */
|
||||
void helper_aam(CPUX86State *env, int base)
|
||||
target_ulong helper_aam(target_ulong al, target_ulong base)
|
||||
{
|
||||
int al, ah;
|
||||
int ah;
|
||||
|
||||
al = env->regs[R_EAX] & 0xff;
|
||||
al &= 0xff;
|
||||
ah = al / base;
|
||||
al = al % base;
|
||||
env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
|
||||
CC_DST = al;
|
||||
return al | (ah << 8);
|
||||
}
|
||||
|
||||
void helper_aad(CPUX86State *env, int base)
|
||||
target_ulong helper_aad(target_ulong ax, target_ulong base)
|
||||
{
|
||||
int al, ah;
|
||||
|
||||
al = env->regs[R_EAX] & 0xff;
|
||||
ah = (env->regs[R_EAX] >> 8) & 0xff;
|
||||
al = ax & 0xff;
|
||||
ah = (ax >> 8) & 0xff;
|
||||
al = ((ah * base) + al) & 0xff;
|
||||
env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al;
|
||||
CC_DST = al;
|
||||
return al;
|
||||
}
|
||||
|
||||
void helper_aaa(CPUX86State *env)
|
||||
|
@ -30,13 +30,17 @@ static void test_topo_bits(void)
|
||||
{
|
||||
X86CPUTopoInfo topo_info = {0};
|
||||
|
||||
/* simple tests for 1 thread per core, 1 core per die, 1 die per package */
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1};
|
||||
/*
|
||||
* simple tests for 1 thread per core, 1 core per module,
|
||||
* 1 module per die, 1 die per package
|
||||
*/
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 1};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 0);
|
||||
g_assert_cmpuint(apicid_core_width(&topo_info), ==, 0);
|
||||
g_assert_cmpuint(apicid_module_width(&topo_info), ==, 0);
|
||||
g_assert_cmpuint(apicid_die_width(&topo_info), ==, 0);
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 1};
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 0), ==, 0);
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1), ==, 1);
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 2), ==, 2);
|
||||
@ -45,39 +49,48 @@ static void test_topo_bits(void)
|
||||
|
||||
/* Test field width calculation for multiple values
|
||||
*/
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 2};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 2};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 1);
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 3};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 3};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2);
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 4};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 4};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2);
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 14};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 14};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 4);
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 15};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 15};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 4);
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 16};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 16};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 4);
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 17};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 1, 17};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 5);
|
||||
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 30, 2};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 30, 2};
|
||||
g_assert_cmpuint(apicid_core_width(&topo_info), ==, 5);
|
||||
topo_info = (X86CPUTopoInfo) {1, 31, 2};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 31, 2};
|
||||
g_assert_cmpuint(apicid_core_width(&topo_info), ==, 5);
|
||||
topo_info = (X86CPUTopoInfo) {1, 32, 2};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 32, 2};
|
||||
g_assert_cmpuint(apicid_core_width(&topo_info), ==, 5);
|
||||
topo_info = (X86CPUTopoInfo) {1, 33, 2};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 33, 2};
|
||||
g_assert_cmpuint(apicid_core_width(&topo_info), ==, 6);
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 30, 2};
|
||||
topo_info = (X86CPUTopoInfo) {1, 6, 30, 2};
|
||||
g_assert_cmpuint(apicid_module_width(&topo_info), ==, 3);
|
||||
topo_info = (X86CPUTopoInfo) {1, 7, 30, 2};
|
||||
g_assert_cmpuint(apicid_module_width(&topo_info), ==, 3);
|
||||
topo_info = (X86CPUTopoInfo) {1, 8, 30, 2};
|
||||
g_assert_cmpuint(apicid_module_width(&topo_info), ==, 3);
|
||||
topo_info = (X86CPUTopoInfo) {1, 9, 30, 2};
|
||||
g_assert_cmpuint(apicid_module_width(&topo_info), ==, 4);
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 6, 30, 2};
|
||||
g_assert_cmpuint(apicid_die_width(&topo_info), ==, 0);
|
||||
topo_info = (X86CPUTopoInfo) {2, 30, 2};
|
||||
topo_info = (X86CPUTopoInfo) {2, 6, 30, 2};
|
||||
g_assert_cmpuint(apicid_die_width(&topo_info), ==, 1);
|
||||
topo_info = (X86CPUTopoInfo) {3, 30, 2};
|
||||
topo_info = (X86CPUTopoInfo) {3, 6, 30, 2};
|
||||
g_assert_cmpuint(apicid_die_width(&topo_info), ==, 2);
|
||||
topo_info = (X86CPUTopoInfo) {4, 30, 2};
|
||||
topo_info = (X86CPUTopoInfo) {4, 6, 30, 2};
|
||||
g_assert_cmpuint(apicid_die_width(&topo_info), ==, 2);
|
||||
|
||||
/* build a weird topology and see if IDs are calculated correctly
|
||||
@ -85,18 +98,19 @@ static void test_topo_bits(void)
|
||||
|
||||
/* This will use 2 bits for thread ID and 3 bits for core ID
|
||||
*/
|
||||
topo_info = (X86CPUTopoInfo) {1, 6, 3};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 6, 3};
|
||||
g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2);
|
||||
g_assert_cmpuint(apicid_core_offset(&topo_info), ==, 2);
|
||||
g_assert_cmpuint(apicid_module_offset(&topo_info), ==, 5);
|
||||
g_assert_cmpuint(apicid_die_offset(&topo_info), ==, 5);
|
||||
g_assert_cmpuint(apicid_pkg_offset(&topo_info), ==, 5);
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 6, 3};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 6, 3};
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 0), ==, 0);
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1), ==, 1);
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 2), ==, 2);
|
||||
|
||||
topo_info = (X86CPUTopoInfo) {1, 6, 3};
|
||||
topo_info = (X86CPUTopoInfo) {1, 1, 6, 3};
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1 * 3 + 0), ==,
|
||||
(1 << 2) | 0);
|
||||
g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1 * 3 + 1), ==,
|
||||
|
Loading…
Reference in New Issue
Block a user