aarch64.c revision 1.3 1 /* $NetBSD: aarch64.c,v 1.3 2018/11/20 01:59:51 mrg 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.3 2018/11/20 01:59:51 mrg 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 int bitpos;
64 int bitwidth;
65 const char *name;
66 const char * const *info;
67 };
68
69
70 #define CPU_PARTMASK (CPU_ID_IMPLEMENTOR_MASK | CPU_ID_PARTNO_MASK)
71 const struct cpuidtab cpuids[] = {
72 { CPU_ID_CORTEXA53R0 & CPU_PARTMASK, "Cortex-A53", "Cortex", "V8-A" },
73 { CPU_ID_CORTEXA57R0 & CPU_PARTMASK, "Cortex-A57", "Cortex", "V8-A" },
74 { CPU_ID_CORTEXA72R0 & CPU_PARTMASK, "Cortex-A72", "Cortex", "V8-A" },
75 { CPU_ID_CORTEXA73R0 & CPU_PARTMASK, "Cortex-A73", "Cortex", "V8-A" },
76 { CPU_ID_CORTEXA55R1 & CPU_PARTMASK, "Cortex-A55", "Cortex", "V8.2-A" },
77 { CPU_ID_CORTEXA75R2 & CPU_PARTMASK, "Cortex-A75", "Cortex", "V8.2-A" }
78 };
79
80 const struct impltab implids[] = {
81 { CPU_ID_ARM_LTD, "ARM Limited" },
82 { CPU_ID_BROADCOM, "Broadcom Corporation" },
83 { CPU_ID_CAVIUM, "Cavium Inc." },
84 { CPU_ID_DEC, "Digital Equipment Corporation" },
85 { CPU_ID_INFINEON, "Infineon Technologies AG" },
86 { CPU_ID_MOTOROLA, "Motorola or Freescale Semiconductor Inc." },
87 { CPU_ID_NVIDIA, "NVIDIA Corporation" },
88 { CPU_ID_APM, "Applied Micro Circuits Corporation" },
89 { CPU_ID_QUALCOMM, "Qualcomm Inc." },
90 { CPU_ID_SAMSUNG, "SAMSUNG" },
91 { CPU_ID_TI, "Texas Instruments" },
92 { CPU_ID_MARVELL, "Marvell International Ltd." },
93 { CPU_ID_APPLE, "Apple Inc." },
94 { CPU_ID_FARADAY, "Faraday Technology Corporation" },
95 { CPU_ID_INTEL, "Intel Corporation" }
96 };
97
98 /* ID_AA64PFR0_EL1 - AArch64 Processor Feature Register 0 */
99 struct fieldinfo id_aa64pfr0_fieldinfo[] = {
100 {
101 .bitpos = 0, .bitwidth = 4, .name = "EL0",
102 .info = (const char *[16]) { /* 16=4bit */
103 [0] = "No EL0",
104 [1] = "AArch64",
105 [2] = "AArch64/AArch32"
106 }
107 },
108 {
109 .bitpos = 4, .bitwidth = 4, .name = "EL1",
110 .info = (const char *[16]) { /* 16=4bit */
111 [0] = "No EL1",
112 [1] = "AArch64",
113 [2] = "AArch64/AArch32"
114 }
115 },
116 {
117 .bitpos = 8, .bitwidth = 4, .name = "EL2",
118 .info = (const char *[16]) { /* 16=4bit */
119 [0] = "No EL2",
120 [1] = "AArch64",
121 [2] = "AArch64/AArch32"
122 }
123 },
124 {
125 .bitpos = 12, .bitwidth = 4, .name = "EL3",
126 .info = (const char *[16]) { /* 16=4bit */
127 [0] = "No EL3",
128 [1] = "AArch64",
129 [2] = "AArch64/AArch32"
130 }
131 },
132 {
133 .bitpos = 16, .bitwidth = 4, .name = "FP",
134 .info = (const char *[16]) { /* 16=4bit */
135 [0] = "Floating Point",
136 [15] = "No Floating Point"
137 }
138 },
139 {
140 .bitpos = 20, .bitwidth = 4, .name = "AdvSIMD",
141 .info = (const char *[16]) { /* 16=4bit */
142 [0] = "Advanced SIMD",
143 [15] = "No Advanced SIMD"
144 }
145 },
146 {
147 .bitpos = 24, .bitwidth = 4, .name = "GIC",
148 .info = (const char *[16]) { /* 16=4bit */
149 [0] = "No GIC",
150 [1] = "GICv3"
151 }
152 },
153 { .bitwidth = 0 } /* end of table */
154 };
155
156 /* ID_AA64ISAR0_EL1 - AArch64 Instruction Set Attribute Register 0 */
157 struct fieldinfo id_aa64isar0_fieldinfo[] = {
158 {
159 .bitpos = 4, .bitwidth = 4, .name = "AES",
160 .info = (const char *[16]) { /* 16=4bit */
161 [0] = "No AES",
162 [1] = "AESE/AESD/AESMC/AESIMC",
163 [2] = "AESE/AESD/AESMC/AESIMC+PMULL/PMULL2"
164 }
165 },
166 {
167 .bitpos = 8, .bitwidth = 4, .name = "SHA1",
168 .info = (const char *[16]) { /* 16=4bit */
169 [0] = "No SHA1",
170 [1] = "SHA1C/SHA1P/SHA1M/SHA1H/SHA1SU0/SHA1SU1"
171 }
172 },
173 {
174 .bitpos = 12, .bitwidth = 4, .name = "SHA2",
175 .info = (const char *[16]) { /* 16=4bit */
176 [0] = "No SHA2",
177 [1] = "SHA256H/SHA256H2/SHA256SU0/SHA256U1"
178 }
179 },
180 {
181 .bitpos = 16, .bitwidth = 4, .name = "CRC32",
182 .info = (const char *[16]) { /* 16=4bit */
183 [0] = "No CRC32",
184 [1] = "CRC32B/CRC32H/CRC32W/CRC32X"
185 "/CRC32CB/CRC32CH/CRC32CW/CRC32CX"
186 }
187 },
188 { .bitwidth = 0 } /* end of table */
189 };
190
191 /* ID_AA64MMFR0_EL1 - AArch64 Memory Model Feature Register 0 */
192 struct fieldinfo id_aa64mmfr0_fieldinfo[] = {
193 {
194 .bitpos = 0, .bitwidth = 4, .name = "PARange",
195 .info = (const char *[16]) { /* 16=4bit */
196 [0] = "32bits/4GB",
197 [1] = "36bits/64GB",
198 [2] = "40bits/1TB",
199 [3] = "42bits/4TB",
200 [4] = "44bits/16TB",
201 [5] = "48bits/256TB"
202 }
203 },
204 {
205 .bitpos = 4, .bitwidth = 4, .name = "ASIDBit",
206 .info = (const char *[16]) { /* 16=4bit */
207 [0] = "8bits",
208 [2] = "16bits"
209 }
210 },
211 {
212 .bitpos = 8, .bitwidth = 4, .name = "BigEnd",
213 .info = (const char *[16]) { /* 16=4bit */
214 [0] = "No mixed-endian",
215 [1] = "Mixed-endian"
216 }
217 },
218 {
219 .bitpos = 12, .bitwidth = 4, .name = "SNSMem",
220 .info = (const char *[16]) { /* 16=4bit */
221 [0] = "No distinction B/W Secure and Non-secure Memory",
222 [1] = "Distinction B/W Secure and Non-secure Memory"
223 }
224 },
225 {
226 .bitpos = 16, .bitwidth = 4, .name = "BigEndEL0",
227 .info = (const char *[16]) { /* 16=4bit */
228 [0] = "No mixed-endian at EL0",
229 [1] = "Mixed-endian at EL0"
230 }
231 },
232 {
233 .bitpos = 20, .bitwidth = 4, .name = "TGran16",
234 .info = (const char *[16]) { /* 16=4bit */
235 [0] = "No 16KB granule",
236 [1] = "16KB granule"
237 }
238 },
239 {
240 .bitpos = 24, .bitwidth = 4, .name = "TGran64",
241 .info = (const char *[16]) { /* 16=4bit */
242 [0] = "64KB granule",
243 [15] = "No 64KB granule"
244 }
245 },
246 {
247 .bitpos = 28, .bitwidth = 4, .name = "TGran4",
248 .info = (const char *[16]) { /* 16=4bit */
249 [0] = "4KB granule",
250 [15] = "No 4KB granule"
251 }
252 },
253 { .bitwidth = 0 } /* end of table */
254 };
255
256 /* MVFR0_EL1 - Media and VFP Feature Register 0 */
257 struct fieldinfo mvfr0_fieldinfo[] = {
258 {
259 .bitpos = 0, .bitwidth = 4, .name = "SIMDreg",
260 .info = (const char *[16]) { /* 16=4bit */
261 [0] = "No SIMD",
262 [1] = "16x64-bit SIMD",
263 [2] = "32x64-bit SIMD"
264 }
265 },
266 {
267 .bitpos = 4, .bitwidth = 4, .name = "FPSP",
268 .info = (const char *[16]) { /* 16=4bit */
269 [0] = "No VFP support single precision",
270 [1] = "VFPv2 support single precision",
271 [2] = "VFPv2/VFPv3/VFPv4 support single precision"
272 }
273 },
274 {
275 .bitpos = 8, .bitwidth = 4, .name = "FPDP",
276 .info = (const char *[16]) { /* 16=4bit */
277 [0] = "No VFP support double precision",
278 [1] = "VFPv2 support double precision",
279 [2] = "VFPv2/VFPv3/VFPv4 support double precision"
280 }
281 },
282 {
283 .bitpos = 12, .bitwidth = 4, .name = "FPTrap",
284 .info = (const char *[16]) { /* 16=4bit */
285 [0] = "VFPv2 support exception trapping",
286 [1] = "VFPv2/VFPv3/VFPv4 support exception trapping"
287 }
288 },
289 {
290 .bitpos = 16, .bitwidth = 4, .name = "FPDivide",
291 .info = (const char *[16]) { /* 16=4bit */
292 [0] = "VDIV not supported",
293 [1] = "VDIV supported"
294 }
295 },
296 {
297 .bitpos = 20, .bitwidth = 4, .name = "FPSqrt",
298 .info = (const char *[16]) { /* 16=4bit */
299 [0] = "VSQRT not supported",
300 [1] = "VSQRT supported"
301 }
302 },
303 {
304 .bitpos = 24, .bitwidth = 4, .name = "FPShVec",
305 .info = (const char *[16]) { /* 16=4bit */
306 [0] = "Short Vectors not supported",
307 [1] = "Short Vectors supported"
308 }
309 },
310 {
311 .bitpos = 28, .bitwidth = 4, .name = "FPRound",
312 .info = (const char *[16]) { /* 16=4bit */
313 [0] = "Only Round to Nearest mode",
314 [1] = "All rounding modes"
315 }
316 },
317 { .bitwidth = 0 } /* end of table */
318 };
319
320 /* MVFR1_EL1 - Media and VFP Feature Register 1 */
321 struct fieldinfo mvfr1_fieldinfo[] = {
322 {
323 .bitpos = 0, .bitwidth = 4, .name = "FPFtZ",
324 .info = (const char *[16]) { /* 16=4bit */
325 [0] = "only the Flush-to-Zero",
326 [1] = "full Denormalized number arithmetic"
327 }
328 },
329 {
330 .bitpos = 4, .bitwidth = 4, .name = "FPDNan",
331 .info = (const char *[16]) { /* 16=4bit */
332 [0] = "Default NaN",
333 [1] = "Propagation of NaN"
334 }
335 },
336 {
337 .bitpos = 8, .bitwidth = 4, .name = "SIMDLS",
338 .info = (const char *[16]) { /* 16=4bit */
339 [0] = "No Advanced SIMD Load/Store",
340 [1] = "Advanced SIMD Load/Store"
341 }
342 },
343 {
344 .bitpos = 12, .bitwidth = 4, .name = "SIMDInt",
345 .info = (const char *[16]) { /* 16=4bit */
346 [0] = "No Advanced SIMD Integer",
347 [1] = "Advanced SIMD Integer"
348 }
349 },
350 {
351 .bitpos = 16, .bitwidth = 4, .name = "SIMDSP",
352 .info = (const char *[16]) { /* 16=4bit */
353 [0] = "No Advanced SIMD single precision",
354 [1] = "Advanced SIMD single precision"
355 }
356 },
357 {
358 .bitpos = 20, .bitwidth = 4, .name = "SIMDHP",
359 .info = (const char *[16]) { /* 16=4bit */
360 [0] = "No Advanced SIMD half precision",
361 [1] = "Advanced SIMD half precision"
362 }
363 },
364 {
365 .bitpos = 24, .bitwidth = 4, .name = "FPHP",
366 .info = (const char *[16]) { /* 16=4bit */
367 [0] = "No half precision conversion",
368 [1] = "half/single precision conversion",
369 [2] = "half/single/double precision conversion"
370 }
371 },
372 {
373 .bitpos = 28, .bitwidth = 4, .name = "SIMDFMAC",
374 .info = (const char *[16]) { /* 16=4bit */
375 [0] = "No Fused Multiply-Accumulate",
376 [1] = "Fused Multiply-Accumulate"
377 }
378 },
379 { .bitwidth = 0 } /* end of table */
380 };
381
382 /* MVFR2_EL1 - Media and VFP Feature Register 2 */
383 struct fieldinfo mvfr2_fieldinfo[] = {
384 {
385 .bitpos = 0, .bitwidth = 4, .name = "SIMDMisc",
386 .info = (const char *[16]) { /* 16=4bit */
387 [0] = "No miscellaneous features",
388 [1] = "Conversion to Integer w/Directed Rounding modes",
389 [2] = "Conversion to Integer w/Directed Rounding modes"
390 ", Round to Integral floating point",
391 [3] = "Conversion to Integer w/Directed Rounding modes"
392 ", Round to Integral floating point"
393 ", MaxNum and MinNum"
394 }
395 },
396 {
397 .bitpos = 4, .bitwidth = 4, .name = "FPMisc",
398 .info = (const char *[16]) { /* 16=4bit */
399 [0] = "No miscellaneous features",
400 [1] = "Floating point selection",
401 [2] = "Floating point selection"
402 ", Conversion to Integer w/Directed Rounding modes",
403 [3] = "Floating point selection"
404 ", Conversion to Integer w/Directed Rounding modes"
405 ", Round to Integral floating point",
406 [4] = "Floating point selection"
407 ", Conversion to Integer w/Directed Rounding modes"
408 ", Round to Integral floating point"
409 ", MaxNum and MinNum"
410 }
411 },
412 { .bitwidth = 0 } /* end of table */
413 };
414
415 static void
416 print_fieldinfo(const char *cpuname, const char *setname,
417 struct fieldinfo *fieldinfo, uint64_t data)
418 {
419 uint64_t v;
420 const char *info;
421 int i;
422
423 #define WIDTHMASK(w) (0xffffffffffffffffULL >> (64 - (w)))
424
425 for (i = 0; fieldinfo[i].bitwidth != 0; i++) {
426 v = (data >> fieldinfo[i].bitpos) &
427 WIDTHMASK(fieldinfo[i].bitwidth);
428
429 info = fieldinfo[i].info[v];
430 if (info == NULL)
431 printf("%s: %s: %s: 0x%"PRIx64"\n",
432 cpuname, setname, fieldinfo[i].name, v);
433 else
434 printf("%s: %s: %s: %s\n",
435 cpuname, setname, fieldinfo[i].name, info);
436 }
437 }
438
439 /* MIDR_EL1 - Main ID Register */
440 static void
441 identify_midr(const char *cpuname, uint32_t cpuid)
442 {
443 unsigned int i;
444 uint32_t implid, cpupart, variant, revision;
445 const char *implementer = NULL;
446 static char implbuf[128];
447
448 implid = cpuid & CPU_ID_IMPLEMENTOR_MASK;
449 cpupart = cpuid & CPU_PARTMASK;
450 variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK);
451 revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK);
452
453 for (i = 0; i < __arraycount(implids); i++) {
454 if (implid == implids[i].impl_id) {
455 implementer = implids[i].impl_name;
456 }
457 }
458 if (implementer == NULL) {
459 snprintf(implbuf, sizeof(implbuf), "unknown implementer: 0x%02x",
460 implid >> 24);
461 implementer = implbuf;
462 }
463
464 for (i = 0; i < __arraycount(cpuids); i++) {
465 if (cpupart == cpuids[i].cpu_partnum) {
466 printf("%s: %s, %s r%dp%d (%s %s core)\n",
467 cpuname, implementer,
468 cpuids[i].cpu_name, variant, revision,
469 cpuids[i].cpu_class,
470 cpuids[i].cpu_architecture);
471 return;
472 }
473 }
474 printf("%s: unknown CPU ID: 0x%08x\n", cpuname, cpuid);
475 }
476
477 /* REVIDR_EL1 - Revision ID Register */
478 static void
479 identify_revidr(const char *cpuname, uint32_t revidr)
480 {
481 printf("%s: revision: 0x%08x\n", cpuname, revidr);
482 }
483
484 /* MPIDR_EL1 - Multiprocessor Affinity Register */
485 static void
486 identify_mpidr(const char *cpuname, uint32_t mpidr)
487 {
488 const char *setname = "multiprocessor affinity";
489
490 printf("%s: %s: Affinity-Level: %"PRIu64"-%"PRIu64"-%"PRIu64"-%"PRIu64"\n",
491 cpuname, setname,
492 __SHIFTOUT(mpidr, MPIDR_AFF3),
493 __SHIFTOUT(mpidr, MPIDR_AFF2),
494 __SHIFTOUT(mpidr, MPIDR_AFF1),
495 __SHIFTOUT(mpidr, MPIDR_AFF0));
496
497 if ((mpidr & MPIDR_U) == 0)
498 printf("%s: %s: Multiprocessor system\n", cpuname, setname);
499 else
500 printf("%s: %s: Uniprocessor system\n", cpuname, setname);
501
502 if ((mpidr & MPIDR_MT) == 0)
503 printf("%s: %s: Core Independent\n", cpuname, setname);
504 else
505 printf("%s: %s: Multi-Threading\n", cpuname, setname);
506
507 }
508
509 void
510 identifycpu(int fd, const char *cpuname)
511 {
512 char path[128];
513 size_t len;
514 struct aarch64_sysctl_cpu_id id;
515
516 snprintf(path, sizeof path, "machdep.%s.cpu_id", cpuname);
517 len = sizeof(id);
518 if (sysctlbyname(path, &id, &len, 0, 0) == -1)
519 err(1, "couldn't get %s", path);
520
521 identify_midr(cpuname, id.ac_midr);
522 identify_revidr(cpuname, id.ac_revidr);
523 identify_mpidr(cpuname, id.ac_mpidr);
524 print_fieldinfo(cpuname, "isa features 0",
525 id_aa64isar0_fieldinfo, id.ac_aa64isar0);
526 print_fieldinfo(cpuname, "memory model 0",
527 id_aa64mmfr0_fieldinfo, id.ac_aa64mmfr0);
528 print_fieldinfo(cpuname, "processor feature 0",
529 id_aa64pfr0_fieldinfo, id.ac_aa64pfr0);
530
531 print_fieldinfo(cpuname, "media and VFP features 0",
532 mvfr0_fieldinfo, id.ac_mvfr0);
533 print_fieldinfo(cpuname, "media and VFP features 1",
534 mvfr1_fieldinfo, id.ac_mvfr1);
535 print_fieldinfo(cpuname, "media and VFP features 2",
536 mvfr2_fieldinfo, id.ac_mvfr2);
537 }
538
539 bool
540 identifycpu_bind(void)
541 {
542 return false;
543 }
544
545 int
546 ucodeupdate_check(int fd, struct cpu_ucode *uc)
547 {
548 return 0;
549 }
550