Home | History | Annotate | Line # | Download | only in arch
aarch64.c revision 1.11
      1 /*	$NetBSD: aarch64.c,v 1.11 2020/07/05 19:40:27 riastradh 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.11 2020/07/05 19:40:27 riastradh 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 = 20, .bitwidth = 4, .name = "Atomic",
    233 		.info = (const char *[16]) { /* 16=4bit */
    234 			[0] = "No Atomic",
    235 			[1] = "LDADD/LDCLR/LDEOR/LDSET/LDSMAX/LDSMIN"
    236 			    "/LDUMAX/LDUMIN/CAS/CASP/SWP",
    237 		}
    238 	},
    239 	{
    240 		.bitpos = 28, .bitwidth = 4, .name = "RDM",
    241 		.info = (const char *[16]) { /* 16=4bit */
    242 			[0] = "No RDMA",
    243 			[1] = "SQRDMLAH/SQRDMLSH",
    244 		}
    245 	},
    246 	{
    247 		.bitpos = 32, .bitwidth = 4, .name = "SHA3",
    248 		.info = (const char *[16]) { /* 16=4bit */
    249 			[0] = "No SHA3",
    250 			[1] = "EOR3/RAX1/XAR/BCAX",
    251 		}
    252 	},
    253 	{
    254 		.bitpos = 36, .bitwidth = 4, .name = "SM3",
    255 		.info = (const char *[16]) { /* 16=4bit */
    256 			[0] = "No SM3",
    257 			[1] = "SM3SS1/SM3TT1A/SM3TT1B/SM3TT2A/SM3TT2B"
    258 			    "/SM3PARTW1/SM3PARTW2",
    259 		}
    260 	},
    261 	{
    262 		.bitpos = 40, .bitwidth = 4, .name = "SM4",
    263 		.info = (const char *[16]) { /* 16=4bit */
    264 			[0] = "No SM4",
    265 			[1] = "SM4E/SM4EKEY",
    266 		}
    267 	},
    268 	{
    269 		.bitpos = 44, .bitwidth = 4, .name = "DP",
    270 		.info = (const char *[16]) { /* 16=4bit */
    271 			[0] = "No Dot Product",
    272 			[1] = "UDOT/SDOT",
    273 		}
    274 	},
    275 	{
    276 		.bitpos = 48, .bitwidth = 4, .name = "FHM",
    277 		.info = (const char *[16]) { /* 16=4bit */
    278 			[0] = "No FHM",
    279 			[1] = "FMLAL/FMLSL",
    280 		}
    281 	},
    282 	{
    283 		.bitpos = 52, .bitwidth = 4, .name = "TS",
    284 		.info = (const char *[16]) { /* 16=4bit */
    285 			[0] = "No TS",
    286 			[1] = "CFINV/RMIF/SETF16/SETF8",
    287 			[2] = "CFINV/RMIF/SETF16/SETF8/AXFLAG/XAFLAG",
    288 		}
    289 	},
    290 	{
    291 		.bitpos = 56, .bitwidth = 4, .name = "TLBI",
    292 		.info = (const char *[16]) { /* 16=4bit */
    293 			[0] = "No outer shareable and TLB range maintenance"
    294 			    " instructions",
    295 			[1] = "Outer shareable TLB maintenance instructions",
    296 			[2] = "Outer shareable and TLB range maintenance"
    297 			    " instructions",
    298 		}
    299 	},
    300 	{
    301 		.bitpos = 60, .bitwidth = 4, .name = "RNDR",
    302 		.info = (const char *[16]) { /* 16=4bit */
    303 			[0] = "No RNDR/RNDRRS",
    304 			[1] = "RNDR/RNDRRS",
    305 		},
    306 	},
    307 	{ .bitwidth = 0 }	/* end of table */
    308 };
    309 
    310 /* ID_AA64MMFR0_EL1 - AArch64 Memory Model Feature Register 0 */
    311 struct fieldinfo id_aa64mmfr0_fieldinfo[] = {
    312 	{
    313 		.bitpos = 0, .bitwidth = 4, .name = "PARange",
    314 		.info = (const char *[16]) { /* 16=4bit */
    315 			[0] = "32bits/4GB",
    316 			[1] = "36bits/64GB",
    317 			[2] = "40bits/1TB",
    318 			[3] = "42bits/4TB",
    319 			[4] = "44bits/16TB",
    320 			[5] = "48bits/256TB"
    321 		}
    322 	},
    323 	{
    324 		.bitpos = 4, .bitwidth = 4, .name = "ASIDBit",
    325 		.info = (const char *[16]) { /* 16=4bit */
    326 			[0] = "8bits",
    327 			[2] = "16bits"
    328 		}
    329 	},
    330 	{
    331 		.bitpos = 8, .bitwidth = 4, .name = "BigEnd",
    332 		.info = (const char *[16]) { /* 16=4bit */
    333 			[0] = "No mixed-endian",
    334 			[1] = "Mixed-endian"
    335 		}
    336 	},
    337 	{
    338 		.bitpos = 12, .bitwidth = 4, .name = "SNSMem",
    339 		.info = (const char *[16]) { /* 16=4bit */
    340 			[0] = "No distinction B/W Secure and Non-secure Memory",
    341 			[1] = "Distinction B/W Secure and Non-secure Memory"
    342 		}
    343 	},
    344 	{
    345 		.bitpos = 16, .bitwidth = 4, .name = "BigEndEL0",
    346 		.info = (const char *[16]) { /* 16=4bit */
    347 			[0] = "No mixed-endian at EL0",
    348 			[1] = "Mixed-endian at EL0"
    349 		}
    350 	},
    351 	{
    352 		.bitpos = 20, .bitwidth = 4, .name = "TGran16",
    353 		.info = (const char *[16]) { /* 16=4bit */
    354 			[0] = "No 16KB granule",
    355 			[1] = "16KB granule"
    356 		}
    357 	},
    358 	{
    359 		.bitpos = 24, .bitwidth = 4, .name = "TGran64",
    360 		.info = (const char *[16]) { /* 16=4bit */
    361 			[0] = "64KB granule",
    362 			[15] = "No 64KB granule"
    363 		}
    364 	},
    365 	{
    366 		.bitpos = 28, .bitwidth = 4, .name = "TGran4",
    367 		.info = (const char *[16]) { /* 16=4bit */
    368 			[0] = "4KB granule",
    369 			[15] = "No 4KB granule"
    370 		}
    371 	},
    372 	{ .bitwidth = 0 }	/* end of table */
    373 };
    374 
    375 /* ID_AA64MMFR1_EL1 - AArch64 Memory Model Feature Register 1 */
    376 struct fieldinfo id_aa64mmfr1_fieldinfo[] = {
    377 	{
    378 		.bitpos = 0, .bitwidth = 4, .name = "HAFDBS",
    379 		.info = (const char *[16]) { /* 16=4bit */
    380 			[0] = "Access and Dirty flags not supported",
    381 			[1] = "Access flag supported",
    382 			[2] = "Access and Dirty flags supported",
    383 		}
    384 	},
    385 	{
    386 		.bitpos = 4, .bitwidth = 4, .name = "VMIDBits",
    387 		.info = (const char *[16]) { /* 16=4bit */
    388 			[0] = "8bits",
    389 			[2] = "16bits"
    390 		}
    391 	},
    392 	{
    393 		.bitpos = 8, .bitwidth = 4, .name = "VH",
    394 		.info = (const char *[16]) { /* 16=4bit */
    395 			[0] = "Virtualization Host Extensions not supported",
    396 			[1] = "Virtualization Host Extensions supported",
    397 		}
    398 	},
    399 	{
    400 		.bitpos = 12, .bitwidth = 4, .name = "HPDS",
    401 		.info = (const char *[16]) { /* 16=4bit */
    402 			[0] = "Disabling of hierarchical controls not supported",
    403 			[1] = "Disabling of hierarchical controls supported",
    404 			[2] = "Disabling of hierarchical controls supported, plus PTD"
    405 		}
    406 	},
    407 	{
    408 		.bitpos = 16, .bitwidth = 4, .name = "LO",
    409 		.info = (const char *[16]) { /* 16=4bit */
    410 			[0] = "LORegions not supported",
    411 			[1] = "LORegions supported"
    412 		}
    413 	},
    414 	{
    415 		.bitpos = 20, .bitwidth = 4, .name = "PAN",
    416 		.info = (const char *[16]) { /* 16=4bit */
    417 			[0] = "PAN not supported",
    418 			[1] = "PAN supported",
    419 			[2] = "PAN supported, and instructions supported"
    420 		}
    421 	},
    422 	{
    423 		.bitpos = 24, .bitwidth = 4, .name = "SpecSEI",
    424 		.info = (const char *[16]) { /* 16=4bit */
    425 			[0] = "SError interrupt not supported",
    426 			[1] = "SError interrupt supported"
    427 		}
    428 	},
    429 	{
    430 		.bitpos = 28, .bitwidth = 4, .name = "XNX",
    431 		.info = (const char *[16]) { /* 16=4bit */
    432 			[0] = "Distinction between EL0 and EL1 XN control at stage 2 not supported",
    433 			[1] = "Distinction between EL0 and EL1 XN control at stage 2 supported"
    434 		}
    435 	},
    436 	{ .bitwidth = 0 }	/* end of table */
    437 };
    438 
    439 /* ID_AA64DFR0_EL1 - AArch64 Debug Feature Register 0 */
    440 struct fieldinfo id_aa64dfr0_fieldinfo[] = {
    441 	{
    442 		.bitpos = 0, .bitwidth = 4, .name = "DebugVer",
    443 		.info = (const char *[16]) { /* 16=4bit */
    444 			[6] = "v8-A debug architecture"
    445 		}
    446 	},
    447 	{
    448 		.bitpos = 4, .bitwidth = 4, .name = "TraceVer",
    449 		.info = (const char *[16]) { /* 16=4bit */
    450 			[0] = "Trace supported",
    451 			[1] = "Trace not supported"
    452 		}
    453 	},
    454 	{
    455 		.bitpos = 8, .bitwidth = 4, .name = "PMUVer",
    456 		.info = (const char *[16]) { /* 16=4bit */
    457 			[0] = "No Performance monitor",
    458 			[1] = "Performance monitor unit v3"
    459 		}
    460 	},
    461 	{ .bitwidth = 0 }	/* end of table */
    462 };
    463 
    464 
    465 /* MVFR0_EL1 - Media and VFP Feature Register 0 */
    466 struct fieldinfo mvfr0_fieldinfo[] = {
    467 	{
    468 		.bitpos = 0, .bitwidth = 4, .name = "SIMDreg",
    469 		.info = (const char *[16]) { /* 16=4bit */
    470 			[0] = "No SIMD",
    471 			[1] = "16x64-bit SIMD",
    472 			[2] = "32x64-bit SIMD"
    473 		}
    474 	},
    475 	{
    476 		.bitpos = 4, .bitwidth = 4, .name = "FPSP",
    477 		.info = (const char *[16]) { /* 16=4bit */
    478 			[0] = "No VFP support single precision",
    479 			[1] = "VFPv2 support single precision",
    480 			[2] = "VFPv2/VFPv3/VFPv4 support single precision"
    481 		}
    482 	},
    483 	{
    484 		.bitpos = 8, .bitwidth = 4, .name = "FPDP",
    485 		.info = (const char *[16]) { /* 16=4bit */
    486 			[0] = "No VFP support double precision",
    487 			[1] = "VFPv2 support double precision",
    488 			[2] = "VFPv2/VFPv3/VFPv4 support double precision"
    489 		}
    490 	},
    491 	{
    492 		.bitpos = 12, .bitwidth = 4, .name = "FPTrap",
    493 		.info = (const char *[16]) { /* 16=4bit */
    494 			[0] = "No floating point exception trapping support",
    495 			[1] = "VFPv2/VFPv3/VFPv4 support exception trapping"
    496 		}
    497 	},
    498 	{
    499 		.bitpos = 16, .bitwidth = 4, .name = "FPDivide",
    500 		.info = (const char *[16]) { /* 16=4bit */
    501 			[0] = "VDIV not supported",
    502 			[1] = "VDIV supported"
    503 		}
    504 	},
    505 	{
    506 		.bitpos = 20, .bitwidth = 4, .name = "FPSqrt",
    507 		.info = (const char *[16]) { /* 16=4bit */
    508 			[0] = "VSQRT not supported",
    509 			[1] = "VSQRT supported"
    510 		}
    511 	},
    512 	{
    513 		.bitpos = 24, .bitwidth = 4, .name = "FPShVec",
    514 		.info = (const char *[16]) { /* 16=4bit */
    515 			[0] = "Short Vectors not supported",
    516 			[1] = "Short Vectors supported"
    517 		}
    518 	},
    519 	{
    520 		.bitpos = 28, .bitwidth = 4, .name = "FPRound",
    521 		.info = (const char *[16]) { /* 16=4bit */
    522 			[0] = "Only Round to Nearest mode",
    523 			[1] = "All rounding modes"
    524 		}
    525 	},
    526 	{ .bitwidth = 0 }	/* end of table */
    527 };
    528 
    529 /* MVFR1_EL1 - Media and VFP Feature Register 1 */
    530 struct fieldinfo mvfr1_fieldinfo[] = {
    531 	{
    532 		.bitpos = 0, .bitwidth = 4, .name = "FPFtZ",
    533 		.info = (const char *[16]) { /* 16=4bit */
    534 			[0] = "only the Flush-to-Zero",
    535 			[1] = "full Denormalized number arithmetic"
    536 		}
    537 	},
    538 	{
    539 		.bitpos = 4, .bitwidth = 4, .name = "FPDNan",
    540 		.info = (const char *[16]) { /* 16=4bit */
    541 			[0] = "Default NaN",
    542 			[1] = "Propagation of NaN"
    543 		}
    544 	},
    545 	{
    546 		.bitpos = 8, .bitwidth = 4, .name = "SIMDLS",
    547 		.info = (const char *[16]) { /* 16=4bit */
    548 			[0] = "No Advanced SIMD Load/Store",
    549 			[1] = "Advanced SIMD Load/Store"
    550 		}
    551 	},
    552 	{
    553 		.bitpos = 12, .bitwidth = 4, .name = "SIMDInt",
    554 		.info = (const char *[16]) { /* 16=4bit */
    555 			[0] = "No Advanced SIMD Integer",
    556 			[1] = "Advanced SIMD Integer"
    557 		}
    558 	},
    559 	{
    560 		.bitpos = 16, .bitwidth = 4, .name = "SIMDSP",
    561 		.info = (const char *[16]) { /* 16=4bit */
    562 			[0] = "No Advanced SIMD single precision",
    563 			[1] = "Advanced SIMD single precision"
    564 		}
    565 	},
    566 	{
    567 		.bitpos = 20, .bitwidth = 4, .name = "SIMDHP",
    568 		.info = (const char *[16]) { /* 16=4bit */
    569 			[0] = "No Advanced SIMD half precision",
    570 			[1] = "Advanced SIMD half precision"
    571 		}
    572 	},
    573 	{
    574 		.bitpos = 24, .bitwidth = 4, .name = "FPHP",
    575 		.info = (const char *[16]) { /* 16=4bit */
    576 			[0] = "No half precision conversion",
    577 			[1] = "half/single precision conversion",
    578 			[2] = "half/single/double precision conversion"
    579 		}
    580 	},
    581 	{
    582 		.bitpos = 28, .bitwidth = 4, .name = "SIMDFMAC",
    583 		.info = (const char *[16]) { /* 16=4bit */
    584 			[0] = "No Fused Multiply-Accumulate",
    585 			[1] = "Fused Multiply-Accumulate"
    586 		}
    587 	},
    588 	{ .bitwidth = 0 }	/* end of table */
    589 };
    590 
    591 /* MVFR2_EL1 - Media and VFP Feature Register 2 */
    592 struct fieldinfo mvfr2_fieldinfo[] = {
    593 	{
    594 		.bitpos = 0, .bitwidth = 4, .name = "SIMDMisc",
    595 		.info = (const char *[16]) { /* 16=4bit */
    596 			[0] = "No miscellaneous features",
    597 			[1] = "Conversion to Integer w/Directed Rounding modes",
    598 			[2] = "Conversion to Integer w/Directed Rounding modes"
    599 			    ", Round to Integral floating point",
    600 			[3] = "Conversion to Integer w/Directed Rounding modes"
    601 			    ", Round to Integral floating point"
    602 			    ", MaxNum and MinNum"
    603 		}
    604 	},
    605 	{
    606 		.bitpos = 4, .bitwidth = 4, .name = "FPMisc",
    607 		.info = (const char *[16]) { /* 16=4bit */
    608 			[0] = "No miscellaneous features",
    609 			[1] = "Floating point selection",
    610 			[2] = "Floating point selection"
    611 			    ", Conversion to Integer w/Directed Rounding modes",
    612 			[3] = "Floating point selection"
    613 			    ", Conversion to Integer w/Directed Rounding modes"
    614 			    ", Round to Integral floating point",
    615 			[4] = "Floating point selection"
    616 			    ", Conversion to Integer w/Directed Rounding modes"
    617 			    ", Round to Integral floating point"
    618 			    ", MaxNum and MinNum"
    619 		}
    620 	},
    621 	{ .bitwidth = 0 }	/* end of table */
    622 };
    623 
    624 /* CLIDR_EL1 - Cache Level ID Register */
    625 const char * const clidr_cachetype[8] = { /* 8=3bit */
    626 	[0] = "None",
    627 	[1] = "Instruction cache",
    628 	[2] = "Data cache",
    629 	[3] = "Instruction and Data cache",
    630 	[4] = "Unified cache"
    631 };
    632 
    633 struct fieldinfo clidr_fieldinfo[] = {
    634 	{
    635 		.bitpos = 0, .bitwidth = 3, .name = "L1",
    636 		.info = clidr_cachetype
    637 	},
    638 	{
    639 		.bitpos = 3, .bitwidth = 3, .name = "L2",
    640 		.info = clidr_cachetype
    641 	},
    642 	{
    643 		.bitpos = 6, .bitwidth = 3, .name = "L3",
    644 		.info = clidr_cachetype
    645 	},
    646 	{
    647 		.bitpos = 9, .bitwidth = 3, .name = "L4",
    648 		.info = clidr_cachetype
    649 	},
    650 	{
    651 		.bitpos = 12, .bitwidth = 3, .name = "L5",
    652 		.info = clidr_cachetype
    653 	},
    654 	{
    655 		.bitpos = 15, .bitwidth = 3, .name = "L6",
    656 		.info = clidr_cachetype
    657 	},
    658 	{
    659 		.bitpos = 18, .bitwidth = 3, .name = "L7",
    660 		.info = clidr_cachetype
    661 	},
    662 	{
    663 		.bitpos = 21, .bitwidth = 3, .name = "LoUU",
    664 		.flags = FIELDINFO_FLAGS_DEC
    665 	},
    666 	{
    667 		.bitpos = 24, .bitwidth = 3, .name = "LoC",
    668 		.flags = FIELDINFO_FLAGS_DEC
    669 	},
    670 	{
    671 		.bitpos = 27, .bitwidth = 3, .name = "LoUIS",
    672 		.flags = FIELDINFO_FLAGS_DEC
    673 	},
    674 	{
    675 		.bitpos = 30, .bitwidth = 3, .name = "ICB",
    676 		.flags = FIELDINFO_FLAGS_DEC
    677 	},
    678 	{ .bitwidth = 0 }	/* end of table */
    679 };
    680 
    681 struct fieldinfo ctr_fieldinfo[] = {
    682 	{
    683 		.bitpos = 0, .bitwidth = 4, .name = "IminLine",
    684 		.flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
    685 	},
    686 	{
    687 		.bitpos = 16, .bitwidth = 4, .name = "DminLine",
    688 		.flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
    689 	},
    690 	{
    691 		.bitpos = 14, .bitwidth = 2, .name = "L1 Icache policy",
    692 		.info = (const char *[4]) { /* 4=2bit */
    693 			[0] = "VMID aware PIPT (VPIPT)",
    694 			[1] = "ASID-tagged VIVT (AIVIVT)",
    695 			[2] = "VIPT",
    696 			[3] = "PIPT"
    697 		},
    698 	},
    699 	{
    700 		.bitpos = 20, .bitwidth = 4, .name = "ERG",
    701 		.flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
    702 	},
    703 	{
    704 		.bitpos = 24, .bitwidth = 4, .name = "CWG",
    705 		.flags = FIELDINFO_FLAGS_DEC | FIELDINFO_FLAGS_4LOG2
    706 	},
    707 	{
    708 		.bitpos = 28, .bitwidth = 1, .name = "DIC",
    709 		.flags = FIELDINFO_FLAGS_DEC
    710 	},
    711 	{
    712 		.bitpos = 29, .bitwidth = 1, .name = "IDC",
    713 		.flags = FIELDINFO_FLAGS_DEC
    714 	},
    715 	{ .bitwidth = 0 }	/* end of table */
    716 };
    717 
    718 
    719 static void
    720 print_fieldinfo(const char *cpuname, const char *setname,
    721     struct fieldinfo *fieldinfo, uint64_t data)
    722 {
    723 	uint64_t v;
    724 	const char *info;
    725 	int i, flags;
    726 
    727 #define WIDTHMASK(w)	(0xffffffffffffffffULL >> (64 - (w)))
    728 
    729 	for (i = 0; fieldinfo[i].bitwidth != 0; i++) {
    730 		v = (data >> fieldinfo[i].bitpos) &
    731 		    WIDTHMASK(fieldinfo[i].bitwidth);
    732 
    733 		flags = fieldinfo[i].flags;
    734 		info = NULL;
    735 		if (fieldinfo[i].info != NULL)
    736 			info = fieldinfo[i].info[v];
    737 
    738 		printf("%s: %s: %s: ",
    739 		    cpuname, setname, fieldinfo[i].name);
    740 
    741 		if (info == NULL) {
    742 			if (flags & FIELDINFO_FLAGS_4LOG2)
    743 				v = 4 * (1 << v);
    744 			if (flags & FIELDINFO_FLAGS_DEC)
    745 				printf("%"PRIu64"\n", v);
    746 			else
    747 				printf("0x%"PRIx64"\n", v);
    748 		} else {
    749 			printf("%s\n", info);
    750 		}
    751 	}
    752 }
    753 
    754 /* MIDR_EL1 - Main ID Register */
    755 static void
    756 identify_midr(const char *cpuname, uint32_t cpuid)
    757 {
    758 	unsigned int i;
    759 	uint32_t implid, cpupart, variant, revision;
    760 	const char *implementer = NULL;
    761 	static char implbuf[128];
    762 
    763 	implid = cpuid & CPU_ID_IMPLEMENTOR_MASK;
    764 	cpupart = cpuid & CPU_PARTMASK;
    765 	variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK);
    766 	revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK);
    767 
    768 	for (i = 0; i < __arraycount(implids); i++) {
    769 		if (implid == implids[i].impl_id) {
    770 			implementer = implids[i].impl_name;
    771 		}
    772 	}
    773 	if (implementer == NULL) {
    774 		snprintf(implbuf, sizeof(implbuf), "unknown implementer: 0x%02x",
    775 		    implid >> 24);
    776 		implementer = implbuf;
    777 	}
    778 
    779 	for (i = 0; i < __arraycount(cpuids); i++) {
    780 		if (cpupart == cpuids[i].cpu_partnum) {
    781 			printf("%s: %s, %s r%dp%d (%s %s core)\n",
    782 			    cpuname, implementer,
    783 			    cpuids[i].cpu_name, variant, revision,
    784 			    cpuids[i].cpu_class,
    785 			    cpuids[i].cpu_architecture);
    786 			return;
    787 		}
    788 	}
    789 	printf("%s: unknown CPU ID: 0x%08x\n", cpuname, cpuid);
    790 }
    791 
    792 /* REVIDR_EL1 - Revision ID Register */
    793 static void
    794 identify_revidr(const char *cpuname, uint32_t revidr)
    795 {
    796 	printf("%s: revision: 0x%08x\n", cpuname, revidr);
    797 }
    798 
    799 /* MPIDR_EL1 - Multiprocessor Affinity Register */
    800 static void
    801 identify_mpidr(const char *cpuname, uint32_t mpidr)
    802 {
    803 	const char *setname = "multiprocessor affinity";
    804 
    805 	printf("%s: %s: Affinity-Level: %"PRIu64"-%"PRIu64"-%"PRIu64"-%"PRIu64"\n",
    806 	    cpuname, setname,
    807 	    __SHIFTOUT(mpidr, MPIDR_AFF3),
    808 	    __SHIFTOUT(mpidr, MPIDR_AFF2),
    809 	    __SHIFTOUT(mpidr, MPIDR_AFF1),
    810 	    __SHIFTOUT(mpidr, MPIDR_AFF0));
    811 
    812 	if ((mpidr & MPIDR_U) == 0)
    813 		printf("%s: %s: Multiprocessor system\n", cpuname, setname);
    814 	else
    815 		printf("%s: %s: Uniprocessor system\n", cpuname, setname);
    816 
    817 	if ((mpidr & MPIDR_MT) == 0)
    818 		printf("%s: %s: Core Independent\n", cpuname, setname);
    819 	else
    820 		printf("%s: %s: Multi-Threading\n", cpuname, setname);
    821 
    822 }
    823 
    824 /* AA64DFR0 - Debug feature register 0 */
    825 static void
    826 identify_dfr0(const char *cpuname, uint64_t dfr0)
    827 {
    828 	const char *setname = "debug feature 0";
    829 
    830 	printf("%s: %s: CTX_CMPs: %lu context-aware breakpoints\n",
    831 	    cpuname, setname, __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_CTX_CMPS) + 1);
    832 	printf("%s: %s: WRPs: %lu watchpoints\n",
    833 	    cpuname, setname, __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_WRPS) + 1);
    834 	printf("%s: %s: BRPs: %lu breakpoints\n",
    835 	    cpuname, setname, __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_BRPS) + 1);
    836 	print_fieldinfo(cpuname, setname,
    837 	    id_aa64dfr0_fieldinfo, dfr0);
    838 }
    839 
    840 void
    841 identifycpu(int fd, const char *cpuname)
    842 {
    843 	char path[128];
    844 	size_t len;
    845 #define SYSCTL_CPU_ID_MAXSIZE	64
    846 	uint64_t sysctlbuf[SYSCTL_CPU_ID_MAXSIZE];
    847 	struct aarch64_sysctl_cpu_id *id =
    848 	    (struct aarch64_sysctl_cpu_id *)sysctlbuf;
    849 
    850 	snprintf(path, sizeof path, "machdep.%s.cpu_id", cpuname);
    851 	len = sizeof(sysctlbuf);
    852 	memset(sysctlbuf, 0, len);
    853 	if (sysctlbyname(path, id, &len, 0, 0) == -1)
    854 		err(1, "couldn't get %s", path);
    855 	if (len != sizeof(struct aarch64_sysctl_cpu_id))
    856 		fprintf(stderr, "Warning: kernel version bumped?\n");
    857 
    858 	if (verbose) {
    859 		printf("%s: MIDR_EL1: 0x%08"PRIx64"\n",
    860 		    cpuname, id->ac_midr);
    861 		printf("%s: MPIDR_EL1: 0x%016"PRIx64"\n",
    862 		    cpuname, id->ac_mpidr);
    863 		printf("%s: ID_AA64DFR0_EL1: 0x%016"PRIx64"\n",
    864 		    cpuname, id->ac_aa64dfr0);
    865 		printf("%s: ID_AA64DFR1_EL1: 0x%016"PRIx64"\n",
    866 		    cpuname, id->ac_aa64dfr1);
    867 		printf("%s: ID_AA64ISAR0_EL1: 0x%016"PRIx64"\n",
    868 		    cpuname, id->ac_aa64isar0);
    869 		printf("%s: ID_AA64ISAR1_EL1: 0x%016"PRIx64"\n",
    870 		    cpuname, id->ac_aa64isar1);
    871 		printf("%s: ID_AA64MMFR0_EL1: 0x%016"PRIx64"\n",
    872 		    cpuname, id->ac_aa64mmfr0);
    873 		printf("%s: ID_AA64MMFR1_EL1: 0x%016"PRIx64"\n",
    874 		    cpuname, id->ac_aa64mmfr1);
    875 		printf("%s: ID_AA64MMFR2_EL1: 0x%016"PRIx64"\n",
    876 		    cpuname, id->ac_aa64mmfr2);
    877 		printf("%s: ID_AA64PFR0_EL1: 0x%08"PRIx64"\n",
    878 		    cpuname, id->ac_aa64pfr0);
    879 		printf("%s: ID_AA64PFR1_EL1: 0x%08"PRIx64"\n",
    880 		    cpuname, id->ac_aa64pfr1);
    881 		printf("%s: ID_AA64ZFR0_EL1: 0x%016"PRIx64"\n",
    882 		    cpuname, id->ac_aa64zfr0);
    883 		printf("%s: MVFR0_EL1: 0x%08"PRIx32"\n",
    884 		    cpuname, id->ac_mvfr0);
    885 		printf("%s: MVFR1_EL1: 0x%08"PRIx32"\n",
    886 		    cpuname, id->ac_mvfr1);
    887 		printf("%s: MVFR2_EL1: 0x%08"PRIx32"\n",
    888 		    cpuname, id->ac_mvfr2);
    889 		printf("%s: CLIDR_EL1: 0x%016"PRIx64"\n",
    890 		    cpuname, id->ac_clidr);
    891 		printf("%s: CTR_EL0: 0x%016"PRIx64"\n",
    892 		    cpuname, id->ac_ctr);
    893 	}
    894 
    895 	identify_midr(cpuname, id->ac_midr);
    896 	identify_revidr(cpuname, id->ac_revidr);
    897 	identify_mpidr(cpuname, id->ac_mpidr);
    898 	print_fieldinfo(cpuname, "isa features 0",
    899 	    id_aa64isar0_fieldinfo, id->ac_aa64isar0);
    900 	print_fieldinfo(cpuname, "memory model 0",
    901 	    id_aa64mmfr0_fieldinfo, id->ac_aa64mmfr0);
    902 	print_fieldinfo(cpuname, "memory model 1",
    903 	    id_aa64mmfr1_fieldinfo, id->ac_aa64mmfr1);
    904 	print_fieldinfo(cpuname, "processor feature 0",
    905 	    id_aa64pfr0_fieldinfo, id->ac_aa64pfr0);
    906 	print_fieldinfo(cpuname, "processor feature 1",
    907 	    id_aa64pfr1_fieldinfo, id->ac_aa64pfr1);
    908 	identify_dfr0(cpuname, id->ac_aa64dfr0);
    909 
    910 	print_fieldinfo(cpuname, "media and VFP features 0",
    911 	    mvfr0_fieldinfo, id->ac_mvfr0);
    912 	print_fieldinfo(cpuname, "media and VFP features 1",
    913 	    mvfr1_fieldinfo, id->ac_mvfr1);
    914 	print_fieldinfo(cpuname, "media and VFP features 2",
    915 	    mvfr2_fieldinfo, id->ac_mvfr2);
    916 
    917 	if (len <= offsetof(struct aarch64_sysctl_cpu_id, ac_clidr))
    918 		return;
    919 	print_fieldinfo(cpuname, "cache level",
    920 	    clidr_fieldinfo, id->ac_clidr);
    921 	print_fieldinfo(cpuname, "cache type",
    922 	    ctr_fieldinfo, id->ac_ctr);
    923 }
    924 
    925 bool
    926 identifycpu_bind(void)
    927 {
    928 	return false;
    929 }
    930 
    931 int
    932 ucodeupdate_check(int fd, struct cpu_ucode *uc)
    933 {
    934 	return 0;
    935 }
    936