Home | History | Annotate | Line # | Download | only in arch
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