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