1 #include <stdint.h>
2
3 #include <cpuinfo.h>
4 #include <x86/cpuid.h>
5 #include <cpuinfo/utils.h>
6 #include <cpuinfo/log.h>
7
8
9 enum cache_type {
10 cache_type_none = 0,
11 cache_type_data = 1,
12 cache_type_instruction = 2,
13 cache_type_unified = 3,
14 };
15
cpuinfo_x86_decode_deterministic_cache_parameters(struct cpuid_regs regs,struct cpuinfo_x86_caches * cache,uint32_t * package_cores_max)16 bool cpuinfo_x86_decode_deterministic_cache_parameters(
17 struct cpuid_regs regs,
18 struct cpuinfo_x86_caches* cache,
19 uint32_t* package_cores_max)
20 {
21 const uint32_t type = regs.eax & UINT32_C(0x1F);
22 if (type == cache_type_none) {
23 return false;
24 }
25
26 /* Level starts at 1 */
27 const uint32_t level = (regs.eax >> 5) & UINT32_C(0x7);
28
29 const uint32_t sets = 1 + regs.ecx;
30 const uint32_t line_size = 1 + (regs.ebx & UINT32_C(0x00000FFF));
31 const uint32_t partitions = 1 + ((regs.ebx >> 12) & UINT32_C(0x000003FF));
32 const uint32_t associativity = 1 + (regs.ebx >> 22);
33
34 *package_cores_max = 1 + (regs.eax >> 26);
35 const uint32_t processors = 1 + ((regs.eax >> 14) & UINT32_C(0x00000FFF));
36 const uint32_t apic_bits = bit_length(processors);
37
38 uint32_t flags = 0;
39 if (regs.edx & UINT32_C(0x00000002)) {
40 flags |= CPUINFO_CACHE_INCLUSIVE;
41 }
42 if (regs.edx & UINT32_C(0x00000004)) {
43 flags |= CPUINFO_CACHE_COMPLEX_INDEXING;
44 }
45 switch (level) {
46 case 1:
47 switch (type) {
48 case cache_type_unified:
49 cache->l1d = cache->l1i = (struct cpuinfo_x86_cache) {
50 .size = associativity * partitions * line_size * sets,
51 .associativity = associativity,
52 .sets = sets,
53 .partitions = partitions,
54 .line_size = line_size,
55 .flags = flags | CPUINFO_CACHE_UNIFIED,
56 .apic_bits = apic_bits
57 };
58 break;
59 case cache_type_data:
60 cache->l1d = (struct cpuinfo_x86_cache) {
61 .size = associativity * partitions * line_size * sets,
62 .associativity = associativity,
63 .sets = sets,
64 .partitions = partitions,
65 .line_size = line_size,
66 .flags = flags,
67 .apic_bits = apic_bits
68 };
69 break;
70 case cache_type_instruction:
71 cache->l1i = (struct cpuinfo_x86_cache) {
72 .size = associativity * partitions * line_size * sets,
73 .associativity = associativity,
74 .sets = sets,
75 .partitions = partitions,
76 .line_size = line_size,
77 .flags = flags,
78 .apic_bits = apic_bits
79 };
80 break;
81 }
82 break;
83 case 2:
84 switch (type) {
85 case cache_type_instruction:
86 cpuinfo_log_warning("unexpected L2 instruction cache reported in leaf 0x00000004 is ignored");
87 break;
88 case cache_type_unified:
89 flags |= CPUINFO_CACHE_UNIFIED;
90 case cache_type_data:
91 cache->l2 = (struct cpuinfo_x86_cache) {
92 .size = associativity * partitions * line_size * sets,
93 .associativity = associativity,
94 .sets = sets,
95 .partitions = partitions,
96 .line_size = line_size,
97 .flags = flags,
98 .apic_bits = apic_bits
99 };
100 break;
101 }
102 break;
103 case 3:
104 switch (type) {
105 case cache_type_instruction:
106 cpuinfo_log_warning("unexpected L3 instruction cache reported in leaf 0x00000004 is ignored");
107 break;
108 case cache_type_unified:
109 flags |= CPUINFO_CACHE_UNIFIED;
110 case cache_type_data:
111 cache->l3 = (struct cpuinfo_x86_cache) {
112 .size = associativity * partitions * line_size * sets,
113 .associativity = associativity,
114 .sets = sets,
115 .partitions = partitions,
116 .line_size = line_size,
117 .flags = flags,
118 .apic_bits = apic_bits
119 };
120 break;
121 }
122 break;
123 case 4:
124 switch (type) {
125 case cache_type_instruction:
126 cpuinfo_log_warning("unexpected L4 instruction cache reported in leaf 0x00000004 is ignored");
127 break;
128 case cache_type_unified:
129 flags |= CPUINFO_CACHE_UNIFIED;
130 case cache_type_data:
131 cache->l4 = (struct cpuinfo_x86_cache) {
132 .size = associativity * partitions * line_size * sets,
133 .associativity = associativity,
134 .sets = sets,
135 .partitions = partitions,
136 .line_size = line_size,
137 .flags = flags,
138 .apic_bits = apic_bits
139 };
140 break;
141 }
142 break;
143 default:
144 cpuinfo_log_warning("unexpected L%"PRIu32" cache reported in leaf 0x00000004 is ignored", level);
145 break;
146 }
147 return true;
148 }
149
150
cpuinfo_x86_decode_cache_properties(struct cpuid_regs regs,struct cpuinfo_x86_caches * cache)151 bool cpuinfo_x86_decode_cache_properties(
152 struct cpuid_regs regs,
153 struct cpuinfo_x86_caches* cache)
154 {
155 const uint32_t type = regs.eax & UINT32_C(0x1F);
156 if (type == cache_type_none) {
157 return false;
158 }
159
160 const uint32_t level = (regs.eax >> 5) & UINT32_C(0x7);
161 const uint32_t cores = 1 + ((regs.eax >> 14) & UINT32_C(0x00000FFF));
162 const uint32_t apic_bits = bit_length(cores);
163
164 const uint32_t sets = 1 + regs.ecx;
165 const uint32_t line_size = 1 + (regs.ebx & UINT32_C(0x00000FFF));
166 const uint32_t partitions = 1 + ((regs.ebx >> 12) & UINT32_C(0x000003FF));
167 const uint32_t associativity = 1 + (regs.ebx >> 22);
168
169 uint32_t flags = 0;
170 if (regs.edx & UINT32_C(0x00000002)) {
171 flags |= CPUINFO_CACHE_INCLUSIVE;
172 }
173
174 switch (level) {
175 case 1:
176 switch (type) {
177 case cache_type_unified:
178 cache->l1d = cache->l1i = (struct cpuinfo_x86_cache) {
179 .size = associativity * partitions * line_size * sets,
180 .associativity = associativity,
181 .sets = sets,
182 .partitions = partitions,
183 .line_size = line_size,
184 .flags = flags | CPUINFO_CACHE_UNIFIED,
185 .apic_bits = apic_bits
186 };
187 break;
188 case cache_type_data:
189 cache->l1d = (struct cpuinfo_x86_cache) {
190 .size = associativity * partitions * line_size * sets,
191 .associativity = associativity,
192 .sets = sets,
193 .partitions = partitions,
194 .line_size = line_size,
195 .flags = flags,
196 .apic_bits = apic_bits
197 };
198 break;
199 case cache_type_instruction:
200 cache->l1i = (struct cpuinfo_x86_cache) {
201 .size = associativity * partitions * line_size * sets,
202 .associativity = associativity,
203 .sets = sets,
204 .partitions = partitions,
205 .line_size = line_size,
206 .flags = flags,
207 .apic_bits = apic_bits
208 };
209 break;
210 }
211 break;
212 case 2:
213 switch (type) {
214 case cache_type_instruction:
215 cpuinfo_log_warning("unexpected L2 instruction cache reported in leaf 0x8000001D is ignored");
216 break;
217 case cache_type_unified:
218 flags |= CPUINFO_CACHE_UNIFIED;
219 case cache_type_data:
220 cache->l2 = (struct cpuinfo_x86_cache) {
221 .size = associativity * partitions * line_size * sets,
222 .associativity = associativity,
223 .sets = sets,
224 .partitions = partitions,
225 .line_size = line_size,
226 .flags = flags,
227 .apic_bits = apic_bits
228 };
229 break;
230 }
231 break;
232 case 3:
233 switch (type) {
234 case cache_type_instruction:
235 cpuinfo_log_warning("unexpected L3 instruction cache reported in leaf 0x8000001D is ignored");
236 break;
237 case cache_type_unified:
238 flags |= CPUINFO_CACHE_UNIFIED;
239 case cache_type_data:
240 cache->l3 = (struct cpuinfo_x86_cache) {
241 .size = associativity * partitions * line_size * sets,
242 .associativity = associativity,
243 .sets = sets,
244 .partitions = partitions,
245 .line_size = line_size,
246 .flags = flags,
247 .apic_bits = apic_bits
248 };
249 break;
250 }
251 break;
252 default:
253 cpuinfo_log_warning("unexpected L%"PRIu32" cache reported in leaf 0x8000001D is ignored", level);
254 break;
255 }
256 return true;
257 }
258