aboutsummaryrefslogtreecommitdiff
path: root/target/i386/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/i386/cpu.c')
-rw-r--r--target/i386/cpu.c1165
1 files changed, 890 insertions, 275 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 0d35e95..251d576 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -28,6 +28,7 @@
#include "system/hvf.h"
#include "hvf/hvf-i386.h"
#include "kvm/kvm_i386.h"
+#include "kvm/tdx.h"
#include "sev.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -44,6 +45,7 @@
#include "hw/boards.h"
#include "hw/i386/sgx-epc.h"
#endif
+#include "system/qtest.h"
#include "tcg/tcg-cpu.h"
#include "disas/capstone.h"
@@ -66,6 +68,7 @@ struct CPUID2CacheDescriptorInfo {
/*
* Known CPUID 2 cache descriptors.
+ * TLB, prefetch and sectored cache related descriptors are not included.
* From Intel SDM Volume 2A, CPUID instruction
*/
struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = {
@@ -87,18 +90,29 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = {
.associativity = 2, .line_size = 64, },
[0x21] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB,
.associativity = 8, .line_size = 64, },
- /* lines per sector is not supported cpuid2_cache_descriptor(),
- * so descriptors 0x22, 0x23 are not included
- */
+ /*
+ * lines per sector is not supported cpuid2_cache_descriptor(),
+ * so descriptors 0x22, 0x23 are not included
+ */
[0x24] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB,
.associativity = 16, .line_size = 64, },
- /* lines per sector is not supported cpuid2_cache_descriptor(),
- * so descriptors 0x25, 0x20 are not included
- */
+ /*
+ * lines per sector is not supported cpuid2_cache_descriptor(),
+ * so descriptors 0x25, 0x29 are not included
+ */
[0x2C] = { .level = 1, .type = DATA_CACHE, .size = 32 * KiB,
.associativity = 8, .line_size = 64, },
[0x30] = { .level = 1, .type = INSTRUCTION_CACHE, .size = 32 * KiB,
.associativity = 8, .line_size = 64, },
+ /*
+ * Newer Intel CPUs (having the cores without L3, e.g., Intel MTL, ARL)
+ * use CPUID 0x4 leaf to describe cache topology, by encoding CPUID 0x2
+ * leaf with 0xFF. For older CPUs (without 0x4 leaf), it's also valid
+ * to just ignore L3's code if there's no L3.
+ *
+ * This already covers all the cases in QEMU, so code 0x40 is not
+ * included.
+ */
[0x41] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB,
.associativity = 4, .line_size = 32, },
[0x42] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB,
@@ -115,7 +129,18 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = {
.associativity = 8, .line_size = 64, },
[0x48] = { .level = 2, .type = UNIFIED_CACHE, .size = 3 * MiB,
.associativity = 12, .line_size = 64, },
- /* Descriptor 0x49 depends on CPU family/model, so it is not included */
+ /*
+ * Descriptor 0x49 has 2 cases:
+ * - 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size.
+ * - 3rd-level cache: 4MB, 16-way set associative, 64-byte line size
+ * (Intel Xeon processor MP, Family 0FH, Model 06H).
+ *
+ * When it represents L3, then it depends on CPU family/model. Fortunately,
+ * the legacy cache/CPU models don't have such special L3. So, just add it
+ * to represent the general L2 case.
+ */
+ [0x49] = { .level = 2, .type = UNIFIED_CACHE, .size = 4 * MiB,
+ .associativity = 16, .line_size = 64, },
[0x4A] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB,
.associativity = 12, .line_size = 64, },
[0x4B] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB,
@@ -136,9 +161,10 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = {
.associativity = 4, .line_size = 64, },
[0x78] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB,
.associativity = 4, .line_size = 64, },
- /* lines per sector is not supported cpuid2_cache_descriptor(),
- * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included.
- */
+ /*
+ * lines per sector is not supported cpuid2_cache_descriptor(),
+ * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included.
+ */
[0x7D] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB,
.associativity = 8, .line_size = 64, },
[0x7F] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB,
@@ -199,7 +225,7 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = {
* Return a CPUID 2 cache descriptor for a given cache.
* If no known descriptor is found, return CACHE_DESCRIPTOR_UNAVAILABLE
*/
-static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache)
+static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache, bool *unmacthed)
{
int i;
@@ -216,9 +242,46 @@ static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache)
}
}
+ *unmacthed |= true;
return CACHE_DESCRIPTOR_UNAVAILABLE;
}
+static const CPUCaches legacy_intel_cpuid2_cache_info;
+
+/* Encode cache info for CPUID[2] */
+static void encode_cache_cpuid2(X86CPU *cpu,
+ const CPUCaches *caches,
+ uint32_t *eax, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
+{
+ CPUX86State *env = &cpu->env;
+ int l1d, l1i, l2, l3;
+ bool unmatched = false;
+
+ *eax = 1; /* Number of CPUID[EAX=2] calls required */
+ *ebx = *ecx = *edx = 0;
+
+ l1d = cpuid2_cache_descriptor(caches->l1d_cache, &unmatched);
+ l1i = cpuid2_cache_descriptor(caches->l1i_cache, &unmatched);
+ l2 = cpuid2_cache_descriptor(caches->l2_cache, &unmatched);
+ l3 = cpuid2_cache_descriptor(caches->l3_cache, &unmatched);
+
+ if (!cpu->consistent_cache ||
+ (env->cpuid_min_level < 0x4 && !unmatched)) {
+ /*
+ * Though SDM defines code 0x40 for cases with no L2 or L3. It's
+ * also valid to just ignore l3's code if there's no l2.
+ */
+ if (cpu->enable_l3_cache) {
+ *ecx = l3;
+ }
+ *edx = (l1d << 16) | (l1i << 8) | l2;
+ } else {
+ *ecx = 0;
+ *edx = CACHE_DESCRIPTOR_UNAVAILABLE;
+ }
+}
+
/* CPUID Leaf 4 constants: */
/* EAX: */
@@ -286,11 +349,17 @@ static void encode_cache_cpuid4(CPUCacheInfo *cache,
assert(cache->size == cache->line_size * cache->associativity *
cache->partitions * cache->sets);
+ /*
+ * The following fields have bit-width limitations, so consider the
+ * maximum values to avoid overflow:
+ * Bits 25-14: maximum 4095.
+ * Bits 31-26: maximum 63.
+ */
*eax = CACHE_TYPE(cache->type) |
CACHE_LEVEL(cache->level) |
(cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) |
- (max_core_ids_in_package(topo_info) << 26) |
- (max_thread_ids_for_cache(topo_info, cache->share_level) << 14);
+ (MIN(max_core_ids_in_package(topo_info), 63) << 26) |
+ (MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14);
assert(cache->line_size > 0);
assert(cache->partitions > 0);
@@ -430,7 +499,6 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count,
static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache)
{
assert(cache->size % 1024 == 0);
- assert(cache->lines_per_tag > 0);
assert(cache->associativity > 0);
assert(cache->line_size > 0);
return ((cache->size / 1024) << 24) | (cache->associativity << 16) |
@@ -439,8 +507,8 @@ static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache)
#define ASSOC_FULL 0xFF
-/* AMD associativity encoding used on CPUID Leaf 0x80000006: */
-#define AMD_ENC_ASSOC(a) (a <= 1 ? a : \
+/* x86 associativity encoding used on CPUID Leaf 0x80000006: */
+#define X86_ENC_ASSOC(a) (a <= 1 ? a : \
a == 2 ? 0x2 : \
a == 4 ? 0x4 : \
a == 8 ? 0x6 : \
@@ -463,19 +531,18 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2,
{
assert(l2->size % 1024 == 0);
assert(l2->associativity > 0);
- assert(l2->lines_per_tag > 0);
assert(l2->line_size > 0);
*ecx = ((l2->size / 1024) << 16) |
- (AMD_ENC_ASSOC(l2->associativity) << 12) |
+ (X86_ENC_ASSOC(l2->associativity) << 12) |
(l2->lines_per_tag << 8) | (l2->line_size);
+ /* For Intel, EDX is reserved. */
if (l3) {
assert(l3->size % (512 * 1024) == 0);
assert(l3->associativity > 0);
- assert(l3->lines_per_tag > 0);
assert(l3->line_size > 0);
*edx = ((l3->size / (512 * 1024)) << 18) |
- (AMD_ENC_ASSOC(l3->associativity) << 12) |
+ (X86_ENC_ASSOC(l3->associativity) << 12) |
(l3->lines_per_tag << 8) | (l3->line_size);
} else {
*edx = 0;
@@ -493,7 +560,8 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache,
*eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) |
(cache->self_init ? CACHE_SELF_INIT_LEVEL : 0);
- *eax |= max_thread_ids_for_cache(topo_info, cache->share_level) << 14;
+ /* Bits 25:14 - NumSharingCache: maximum 4095. */
+ *eax |= MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14;
assert(cache->line_size > 0);
assert(cache->partitions > 0);
@@ -573,117 +641,172 @@ static void encode_topo_cpuid8000001e(X86CPU *cpu, X86CPUTopoInfo *topo_info,
* These are legacy cache values. If there is a need to change any
* of these values please use builtin_x86_defs
*/
-
-/* L1 data cache: */
-static CPUCacheInfo legacy_l1d_cache = {
- .type = DATA_CACHE,
- .level = 1,
- .size = 32 * KiB,
- .self_init = 1,
- .line_size = 64,
- .associativity = 8,
- .sets = 64,
- .partitions = 1,
- .no_invd_sharing = true,
- .share_level = CPU_TOPOLOGY_LEVEL_CORE,
-};
-
-/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
-static CPUCacheInfo legacy_l1d_cache_amd = {
- .type = DATA_CACHE,
- .level = 1,
- .size = 64 * KiB,
- .self_init = 1,
- .line_size = 64,
- .associativity = 2,
- .sets = 512,
- .partitions = 1,
- .lines_per_tag = 1,
- .no_invd_sharing = true,
- .share_level = CPU_TOPOLOGY_LEVEL_CORE,
-};
-
-/* L1 instruction cache: */
-static CPUCacheInfo legacy_l1i_cache = {
- .type = INSTRUCTION_CACHE,
- .level = 1,
- .size = 32 * KiB,
- .self_init = 1,
- .line_size = 64,
- .associativity = 8,
- .sets = 64,
- .partitions = 1,
- .no_invd_sharing = true,
- .share_level = CPU_TOPOLOGY_LEVEL_CORE,
-};
-
-/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
-static CPUCacheInfo legacy_l1i_cache_amd = {
- .type = INSTRUCTION_CACHE,
- .level = 1,
- .size = 64 * KiB,
- .self_init = 1,
- .line_size = 64,
- .associativity = 2,
- .sets = 512,
- .partitions = 1,
- .lines_per_tag = 1,
- .no_invd_sharing = true,
- .share_level = CPU_TOPOLOGY_LEVEL_CORE,
-};
-
-/* Level 2 unified cache: */
-static CPUCacheInfo legacy_l2_cache = {
- .type = UNIFIED_CACHE,
- .level = 2,
- .size = 4 * MiB,
- .self_init = 1,
- .line_size = 64,
- .associativity = 16,
- .sets = 4096,
- .partitions = 1,
- .no_invd_sharing = true,
- .share_level = CPU_TOPOLOGY_LEVEL_CORE,
-};
-
-/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */
-static CPUCacheInfo legacy_l2_cache_cpuid2 = {
- .type = UNIFIED_CACHE,
- .level = 2,
- .size = 2 * MiB,
- .line_size = 64,
- .associativity = 8,
- .share_level = CPU_TOPOLOGY_LEVEL_INVALID,
+static const CPUCaches legacy_amd_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ .type = DATA_CACHE,
+ .level = 1,
+ .size = 64 * KiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 2,
+ .sets = 512,
+ .partitions = 1,
+ .lines_per_tag = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .size = 64 * KiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 2,
+ .sets = 512,
+ .partitions = 1,
+ .lines_per_tag = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .size = 512 * KiB,
+ .line_size = 64,
+ .lines_per_tag = 1,
+ .associativity = 16,
+ .sets = 512,
+ .partitions = 1,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .size = 16 * MiB,
+ .line_size = 64,
+ .associativity = 16,
+ .sets = 16384,
+ .partitions = 1,
+ .lines_per_tag = 1,
+ .self_init = true,
+ .inclusive = true,
+ .complex_indexing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_DIE,
+ },
};
-
-/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */
-static CPUCacheInfo legacy_l2_cache_amd = {
- .type = UNIFIED_CACHE,
- .level = 2,
- .size = 512 * KiB,
- .line_size = 64,
- .lines_per_tag = 1,
- .associativity = 16,
- .sets = 512,
- .partitions = 1,
- .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+/*
+ * Only used for the CPU models with CPUID level < 4.
+ * These CPUs (CPUID level < 4) only use CPUID leaf 2 to present
+ * cache information.
+ *
+ * Note: This cache model is just a default one, and is not
+ * guaranteed to match real hardwares.
+ */
+static const CPUCaches legacy_intel_cpuid2_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ .type = DATA_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 8,
+ .sets = 64,
+ .partitions = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 8,
+ .sets = 64,
+ .partitions = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .size = 2 * MiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 8,
+ .sets = 4096,
+ .partitions = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .size = 16 * MiB,
+ .line_size = 64,
+ .associativity = 16,
+ .sets = 16384,
+ .partitions = 1,
+ .lines_per_tag = 1,
+ .self_init = true,
+ .inclusive = true,
+ .complex_indexing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_DIE,
+ },
};
-/* Level 3 unified cache: */
-static CPUCacheInfo legacy_l3_cache = {
- .type = UNIFIED_CACHE,
- .level = 3,
- .size = 16 * MiB,
- .line_size = 64,
- .associativity = 16,
- .sets = 16384,
- .partitions = 1,
- .lines_per_tag = 1,
- .self_init = true,
- .inclusive = true,
- .complex_indexing = true,
- .share_level = CPU_TOPOLOGY_LEVEL_DIE,
+static const CPUCaches legacy_intel_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ .type = DATA_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 8,
+ .sets = 64,
+ .partitions = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 8,
+ .sets = 64,
+ .partitions = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .size = 4 * MiB,
+ .self_init = 1,
+ .line_size = 64,
+ .associativity = 16,
+ .sets = 4096,
+ .partitions = 1,
+ .no_invd_sharing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .size = 16 * MiB,
+ .line_size = 64,
+ .associativity = 16,
+ .sets = 16384,
+ .partitions = 1,
+ .lines_per_tag = 1,
+ .self_init = true,
+ .inclusive = true,
+ .complex_indexing = true,
+ .share_level = CPU_TOPOLOGY_LEVEL_DIE,
+ },
};
/* TLB definitions: */
@@ -1943,7 +2066,7 @@ uint32_t xsave_area_size(uint64_t mask, bool compacted)
static inline bool accel_uses_host_cpuid(void)
{
- return kvm_enabled() || hvf_enabled();
+ return !tcg_enabled() && !qtest_enabled();
}
static inline uint64_t x86_cpu_xsave_xcr0_components(X86CPU *cpu)
@@ -2764,6 +2887,378 @@ static const CPUCaches epyc_turin_cache_info = {
.no_invd_sharing = true,
.complex_indexing = false,
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
+ }
+};
+
+static const CPUCaches xeon_spr_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x0.EAX */
+ .type = DATA_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x0.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 12,
+
+ /* CPUID 0x4.0x0.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x0.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 48 * KiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x1.EAX */
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x1.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 8,
+
+ /* CPUID 0x4.0x1.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x1.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 32 * KiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x2.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .self_init = true,
+
+ /* CPUID 0x4.0x2.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x2.ECX */
+ .sets = 2048,
+
+ /* CPUID 0x4.0x2.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 2 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x3.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .self_init = true,
+
+ /* CPUID 0x4.0x3.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 15,
+
+ /* CPUID 0x4.0x3.ECX */
+ .sets = 65536,
+
+ /* CPUID 0x4.0x3.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = true,
+
+ .size = 60 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_SOCKET,
+ },
+};
+
+static const CPUCaches xeon_gnr_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x0.EAX */
+ .type = DATA_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x0.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 12,
+
+ /* CPUID 0x4.0x0.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x0.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 48 * KiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x1.EAX */
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x1.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x1.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x1.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 64 * KiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x2.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .self_init = true,
+
+ /* CPUID 0x4.0x2.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x2.ECX */
+ .sets = 2048,
+
+ /* CPUID 0x4.0x2.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 2 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x3.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .self_init = true,
+
+ /* CPUID 0x4.0x3.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x3.ECX */
+ .sets = 294912,
+
+ /* CPUID 0x4.0x3.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = true,
+
+ .size = 288 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_SOCKET,
+ },
+};
+
+static const CPUCaches xeon_srf_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x0.EAX */
+ .type = DATA_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x0.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 8,
+
+ /* CPUID 0x4.0x0.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x0.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 32 * KiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x1.EAX */
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x1.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 8,
+
+ /* CPUID 0x4.0x1.ECX */
+ .sets = 128,
+
+ /* CPUID 0x4.0x1.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 64 * KiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x2.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .self_init = true,
+
+ /* CPUID 0x4.0x2.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x2.ECX */
+ .sets = 4096,
+
+ /* CPUID 0x4.0x2.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ .size = 4 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_MODULE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x3.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .self_init = true,
+
+ /* CPUID 0x4.0x3.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 12,
+
+ /* CPUID 0x4.0x3.ECX */
+ .sets = 147456,
+
+ /* CPUID 0x4.0x3.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = true,
+
+ .size = 108 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_SOCKET,
+ },
+};
+
+static const CPUCaches yongfeng_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x0.EAX */
+ .type = DATA_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x0.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 8,
+
+ /* CPUID 0x4.0x0.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x0.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ /* CPUID 0x80000005.ECX */
+ .lines_per_tag = 1,
+ .size = 32 * KiB,
+
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x1.EAX */
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .self_init = true,
+
+ /* CPUID 0x4.0x1.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x1.ECX */
+ .sets = 64,
+
+ /* CPUID 0x4.0x1.EDX */
+ .no_invd_sharing = false,
+ .inclusive = false,
+ .complex_indexing = false,
+
+ /* CPUID 0x80000005.EDX */
+ .lines_per_tag = 1,
+ .size = 64 * KiB,
+
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x2.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .self_init = true,
+
+ /* CPUID 0x4.0x2.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 8,
+
+ /* CPUID 0x4.0x2.ECX */
+ .sets = 512,
+
+ /* CPUID 0x4.0x2.EDX */
+ .no_invd_sharing = false,
+ .inclusive = true,
+ .complex_indexing = false,
+
+ /* CPUID 0x80000006.ECX */
+ .size = 256 * KiB,
+
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ /* CPUID 0x4.0x3.EAX */
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .self_init = true,
+
+ /* CPUID 0x4.0x3.EBX */
+ .line_size = 64,
+ .partitions = 1,
+ .associativity = 16,
+
+ /* CPUID 0x4.0x3.ECX */
+ .sets = 8192,
+
+ /* CPUID 0x4.0x3.EDX */
+ .no_invd_sharing = true,
+ .inclusive = true,
+ .complex_indexing = false,
+
+ .size = 8 * MiB,
+ .share_level = CPU_TOPOLOGY_LEVEL_DIE,
},
};
@@ -3019,6 +3514,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
I486_FEATURES,
.xlevel = 0,
.model_id = "",
+ .cache_info = &legacy_intel_cpuid2_cache_info,
},
{
.name = "pentium",
@@ -3031,6 +3527,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
PENTIUM_FEATURES,
.xlevel = 0,
.model_id = "",
+ .cache_info = &legacy_intel_cpuid2_cache_info,
},
{
.name = "pentium2",
@@ -3043,6 +3540,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
PENTIUM2_FEATURES,
.xlevel = 0,
.model_id = "",
+ .cache_info = &legacy_intel_cpuid2_cache_info,
},
{
.name = "pentium3",
@@ -3055,6 +3553,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
PENTIUM3_FEATURES,
.xlevel = 0,
.model_id = "",
+ .cache_info = &legacy_intel_cpuid2_cache_info,
},
{
.name = "athlon",
@@ -4587,6 +5086,15 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 4,
+ .note = "with spr-sp cache model and 0x1f leaf",
+ .cache_info = &xeon_spr_cache_info,
+ .props = (PropValue[]) {
+ { "x-force-cpuid-0x1f", "on" },
+ { /* end of list */ },
+ }
+ },
{ /* end of list */ }
}
},
@@ -4740,6 +5248,15 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 3,
+ .note = "with gnr-sp cache model and 0x1f leaf",
+ .cache_info = &xeon_gnr_cache_info,
+ .props = (PropValue[]) {
+ { "x-force-cpuid-0x1f", "on" },
+ { /* end of list */ },
+ }
+ },
{ /* end of list */ },
},
},
@@ -4885,6 +5402,15 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 3,
+ .note = "with srf-sp cache model and 0x1f leaf",
+ .cache_info = &xeon_srf_cache_info,
+ .props = (PropValue[]) {
+ { "x-force-cpuid-0x1f", "on" },
+ { /* end of list */ },
+ }
+ },
{ /* end of list */ },
},
},
@@ -6027,6 +6553,15 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 3,
+ .note = "with the cache model and 0x1f leaf",
+ .cache_info = &yongfeng_cache_info,
+ .props = (PropValue[]) {
+ { "x-force-cpuid-0x1f", "on" },
+ { /* end of list */ },
+ }
+ },
{ /* end of list */ }
}
},
@@ -6187,6 +6722,7 @@ static void max_x86_cpu_class_init(ObjectClass *oc, const void *data)
xcc->ordering = 9;
+ xcc->max_features = true;
xcc->model_description =
"Enables all features supported by the accelerator in the current host";
@@ -6197,22 +6733,21 @@ static void max_x86_cpu_class_init(ObjectClass *oc, const void *data)
static void max_x86_cpu_initfn(Object *obj)
{
X86CPU *cpu = X86_CPU(obj);
-
- /* We can't fill the features array here because we don't know yet if
- * "migratable" is true or false.
- */
- cpu->max_features = true;
- object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort);
+ CPUX86State *env = &cpu->env;
/*
- * these defaults are used for TCG and all other accelerators
- * besides KVM and HVF, which overwrite these values
+ * these defaults are used for TCG, other accelerators have overwritten
+ * these values
*/
- object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD,
- &error_abort);
- object_property_set_str(OBJECT(cpu), "model-id",
- "QEMU TCG CPU version " QEMU_HW_VERSION,
- &error_abort);
+ if (!env->cpuid_vendor1) {
+ object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD,
+ &error_abort);
+ }
+ if (!env->cpuid_model[0]) {
+ object_property_set_str(OBJECT(cpu), "model-id",
+ "QEMU TCG CPU version " QEMU_HW_VERSION,
+ &error_abort);
+ }
}
static const TypeInfo max_x86_cpu_type_info = {
@@ -6324,10 +6859,7 @@ static void x86_cpuid_version_get_family(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
uint64_t value;
- value = (env->cpuid_version >> 8) & 0xf;
- if (value == 0xf) {
- value += (env->cpuid_version >> 20) & 0xff;
- }
+ value = x86_cpu_family(env->cpuid_version);
visit_type_uint64(v, name, &value, errp);
}
@@ -6365,8 +6897,7 @@ static void x86_cpuid_version_get_model(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
uint64_t value;
- value = (env->cpuid_version >> 4) & 0xf;
- value |= ((env->cpuid_version >> 16) & 0xf) << 4;
+ value = x86_cpu_model(env->cpuid_version);
visit_type_uint64(v, name, &value, errp);
}
@@ -6400,7 +6931,7 @@ static void x86_cpuid_version_get_stepping(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
uint64_t value;
- value = env->cpuid_version & 0xf;
+ value = x86_cpu_stepping(env->cpuid_version);
visit_type_uint64(v, name, &value, errp);
}
@@ -6468,11 +6999,11 @@ static char *x86_cpuid_get_model_id(Object *obj, Error **errp)
char *value;
int i;
- value = g_malloc(48 + 1);
- for (i = 0; i < 48; i++) {
+ value = g_malloc(CPUID_MODEL_ID_SZ + 1);
+ for (i = 0; i < CPUID_MODEL_ID_SZ; i++) {
value[i] = env->cpuid_model[i >> 2] >> (8 * (i & 3));
}
- value[48] = '\0';
+ value[CPUID_MODEL_ID_SZ] = '\0';
return value;
}
@@ -6487,7 +7018,7 @@ static void x86_cpuid_set_model_id(Object *obj, const char *model_id,
model_id = "";
}
len = strlen(model_id);
- memset(env->cpuid_model, 0, 48);
+ memset(env->cpuid_model, 0, CPUID_MODEL_ID_SZ);
for (i = 0; i < 48; i++) {
if (i >= len) {
c = '\0';
@@ -7347,11 +7878,35 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
*edx = env->features[FEAT_1_EDX];
if (threads_per_pkg > 1) {
- *ebx |= threads_per_pkg << 16;
+ uint32_t num;
+
+ /*
+ * For CPUID.01H.EBX[Bits 23-16], AMD requires logical processor
+ * count, but Intel needs maximum number of addressable IDs for
+ * logical processors per package.
+ */
+ if (cpu->vendor_cpuid_only_v2 &&
+ (IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
+ num = 1 << apicid_pkg_offset(topo_info);
+ } else {
+ num = threads_per_pkg;
+ }
+
+ /* Fixup overflow: max value for bits 23-16 is 255. */
+ *ebx |= MIN(num, 255) << 16;
}
break;
- case 2:
- /* cache info: needed for Pentium Pro compatibility */
+ case 2: { /* cache info: needed for Pentium Pro compatibility */
+ const CPUCaches *caches;
+
+ if (env->enable_legacy_cpuid2_cache) {
+ caches = &legacy_intel_cpuid2_cache_info;
+ } else if (env->enable_legacy_vendor_cache) {
+ caches = &legacy_intel_cache_info;
+ } else {
+ caches = &env->cache_info;
+ }
+
if (cpu->cache_info_passthrough) {
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
break;
@@ -7359,18 +7914,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*eax = *ebx = *ecx = *edx = 0;
break;
}
- *eax = 1; /* Number of CPUID[EAX=2] calls required */
- *ebx = 0;
- if (!cpu->enable_l3_cache) {
- *ecx = 0;
+ encode_cache_cpuid2(cpu, caches, eax, ebx, ecx, edx);
+ break;
+ }
+ case 4: {
+ const CPUCaches *caches;
+
+ if (env->enable_legacy_vendor_cache) {
+ caches = &legacy_intel_cache_info;
} else {
- *ecx = cpuid2_cache_descriptor(env->cache_info_cpuid2.l3_cache);
+ caches = &env->cache_info;
}
- *edx = (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1d_cache) << 16) |
- (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1i_cache) << 8) |
- (cpuid2_cache_descriptor(env->cache_info_cpuid2.l2_cache));
- break;
- case 4:
+
/* cache info: needed for Core compatibility */
if (cpu->cache_info_passthrough) {
x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx);
@@ -7382,13 +7937,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14);
*eax &= ~0xFC000000;
- *eax |= max_core_ids_in_package(topo_info) << 26;
+ *eax |= MIN(max_core_ids_in_package(topo_info), 63) << 26;
if (host_vcpus_per_cache > threads_per_pkg) {
*eax &= ~0x3FFC000;
/* Share the cache at package level. */
- *eax |= max_thread_ids_for_cache(topo_info,
- CPU_TOPOLOGY_LEVEL_SOCKET) << 14;
+ *eax |= MIN(max_thread_ids_for_cache(topo_info,
+ CPU_TOPOLOGY_LEVEL_SOCKET), 4095) << 14;
}
}
} else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) {
@@ -7398,30 +7953,26 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
switch (count) {
case 0: /* L1 dcache info */
- encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache,
- topo_info,
+ encode_cache_cpuid4(caches->l1d_cache, 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,
- topo_info,
+ encode_cache_cpuid4(caches->l1i_cache, 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,
- topo_info,
+ encode_cache_cpuid4(caches->l2_cache, topo_info,
eax, ebx, ecx, edx);
break;
case 3: /* L3 cache info */
if (cpu->enable_l3_cache) {
- encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache,
- topo_info,
+ encode_cache_cpuid4(caches->l3_cache, topo_info,
eax, ebx, ecx, edx);
break;
}
@@ -7432,6 +7983,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
}
break;
+ }
case 5:
/* MONITOR/MWAIT Leaf */
*eax = cpu->mwait.eax; /* Smallest monitor-line size in bytes */
@@ -7522,21 +8074,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
assert(!(*eax & ~0x1f));
*ebx &= 0xffff; /* The count doesn't need to be reliable. */
break;
- case 0x1C:
- if (cpu->enable_pmu && (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) {
- x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx);
- *edx = 0;
- }
- break;
- case 0x1F:
- /* V2 Extended Topology Enumeration Leaf */
- if (!x86_has_cpuid_0x1f(cpu)) {
- *eax = *ebx = *ecx = *edx = 0;
- break;
- }
-
- encode_topo_cpuid1f(env, count, topo_info, eax, ebx, ecx, edx);
- break;
case 0xD: {
/* Processor Extended State */
*eax = 0;
@@ -7677,6 +8214,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
break;
}
+ case 0x1C:
+ if (cpu->enable_pmu && (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) {
+ x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx);
+ *edx = 0;
+ }
+ break;
case 0x1D: {
/* AMX TILE, for now hardcoded for Sapphire Rapids*/
*eax = 0;
@@ -7714,6 +8257,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
break;
}
+ case 0x1F:
+ /* V2 Extended Topology Enumeration Leaf */
+ if (!x86_has_cpuid_0x1f(cpu)) {
+ *eax = *ebx = *ecx = *edx = 0;
+ break;
+ }
+
+ encode_topo_cpuid1f(env, count, topo_info, eax, ebx, ecx, edx);
+ break;
case 0x24: {
*eax = 0;
*ebx = 0;
@@ -7750,9 +8302,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 0x80000000:
*eax = env->cpuid_xlevel;
- *ebx = env->cpuid_vendor1;
- *edx = env->cpuid_vendor2;
- *ecx = env->cpuid_vendor3;
+
+ if (cpu->vendor_cpuid_only_v2 &&
+ (IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
+ *ebx = *ecx = *edx = 0;
+ } else {
+ *ebx = env->cpuid_vendor1;
+ *edx = env->cpuid_vendor2;
+ *ecx = env->cpuid_vendor3;
+ }
break;
case 0x80000001:
*eax = env->cpuid_version;
@@ -7760,7 +8318,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = env->features[FEAT_8000_0001_ECX];
*edx = env->features[FEAT_8000_0001_EDX];
- if (tcg_enabled() && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 &&
+ if (tcg_enabled() && IS_INTEL_CPU(env) &&
!(env->hflags & HF_LMA_MASK)) {
*edx &= ~CPUID_EXT2_SYSCALL;
}
@@ -7773,41 +8331,78 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2];
*edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
break;
- case 0x80000005:
- /* cache info (L1 cache) */
+ case 0x80000005: {
+ /* cache info (L1 cache/TLB Associativity Field) */
+ const CPUCaches *caches;
+
+ if (env->enable_legacy_vendor_cache) {
+ caches = &legacy_amd_cache_info;
+ } else {
+ caches = &env->cache_info;
+ }
+
if (cpu->cache_info_passthrough) {
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
break;
}
+
+ if (cpu->vendor_cpuid_only_v2 && IS_INTEL_CPU(env)) {
+ *eax = *ebx = *ecx = *edx = 0;
+ break;
+ }
+
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) |
(L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES);
*ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) |
(L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES);
- *ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache);
- *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache);
+ *ecx = encode_cache_cpuid80000005(caches->l1d_cache);
+ *edx = encode_cache_cpuid80000005(caches->l1i_cache);
break;
- case 0x80000006:
- /* cache info (L2 cache) */
+ }
+ case 0x80000006: { /* cache info (L2 cache/TLB/L3 cache) */
+ const CPUCaches *caches;
+
+ if (env->enable_legacy_vendor_cache) {
+ caches = &legacy_amd_cache_info;
+ } else {
+ caches = &env->cache_info;
+ }
+
if (cpu->cache_info_passthrough) {
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
break;
}
- *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) |
+
+ if (cpu->vendor_cpuid_only_v2 &&
+ (IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
+ *eax = *ebx = 0;
+ encode_cache_cpuid80000006(caches->l2_cache,
+ NULL, ecx, edx);
+ break;
+ }
+
+ *eax = (X86_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) |
(L2_DTLB_2M_ENTRIES << 16) |
- (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) |
+ (X86_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) |
(L2_ITLB_2M_ENTRIES);
- *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) |
+ *ebx = (X86_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) |
(L2_DTLB_4K_ENTRIES << 16) |
- (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) |
+ (X86_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) |
(L2_ITLB_4K_ENTRIES);
- encode_cache_cpuid80000006(env->cache_info_amd.l2_cache,
+
+ encode_cache_cpuid80000006(caches->l2_cache,
cpu->enable_l3_cache ?
- env->cache_info_amd.l3_cache : NULL,
+ caches->l3_cache : NULL,
ecx, edx);
break;
+ }
case 0x80000007:
*eax = 0;
- *ebx = env->features[FEAT_8000_0007_EBX];
+ if (cpu->vendor_cpuid_only_v2 && IS_INTEL_CPU(env)) {
+ *ebx = 0;
+ } else {
+ *ebx = env->features[FEAT_8000_0007_EBX];
+ }
*ecx = 0;
*edx = env->features[FEAT_8000_0007_EDX];
break;
@@ -7820,6 +8415,17 @@ 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];
+
+ /*
+ * Don't emulate Bits [7:0] & Bits [15:12] for Intel/Zhaoxin, since
+ * they're using 0x1f leaf.
+ */
+ if (cpu->vendor_cpuid_only_v2 &&
+ (IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
+ *ecx = *edx = 0;
+ break;
+ }
+
if (threads_per_pkg > 1) {
/*
* Bits 15:12 is "The number of bits in the initial
@@ -7855,19 +8461,19 @@ 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,
+ encode_cache_cpuid8000001d(env->cache_info.l1d_cache,
topo_info, eax, ebx, ecx, edx);
break;
case 1: /* L1 icache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache,
+ encode_cache_cpuid8000001d(env->cache_info.l1i_cache,
topo_info, eax, ebx, ecx, edx);
break;
case 2: /* L2 cache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache,
+ encode_cache_cpuid8000001d(env->cache_info.l2_cache,
topo_info, eax, ebx, ecx, edx);
break;
case 3: /* L3 cache info */
- encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache,
+ encode_cache_cpuid8000001d(env->cache_info.l3_cache,
topo_info, eax, ebx, ecx, edx);
break;
default: /* end of info */
@@ -7888,6 +8494,21 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*edx = 0;
}
break;
+ case 0x8000001F:
+ *eax = *ebx = *ecx = *edx = 0;
+ if (sev_enabled()) {
+ *eax = 0x2;
+ *eax |= sev_es_enabled() ? 0x8 : 0;
+ *eax |= sev_snp_enabled() ? 0x10 : 0;
+ *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
+ *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */
+ }
+ break;
+ case 0x80000021:
+ *eax = *ebx = *ecx = *edx = 0;
+ *eax = env->features[FEAT_8000_0021_EAX];
+ *ebx = env->features[FEAT_8000_0021_EBX];
+ break;
case 0x80000022:
*eax = *ebx = *ecx = *edx = 0;
/* AMD Extended Performance Monitoring and Debug */
@@ -7920,21 +8541,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = 0;
*edx = 0;
break;
- case 0x8000001F:
- *eax = *ebx = *ecx = *edx = 0;
- if (sev_enabled()) {
- *eax = 0x2;
- *eax |= sev_es_enabled() ? 0x8 : 0;
- *eax |= sev_snp_enabled() ? 0x10 : 0;
- *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
- *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */
- }
- break;
- case 0x80000021:
- *eax = *ebx = *ecx = *edx = 0;
- *eax = env->features[FEAT_8000_0021_EAX];
- *ebx = env->features[FEAT_8000_0021_EBX];
- break;
default:
/* reserved values: zero */
*eax = 0;
@@ -8154,7 +8760,7 @@ static void mce_init(X86CPU *cpu)
CPUX86State *cenv = &cpu->env;
unsigned int bank;
- if (((cenv->cpuid_version >> 8) & 0xf) >= 6
+ if (x86_cpu_family(cenv->cpuid_version) >= 6
&& (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
(CPUID_MCE | CPUID_MCA)) {
cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF |
@@ -8282,6 +8888,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu)
*/
void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
{
+ X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
CPUX86State *env = &cpu->env;
FeatureWord w;
int i;
@@ -8301,12 +8908,12 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
}
}
- /*TODO: Now cpu->max_features doesn't overwrite features
+ /* TODO: Now xcc->max_features doesn't overwrite features
* set using QOM properties, and we can convert
* plus_features & minus_features to global properties
* inside x86_cpu_parse_featurestr() too.
*/
- if (cpu->max_features) {
+ if (xcc->max_features) {
for (w = 0; w < FEATURE_WORDS; w++) {
/* Override only features that weren't set explicitly
* by the user.
@@ -8338,7 +8945,8 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
}
}
- if (!cpu->enable_pmu) {
+ /* PDCM is fixed1 bit for TDX */
+ if (!cpu->enable_pmu && !is_tdx_vm()) {
mark_unavailable_features(cpu, FEAT_1_ECX,
env->user_features[FEAT_1_ECX] & CPUID_EXT_PDCM,
"This feature is not available due to PMU being disabled");
@@ -8574,46 +9182,34 @@ static bool x86_cpu_update_smp_cache_topo(MachineState *ms, X86CPU *cpu,
level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D);
if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) {
- env->cache_info_cpuid4.l1d_cache->share_level = level;
- env->cache_info_amd.l1d_cache->share_level = level;
+ env->cache_info.l1d_cache->share_level = level;
} else {
machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D,
- env->cache_info_cpuid4.l1d_cache->share_level);
- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D,
- env->cache_info_amd.l1d_cache->share_level);
+ env->cache_info.l1d_cache->share_level);
}
level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I);
if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) {
- env->cache_info_cpuid4.l1i_cache->share_level = level;
- env->cache_info_amd.l1i_cache->share_level = level;
+ env->cache_info.l1i_cache->share_level = level;
} else {
machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I,
- env->cache_info_cpuid4.l1i_cache->share_level);
- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I,
- env->cache_info_amd.l1i_cache->share_level);
+ env->cache_info.l1i_cache->share_level);
}
level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2);
if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) {
- env->cache_info_cpuid4.l2_cache->share_level = level;
- env->cache_info_amd.l2_cache->share_level = level;
+ env->cache_info.l2_cache->share_level = level;
} else {
machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2,
- env->cache_info_cpuid4.l2_cache->share_level);
- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2,
- env->cache_info_amd.l2_cache->share_level);
+ env->cache_info.l2_cache->share_level);
}
level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3);
if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) {
- env->cache_info_cpuid4.l3_cache->share_level = level;
- env->cache_info_amd.l3_cache->share_level = level;
+ env->cache_info.l3_cache->share_level = level;
} else {
machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3,
- env->cache_info_cpuid4.l3_cache->share_level);
- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3,
- env->cache_info_amd.l3_cache->share_level);
+ env->cache_info.l3_cache->share_level);
}
if (!machine_check_smp_cache(ms, errp)) {
@@ -8637,6 +9233,16 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
tcg_cflags_set(cs, CF_PCREL);
#endif
+ /*
+ * x-vendor-cpuid-only and v2 should be initernal only. But
+ * QEMU doesn't support "internal" property.
+ */
+ if (!cpu->vendor_cpuid_only && cpu->vendor_cpuid_only_v2) {
+ error_setg(errp, "x-vendor-cpuid-only-v2 property "
+ "depends on x-vendor-cpuid-only");
+ return;
+ }
+
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
error_setg(errp, "apic-id property was not initialized properly");
return;
@@ -8840,24 +9446,22 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
"CPU model '%s' doesn't support legacy-cache=off", name);
return;
}
- env->cache_info_cpuid2 = env->cache_info_cpuid4 = env->cache_info_amd =
- *cache_info;
+ env->cache_info = *cache_info;
} else {
/* Build legacy cache information */
- env->cache_info_cpuid2.l1d_cache = &legacy_l1d_cache;
- env->cache_info_cpuid2.l1i_cache = &legacy_l1i_cache;
- env->cache_info_cpuid2.l2_cache = &legacy_l2_cache_cpuid2;
- env->cache_info_cpuid2.l3_cache = &legacy_l3_cache;
+ if (!cpu->consistent_cache) {
+ env->enable_legacy_cpuid2_cache = true;
+ }
- env->cache_info_cpuid4.l1d_cache = &legacy_l1d_cache;
- env->cache_info_cpuid4.l1i_cache = &legacy_l1i_cache;
- env->cache_info_cpuid4.l2_cache = &legacy_l2_cache;
- env->cache_info_cpuid4.l3_cache = &legacy_l3_cache;
+ if (!cpu->vendor_cpuid_only_v2) {
+ env->enable_legacy_vendor_cache = true;
+ }
- env->cache_info_amd.l1d_cache = &legacy_l1d_cache_amd;
- env->cache_info_amd.l1i_cache = &legacy_l1i_cache_amd;
- env->cache_info_amd.l2_cache = &legacy_l2_cache_amd;
- env->cache_info_amd.l3_cache = &legacy_l3_cache;
+ if (IS_AMD_CPU(env)) {
+ env->cache_info = legacy_amd_cache_info;
+ } else {
+ env->cache_info = legacy_intel_cache_info;
+ }
}
#ifndef CONFIG_USER_ONLY
@@ -9016,6 +9620,16 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc,
static void x86_cpu_post_initfn(Object *obj)
{
+#ifndef CONFIG_USER_ONLY
+ if (current_machine && current_machine->cgs) {
+ x86_confidential_guest_cpu_instance_init(
+ X86_CONFIDENTIAL_GUEST(current_machine->cgs), (CPU(obj)));
+ }
+#endif
+}
+
+static void x86_cpu_init_xsave(void)
+{
static bool first = true;
uint64_t supported_xcr0;
int i;
@@ -9035,15 +9649,6 @@ static void x86_cpu_post_initfn(Object *obj)
}
}
}
-
- accel_cpu_instance_init(CPU(obj));
-
-#ifndef CONFIG_USER_ONLY
- if (current_machine && current_machine->cgs) {
- x86_confidential_guest_cpu_instance_init(
- X86_CONFIDENTIAL_GUEST(current_machine->cgs), (CPU(obj)));
- }
-#endif
}
static void x86_cpu_init_default_topo(X86CPU *cpu)
@@ -9112,6 +9717,13 @@ static void x86_cpu_initfn(Object *obj)
if (xcc->model) {
x86_cpu_load_model(cpu, xcc->model);
}
+
+ /*
+ * accel's cpu_instance_init may have the xsave check,
+ * so x86_ext_save_areas[] must be initialized before this.
+ */
+ x86_cpu_init_xsave();
+ accel_cpu_instance_init(CPU(obj));
}
static int64_t x86_cpu_get_arch_id(CPUState *cs)
@@ -9358,6 +9970,7 @@ static const Property x86_cpu_properties[] = {
DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor),
DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true),
DEFINE_PROP_BOOL("x-vendor-cpuid-only", X86CPU, vendor_cpuid_only, true),
+ DEFINE_PROP_BOOL("x-vendor-cpuid-only-v2", X86CPU, vendor_cpuid_only_v2, true),
DEFINE_PROP_BOOL("x-amd-topoext-features-only", X86CPU, amd_topoext_features_only, true),
DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false),
DEFINE_PROP_BOOL("l3-cache", X86CPU, enable_l3_cache, true),
@@ -9372,6 +9985,7 @@ static const Property x86_cpu_properties[] = {
* own cache information (see x86_cpu_load_def()).
*/
DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, true),
+ DEFINE_PROP_BOOL("x-consistent-cache", X86CPU, consistent_cache, true),
DEFINE_PROP_BOOL("legacy-multi-node", X86CPU, legacy_multi_node, false),
DEFINE_PROP_BOOL("xen-vapic", X86CPU, xen_vapic, false),
@@ -9393,6 +10007,7 @@ static const Property x86_cpu_properties[] = {
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_BOOL("x-force-cpuid-0x1f", X86CPU, force_cpuid_0x1f, false),
};
#ifndef CONFIG_USER_ONLY