On 4/23/25 7:46 PM, Zhao Liu wrote:
Per SDM, 0x80000005 leaf is reserved for Intel CPU, and its current
"assert" check blocks adding new cache model for non-AMD CPUs.
Therefore, check the vendor and encode this leaf as all-0 for Intel
CPU. And since Zhaoxin mostly follows Intel behavior, apply the vendor
check for Zhaoxin as well.
Note, for !vendor_cpuid_only case, non-AMD CPU would get the wrong
information, i.e., get AMD's cache model for Intel or Zhaoxin CPUs.
For this case, there is no need to tweak for non-AMD CPUs, because
vendor_cpuid_only has been turned on by default since PC machine v6.1.
Signed-off-by: Zhao Liu <zhao1....@intel.com>
---
target/i386/cpu.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 1b64ceaaba46..8fdafa8aedaf 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -7248,11 +7248,23 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index,
uint32_t count,
*edx = env->cpuid_model[(index - 0x80000002) * 4 + 3];
break;
case 0x80000005:
- /* cache info (L1 cache) */
- if (cpu->cache_info_passthrough) {
+ /*
+ * cache info (L1 cache)
+ *
+ * For !vendor_cpuid_only case, non-AMD CPU would get the wrong
+ * information, i.e., get AMD's cache model. It doesn't matter,
+ * vendor_cpuid_only has been turned on by default since
+ * PC machine v6.1.
+ */
+ if (cpu->vendor_cpuid_only &&
+ (IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
+ *eax = *ebx = *ecx = *edx = 0;
+ break;
+ } else if (cpu->cache_info_passthrough) {
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
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) |
I've reviewed the cache-related CPUID path and noticed an oddity: every AMD vCPU
model still reports identical hard-coded values for the L1 ITLB and L1 DTLB
fields in leaf 0x8000_0005. Your patch fixes this for Intel(and Zhaoxin), but
all AMD models continue to receive the same constants in EAX/EBX.
Do you know the reason for this choice? Is the guest expected to ignore those L1
TLB numbers? If so, I'll prepare a patch that adjusts only the Zhaoxin defaults
in leaf 0x8000_0005 like below, matching real YongFeng behaviour in ecx and edx,
but keep eax and ebx following AMD's behaviour.
## Notes
1. Changes tied to "-machine smp-cache xxx" (mainly
x86_cpu_update_smp_cache_topo()) are not included here.
2. Do you think I need Zhaoxin-specific legacy_l1d/l1i/l2/l3_cache helpers? If
yes, I'll add them with YongFeng sillicon topology data.
--- patch prototype start ---
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 7b223642ba..8a17e5ffe9 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -2726,6 +2726,66 @@ static const CPUCaches xeon_srf_cache_info = {
},
};
+static const CPUCaches yongfeng_cache_info = {
+ .l1d_cache = &(CPUCacheInfo) {
+ .type = DATA_CACHE,
+ .level = 1,
+ .size = 32 * KiB,
+ .line_size = 64,
+ .associativity = 8,
+ .partitions = 1,
+ .sets = 64,
+ .lines_per_tag = 1,
+ .inclusive = false,
+ .self_init = true,
+ .no_invd_sharing = false,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l1i_cache = &(CPUCacheInfo) {
+ .type = INSTRUCTION_CACHE,
+ .level = 1,
+ .size = 64 * KiB,
+ .line_size = 64,
+ .associativity = 16,
+ .partitions = 1,
+ .sets = 64,
+ .lines_per_tag = 1,
+ .inclusive = false,
+ .self_init = true,
+ .no_invd_sharing = false,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l2_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 2,
+ .size = 256 * KiB,
+ .line_size = 64,
+ .associativity = 8,
+ .partitions = 1,
+ .sets = 512,
+ .lines_per_tag = 1,
+ .inclusive = true,
+ .self_init = true,
+ .no_invd_sharing = false,
+ .share_level = CPU_TOPOLOGY_LEVEL_CORE,
+ },
+ .l3_cache = &(CPUCacheInfo) {
+ .type = UNIFIED_CACHE,
+ .level = 3,
+ .size = 8 * MiB,
+ .line_size = 64,
+ .associativity = 16,
+ .partitions = 1,
+ .sets = 8192,
+ .lines_per_tag = 1,
+ .self_init = true,
+ .inclusive = true,
+ .no_invd_sharing = true,
+ .complex_indexing = false,
+ .share_level = CPU_TOPOLOGY_LEVEL_DIE,
+ },
+};
+
/* The following VMX features are not supported by KVM and are left out in the
* CPU definitions:
*
@@ -5928,6 +5988,15 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+ {
+ .version = 3,
+ .note = "wiith the correct model number and cache info",
+ .props = (PropValue[]) {
+ { "model", "0x5b" },
+ { /* end of list */ }
+ },
+ .cache_info = &yongfeng_cache_info
+ },
{ /* end of list */ }
}
},
@@ -7565,8 +7634,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index,
uint32_t count,
* vendor_cpuid_only has been turned on by default since
* PC machine v6.1.
*/
- if (cpu->vendor_cpuid_only &&
- (IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
+ if (cpu->vendor_cpuid_only && IS_INTEL_CPU(env)) {
*eax = *ebx = *ecx = *edx = 0;
break;
} else if (cpu->cache_info_passthrough) {
@@ -7578,8 +7646,21 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index,
uint32_t count,
(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);
+
+ if (IS_AMD_CPU(env)) {
+ *ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache);
+ *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache);
+ break;
+ }
+ /* Zhaoxin follows AMD behaviour on leaf 0x8000_0005 */
+ if (IS_ZHAOXIN_CPU(env)) {
+ *ecx =
encode_cache_cpuid80000005(env->cache_info_zhaoxin.l1d_cache);
+ *edx =
encode_cache_cpuid80000005(env->cache_info_zhaoxin.l1i_cache);
+ break;
+ }
+
+ /* Other vendors */
+ *eax = *ebx = *ecx = *edx = 0;
break;
case 0x80000006:
/* cache info (L2 cache) */
@@ -8638,7 +8719,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error
**errp)
return;
}
env->cache_info_cpuid2 = env->cache_info_cpuid4 = env->cache_info_amd =
- *cache_info;
+ env->cache_info_zhaoxin = *cache_info;
} else {
/* Build legacy cache information */
env->cache_info_cpuid2.l1d_cache = &legacy_l1d_cache;
@@ -8655,6 +8736,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error
**errp)
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;
+
+ env->cache_info_zhaoxin.l1d_cache = &legacy_l1d_cache;
+ env->cache_info_zhaoxin.l1i_cache = &legacy_l1i_cache;
+ env->cache_info_zhaoxin.l2_cache = &legacy_l2_cache;
+ env->cache_info_zhaoxin.l3_cache = &legacy_l3_cache;
}
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index d98c9ba282..46bfd6f6b0 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2062,6 +2062,7 @@ typedef struct CPUArchState {
* with old QEMU versions.
*/
CPUCaches cache_info_cpuid2, cache_info_cpuid4, cache_info_amd;
+ CPUCaches cache_info_zhaoxin;
/* MTRRs */
uint64_t mtrr_fixed[11];