Skip to content

Commit 5e891bf

Browse files
ehabkostafaerber
authored andcommitted
target-i386: Use #defines instead of magic numbers for CPUID cache info
This is an attempt to make the CPUID cache topology code clearer, by replacing the magic numbers in the code with #defines, and moving all the cache information to the same place in the file. I took care of comparing the assembly output of compiling target-i386/cpu.c before and after applying this change, to make sure not a single bit was changed on cpu_x86_cpuid() before and after applying this patch (unfortunately I had to manually check existing differences, because of __LINE__ expansions on object_class_dynamic_cast_assert() calls). This even keeps the code bug-compatible with the previous version: today the cache information returned on AMD cache information leaves (CPUID 0x80000005 & 0x80000006) do not match the information returned on CPUID leaves 2 and 4. The L2 cache information on CPUID leaf 2 also doesn't match the information on CPUID leaf 2. The new constants should make it easier to eventually fix those inconsistencies. All inconsistencies I have found are documented in code comments. Signed-off-by: Eduardo Habkost <[email protected]> Reviewed-by: liguang <[email protected]> Signed-off-by: Andreas Färber <[email protected]>
1 parent 38fcbd3 commit 5e891bf

File tree

1 file changed

+162
-22
lines changed

1 file changed

+162
-22
lines changed

target-i386/cpu.c

Lines changed: 162 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,118 @@
4848
#include "hw/i386/apic_internal.h"
4949
#endif
5050

51+
52+
/* Cache topology CPUID constants: */
53+
54+
/* CPUID Leaf 2 Descriptors */
55+
56+
#define CPUID_2_L1D_32KB_8WAY_64B 0x2c
57+
#define CPUID_2_L1I_32KB_8WAY_64B 0x30
58+
#define CPUID_2_L2_2MB_8WAY_64B 0x7d
59+
60+
61+
/* CPUID Leaf 4 constants: */
62+
63+
/* EAX: */
64+
#define CPUID_4_TYPE_DCACHE 1
65+
#define CPUID_4_TYPE_ICACHE 2
66+
#define CPUID_4_TYPE_UNIFIED 3
67+
68+
#define CPUID_4_LEVEL(l) ((l) << 5)
69+
70+
#define CPUID_4_SELF_INIT_LEVEL (1 << 8)
71+
#define CPUID_4_FULLY_ASSOC (1 << 9)
72+
73+
/* EDX: */
74+
#define CPUID_4_NO_INVD_SHARING (1 << 0)
75+
#define CPUID_4_INCLUSIVE (1 << 1)
76+
#define CPUID_4_COMPLEX_IDX (1 << 2)
77+
78+
#define ASSOC_FULL 0xFF
79+
80+
/* AMD associativity encoding used on CPUID Leaf 0x80000006: */
81+
#define AMD_ENC_ASSOC(a) (a <= 1 ? a : \
82+
a == 2 ? 0x2 : \
83+
a == 4 ? 0x4 : \
84+
a == 8 ? 0x6 : \
85+
a == 16 ? 0x8 : \
86+
a == 32 ? 0xA : \
87+
a == 48 ? 0xB : \
88+
a == 64 ? 0xC : \
89+
a == 96 ? 0xD : \
90+
a == 128 ? 0xE : \
91+
a == ASSOC_FULL ? 0xF : \
92+
0 /* invalid value */)
93+
94+
95+
/* Definitions of the hardcoded cache entries we expose: */
96+
97+
/* L1 data cache: */
98+
#define L1D_LINE_SIZE 64
99+
#define L1D_ASSOCIATIVITY 8
100+
#define L1D_SETS 64
101+
#define L1D_PARTITIONS 1
102+
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
103+
#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B
104+
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
105+
#define L1D_LINES_PER_TAG 1
106+
#define L1D_SIZE_KB_AMD 64
107+
#define L1D_ASSOCIATIVITY_AMD 2
108+
109+
/* L1 instruction cache: */
110+
#define L1I_LINE_SIZE 64
111+
#define L1I_ASSOCIATIVITY 8
112+
#define L1I_SETS 64
113+
#define L1I_PARTITIONS 1
114+
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */
115+
#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B
116+
/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */
117+
#define L1I_LINES_PER_TAG 1
118+
#define L1I_SIZE_KB_AMD 64
119+
#define L1I_ASSOCIATIVITY_AMD 2
120+
121+
/* Level 2 unified cache: */
122+
#define L2_LINE_SIZE 64
123+
#define L2_ASSOCIATIVITY 16
124+
#define L2_SETS 4096
125+
#define L2_PARTITIONS 1
126+
/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */
127+
/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */
128+
#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B
129+
/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */
130+
#define L2_LINES_PER_TAG 1
131+
#define L2_SIZE_KB_AMD 512
132+
133+
/* No L3 cache: */
134+
#define L3_SIZE_KB 0 /* disabled */
135+
#define L3_ASSOCIATIVITY 0 /* disabled */
136+
#define L3_LINES_PER_TAG 0 /* disabled */
137+
#define L3_LINE_SIZE 0 /* disabled */
138+
139+
/* TLB definitions: */
140+
141+
#define L1_DTLB_2M_ASSOC 1
142+
#define L1_DTLB_2M_ENTRIES 255
143+
#define L1_DTLB_4K_ASSOC 1
144+
#define L1_DTLB_4K_ENTRIES 255
145+
146+
#define L1_ITLB_2M_ASSOC 1
147+
#define L1_ITLB_2M_ENTRIES 255
148+
#define L1_ITLB_4K_ASSOC 1
149+
#define L1_ITLB_4K_ENTRIES 255
150+
151+
#define L2_DTLB_2M_ASSOC 0 /* disabled */
152+
#define L2_DTLB_2M_ENTRIES 0 /* disabled */
153+
#define L2_DTLB_4K_ASSOC 4
154+
#define L2_DTLB_4K_ENTRIES 512
155+
156+
#define L2_ITLB_2M_ASSOC 0 /* disabled */
157+
#define L2_ITLB_2M_ENTRIES 0 /* disabled */
158+
#define L2_ITLB_4K_ASSOC 4
159+
#define L2_ITLB_4K_ENTRIES 512
160+
161+
162+
51163
static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
52164
uint32_t vendor2, uint32_t vendor3)
53165
{
@@ -1950,10 +2062,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
19502062
break;
19512063
case 2:
19522064
/* cache info: needed for Pentium Pro compatibility */
1953-
*eax = 1;
2065+
*eax = 1; /* Number of CPUID[EAX=2] calls required */
19542066
*ebx = 0;
19552067
*ecx = 0;
1956-
*edx = 0x2c307d;
2068+
*edx = (L1D_DESCRIPTOR << 16) | \
2069+
(L1I_DESCRIPTOR << 8) | \
2070+
(L2_DESCRIPTOR);
19572071
break;
19582072
case 4:
19592073
/* cache info: needed for Core compatibility */
@@ -1964,25 +2078,37 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
19642078
}
19652079
switch (count) {
19662080
case 0: /* L1 dcache info */
1967-
*eax |= 0x0000121;
1968-
*ebx = 0x1c0003f;
1969-
*ecx = 0x000003f;
1970-
*edx = 0x0000001;
2081+
*eax |= CPUID_4_TYPE_DCACHE | \
2082+
CPUID_4_LEVEL(1) | \
2083+
CPUID_4_SELF_INIT_LEVEL;
2084+
*ebx = (L1D_LINE_SIZE - 1) | \
2085+
((L1D_PARTITIONS - 1) << 12) | \
2086+
((L1D_ASSOCIATIVITY - 1) << 22);
2087+
*ecx = L1D_SETS - 1;
2088+
*edx = CPUID_4_NO_INVD_SHARING;
19712089
break;
19722090
case 1: /* L1 icache info */
1973-
*eax |= 0x0000122;
1974-
*ebx = 0x1c0003f;
1975-
*ecx = 0x000003f;
1976-
*edx = 0x0000001;
2091+
*eax |= CPUID_4_TYPE_ICACHE | \
2092+
CPUID_4_LEVEL(1) | \
2093+
CPUID_4_SELF_INIT_LEVEL;
2094+
*ebx = (L1I_LINE_SIZE - 1) | \
2095+
((L1I_PARTITIONS - 1) << 12) | \
2096+
((L1I_ASSOCIATIVITY - 1) << 22);
2097+
*ecx = L1I_SETS - 1;
2098+
*edx = CPUID_4_NO_INVD_SHARING;
19772099
break;
19782100
case 2: /* L2 cache info */
1979-
*eax |= 0x0000143;
2101+
*eax |= CPUID_4_TYPE_UNIFIED | \
2102+
CPUID_4_LEVEL(2) | \
2103+
CPUID_4_SELF_INIT_LEVEL;
19802104
if (cs->nr_threads > 1) {
19812105
*eax |= (cs->nr_threads - 1) << 14;
19822106
}
1983-
*ebx = 0x3c0003f;
1984-
*ecx = 0x0000fff;
1985-
*edx = 0x0000001;
2107+
*ebx = (L2_LINE_SIZE - 1) | \
2108+
((L2_PARTITIONS - 1) << 12) | \
2109+
((L2_ASSOCIATIVITY - 1) << 22);
2110+
*ecx = L2_SETS - 1;
2111+
*edx = CPUID_4_NO_INVD_SHARING;
19862112
break;
19872113
default: /* end of info */
19882114
*eax = 0;
@@ -2102,17 +2228,31 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
21022228
break;
21032229
case 0x80000005:
21042230
/* cache info (L1 cache) */
2105-
*eax = 0x01ff01ff;
2106-
*ebx = 0x01ff01ff;
2107-
*ecx = 0x40020140;
2108-
*edx = 0x40020140;
2231+
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \
2232+
(L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES);
2233+
*ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \
2234+
(L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES);
2235+
*ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \
2236+
(L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE);
2237+
*edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \
2238+
(L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE);
21092239
break;
21102240
case 0x80000006:
21112241
/* cache info (L2 cache) */
2112-
*eax = 0;
2113-
*ebx = 0x42004200;
2114-
*ecx = 0x02008140;
2115-
*edx = 0;
2242+
*eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \
2243+
(L2_DTLB_2M_ENTRIES << 16) | \
2244+
(AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \
2245+
(L2_ITLB_2M_ENTRIES);
2246+
*ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | \
2247+
(L2_DTLB_4K_ENTRIES << 16) | \
2248+
(AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \
2249+
(L2_ITLB_4K_ENTRIES);
2250+
*ecx = (L2_SIZE_KB_AMD << 16) | \
2251+
(AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \
2252+
(L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE);
2253+
*edx = ((L3_SIZE_KB/512) << 18) | \
2254+
(AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \
2255+
(L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE);
21162256
break;
21172257
case 0x80000008:
21182258
/* virtual & phys address size in low 2 bytes. */

0 commit comments

Comments
 (0)