1251881Speter/* $NetBSD: cpu.c,v 1.76 2024/05/09 12:41:08 pho Exp $ */ 2251881Speter 3251881Speter/* 4251881Speter * Copyright (c) 2017 Ryo Shimizu 5251881Speter * All rights reserved. 6251881Speter * 7251881Speter * Redistribution and use in source and binary forms, with or without 8251881Speter * modification, are permitted provided that the following conditions 9251881Speter * are met: 10251881Speter * 1. Redistributions of source code must retain the above copyright 11251881Speter * notice, this list of conditions and the following disclaimer. 12251881Speter * 2. Redistributions in binary form must reproduce the above copyright 13251881Speter * notice, this list of conditions and the following disclaimer in the 14251881Speter * documentation and/or other materials provided with the distribution. 15251881Speter * 16251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17251881Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18251881Speter * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19251881Speter * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20251881Speter * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21251881Speter * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22251881Speter * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24251881Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25251881Speter * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26251881Speter * POSSIBILITY OF SUCH DAMAGE. 27251881Speter */ 28251881Speter 29251881Speter#include <sys/cdefs.h> 30251881Speter__KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.76 2024/05/09 12:41:08 pho Exp $"); 31251881Speter 32251881Speter#include "locators.h" 33251881Speter#include "opt_arm_debug.h" 34251881Speter#include "opt_ddb.h" 35251881Speter#include "opt_fdt.h" 36251881Speter#include "opt_multiprocessor.h" 37251881Speter 38251881Speter#include <sys/param.h> 39251881Speter#include <sys/atomic.h> 40251881Speter#include <sys/cpu.h> 41251881Speter#include <sys/device.h> 42253734Speter#include <sys/kmem.h> 43253734Speter#include <sys/reboot.h> 44251881Speter#include <sys/rndsource.h> 45251881Speter#include <sys/sysctl.h> 46251881Speter#include <sys/systm.h> 47251881Speter 48251881Speter#include <crypto/aes/aes_impl.h> 49253734Speter#include <crypto/aes/arch/arm/aes_armv8.h> 50253734Speter#include <crypto/aes/arch/arm/aes_neon.h> 51253734Speter#include <crypto/chacha/chacha_impl.h> 52253734Speter#include <crypto/chacha/arch/arm/chacha_neon.h> 53253734Speter 54253734Speter#include <aarch64/armreg.h> 55253734Speter#include <aarch64/cpu.h> 56253734Speter#include <aarch64/cpu_counter.h> 57253734Speter#ifdef DDB 58253734Speter#include <aarch64/db_machdep.h> 59251881Speter#endif 60251881Speter#include <aarch64/machdep.h> 61251881Speter 62251881Speter#include <arm/cpufunc.h> 63251881Speter#include <arm/cpuvar.h> 64251881Speter#include <arm/cpu_topology.h> 65251881Speter#ifdef FDT 66251881Speter#include <arm/fdt/arm_fdtvar.h> 67251881Speter#endif 68251881Speter 69251881Speter#ifdef VERBOSE_INIT_ARM 70251881Speter#define VPRINTF(...) printf(__VA_ARGS__) 71251881Speter#else 72251881Speter#define VPRINTF(...) __nothing 73251881Speter#endif 74251881Speter 75251881Spetervoid cpu_attach(device_t, cpuid_t); 76251881Spetervoid cpu_setup_id(struct cpu_info *); 77251881Speter 78251881Speterstatic void identify_aarch64_model(uint32_t, char *, size_t); 79251881Speterstatic void cpu_identify(device_t self, struct cpu_info *); 80251881Speterstatic void cpu_identify1(device_t self, struct cpu_info *); 81251881Speterstatic void cpu_identify2(device_t self, struct cpu_info *); 82251881Speterstatic void cpu_init_counter(struct cpu_info *); 83251881Speterstatic void cpu_setup_sysctl(device_t, struct cpu_info *); 84251881Speterstatic void cpu_setup_rng(device_t, struct cpu_info *); 85251881Speterstatic void cpu_setup_aes(device_t, struct cpu_info *); 86251881Speterstatic void cpu_setup_chacha(device_t, struct cpu_info *); 87251881Speter 88251881Speter#ifdef MULTIPROCESSOR 89251881Speter#define NCPUINFO MAXCPUS 90251881Speter#else 91251881Speter#define NCPUINFO 1 92251881Speter#endif /* MULTIPROCESSOR */ 93251881Speter 94251881Speter/* 95251881Speter * Our exported cpu_info structs; these will be first used by the 96251881Speter * secondary cpus as part of cpu_mpstart and the hatching process. 97251881Speter */ 98251881Speterstruct cpu_info cpu_info_store[NCPUINFO] = { 99251881Speter [0] = { 100251881Speter .ci_cpl = IPL_HIGH, 101251881Speter .ci_curlwp = &lwp0 102251881Speter } 103251881Speter}; 104251881Speter 105251881Spetervoid 106251881Spetercpu_attach(device_t dv, cpuid_t id) 107251881Speter{ 108251881Speter struct cpu_info *ci; 109251881Speter const int unit = device_unit(dv); 110251881Speter 111251881Speter if (unit == 0) { 112251881Speter ci = curcpu(); 113251881Speter ci->ci_cpuid = id; 114251881Speter } else { 115251881Speter#ifdef MULTIPROCESSOR 116251881Speter if ((boothowto & RB_MD1) != 0) { 117251881Speter aprint_naive("\n"); 118251881Speter aprint_normal(": multiprocessor boot disabled\n"); 119251881Speter return; 120251881Speter } 121251881Speter 122251881Speter KASSERT(unit < MAXCPUS); 123251881Speter ci = &cpu_info_store[unit]; 124251881Speter 125251881Speter ci->ci_cpl = IPL_HIGH; 126251881Speter ci->ci_cpuid = id; 127251881Speter /* ci_id is stored by own cpus when hatching */ 128251881Speter 129251881Speter cpu_info[ncpu] = ci; 130251881Speter if (cpu_hatched_p(unit) == 0) { 131251881Speter ci->ci_dev = dv; 132251881Speter device_set_private(dv, ci); 133251881Speter ci->ci_index = -1; 134251881Speter 135251881Speter aprint_naive(": disabled\n"); 136251881Speter aprint_normal(": disabled (unresponsive)\n"); 137251881Speter return; 138251881Speter } 139251881Speter#else /* MULTIPROCESSOR */ 140251881Speter aprint_naive(": disabled\n"); 141251881Speter aprint_normal(": disabled (uniprocessor kernel)\n"); 142251881Speter return; 143251881Speter#endif /* MULTIPROCESSOR */ 144251881Speter } 145251881Speter 146251881Speter ci->ci_dev = dv; 147251881Speter device_set_private(dv, ci); 148251881Speter 149251881Speter ci->ci_kfpu_spl = -1; 150251881Speter 151251881Speter arm_cpu_do_topology(ci); // XXXNH move this after mi_cpu_attach 152251881Speter cpu_identify(dv, ci); 153251881Speter 154251881Speter cpu_setup_sysctl(dv, ci); 155251881Speter 156251881Speter#ifdef MULTIPROCESSOR 157251881Speter if (unit != 0) { 158251881Speter mi_cpu_attach(ci); 159251881Speter pmap_tlb_info_attach(&pmap_tlb0_info, ci); 160251881Speter aarch64_parsecacheinfo(ci); 161251881Speter } 162251881Speter#endif /* MULTIPROCESSOR */ 163251881Speter 164251881Speter fpu_attach(ci); 165251881Speter 166251881Speter cpu_identify1(dv, ci); 167251881Speter aarch64_printcacheinfo(dv, ci); 168251881Speter cpu_identify2(dv, ci); 169251881Speter 170251881Speter if (unit != 0) { 171251881Speter return; 172251881Speter } 173251881Speter 174251881Speter#ifdef DDB 175251881Speter db_machdep_init(ci); 176251881Speter#endif 177251881Speter 178251881Speter cpu_init_counter(ci); 179251881Speter 180251881Speter /* These currently only check the BP. */ 181251881Speter cpu_setup_rng(dv, ci); 182251881Speter cpu_setup_aes(dv, ci); 183251881Speter cpu_setup_chacha(dv, ci); 184251881Speter 185251881Speter cpu_rescan(dv, NULL, NULL); 186251881Speter} 187251881Speter 188251881Speterint 189251881Spetercpu_rescan(device_t dv, const char *ifattr, const int *locators) 190251881Speter{ 191251881Speter struct cpu_info *ci = device_private(dv); 192251881Speter 193251881Speter if (ifattr_match(ifattr, "cpufeaturebus")) { 194251881Speter struct cpufeature_attach_args cfaa = { 195251881Speter .ci = ci, 196251881Speter }; 197251881Speter config_found(dv, &cfaa, NULL, CFARGS(.iattr = "cpufeaturebus")); 198251881Speter } 199251881Speter 200251881Speter return 0; 201251881Speter} 202251881Speter 203251881Spetervoid 204251881Spetercpu_childdetached(device_t dv, device_t child) 205251881Speter{ 206251881Speter /* Nada */ 207251881Speter} 208251881Speter 209251881Speterstruct cpuidtab { 210251881Speter uint32_t cpu_partnum; 211251881Speter const char *cpu_name; 212251881Speter const char *cpu_vendor; 213251881Speter const char *cpu_architecture; 214251881Speter}; 215251881Speter 216251881Speter#define CPU_PARTMASK (CPU_ID_IMPLEMENTOR_MASK | CPU_ID_PARTNO_MASK) 217251881Speter 218251881Speterconst struct cpuidtab cpuids[] = { 219251881Speter { CPU_ID_CORTEXA35R0 & CPU_PARTMASK, "Cortex-A35", "Arm", "v8-A" }, 220251881Speter { CPU_ID_CORTEXA53R0 & CPU_PARTMASK, "Cortex-A53", "Arm", "v8-A" }, 221251881Speter { CPU_ID_CORTEXA57R0 & CPU_PARTMASK, "Cortex-A57", "Arm", "v8-A" }, 222251881Speter { CPU_ID_CORTEXA55R1 & CPU_PARTMASK, "Cortex-A55", "Arm", "v8.2-A+" }, 223251881Speter { CPU_ID_CORTEXA65R0 & CPU_PARTMASK, "Cortex-A65", "Arm", "v8.2-A+" }, 224251881Speter { CPU_ID_CORTEXA72R0 & CPU_PARTMASK, "Cortex-A72", "Arm", "v8-A" }, 225251881Speter { CPU_ID_CORTEXA73R0 & CPU_PARTMASK, "Cortex-A73", "Arm", "v8-A" }, 226251881Speter { CPU_ID_CORTEXA75R2 & CPU_PARTMASK, "Cortex-A75", "Arm", "v8.2-A+" }, 227251881Speter { CPU_ID_CORTEXA76R3 & CPU_PARTMASK, "Cortex-A76", "Arm", "v8.2-A+" }, 228251881Speter { CPU_ID_CORTEXA76AER1 & CPU_PARTMASK, "Cortex-A76AE", "Arm", "v8.2-A+" }, 229251881Speter { CPU_ID_CORTEXA77R0 & CPU_PARTMASK, "Cortex-A77", "Arm", "v8.2-A+" }, 230251881Speter { CPU_ID_NVIDIADENVER2 & CPU_PARTMASK, "Denver2", "NVIDIA", "v8-A" }, 231251881Speter { CPU_ID_EMAG8180 & CPU_PARTMASK, "eMAG", "Ampere", "v8-A" }, 232251881Speter { CPU_ID_NEOVERSEE1R1 & CPU_PARTMASK, "Neoverse E1", "Arm", "v8.2-A+" }, 233251881Speter { CPU_ID_NEOVERSEN1R3 & CPU_PARTMASK, "Neoverse N1", "Arm", "v8.2-A+" }, 234251881Speter { CPU_ID_THUNDERXRX, "ThunderX", "Cavium", "v8-A" }, 235251881Speter { CPU_ID_THUNDERX81XXRX, "ThunderX CN81XX", "Cavium", "v8-A" }, 236251881Speter { CPU_ID_THUNDERX83XXRX, "ThunderX CN83XX", "Cavium", "v8-A" }, 237251881Speter { CPU_ID_THUNDERX2RX, "ThunderX2", "Marvell", "v8.1-A" }, 238251881Speter { CPU_ID_APPLE_M1_ICESTORM & CPU_PARTMASK, "M1 Icestorm", "Apple", "Apple Silicon" }, 239251881Speter { CPU_ID_APPLE_M1_FIRESTORM & CPU_PARTMASK, "M1 Firestorm", "Apple", "Apple Silicon" }, 240251881Speter}; 241251881Speter 242251881Speterstatic void 243251881Speteridentify_aarch64_model(uint32_t cpuid, char *buf, size_t len) 244251881Speter{ 245251881Speter int i; 246251881Speter uint32_t cpupart, variant, revision; 247251881Speter 248251881Speter cpupart = cpuid & CPU_PARTMASK; 249251881Speter variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK); 250251881Speter revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK); 251251881Speter 252251881Speter for (i = 0; i < __arraycount(cpuids); i++) { 253251881Speter if (cpupart == cpuids[i].cpu_partnum) { 254251881Speter snprintf(buf, len, "%s %s r%dp%d (%s)", 255251881Speter cpuids[i].cpu_vendor, cpuids[i].cpu_name, 256251881Speter variant, revision, 257251881Speter cpuids[i].cpu_architecture); 258251881Speter return; 259251881Speter } 260251881Speter } 261251881Speter 262251881Speter snprintf(buf, len, "unknown CPU (ID = 0x%08x)", cpuid); 263251881Speter} 264251881Speter 265251881Speterstatic void 266251881Spetercpu_identify(device_t self, struct cpu_info *ci) 267251881Speter{ 268251881Speter char model[128]; 269251881Speter const char *m; 270251881Speter 271251881Speter identify_aarch64_model(ci->ci_id.ac_midr, model, sizeof(model)); 272251881Speter 273251881Speter aprint_naive("\n"); 274251881Speter aprint_normal(": %s, id 0x%lx\n", model, ci->ci_cpuid); 275251881Speter aprint_normal_dev(ci->ci_dev, "package %u, core %u, smt %u\n", 276251881Speter ci->ci_package_id, ci->ci_core_id, ci->ci_smt_id); 277251881Speter 278251881Speter if (ci->ci_index == 0) { 279251881Speter m = cpu_getmodel(); 280251881Speter if (m == NULL || *m == 0) 281251881Speter cpu_setmodel("%s", model); 282251881Speter 283251881Speter if (CPU_ID_ERRATA_CAVIUM_THUNDERX_1_1_P(ci->ci_id.ac_midr)) 284251881Speter aprint_normal("WARNING: ThunderX Pass 1.1 detected.\n" 285251881Speter "This has known hardware bugs that may cause the " 286251881Speter "incorrect operation of atomic operations.\n"); 287251881Speter } 288251881Speter} 289 290static void 291cpu_identify1(device_t self, struct cpu_info *ci) 292{ 293 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 294 uint64_t sctlr = ci->ci_sctlr_el1; 295 296 if (sctlr & SCTLR_I) 297 aprint_verbose_dev(self, "IC enabled"); 298 else 299 aprint_verbose_dev(self, "IC disabled"); 300 301 if (sctlr & SCTLR_C) 302 aprint_verbose(", DC enabled"); 303 else 304 aprint_verbose(", DC disabled"); 305 306 if (sctlr & SCTLR_A) 307 aprint_verbose(", Alignment check enabled\n"); 308 else { 309 switch (sctlr & (SCTLR_SA | SCTLR_SA0)) { 310 case SCTLR_SA | SCTLR_SA0: 311 aprint_verbose( 312 ", EL0/EL1 stack Alignment check enabled\n"); 313 break; 314 case SCTLR_SA: 315 aprint_verbose(", EL1 stack Alignment check enabled\n"); 316 break; 317 case SCTLR_SA0: 318 aprint_verbose(", EL0 stack Alignment check enabled\n"); 319 break; 320 case 0: 321 aprint_verbose(", Alignment check disabled\n"); 322 break; 323 } 324 } 325 326 /* 327 * CTR - Cache Type Register 328 */ 329 const uint64_t ctr = id->ac_ctr; 330 const uint64_t clidr = id->ac_clidr; 331 aprint_verbose_dev(self, "Cache Writeback Granule %" PRIu64 "B," 332 " Exclusives Reservation Granule %" PRIu64 "B\n", 333 __SHIFTOUT(ctr, CTR_EL0_CWG_LINE) * 4, 334 __SHIFTOUT(ctr, CTR_EL0_ERG_LINE) * 4); 335 336 aprint_verbose_dev(self, "Dcache line %ld, Icache line %ld" 337 ", DIC=%lu, IDC=%lu, LoUU=%lu, LoC=%lu, LoUIS=%lu\n", 338 sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_DMIN_LINE), 339 sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_IMIN_LINE), 340 __SHIFTOUT(ctr, CTR_EL0_DIC), 341 __SHIFTOUT(ctr, CTR_EL0_IDC), 342 __SHIFTOUT(clidr, CLIDR_LOUU), 343 __SHIFTOUT(clidr, CLIDR_LOC), 344 __SHIFTOUT(clidr, CLIDR_LOUIS)); 345} 346 347 348/* 349 * identify vfp, etc. 350 */ 351static void 352cpu_identify2(device_t self, struct cpu_info *ci) 353{ 354 struct aarch64_sysctl_cpu_id * const id = &ci->ci_id; 355 356 aprint_debug_dev(self, "midr=0x%" PRIx64 " mpidr=0x%" PRIx64 "\n", 357 id->ac_midr, id->ac_mpidr); 358 aprint_verbose_dev(self, "revID=0x%" PRIx64, id->ac_revidr); 359 360 /* ID_AA64DFR0_EL1 */ 361 switch (__SHIFTOUT(id->ac_aa64dfr0, ID_AA64DFR0_EL1_PMUVER)) { 362 case ID_AA64DFR0_EL1_PMUVER_V3: 363 aprint_verbose(", PMCv3"); 364 break; 365 case ID_AA64DFR0_EL1_PMUVER_NOV3: 366 aprint_verbose(", PMC"); 367 break; 368 } 369 370 /* ID_AA64MMFR0_EL1 */ 371 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN4)) { 372 case ID_AA64MMFR0_EL1_TGRAN4_4KB: 373 aprint_verbose(", 4k table"); 374 break; 375 } 376 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN16)) { 377 case ID_AA64MMFR0_EL1_TGRAN16_16KB: 378 aprint_verbose(", 16k table"); 379 break; 380 } 381 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN64)) { 382 case ID_AA64MMFR0_EL1_TGRAN64_64KB: 383 aprint_verbose(", 64k table"); 384 break; 385 } 386 387 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_ASIDBITS)) { 388 case ID_AA64MMFR0_EL1_ASIDBITS_8BIT: 389 aprint_verbose(", 8bit ASID"); 390 break; 391 case ID_AA64MMFR0_EL1_ASIDBITS_16BIT: 392 aprint_verbose(", 16bit ASID"); 393 break; 394 } 395 aprint_verbose("\n"); 396 397 aprint_verbose_dev(self, "auxID=0x%" PRIx64, ci->ci_id.ac_aa64isar0); 398 399 /* PFR0 */ 400 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV3)) { 401 case ID_AA64PFR0_EL1_CSV3_IMPL: 402 aprint_verbose(", CSV3"); 403 break; 404 } 405 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV2)) { 406 case ID_AA64PFR0_EL1_CSV2_IMPL: 407 aprint_verbose(", CSV2"); 408 break; 409 } 410 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_GIC)) { 411 case ID_AA64PFR0_EL1_GIC_CPUIF_EN: 412 aprint_verbose(", GICv3"); 413 break; 414 } 415 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_FP)) { 416 case ID_AA64PFR0_EL1_FP_NONE: 417 break; 418 default: 419 aprint_verbose(", FP"); 420 break; 421 } 422 423 /* ISAR0 */ 424 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_CRC32)) { 425 case ID_AA64ISAR0_EL1_CRC32_CRC32X: 426 aprint_verbose(", CRC32"); 427 break; 428 } 429 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA1)) { 430 case ID_AA64ISAR0_EL1_SHA1_SHA1CPMHSU: 431 aprint_verbose(", SHA1"); 432 break; 433 } 434 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA2)) { 435 case ID_AA64ISAR0_EL1_SHA2_SHA256HSU: 436 aprint_verbose(", SHA256"); 437 break; 438 } 439 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { 440 case ID_AA64ISAR0_EL1_AES_AES: 441 aprint_verbose(", AES"); 442 break; 443 case ID_AA64ISAR0_EL1_AES_PMUL: 444 aprint_verbose(", AES+PMULL"); 445 break; 446 } 447 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { 448 case ID_AA64ISAR0_EL1_RNDR_RNDRRS: 449 aprint_verbose(", RNDRRS"); 450 break; 451 } 452 453 /* PFR0:DIT -- data-independent timing support */ 454 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_DIT)) { 455 case ID_AA64PFR0_EL1_DIT_IMPL: 456 aprint_verbose(", DIT"); 457 break; 458 } 459 460 /* PFR0:AdvSIMD */ 461 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { 462 case ID_AA64PFR0_EL1_ADV_SIMD_NONE: 463 break; 464 default: 465 aprint_verbose(", NEON"); 466 break; 467 } 468 469 /* MVFR0/MVFR1 */ 470 switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPROUND)) { 471 case MVFR0_FPROUND_ALL: 472 aprint_verbose(", rounding"); 473 break; 474 } 475 switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPTRAP)) { 476 case MVFR0_FPTRAP_TRAP: 477 aprint_verbose(", exceptions"); 478 break; 479 } 480 switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPDNAN)) { 481 case MVFR1_FPDNAN_NAN: 482 aprint_verbose(", NaN propagation"); 483 break; 484 } 485 switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPFTZ)) { 486 case MVFR1_FPFTZ_DENORMAL: 487 aprint_verbose(", denormals"); 488 break; 489 } 490 switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_SIMDREG)) { 491 case MVFR0_SIMDREG_16x64: 492 aprint_verbose(", 16x64bitRegs"); 493 break; 494 case MVFR0_SIMDREG_32x64: 495 aprint_verbose(", 32x64bitRegs"); 496 break; 497 } 498 switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_SIMDFMAC)) { 499 case MVFR1_SIMDFMAC_FMAC: 500 aprint_verbose(", Fused Multiply-Add"); 501 break; 502 } 503 504 aprint_verbose("\n"); 505} 506 507/* 508 * Enable the performance counter, then estimate frequency for 509 * the current PE and store the result in cpu_cc_freq. 510 */ 511static void 512cpu_init_counter(struct cpu_info *ci) 513{ 514 const uint64_t dfr0 = reg_id_aa64dfr0_el1_read(); 515 const u_int pmuver = __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_PMUVER); 516 if (pmuver == ID_AA64DFR0_EL1_PMUVER_NONE) { 517 /* Performance Monitors Extension not implemented. */ 518 return; 519 } 520 if (pmuver == ID_AA64DFR0_EL1_PMUVER_IMPL) { 521 /* Non-standard Performance Monitors are not supported. */ 522 return; 523 } 524 525 reg_pmcr_el0_write(PMCR_E | PMCR_C | PMCR_LC); 526 reg_pmintenclr_el1_write(PMINTEN_C | PMINTEN_P); 527 reg_pmcntenset_el0_write(PMCNTEN_C); 528 529 const uint32_t prev = cpu_counter32(); 530 delay(100000); 531 ci->ci_data.cpu_cc_freq = (cpu_counter32() - prev) * 10; 532} 533 534/* 535 * Fill in this CPUs id data. Must be called on all cpus. 536 */ 537void __noasan 538cpu_setup_id(struct cpu_info *ci) 539{ 540 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 541 542 /* SCTLR - System Control Register */ 543 ci->ci_sctlr_el1 = reg_sctlr_el1_read(); 544 545 memset(id, 0, sizeof *id); 546 547 id->ac_midr = reg_midr_el1_read(); 548 id->ac_revidr = reg_revidr_el1_read(); 549 id->ac_mpidr = reg_mpidr_el1_read(); 550 551 id->ac_aa64dfr0 = reg_id_aa64dfr0_el1_read(); 552 id->ac_aa64dfr1 = reg_id_aa64dfr1_el1_read(); 553 554 id->ac_aa64isar0 = reg_id_aa64isar0_el1_read(); 555 id->ac_aa64isar1 = reg_id_aa64isar1_el1_read(); 556 557 id->ac_aa64mmfr0 = reg_id_aa64mmfr0_el1_read(); 558 id->ac_aa64mmfr1 = reg_id_aa64mmfr1_el1_read(); 559 id->ac_aa64mmfr2 = reg_id_aa64mmfr2_el1_read(); 560 561 id->ac_mvfr0 = reg_mvfr0_el1_read(); 562 id->ac_mvfr1 = reg_mvfr1_el1_read(); 563 id->ac_mvfr2 = reg_mvfr2_el1_read(); 564 565 id->ac_clidr = reg_clidr_el1_read(); 566 id->ac_ctr = reg_ctr_el0_read(); 567 568 /* Only in ARMv8.2. */ 569 id->ac_aa64zfr0 = 0 /* reg_id_aa64zfr0_el1_read() */; 570 571 id->ac_aa64pfr0 = reg_id_aa64pfr0_el1_read(); 572 id->ac_aa64pfr1 = reg_id_aa64pfr1_el1_read(); 573} 574 575/* 576 * setup the per-cpu sysctl tree. 577 */ 578static void 579cpu_setup_sysctl(device_t dv, struct cpu_info *ci) 580{ 581 const struct sysctlnode *cpunode = NULL; 582 583 sysctl_createv(NULL, 0, NULL, &cpunode, 584 CTLFLAG_PERMANENT, 585 CTLTYPE_NODE, device_xname(dv), NULL, 586 NULL, 0, NULL, 0, 587 CTL_MACHDEP, 588 CTL_CREATE, CTL_EOL); 589 590 if (cpunode == NULL) 591 return; 592 593 sysctl_createv(NULL, 0, &cpunode, NULL, 594 CTLFLAG_PERMANENT, 595 CTLTYPE_STRUCT, "cpu_id", NULL, 596 NULL, 0, &ci->ci_id, sizeof(ci->ci_id), 597 CTL_CREATE, CTL_EOL); 598} 599 600static struct krndsource rndrrs_source; 601 602static void 603rndrrs_get(size_t nbytes, void *cookie) 604{ 605 /* Entropy bits per data byte, wild-arse guess. */ 606 const unsigned bpb = 4; 607 size_t nbits = nbytes*NBBY; 608 uint64_t x; 609 int error; 610 611 while (nbits) { 612 /* 613 * x := random 64-bit sample 614 * error := Z bit, set to 1 if sample is bad 615 * 616 * XXX This should be done by marking the function 617 * __attribute__((target("arch=armv8.5-a+rng"))) and 618 * using `mrs %0, rndrrs', but: 619 * 620 * (a) the version of gcc we use doesn't support that, 621 * and 622 * (b) clang doesn't seem to like `rndrrs' itself. 623 * 624 * So we use the numeric encoding for now. 625 */ 626 __asm __volatile("" 627 "mrs %0, s3_3_c2_c4_1\n" 628 "cset %w1, eq" 629 : "=r"(x), "=r"(error)); 630 if (error) 631 break; 632 rnd_add_data_sync(&rndrrs_source, &x, sizeof(x), 633 bpb*sizeof(x)); 634 nbits -= MIN(nbits, bpb*sizeof(x)); 635 } 636 637 explicit_memset(&x, 0, sizeof x); 638} 639 640/* 641 * setup the RNDRRS entropy source 642 */ 643static void 644cpu_setup_rng(device_t dv, struct cpu_info *ci) 645{ 646 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 647 648 /* Verify that it is supported. */ 649 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { 650 case ID_AA64ISAR0_EL1_RNDR_RNDRRS: 651 break; 652 default: 653 return; 654 } 655 656 /* Attach it. */ 657 rndsource_setcb(&rndrrs_source, rndrrs_get, NULL); 658 rnd_attach_source(&rndrrs_source, "rndrrs", RND_TYPE_RNG, 659 RND_FLAG_DEFAULT|RND_FLAG_HASCB); 660} 661 662/* 663 * setup the AES implementation 664 */ 665static void 666cpu_setup_aes(device_t dv, struct cpu_info *ci) 667{ 668 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 669 670 /* Check for ARMv8.0-AES support. */ 671 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { 672 case ID_AA64ISAR0_EL1_AES_AES: 673 case ID_AA64ISAR0_EL1_AES_PMUL: 674 aes_md_init(&aes_armv8_impl); 675 return; 676 default: 677 break; 678 } 679 680 /* Failing that, check for SIMD support. */ 681 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { 682 case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: 683 aes_md_init(&aes_neon_impl); 684 return; 685 default: 686 break; 687 } 688} 689 690/* 691 * setup the ChaCha implementation 692 */ 693static void 694cpu_setup_chacha(device_t dv, struct cpu_info *ci) 695{ 696 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 697 698 /* Check for SIMD support. */ 699 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { 700 case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: 701 chacha_md_init(&chacha_neon_impl); 702 return; 703 default: 704 break; 705 } 706} 707 708#ifdef MULTIPROCESSOR 709/* 710 * Initialise a secondary processor. 711 * 712 * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet. 713 * 714 */ 715void __noasan 716cpu_init_secondary_processor(int cpuindex) 717{ 718 struct cpu_info * ci = &cpu_info_store[cpuindex]; 719 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 720 721 aarch64_setcpufuncs(ci); 722 723 /* Sets ci->ci_{sctlr,midr,mpidr}, etc */ 724 cpu_setup_id(ci); 725 726 arm_cpu_topology_set(ci, id->ac_mpidr); 727 aarch64_getcacheinfo(ci); 728 729 cpu_set_hatched(cpuindex); 730 731 /* 732 * return to assembly to wait for cpu_boot_secondary_processors 733 */ 734} 735 736 737/* 738 * When we are called, the MMU and caches are on and we are running on the stack 739 * of the idlelwp for this cpu. 740 */ 741void 742cpu_hatch(struct cpu_info *ci) 743{ 744 KASSERT(curcpu() == ci); 745 KASSERT((reg_tcr_el1_read() & TCR_EPD0) != 0); 746 747#ifdef DDB 748 db_machdep_cpu_init(); 749#endif 750 751 cpu_init_counter(ci); 752 753 intr_cpu_init(ci); 754 755#ifdef FDT 756 arm_fdt_cpu_hatch(ci); 757#endif 758 759 /* 760 * clear my bit of arm_cpu_mbox to tell cpu_boot_secondary_processors(). 761 * there are cpu0,1,2,3, and if cpu2 is unresponsive, 762 * ci_index are each cpu0=0, cpu1=1, cpu2=undef, cpu3=2. 763 * therefore we have to use device_unit instead of ci_index for mbox. 764 */ 765 766 cpu_clr_mbox(device_unit(ci->ci_dev)); 767} 768#endif /* MULTIPROCESSOR */ 769