aarch64.c revision 1.10 1 /* $NetBSD: aarch64.c,v 1.10 2020/07/01 08:03:10 ryo Exp $ */
2
3 /*
4 * Copyright (c) 2018 Ryo Shimizu <ryo (at) nerv.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30
31 #ifndef lint
32 __RCSID("$NetBSD: aarch64.c,v 1.10 2020/07/01 08:03:10 ryo Exp $");
33 #endif /* no lint */
34
35 #include <sys/types.h>
36 #include <sys/cpuio.h>
37 #include <sys/sysctl.h>
38 #include <stdio.h>
39 #include <stdbool.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <inttypes.h>
43 #include <err.h>
44
45 #include <arm/cputypes.h>
46 #include <aarch64/armreg.h>
47
48 #include "../cpuctl.h"
49
50 struct cpuidtab {
51 uint32_t cpu_partnum;
52 const char *cpu_name;
53 const char *cpu_class;
54 const char *cpu_architecture;
55 };
56
57 struct impltab {
58 uint32_t impl_id;
59 const char *impl_name;
60 };
61
62 struct fieldinfo {
63 unsigned int flags;
64 #define FIELDINFO_FLAGS_DEC 0x0001
65 #define FIELDINFO_FLAGS_4LOG2 0x0002
66 unsigned char bitpos;
67 unsigned char bitwidth;
68 const char *name;
69 const char * const *info;
70 };
71
72
73 #define CPU_PARTMASK (CPU_ID_IMPLEMENTOR_MASK | CPU_ID_PARTNO_MASK)
74 const struct cpuidtab cpuids[] = {
75 { CPU_ID_CORTEXA53R0 & CPU_PARTMASK, "Cortex-A53", "Cortex", "V8-A" },
76 { CPU_ID_CORTEXA57R0 & CPU_PARTMASK, "Cortex-A57", "Cortex", "V8-A" },
77 { CPU_ID_CORTEXA72R0 & CPU_PARTMASK, "Cortex-A72", "Cortex", "V8-A" },
78 { CPU_ID_CORTEXA73R0 & CPU_PARTMASK, "Cortex-A73", "Cortex", "V8-A" },
79 { CPU_ID_CORTEXA55R1 & CPU_PARTMASK, "Cortex-A55", "Cortex", "V8.2-A" },
80 { CPU_ID_CORTEXA75R2 & CPU_PARTMASK, "Cortex-A75", "Cortex", "V8.2-A" },
81 { CPU_ID_CORTEXA76R3 & CPU_PARTMASK, "Cortex-A76", "Cortex", "V8.2-A" },
82 { CPU_ID_THUNDERXRX, "Cavium ThunderX", "Cavium", "V8-A" },
83 { CPU_ID_THUNDERX81XXRX, "Cavium ThunderX CN81XX", "Cavium", "V8-A" },
84 { CPU_ID_THUNDERX83XXRX, "Cavium ThunderX CN83XX", "Cavium", "V8-A" },
85 { CPU_ID_THUNDERX2RX, "Cavium ThunderX2", "Cavium", "V8.1-A" },
86 };
87
88 const struct impltab implids[] = {
89 { CPU_ID_ARM_LTD, "ARM Limited" },
90 { CPU_ID_BROADCOM, "Broadcom Corporation" },
91 { CPU_ID_CAVIUM, "Cavium Inc." },
92 { CPU_ID_DEC, "Digital Equipment Corporation" },
93 { CPU_ID_INFINEON, "Infineon Technologies AG" },
94 { CPU_ID_MOTOROLA, "Motorola or Freescale Semiconductor Inc." },
95 { CPU_ID_NVIDIA, "NVIDIA Corporation" },
96 { CPU_ID_APM, "Applied Micro Circuits Corporation" },
97 { CPU_ID_QUALCOMM, "Qualcomm Inc." },
98 { CPU_ID_SAMSUNG, "SAMSUNG" },
99 { CPU_ID_TI, "Texas Instruments" },
100 { CPU_ID_MARVELL, "Marvell International Ltd." },
101 { CPU_ID_APPLE, "Apple Inc." },
102 { CPU_ID_FARADAY, "Faraday Technology Corporation" },
103 { CPU_ID_INTEL, "Intel Corporation" }
104 };
105
106 /* ID_AA64PFR0_EL1 - AArch64 Processor Feature Register 0 */
107 struct fieldinfo id_aa64pfr0_fieldinfo[] = {
108 {
109 .bitpos = 0, .bitwidth = 4, .name = "EL0",
110 .info = (const char *[16]) { /* 16=4bit */
111 [0] = "No EL0",
112 [1] = "AArch64",
113 [2] = "AArch64/AArch32"
114 }
115 },
116 {
117 .bitpos = 4, .bitwidth = 4, .name = "EL1",
118 .info = (const char *[16]) { /* 16=4bit */
119 [0] = "No EL1",
120 [1] = "AArch64",
121 [2] = "AArch64/AArch32"
122 }
123 },
124 {
125 .bitpos = 8, .bitwidth = 4, .name = "EL2",
126 .info = (const char *[16]) { /* 16=4bit */
127 [0] = "No EL2",
128 [1] = "AArch64",
129 [2] = "AArch64/AArch32"
130 }
131 },
132 {
133 .bitpos = 12, .bitwidth = 4, .name = "EL3",
134 .info = (const char *[16]) { /* 16=4bit */
135 [0] = "No EL3",
136 [1] = "AArch64",
137 [2] = "AArch64/AArch32"
138 }
139 },
140 {
141 .bitpos = 16, .bitwidth = 4, .name = "FP",
142 .info = (const char *[16]) { /* 16=4bit */
143 [0] = "Floating Point",
144 [15] = "No Floating Point"
145 }
146 },
147 {
148 .bitpos = 20, .bitwidth = 4, .name = "AdvSIMD",
149 .info = (const char *[16]) { /* 16=4bit */
150 [0] = "Advanced SIMD",
151 [15] = "No Advanced SIMD"
152 }
153 },
154 {
155 .bitpos = 24, .bitwidth = 4, .name = "GIC",
156 .info = (const char *[16]) { /* 16=4bit */
157 [0] = "No GIC",
158 [1] = "GICv3"
159 }
160 },
161 { .bitwidth = 0 } /* end of table */
162 };
163
164 /* ID_AA64PFR1_EL1 - AArch64 Processor Feature Register 1 */
165 struct fieldinfo id_aa64pfr1_fieldinfo[] = {
166 {
167 .bitpos = 0, .bitwidth = 4, .name = "BT",
168 .info = (const char *[16]) { /* 16=4bit */
169 [0] = "Branch Target Identification not implemented",
170 [1] = "Branch Target Identification implemented",
171 }
172 },
173 {
174 .bitpos = 4, .bitwidth = 4, .name = "SSBS",
175 .info = (const char *[16]) { /* 16=4bit */
176 [0] = "Speculative Store Bypassing control not implemented",
177 [1] = "Speculative Store Bypassing control implemented",
178 [2] = "Speculative Store Bypassing control implemented, plus MSR/MRS"
179 }
180 },
181 {
182 .bitpos = 8, .bitwidth = 4, .name = "MTE",
183 .info = (const char *[16]) { /* 16=4bit */
184 [0] = "Tagged Memory Extension not implemented",
185 [1] = "Tagged Memory Extension implemented, EL0 only",
186 [2] = "Tagged Memory Extension implemented"
187 }
188 },
189 {
190 .bitpos = 12, .bitwidth = 4, .name = "RAS_frac",
191 .info = (const char *[16]) { /* 16=4bit */
192 [0] = "Regular RAS",
193 [1] = "RAS plus registers",
194 }
195 },
196 { .bitwidth = 0 } /* end of table */
197 };
198
199 /* ID_AA64ISAR0_EL1 - AArch64 Instruction Set Attribute Register 0 */
200 struct fieldinfo id_aa64isar0_fieldinfo[] = {
201 {
202 .bitpos = 4, .bitwidth = 4, .name = "AES",
203 .info = (const char *[16]) { /* 16=4bit */
204 [0] = "No AES",
205 [1] = "AESE/AESD/AESMC/AESIMC",
206 [2] = "AESE/AESD/AESMC/AESIMC+PMULL/PMULL2"
207 }
208 },
209 {
210 .bitpos = 8, .bitwidth = 4, .name = "SHA1",
211 .info = (const char *[16]) { /* 16=4bit */
212 [0] = "No SHA1",
213 [1] = "SHA1C/SHA1P/SHA1M/SHA1H/SHA1SU0/SHA1SU1"
214 }
215 },
216 {
217 .bitpos = 12, .bitwidth = 4, .name = "SHA2",
218 .info = (const char *[16]) { /* 16=4bit */
219 [0] = "No SHA2",
220 [1] = "SHA256H/SHA256H2/SHA256SU0/SHA256U1"
221 }
222 },
223 {
224 .bitpos = 16, .bitwidth = 4, .name = "CRC32",
225 .info = (const char *[16]) { /* 16=4bit */
226 [0] = "No CRC32",
227 [1] = "CRC32B/CRC32H/CRC32W/CRC32X"
228 "/CRC32CB/CRC32CH/CRC32CW/CRC32CX"
229 }
230 },
231 {
232 .bitpos = 60, .bitwidth = 4, .name = "RNDR",
233 .info = (const char *[16]) { /* 16=4bit */
234 [0] = "No RNDR/RNDRRS",
235 [1] = "RNDR/RNDRRS",
236 },
237 },
238 { .bitwidth = 0 } /* end of table */
239 };
240
241 /* ID_AA64MMFR0_EL1 - AArch64 Memory Model Feature Register 0 */
242 struct fieldinfo id_aa64mmfr0_fieldinfo[] = {
243 {
244 .bitpos = 0, .bitwidth = 4, .name = "PARange",
245 .info = (const char *[16]) { /* 16=4bit */
246 [0] = "32bits/4GB",
247 [1] = "36bits/64GB",
248 [2] = "40bits/1TB",
249 [3] = "42bits/4TB",
250 [4] = "44bits/16TB",
251 [5] = "48bits/256TB"
252 }
253 },
254 {
255 .bitpos = 4, .bitwidth = 4, .name = "ASIDBit",
256 .info = (const char *[16]) { /* 16=4bit */
257 [0] = "8bits",
258 [2] = "16bits"
259 }
260 },
261 {
262 .bitpos = 8, .bitwidth = 4, .name = "BigEnd",
263 .info = (const char *[16]) { /* 16=4bit */
264 [0] = "No mixed-endian",
265 [1] = "Mixed-endian"
266 }
267 },
268 {
269 .bitpos = 12, .bitwidth = 4, .name = "SNSMem",
270 .info = (const char *[16]) { /* 16=4bit */
271 [0] = "No distinction B/W Secure and Non-secure Memory",
272 [1] = "Distinction B/W Secure and Non-secure Memory"
273 }
274 },
275 {
276 .bitpos = 16, .bitwidth = 4, .name = "BigEndEL0",
277 .info = (const char *[16]) { /* 16=4bit */
278 [0] = "No mixed-endian at EL0",
279 [1] = "Mixed-endian at EL0"
280 }
281 },
282 {
283 .bitpos = 20, .bitwidth = 4, .name = "TGran16",
284 .info = (const char *[16]) { /* 16=4bit */
285 [0] = "No 16KB granule",
286 [1] = "16KB granule"
287 }
288 },
289 {
290 .bitpos = 24, .bitwidth = 4, .name = "TGran64",
291 .info = (const char *[16]) { /* 16=4bit */
292 [0] = "64KB granule",
293 [15] = "No 64KB granule"
294 }
295 },
296 {
297 .bitpos = 28, .bitwidth = 4, .name = "TGran4",
298 .info = (const char *[16]) { /* 16=4bit */
299 [0] = "4KB granule",
300 [15] = "No 4KB granule"
301 }
302 },
303 { .bitwidth = 0 } /* end of table */
304 };
305
306 /* ID_AA64MMFR1_EL1 - AArch64 Memory Model Feature Register 1 */
307 struct fieldinfo id_aa64mmfr1_fieldinfo[] = {
308 {
309 .bitpos = 0, .bitwidth = 4, .name = "HAFDBS",
310 .info = (const char *[16]) { /* 16=4bit */
311 [0] = "Access and Dirty flags not supported",
312 [1] = "Access flag supported",
313 [2] = "Access and Dirty flags supported",
314 }
315 },
316 {
317 .bitpos = 4, .bitwidth = 4, .name = "VMIDBits",
318 .info = (const char *[16]) { /* 16=4bit */
319 [0] = "8bits",
320 [2] = "16bits"
321 }
322 },
323 {
324 .bitpos = 8, .bitwidth = 4, .name = "VH",
325 .info = (const char *[16]) { /* 16=4bit */
326 [0] = "Virtualization Host Extensions not supported",
327 [1] = "Virtualization Host Extensions supported",
328 }
329 },
330 {
331 .bitpos = 12, .bitwidth = 4, .name = "HPDS",
332 .info = (const char *[16]) { /* 16=4bit */
333 [0] = "Disabling of hierarchical controls not supported",
334 [1] = "Disabling of hierarchical controls supported",
335 [2] = "Disabling of hierarchical controls supported, plus PTD"
336 }
337 },
338 {
339 .bitpos = 16, .bitwidth = 4, .name = "LO",
340 .info = (const char *[16]) { /* 16=4bit */
341 [0] = "LORegions not supported",
342 [1] = "LORegions supported"
343 }
344 },
345 {
346 .bitpos = 20, .bitwidth = 4, .name = "PAN",
347 .info = (const char *[16]) { /* 16=4bit */
348 [0] = "PAN not supported",
349 [1] = "PAN supported",
350 [2] = "PAN supported, and instructions supported"
351 }
352 },
353 {
354 .bitpos = 24, .bitwidth = 4, .name = "SpecSEI",
355 .info = (const char *[16]) { /* 16=4bit */
356 [0] = "SError interrupt not supported",
357 [1] = "SError interrupt supported"
358 }
359 },
360 {
361 .bitpos = 28, .bitwidth = 4, .name = "XNX",
362 .info = (const char *[16]) { /* 16=4bit */
363 [0] = "Distinction between EL0 and EL1 XN control at stage 2 not supported",
364 [1] = "Distinction between EL0 and EL1 XN control at stage 2 supported"
365 }
366 },
367 { .bitwidth = 0 } /* end of table */
368 };
369
370 /* ID_AA64DFR0_EL1 - AArch64 Debug Feature Register 0 */
371 struct fieldinfo id_aa64dfr0_fieldinfo[] = {
372 {
373 .bitpos = 0, .bitwidth = 4, .name = "DebugVer",
374 .info = (const char *[16]) { /* 16=4bit */
375 [6] = "v8-A debug architecture"
376 }
377 },
378 {
379 .bitpos = 4, .bitwidth = 4, .name = "TraceVer",
380 .info = (const char *[16]) { /* 16=4bit */
381 [0] = "Trace supported",
382 [1] = "Trace not supported"
383 }
384 },
385 {
386 .bitpos = 8, .bitwidth = 4, .name = "PMUVer",
387 .info = (const char *[16]) { /* 16=4bit */
388 [0] = "No Performance monitor",
389 [1] = "Performance monitor unit v3"
390 }
391 },
392 { .bitwidth = 0 } /* end of table */
393 };
394
395
396 /* MVFR0_EL1 - Media and VFP Feature Register 0 */
397 struct fieldinfo mvfr0_fieldinfo[] = {
398 {
399 .bitpos = 0, .bitwidth = 4, .name = "SIMDreg",
400 .info = (const char *[16]) { /* 16=4bit */
401 [0] = "No SIMD",
402 [1] = "16x64-bit SIMD",
403 [2] = "32x64-bit SIMD"
404 }
405 },
406 {
407 .bitpos = 4, .bitwidth = 4, .name = "FPSP",
408 .info = (const char *[16]) { /* 16=4bit */
409 [0] = "No VFP support single precision",
410 [1] = "VFPv2 support single precision",
411 [2] = "VFPv2/VFPv3/VFPv4 support single precision"
412 }
413 },
414 {
415 .bitpos = 8, .bitwidth = 4, .name = "FPDP",
416 .info = (const char *[16]) { /* 16=4bit */
417 [0] = "No VFP support double precision",
418 [1] = "VFPv2 support double precision",
419 [2] = "VFPv2/VFPv3/VFPv4 support double precision"
420 }
421 },
422 {
423 .bitpos = 12, .bitwidth = 4, .name = "FPTrap",
424 .info = (const char *[16]) { /* 16=4bit */
425 [0] = "No floating point exception trapping support",
426 [1] = "VFPv2/VFPv3/VFPv4 support exception trapping"
427 }
428 },
429 {
430 .bitpos = 16, .bitwidth = 4, .name = "FPDivide",
431 .info = (const char *[16]) { /* 16=4bit */
432 [0] = "VDIV not supported",
433 [1] = "VDIV supported"
434 }
435 },
436 {
437 .bitpos = 20, .bitwidth = 4, .name = "FPSqrt",
438 .info = (const char *[16]) { /* 16=4bit */
439 [0] = "VSQRT not supported",
440 [1] = "VSQRT supported"
441 }
442 },
443 {
444 .bitpos = 24, .bitwidth = 4, .name = "FPShVec",
445 .info = (const char *[16]) { /* 16=4bit */
446 [0] = "Short Vectors not supported",
447 [1] = "Short Vectors supported"
448 }
449 },
450 {
451 .bitpos = 28, .bitwidth = 4, .name = "FPRound",
452 .info = (const char *[16]) { /* 16=4bit */
453 [0] = "Only Round to Nearest mode",
454 [1] = "All rounding modes"
455 }
456 },
457 { .bitwidth = 0 } /* end of table */
458 };
459
460 /* MVFR1_EL1 - Media and VFP Feature Register 1 */
461 struct fieldinfo mvfr1_fieldinfo[] = {
462 {
463 .bitpos = 0, .bitwidth = 4, .name = "FPFtZ",
464 .info = (const char *[16]) { /* 16=4bit */
465 [0] = "only the Flush-to-Zero",
466 [1] = "full Denormalized number arithmetic"
467 }
468 },
469 {
470 .bitpos = 4, .bitwidth = 4, .name = "FPDNan",
471 .info = (const char *[16]) { /* 16=4bit */
472 [0] = "Default NaN",
473 [1] = "Propagation of NaN"
474 }
475 },
476 {
477 .bitpos = 8, .bitwidth = 4, .name = "SIMDLS",
478 .info = (const char *[16]) { /* 16=4bit */
479 [0] = "No Advanced SIMD Load/Store",
480 [1] = "Advanced SIMD Load/Store"
481 }
482 },
483 {
484 .bitpos = 12, .bitwidth = 4, .name = "SIMDInt",
485 .info = (const char *[16]) { /* 16=4bit */
486 [0] = "No Advanced SIMD Integer",
487 [1] = "Advanced SIMD Integer"
488 }
489 },
490 {
491 .bitpos = 16, .bitwidth = 4, .name = "SIMDSP",
492 .info = (const char *[16]) { /* 16=4bit */
493 [0] = "No Advanced SIMD single precision",
494 [1] = "Advanced SIMD single precision"
495 }
496 },
497 {
498 .bitpos = 20, .bitwidth = 4, .name = "SIMDHP",
499 .info = (const char *[16]) { /* 16=4bit */
500 [0] = "No Advanced SIMD half precision",
501 [1] = "Advanced SIMD half precision"
502 }
503 },
504 {
505 .bitpos = 24, .bitwidth = 4, .name = "FPHP",
506 .info = (const char *[16]) { /* 16=4bit */
507 [0] = "No half precision conversion",
508 [1] = "half/single precision conversion",
509 [2] = "half/single/double precision conversion"
510 }
511 },
512 {
513 .bitpos = 28, .bitwidth = 4, .name = "SIMDFMAC",
514 .info = (const char *[16]) { /* 16=4bit */
515 [0] = "No Fused Multiply-Accumulate",
516 [1] = "Fused Multiply-Accumulate"
517 }
518 },
519 { .bitwidth = 0 } /* end of table */
520 };
521
522 /* MVFR2_EL1 - Media and VFP Feature Register 2 */
523 struct fieldinfo mvfr2_fieldinfo[] = {
524 {
525 .bitpos = 0, .bitwidth = 4, .name = "SIMDMisc",
526 .info = (const char *[16]) { /* 16=4bit */
527 [0] = "No miscellaneous features",
528 [1] = "Conversion to Integer w/Directed Rounding modes",
529 [2] = "Conversion to Integer w/Directed Rounding modes"
530 ", Round to Integral floating point",
531 [3] = "Conversion to Integer w/Directed Rounding modes"
532 ", Round to Integral floating point"
533 ", MaxNum and MinNum"
534 }
535 },
536 {
537 .bitpos = 4, .bitwidth = 4, .name = "FPMisc",
538 .info = (const char *[16]) { /* 16=4bit */
539 [0] = "No miscellaneous features",
540 [1] = "Floating point selection",
541 [2] = "Floating point selection"
542 ", Conversion to Integer w/Directed Rounding modes",
543 [3] = "Floating point selection"
544 ", Conversion to Integer w/Directed Rounding modes"
545 ", Round to Integral floating point",
546 [4] = "Floating point selection"
547 ", Conversion to Integer w/Directed Rounding modes"
548 ", Round to Integral floating point"
549 ", MaxNum and MinNum"
550 }
551 },
552 { .bitwidth = 0 } /* end of table */
553 };
554
555 /* CLIDR_EL1 - Cache Level ID Register */
556 const char * const clidr_cachetype[8] = { /* 8=3bit */
557 [0] = "None",
558 [1] = "Instruction cache",
559 [2] = "Data cache",
560 [3] = "Instruction and Data cache",
561 [4] = "Unified cache"
562 };
563
564 struct fieldinfo clidr_fieldinfo[] = {
565 {
566 .bitpos = 0, .bitwidth = 3, .name = "L1",
567 .info = clidr_cachetype
568 },
569 {
570 .bitpos = 3, .bitwidth = 3, .name = "L2",
571 .info = clidr_cachetype
572 },
573 {
574 .bitpos = 6, .bitwidth = 3, .name = "L3",
575 .info = clidr_cachetype
576 },
577 {
578 .bitpos = 9, .bitwidth = 3, .name = "L4",
579 .info = clidr_cachetype
580 },
581 {
582 .bitpos = 12, .bitwidth = 3, .name = "L5",
583 .info = clidr_cachetype
584 },
585 {
586 .bitpos = 15, .bitwidth = 3, .name = "L6",
587 .info = clidr_cachetype
588 },
589 {
590 .bitpos = 18, .bitwidth = 3, .name = "L7",
591 .info = clidr_cachetype
592 },
593 {
594 .bitpos = 21, .bitwidth = 3, .name = "LoUU",
595 .flags = FIELDINFO_FLAGS_DEC
596 },
597 {
598 .bitpos = 24, .bitwidth = 3, .name = "LoC",
599 .flags = FIELDINFO_FLAGS_DEC
600 },
601 {
602 .bitpos = 27, .bitwidth = 3, .name = "LoUIS",
603 .flags = FIELDINFO_FLAGS_DEC
604 },
605 {
606 .bitpos = 30, .bitwidth = 3, .name = "ICB",
607 .flags = FIELDINFO_FLAGS_DEC
608 },
609 { .bitwidth = 0 } /* end of table */
610 };
611
612 struct fieldinfo ctr_fieldinfo[] = {
613 {
614 .bitpos = 0, .bitwidth = 4, .name = "IminLine",
615 .flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
616 },
617 {
618 .bitpos = 16, .bitwidth = 4, .name = "DminLine",
619 .flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
620 },
621 {
622 .bitpos = 14, .bitwidth = 2, .name = "L1 Icache policy",
623 .info = (const char *[4]) { /* 4=2bit */
624 [0] = "VMID aware PIPT (VPIPT)",
625 [1] = "ASID-tagged VIVT (AIVIVT)",
626 [2] = "VIPT",
627 [3] = "PIPT"
628 },
629 },
630 {
631 .bitpos = 20, .bitwidth = 4, .name = "ERG",
632 .flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
633 },
634 {
635 .bitpos = 24, .bitwidth = 4, .name = "CWG",
636 .flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
637 },
638 {
639 .bitpos = 28, .bitwidth = 1, .name = "DIC",
640 .flags = FIELDINFO_FLAGS_DEC
641 },
642 {
643 .bitpos = 29, .bitwidth = 1, .name = "IDC",
644 .flags = FIELDINFO_FLAGS_DEC
645 },
646 { .bitwidth = 0 } /* end of table */
647 };
648
649
650 static void
651 print_fieldinfo(const char *cpuname, const char *setname,
652 struct fieldinfo *fieldinfo, uint64_t data)
653 {
654 uint64_t v;
655 const char *info;
656 int i, flags;
657
658 #define WIDTHMASK(w) (0xffffffffffffffffULL >> (64 - (w)))
659
660 for (i = 0; fieldinfo[i].bitwidth != 0; i++) {
661 v = (data >> fieldinfo[i].bitpos) &
662 WIDTHMASK(fieldinfo[i].bitwidth);
663
664 flags = fieldinfo[i].flags;
665 info = NULL;
666 if (fieldinfo[i].info != NULL)
667 info = fieldinfo[i].info[v];
668
669 printf("%s: %s: %s: ",
670 cpuname, setname, fieldinfo[i].name);
671
672 if (info == NULL) {
673 if (flags & FIELDINFO_FLAGS_4LOG2)
674 v = 4 * (1 << v);
675 if (flags & FIELDINFO_FLAGS_DEC)
676 printf("%"PRIu64"\n", v);
677 else
678 printf("0x%"PRIx64"\n", v);
679 } else {
680 printf("%s\n", info);
681 }
682 }
683 }
684
685 /* MIDR_EL1 - Main ID Register */
686 static void
687 identify_midr(const char *cpuname, uint32_t cpuid)
688 {
689 unsigned int i;
690 uint32_t implid, cpupart, variant, revision;
691 const char *implementer = NULL;
692 static char implbuf[128];
693
694 implid = cpuid & CPU_ID_IMPLEMENTOR_MASK;
695 cpupart = cpuid & CPU_PARTMASK;
696 variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK);
697 revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK);
698
699 for (i = 0; i < __arraycount(implids); i++) {
700 if (implid == implids[i].impl_id) {
701 implementer = implids[i].impl_name;
702 }
703 }
704 if (implementer == NULL) {
705 snprintf(implbuf, sizeof(implbuf), "unknown implementer: 0x%02x",
706 implid >> 24);
707 implementer = implbuf;
708 }
709
710 for (i = 0; i < __arraycount(cpuids); i++) {
711 if (cpupart == cpuids[i].cpu_partnum) {
712 printf("%s: %s, %s r%dp%d (%s %s core)\n",
713 cpuname, implementer,
714 cpuids[i].cpu_name, variant, revision,
715 cpuids[i].cpu_class,
716 cpuids[i].cpu_architecture);
717 return;
718 }
719 }
720 printf("%s: unknown CPU ID: 0x%08x\n", cpuname, cpuid);
721 }
722
723 /* REVIDR_EL1 - Revision ID Register */
724 static void
725 identify_revidr(const char *cpuname, uint32_t revidr)
726 {
727 printf("%s: revision: 0x%08x\n", cpuname, revidr);
728 }
729
730 /* MPIDR_EL1 - Multiprocessor Affinity Register */
731 static void
732 identify_mpidr(const char *cpuname, uint32_t mpidr)
733 {
734 const char *setname = "multiprocessor affinity";
735
736 printf("%s: %s: Affinity-Level: %"PRIu64"-%"PRIu64"-%"PRIu64"-%"PRIu64"\n",
737 cpuname, setname,
738 __SHIFTOUT(mpidr, MPIDR_AFF3),
739 __SHIFTOUT(mpidr, MPIDR_AFF2),
740 __SHIFTOUT(mpidr, MPIDR_AFF1),
741 __SHIFTOUT(mpidr, MPIDR_AFF0));
742
743 if ((mpidr & MPIDR_U) == 0)
744 printf("%s: %s: Multiprocessor system\n", cpuname, setname);
745 else
746 printf("%s: %s: Uniprocessor system\n", cpuname, setname);
747
748 if ((mpidr & MPIDR_MT) == 0)
749 printf("%s: %s: Core Independent\n", cpuname, setname);
750 else
751 printf("%s: %s: Multi-Threading\n", cpuname, setname);
752
753 }
754
755 /* AA64DFR0 - Debug feature register 0 */
756 static void
757 identify_dfr0(const char *cpuname, uint64_t dfr0)
758 {
759 const char *setname = "debug feature 0";
760
761 printf("%s: %s: CTX_CMPs: %lu context-aware breakpoints\n",
762 cpuname, setname, __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_CTX_CMPS) + 1);
763 printf("%s: %s: WRPs: %lu watchpoints\n",
764 cpuname, setname, __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_WRPS) + 1);
765 printf("%s: %s: BRPs: %lu breakpoints\n",
766 cpuname, setname, __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_BRPS) + 1);
767 print_fieldinfo(cpuname, setname,
768 id_aa64dfr0_fieldinfo, dfr0);
769 }
770
771 void
772 identifycpu(int fd, const char *cpuname)
773 {
774 char path[128];
775 size_t len;
776 #define SYSCTL_CPU_ID_MAXSIZE 64
777 uint64_t sysctlbuf[SYSCTL_CPU_ID_MAXSIZE];
778 struct aarch64_sysctl_cpu_id *id =
779 (struct aarch64_sysctl_cpu_id *)sysctlbuf;
780
781 snprintf(path, sizeof path, "machdep.%s.cpu_id", cpuname);
782 len = sizeof(sysctlbuf);
783 memset(sysctlbuf, 0, len);
784 if (sysctlbyname(path, id, &len, 0, 0) == -1)
785 err(1, "couldn't get %s", path);
786 if (len != sizeof(struct aarch64_sysctl_cpu_id))
787 fprintf(stderr, "Warning: kernel version bumped?\n");
788
789 if (verbose) {
790 printf("%s: MIDR_EL1: 0x%08"PRIx64"\n",
791 cpuname, id->ac_midr);
792 printf("%s: MPIDR_EL1: 0x%016"PRIx64"\n",
793 cpuname, id->ac_mpidr);
794 printf("%s: ID_AA64DFR0_EL1: 0x%016"PRIx64"\n",
795 cpuname, id->ac_aa64dfr0);
796 printf("%s: ID_AA64DFR1_EL1: 0x%016"PRIx64"\n",
797 cpuname, id->ac_aa64dfr1);
798 printf("%s: ID_AA64ISAR0_EL1: 0x%016"PRIx64"\n",
799 cpuname, id->ac_aa64isar0);
800 printf("%s: ID_AA64ISAR1_EL1: 0x%016"PRIx64"\n",
801 cpuname, id->ac_aa64isar1);
802 printf("%s: ID_AA64MMFR0_EL1: 0x%016"PRIx64"\n",
803 cpuname, id->ac_aa64mmfr0);
804 printf("%s: ID_AA64MMFR1_EL1: 0x%016"PRIx64"\n",
805 cpuname, id->ac_aa64mmfr1);
806 printf("%s: ID_AA64MMFR2_EL1: 0x%016"PRIx64"\n",
807 cpuname, id->ac_aa64mmfr2);
808 printf("%s: ID_AA64PFR0_EL1: 0x%08"PRIx64"\n",
809 cpuname, id->ac_aa64pfr0);
810 printf("%s: ID_AA64PFR1_EL1: 0x%08"PRIx64"\n",
811 cpuname, id->ac_aa64pfr1);
812 printf("%s: ID_AA64ZFR0_EL1: 0x%016"PRIx64"\n",
813 cpuname, id->ac_aa64zfr0);
814 printf("%s: MVFR0_EL1: 0x%08"PRIx32"\n",
815 cpuname, id->ac_mvfr0);
816 printf("%s: MVFR1_EL1: 0x%08"PRIx32"\n",
817 cpuname, id->ac_mvfr1);
818 printf("%s: MVFR2_EL1: 0x%08"PRIx32"\n",
819 cpuname, id->ac_mvfr2);
820 printf("%s: CLIDR_EL1: 0x%016"PRIx64"\n",
821 cpuname, id->ac_clidr);
822 printf("%s: CTR_EL0: 0x%016"PRIx64"\n",
823 cpuname, id->ac_ctr);
824 }
825
826 identify_midr(cpuname, id->ac_midr);
827 identify_revidr(cpuname, id->ac_revidr);
828 identify_mpidr(cpuname, id->ac_mpidr);
829 print_fieldinfo(cpuname, "isa features 0",
830 id_aa64isar0_fieldinfo, id->ac_aa64isar0);
831 print_fieldinfo(cpuname, "memory model 0",
832 id_aa64mmfr0_fieldinfo, id->ac_aa64mmfr0);
833 print_fieldinfo(cpuname, "memory model 1",
834 id_aa64mmfr1_fieldinfo, id->ac_aa64mmfr1);
835 print_fieldinfo(cpuname, "processor feature 0",
836 id_aa64pfr0_fieldinfo, id->ac_aa64pfr0);
837 print_fieldinfo(cpuname, "processor feature 1",
838 id_aa64pfr1_fieldinfo, id->ac_aa64pfr1);
839 identify_dfr0(cpuname, id->ac_aa64dfr0);
840
841 print_fieldinfo(cpuname, "media and VFP features 0",
842 mvfr0_fieldinfo, id->ac_mvfr0);
843 print_fieldinfo(cpuname, "media and VFP features 1",
844 mvfr1_fieldinfo, id->ac_mvfr1);
845 print_fieldinfo(cpuname, "media and VFP features 2",
846 mvfr2_fieldinfo, id->ac_mvfr2);
847
848 if (len <= offsetof(struct aarch64_sysctl_cpu_id, ac_clidr))
849 return;
850 print_fieldinfo(cpuname, "cache level",
851 clidr_fieldinfo, id->ac_clidr);
852 print_fieldinfo(cpuname, "cache type",
853 ctr_fieldinfo, id->ac_ctr);
854 }
855
856 bool
857 identifycpu_bind(void)
858 {
859 return false;
860 }
861
862 int
863 ucodeupdate_check(int fd, struct cpu_ucode *uc)
864 {
865 return 0;
866 }
867