1 /*
2 * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31
32 #include <pexpert/pexpert.h>
33 #include <arm/cpuid.h>
34 #include <arm/cpuid_internal.h>
35 #include <arm/cpu_data_internal.h>
36 #include <vm/vm_page.h>
37 #include "proc_reg.h"
38
39 #include <libkern/section_keywords.h>
40
41 /* Temporary types to aid decoding,
42 * Everything in Little Endian */
43
44 typedef struct {
45 uint32_t
46 Ctype1:3, /* 2:0 */
47 Ctype2:3, /* 5:3 */
48 Ctype3:3, /* 8:6 */
49 Ctypes:15, /* 6:23 - Don't Care */
50 LoC:3, /* 26-24 - Level of Coherency */
51 LoU:3, /* 29:27 - Level of Unification */
52 RAZ:2; /* 31:30 - Read-As-Zero */
53 } arm_cache_clidr_t;
54
55 typedef union {
56 arm_cache_clidr_t bits;
57 uint32_t value;
58 } arm_cache_clidr_info_t;
59
60
61 typedef struct {
62 uint32_t
63 LineSize:3, /* 2:0 - Number of words in cache line */
64 Assoc:10, /* 12:3 - Associativity of cache */
65 NumSets:15, /* 27:13 - Number of sets in cache */
66 c_type:4; /* 31:28 - Cache type */
67 } arm_cache_ccsidr_t;
68
69
70 typedef union {
71 arm_cache_ccsidr_t bits;
72 uint32_t value;
73 } arm_cache_ccsidr_info_t;
74
75 /* Statics */
76
77 static SECURITY_READ_ONLY_LATE(arm_cpu_info_t) cpuid_cpu_info;
78 static SECURITY_READ_ONLY_LATE(cache_info_t *) cpuid_cache_info_boot_cpu;
79 static cache_info_t cpuid_cache_info[MAX_CPU_TYPES] = { 0 };
80 static _Atomic uint8_t cpuid_cache_info_bitmap = 0;
81
82 /* Code */
83
84 __private_extern__
85 void
do_cpuid(void)86 do_cpuid(void)
87 {
88 cpuid_cpu_info.value = machine_read_midr();
89 #if (__ARM_ARCH__ == 8)
90
91 #if defined(HAS_APPLE_PAC)
92 cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8E;
93 #else /* defined(HAS_APPLE_PAC) */
94 cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8;
95 #endif /* defined(HAS_APPLE_PAC) */
96
97 #elif (__ARM_ARCH__ == 7)
98 #ifdef __ARM_SUB_ARCH__
99 cpuid_cpu_info.arm_info.arm_arch = __ARM_SUB_ARCH__;
100 #else /* __ARM_SUB_ARCH__ */
101 cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv7;
102 #endif /* __ARM_SUB_ARCH__ */
103 #else /* (__ARM_ARCH__ != 7) && (__ARM_ARCH__ != 8) */
104 /* 1176 architecture lives in the extended feature register */
105 if (cpuid_cpu_info.arm_info.arm_arch == CPU_ARCH_EXTENDED) {
106 arm_isa_feat1_reg isa = machine_read_isa_feat1();
107
108 /*
109 * if isa feature register 1 [15:12] == 0x2, this chip
110 * supports sign extention instructions, which indicate ARMv6
111 */
112 if (isa.field.sign_zero_ext_support == 0x2) {
113 cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv6;
114 }
115 }
116 #endif /* (__ARM_ARCH__ != 7) && (__ARM_ARCH__ != 8) */
117 }
118
119 arm_cpu_info_t *
cpuid_info(void)120 cpuid_info(void)
121 {
122 return &cpuid_cpu_info;
123 }
124
125 int
cpuid_get_cpufamily(void)126 cpuid_get_cpufamily(void)
127 {
128 int cpufamily = 0;
129
130 switch (cpuid_info()->arm_info.arm_implementor) {
131 case CPU_VID_ARM:
132 switch (cpuid_info()->arm_info.arm_part) {
133 case CPU_PART_CORTEXA9:
134 cpufamily = CPUFAMILY_ARM_14;
135 break;
136 case CPU_PART_CORTEXA8:
137 cpufamily = CPUFAMILY_ARM_13;
138 break;
139 case CPU_PART_CORTEXA7:
140 cpufamily = CPUFAMILY_ARM_15;
141 break;
142 case CPU_PART_1136JFS:
143 case CPU_PART_1176JZFS:
144 cpufamily = CPUFAMILY_ARM_11;
145 break;
146 case CPU_PART_926EJS:
147 case CPU_PART_920T:
148 cpufamily = CPUFAMILY_ARM_9;
149 break;
150 default:
151 cpufamily = CPUFAMILY_UNKNOWN;
152 break;
153 }
154 break;
155
156 case CPU_VID_INTEL:
157 cpufamily = CPUFAMILY_ARM_XSCALE;
158 break;
159
160 case CPU_VID_APPLE:
161 switch (cpuid_info()->arm_info.arm_part) {
162 case CPU_PART_TYPHOON:
163 case CPU_PART_TYPHOON_CAPRI:
164 cpufamily = CPUFAMILY_ARM_TYPHOON;
165 break;
166 case CPU_PART_TWISTER:
167 case CPU_PART_TWISTER_ELBA_MALTA:
168 cpufamily = CPUFAMILY_ARM_TWISTER;
169 break;
170 case CPU_PART_HURRICANE:
171 case CPU_PART_HURRICANE_MYST:
172 cpufamily = CPUFAMILY_ARM_HURRICANE;
173 break;
174 case CPU_PART_MONSOON:
175 case CPU_PART_MISTRAL:
176 cpufamily = CPUFAMILY_ARM_MONSOON_MISTRAL;
177 break;
178 case CPU_PART_VORTEX:
179 case CPU_PART_TEMPEST:
180 case CPU_PART_TEMPEST_M9:
181 case CPU_PART_VORTEX_ARUBA:
182 case CPU_PART_TEMPEST_ARUBA:
183 cpufamily = CPUFAMILY_ARM_VORTEX_TEMPEST;
184 break;
185 case CPU_PART_LIGHTNING:
186 case CPU_PART_THUNDER:
187 #ifndef RC_HIDE_XNU_FIRESTORM
188 case CPU_PART_THUNDER_M10:
189 #endif
190 cpufamily = CPUFAMILY_ARM_LIGHTNING_THUNDER;
191 break;
192 case CPU_PART_FIRESTORM_JADE_CHOP:
193 case CPU_PART_FIRESTORM_JADE_DIE:
194 case CPU_PART_ICESTORM_JADE_CHOP:
195 case CPU_PART_ICESTORM_JADE_DIE:
196 #ifndef RC_HIDE_XNU_FIRESTORM
197 case CPU_PART_FIRESTORM:
198 case CPU_PART_ICESTORM:
199 case CPU_PART_FIRESTORM_TONGA:
200 case CPU_PART_ICESTORM_TONGA:
201 cpufamily = CPUFAMILY_ARM_FIRESTORM_ICESTORM;
202 break;
203 #endif
204 default:
205 cpufamily = CPUFAMILY_UNKNOWN;
206 break;
207 }
208 break;
209
210 default:
211 cpufamily = CPUFAMILY_UNKNOWN;
212 break;
213 }
214
215 return cpufamily;
216 }
217
218 int
cpuid_get_cpusubfamily(void)219 cpuid_get_cpusubfamily(void)
220 {
221 int cpusubfamily = CPUSUBFAMILY_UNKNOWN;
222
223 if (cpuid_info()->arm_info.arm_implementor != CPU_VID_APPLE) {
224 return cpusubfamily;
225 }
226
227 switch (cpuid_info()->arm_info.arm_part) {
228 case CPU_PART_TYPHOON:
229 case CPU_PART_TWISTER:
230 case CPU_PART_HURRICANE:
231 case CPU_PART_MONSOON:
232 case CPU_PART_MISTRAL:
233 case CPU_PART_VORTEX:
234 case CPU_PART_TEMPEST:
235 case CPU_PART_LIGHTNING:
236 case CPU_PART_THUNDER:
237 #ifndef RC_HIDE_XNU_FIRESTORM
238 case CPU_PART_FIRESTORM:
239 case CPU_PART_ICESTORM:
240 #endif
241 cpusubfamily = CPUSUBFAMILY_ARM_HP;
242 break;
243 case CPU_PART_TYPHOON_CAPRI:
244 case CPU_PART_TWISTER_ELBA_MALTA:
245 case CPU_PART_HURRICANE_MYST:
246 case CPU_PART_VORTEX_ARUBA:
247 case CPU_PART_TEMPEST_ARUBA:
248 #ifndef RC_HIDE_XNU_FIRESTORM
249 case CPU_PART_FIRESTORM_TONGA:
250 case CPU_PART_ICESTORM_TONGA:
251 #endif
252 cpusubfamily = CPUSUBFAMILY_ARM_HG;
253 break;
254 case CPU_PART_TEMPEST_M9:
255 #ifndef RC_HIDE_XNU_FIRESTORM
256 case CPU_PART_THUNDER_M10:
257 #endif
258 cpusubfamily = CPUSUBFAMILY_ARM_M;
259 break;
260 case CPU_PART_FIRESTORM_JADE_CHOP:
261 case CPU_PART_ICESTORM_JADE_CHOP:
262 cpusubfamily = CPUSUBFAMILY_ARM_HS;
263 break;
264 case CPU_PART_FIRESTORM_JADE_DIE:
265 case CPU_PART_ICESTORM_JADE_DIE:
266 cpusubfamily = CPUSUBFAMILY_ARM_HC_HD;
267 break;
268 default:
269 cpusubfamily = CPUFAMILY_UNKNOWN;
270 break;
271 }
272
273 return cpusubfamily;
274 }
275
276 void
do_debugid(void)277 do_debugid(void)
278 {
279 machine_do_debugid();
280 }
281
282 arm_debug_info_t *
arm_debug_info(void)283 arm_debug_info(void)
284 {
285 return machine_arm_debug_info();
286 }
287
288 void
do_mvfpid(void)289 do_mvfpid(void)
290 {
291 return machine_do_mvfpid();
292 }
293
294 arm_mvfp_info_t
295 *
arm_mvfp_info(void)296 arm_mvfp_info(void)
297 {
298 return machine_arm_mvfp_info();
299 }
300
301 void
do_cacheid(void)302 do_cacheid(void)
303 {
304 arm_cache_clidr_info_t arm_cache_clidr_info;
305 arm_cache_ccsidr_info_t arm_cache_ccsidr_info;
306
307 /*
308 * We only need to parse cache geometry parameters once per cluster type.
309 * Skip this if some other core of the same type has already parsed them.
310 */
311 cluster_type_t cluster_type = ml_get_topology_info()->cpus[ml_get_cpu_number_local()].cluster_type;
312 uint8_t prev_cpuid_cache_info_bitmap = os_atomic_or_orig(&cpuid_cache_info_bitmap,
313 (uint8_t)(1 << cluster_type), acq_rel);
314 if (prev_cpuid_cache_info_bitmap & (1 << cluster_type)) {
315 return;
316 }
317
318 cache_info_t *cpuid_cache_info_p = &cpuid_cache_info[cluster_type];
319
320 arm_cache_clidr_info.value = machine_read_clidr();
321
322 /*
323 * For compatibility purposes with existing callers, let's cache the boot CPU
324 * cache parameters and return those upon any call to cache_info();
325 */
326 if (prev_cpuid_cache_info_bitmap == 0) {
327 cpuid_cache_info_boot_cpu = cpuid_cache_info_p;
328 }
329
330 /* Select L1 data/unified cache */
331
332 machine_write_csselr(CSSELR_L1, CSSELR_DATA_UNIFIED);
333 arm_cache_ccsidr_info.value = machine_read_ccsidr();
334
335 cpuid_cache_info_p->c_unified = (arm_cache_clidr_info.bits.Ctype1 == 0x4) ? 1 : 0;
336
337 switch (arm_cache_ccsidr_info.bits.c_type) {
338 case 0x1:
339 cpuid_cache_info_p->c_type = CACHE_WRITE_ALLOCATION;
340 break;
341 case 0x2:
342 cpuid_cache_info_p->c_type = CACHE_READ_ALLOCATION;
343 break;
344 case 0x4:
345 cpuid_cache_info_p->c_type = CACHE_WRITE_BACK;
346 break;
347 case 0x8:
348 cpuid_cache_info_p->c_type = CACHE_WRITE_THROUGH;
349 break;
350 default:
351 cpuid_cache_info_p->c_type = CACHE_UNKNOWN;
352 }
353
354 cpuid_cache_info_p->c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
355 cpuid_cache_info_p->c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
356
357 /* I cache size */
358 cpuid_cache_info_p->c_isize = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz * cpuid_cache_info_p->c_assoc;
359
360 /* D cache size */
361 cpuid_cache_info_p->c_dsize = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz * cpuid_cache_info_p->c_assoc;
362
363
364 if ((arm_cache_clidr_info.bits.Ctype3 == 0x4) ||
365 (arm_cache_clidr_info.bits.Ctype2 == 0x4) || (arm_cache_clidr_info.bits.Ctype2 == 0x2)) {
366 if (arm_cache_clidr_info.bits.Ctype3 == 0x4) {
367 /* Select L3 (LLC) if the SoC is new enough to have that.
368 * This will be the second-level cache for the highest-performing ACC. */
369 machine_write_csselr(CSSELR_L3, CSSELR_DATA_UNIFIED);
370 } else {
371 /* Select L2 data cache */
372 machine_write_csselr(CSSELR_L2, CSSELR_DATA_UNIFIED);
373 }
374 arm_cache_ccsidr_info.value = machine_read_ccsidr();
375
376 cpuid_cache_info_p->c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
377 cpuid_cache_info_p->c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
378 cpuid_cache_info_p->c_l2size = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz * cpuid_cache_info_p->c_assoc;
379 cpuid_cache_info_p->c_inner_cache_size = cpuid_cache_info_p->c_dsize;
380 cpuid_cache_info_p->c_bulksize_op = cpuid_cache_info_p->c_l2size;
381
382 /* capri has a 2MB L2 cache unlike every other SoC up to this
383 * point with a 1MB L2 cache, so to get the same performance
384 * gain from coloring, we have to double the number of colors.
385 * Note that in general (and in fact as it's implemented in
386 * i386/cpuid.c), the number of colors is calculated as the
387 * cache line size * the number of sets divided by the page
388 * size. Also note that for H8 devices and up, the page size
389 * will be 16k instead of 4, which will reduce the number of
390 * colors required. Thus, this is really a temporary solution
391 * for capri specifically that we may want to generalize later:
392 *
393 * TODO: Are there any special considerations for our unusual
394 * cache geometries (3MB)?
395 */
396 vm_cache_geometry_colors = ((arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info_p->c_linesz) / PAGE_SIZE;
397 kprintf(" vm_cache_geometry_colors: %d\n", vm_cache_geometry_colors);
398 } else {
399 cpuid_cache_info_p->c_l2size = 0;
400
401 cpuid_cache_info_p->c_inner_cache_size = cpuid_cache_info_p->c_dsize;
402 cpuid_cache_info_p->c_bulksize_op = cpuid_cache_info_p->c_dsize;
403 }
404
405 if (cpuid_cache_info_p->c_unified == 0) {
406 machine_write_csselr(CSSELR_L1, CSSELR_INSTR);
407 arm_cache_ccsidr_info.value = machine_read_ccsidr();
408 uint32_t c_linesz = 4 * (1 << (arm_cache_ccsidr_info.bits.LineSize + 2));
409 uint32_t c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
410 /* I cache size */
411 cpuid_cache_info_p->c_isize = (arm_cache_ccsidr_info.bits.NumSets + 1) * c_linesz * c_assoc;
412 }
413
414 kprintf("%s() - %u bytes %s cache (I:%u D:%u (%s)), %u-way assoc, %u bytes/line\n",
415 __FUNCTION__,
416 cpuid_cache_info_p->c_dsize + cpuid_cache_info_p->c_isize,
417 ((cpuid_cache_info_p->c_type == CACHE_WRITE_BACK) ? "WB" :
418 (cpuid_cache_info_p->c_type == CACHE_WRITE_THROUGH ? "WT" : "Unknown")),
419 cpuid_cache_info_p->c_isize,
420 cpuid_cache_info_p->c_dsize,
421 (cpuid_cache_info_p->c_unified) ? "unified" : "separate",
422 cpuid_cache_info_p->c_assoc,
423 cpuid_cache_info_p->c_linesz);
424 }
425
426 cache_info_t *
cache_info(void)427 cache_info(void)
428 {
429 return cpuid_cache_info_boot_cpu;
430 }
431
432 cache_info_t *
cache_info_type(cluster_type_t cluster_type)433 cache_info_type(cluster_type_t cluster_type)
434 {
435 assert((cluster_type >= 0) && (cluster_type < MAX_CPU_TYPES));
436 return &cpuid_cache_info[cluster_type];
437 }
438