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