• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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