1 /* $NetBSD: cpu.c,v 1.84 2026/03/29 11:15:03 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Ryo Shimizu 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 __KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.84 2026/03/29 11:15:03 skrll Exp $"); 31 32 #include "locators.h" 33 #include "opt_arm_debug.h" 34 #include "opt_ddb.h" 35 #include "opt_fdt.h" 36 #include "opt_multiprocessor.h" 37 38 #include <sys/param.h> 39 #include <sys/atomic.h> 40 #include <sys/cpu.h> 41 #include <sys/device.h> 42 #include <sys/kmem.h> 43 #include <sys/reboot.h> 44 #include <sys/rndsource.h> 45 #include <sys/sdt.h> 46 #include <sys/sysctl.h> 47 #include <sys/systm.h> 48 49 #include <crypto/aes/aes_impl.h> 50 #include <crypto/aes/arch/arm/aes_armv8.h> 51 #include <crypto/aes/arch/arm/aes_neon.h> 52 #include <crypto/chacha/chacha_impl.h> 53 #include <crypto/chacha/arch/arm/chacha_neon.h> 54 55 #include <aarch64/armreg.h> 56 #include <aarch64/cpu.h> 57 #include <aarch64/cpu_counter.h> 58 #ifdef DDB 59 #include <aarch64/db_machdep.h> 60 #endif 61 #include <aarch64/machdep.h> 62 63 #include <arm/cpufunc.h> 64 #include <arm/cpuvar.h> 65 #include <arm/cpu_topology.h> 66 #ifdef FDT 67 #include <arm/fdt/arm_fdtvar.h> 68 #endif 69 70 #ifdef VERBOSE_INIT_ARM 71 #define VPRINTF(...) printf(__VA_ARGS__) 72 #else 73 #define VPRINTF(...) __nothing 74 #endif 75 76 void cpu_attach(device_t, cpuid_t); 77 void cpu_setup_id(struct cpu_info *); 78 79 static void identify_aarch64_model(uint32_t, char *, size_t); 80 static void cpu_identify(device_t self, struct cpu_info *); 81 static void cpu_identify1(device_t self, struct cpu_info *); 82 static void cpu_identify2(device_t self, struct cpu_info *); 83 static void cpu_init_counter(struct cpu_info *); 84 static void cpu_setup_sysctl(device_t, struct cpu_info *); 85 static void cpu_setup_rng(device_t, struct cpu_info *); 86 static void cpu_setup_aes(device_t, struct cpu_info *); 87 static void cpu_setup_chacha(device_t, struct cpu_info *); 88 89 #ifdef MULTIPROCESSOR 90 #define NCPUINFO MAXCPUS 91 #else 92 #define NCPUINFO 1 93 #endif /* MULTIPROCESSOR */ 94 95 /* 96 * Our exported cpu_info structs; these will be first used by the 97 * secondary cpus as part of cpu_mpstart and the hatching process. 98 */ 99 struct cpu_info cpu_info_store[NCPUINFO] = { 100 [0] = { 101 .ci_cpl = IPL_HIGH, 102 .ci_curlwp = &lwp0 103 } 104 }; 105 106 void 107 cpu_attach(device_t dv, cpuid_t id) 108 { 109 struct cpu_info *ci; 110 const int unit = device_unit(dv); 111 112 if (unit == 0) { 113 ci = curcpu(); 114 ci->ci_cpuid = id; 115 } else { 116 #ifdef MULTIPROCESSOR 117 if ((boothowto & RB_MD1) != 0) { 118 aprint_naive("\n"); 119 aprint_normal(": multiprocessor boot disabled\n"); 120 return; 121 } 122 123 KASSERT(unit < MAXCPUS); 124 ci = &cpu_info_store[unit]; 125 126 ci->ci_cpl = IPL_HIGH; 127 ci->ci_cpuid = id; 128 /* ci_id is stored by own cpus when hatching */ 129 130 cpu_info[ncpu] = ci; 131 if (cpu_hatched_p(unit) == 0) { 132 ci->ci_dev = dv; 133 device_set_private(dv, ci); 134 ci->ci_index = -1; 135 136 aprint_naive(": disabled\n"); 137 aprint_normal(": disabled (unresponsive)\n"); 138 return; 139 } 140 #else /* MULTIPROCESSOR */ 141 aprint_naive(": disabled\n"); 142 aprint_normal(": disabled (uniprocessor kernel)\n"); 143 return; 144 #endif /* MULTIPROCESSOR */ 145 } 146 147 ci->ci_dev = dv; 148 device_set_private(dv, ci); 149 150 ci->ci_kfpu_spl = -1; 151 152 arm_cpu_do_topology(ci); // XXXNH move this after mi_cpu_attach 153 cpu_identify(dv, ci); 154 155 cpu_setup_sysctl(dv, ci); 156 157 #ifdef MULTIPROCESSOR 158 if (unit != 0) { 159 mi_cpu_attach(ci); 160 pmap_tlb_info_attach(&pmap_tlb0_info, ci); 161 aarch64_parsecacheinfo(ci); 162 } 163 #endif /* MULTIPROCESSOR */ 164 165 fpu_attach(ci); 166 167 cpu_identify1(dv, ci); 168 aarch64_printcacheinfo(dv, ci); 169 cpu_identify2(dv, ci); 170 171 cpu_setup_rng(dv, ci); 172 173 if (unit != 0) { 174 return; 175 } 176 177 #ifdef DDB 178 db_machdep_init(ci); 179 #endif 180 181 cpu_init_counter(ci); 182 183 /* These currently only check the BP. */ 184 cpu_setup_aes(dv, ci); 185 cpu_setup_chacha(dv, ci); 186 187 cpu_rescan(dv, NULL, NULL); 188 } 189 190 int 191 cpu_rescan(device_t dv, const char *ifattr, const int *locators) 192 { 193 struct cpu_info *ci = device_private(dv); 194 195 if (ifattr_match(ifattr, "cpufeaturebus")) { 196 struct cpufeature_attach_args cfaa = { 197 .ci = ci, 198 }; 199 config_found(dv, &cfaa, NULL, CFARGS(.iattr = "cpufeaturebus")); 200 } 201 202 return 0; 203 } 204 205 void 206 cpu_childdetached(device_t dv, device_t child) 207 { 208 /* Nada */ 209 } 210 211 struct cpuidtab { 212 uint32_t cpu_partnum; 213 const char *cpu_name; 214 const char *cpu_vendor; 215 const char *cpu_architecture; 216 }; 217 218 #define CPU_PARTMASK (CPU_ID_IMPLEMENTOR_MASK | CPU_ID_PARTNO_MASK) 219 220 const struct cpuidtab cpuids[] = { 221 { CPU_ID_CORTEXA35R0 & CPU_PARTMASK, "Cortex-A35", "Arm", "v8-A" }, 222 { CPU_ID_CORTEXA53R0 & CPU_PARTMASK, "Cortex-A53", "Arm", "v8-A" }, 223 { CPU_ID_CORTEXA57R0 & CPU_PARTMASK, "Cortex-A57", "Arm", "v8-A" }, 224 { CPU_ID_CORTEXA55R1 & CPU_PARTMASK, "Cortex-A55", "Arm", "v8.2-A+" }, 225 { CPU_ID_CORTEXA65R0 & CPU_PARTMASK, "Cortex-A65", "Arm", "v8.2-A+" }, 226 { CPU_ID_CORTEXA72R0 & CPU_PARTMASK, "Cortex-A72", "Arm", "v8-A" }, 227 { CPU_ID_CORTEXA73R0 & CPU_PARTMASK, "Cortex-A73", "Arm", "v8-A" }, 228 { CPU_ID_CORTEXA75R2 & CPU_PARTMASK, "Cortex-A75", "Arm", "v8.2-A+" }, 229 { CPU_ID_CORTEXA76R3 & CPU_PARTMASK, "Cortex-A76", "Arm", "v8.2-A+" }, 230 { CPU_ID_CORTEXA76AER1 & CPU_PARTMASK, "Cortex-A76AE", "Arm", "v8.2-A+" }, 231 { CPU_ID_CORTEXA77R0 & CPU_PARTMASK, "Cortex-A77", "Arm", "v8.2-A+" }, 232 { CPU_ID_CORTEXA520R0 & CPU_PARTMASK, "Cortex-A520", "Arm", "v9.2-A" }, 233 { CPU_ID_CORTEXA710R2 & CPU_PARTMASK, "Cortex-A710", "Arm", "v9.0-A" }, 234 { CPU_ID_CORTEXA720R0 & CPU_PARTMASK, "Cortex-A720", "Arm", "v9.2-A" }, 235 { CPU_ID_NVIDIADENVER2 & CPU_PARTMASK, "Denver2", "NVIDIA", "v8-A" }, 236 { CPU_ID_EMAG8180 & CPU_PARTMASK, "eMAG", "Ampere", "v8-A" }, 237 { CPU_ID_NEOVERSEE1R1 & CPU_PARTMASK, "Neoverse E1", "Arm", "v8.2-A+" }, 238 { CPU_ID_NEOVERSEN1R3 & CPU_PARTMASK, "Neoverse N1", "Arm", "v8.2-A+" }, 239 { CPU_ID_NEOVERSEV1R1 & CPU_PARTMASK, "Neoverse V1", "Arm", "v8.4-A+" }, 240 { CPU_ID_NEOVERSEN2R0 & CPU_PARTMASK, "Neoverse N2", "Arm", "v9.0-A" }, 241 { CPU_ID_THUNDERXRX, "ThunderX", "Cavium", "v8-A" }, 242 { CPU_ID_THUNDERX81XXRX, "ThunderX CN81XX", "Cavium", "v8-A" }, 243 { CPU_ID_THUNDERX83XXRX, "ThunderX CN83XX", "Cavium", "v8-A" }, 244 { CPU_ID_THUNDERX2RX, "ThunderX2", "Marvell", "v8.1-A" }, 245 { CPU_ID_APPLE_M1_ICESTORM & CPU_PARTMASK, "M1 Icestorm", "Apple", "Apple Silicon" }, 246 { CPU_ID_APPLE_M1_FIRESTORM & CPU_PARTMASK, "M1 Firestorm", "Apple", "Apple Silicon" }, 247 { CPU_ID_AMPERE1 & CPU_PARTMASK, "Ampere-1", "Ampere", "v8.6-A+" }, 248 { CPU_ID_AMPERE1A & CPU_PARTMASK, "Ampere-1A", "Ampere", "v8.6-A+" }, 249 { CPU_ID_A64FX & CPU_PARTMASK, "A64FX", "Fujitsu", "v8.2-A+" }, 250 { CPU_ID_ORYON & CPU_PARTMASK, "Oryon", "Qualcomm", "v8.7-A+" }, 251 }; 252 253 static void 254 identify_aarch64_model(uint32_t cpuid, char *buf, size_t len) 255 { 256 int i; 257 uint32_t cpupart, variant, revision; 258 259 cpupart = cpuid & CPU_PARTMASK; 260 variant = __SHIFTOUT(cpuid, CPU_ID_VARIANT_MASK); 261 revision = __SHIFTOUT(cpuid, CPU_ID_REVISION_MASK); 262 263 for (i = 0; i < __arraycount(cpuids); i++) { 264 if (cpupart == cpuids[i].cpu_partnum) { 265 snprintf(buf, len, "%s %s r%dp%d (%s)", 266 cpuids[i].cpu_vendor, cpuids[i].cpu_name, 267 variant, revision, 268 cpuids[i].cpu_architecture); 269 return; 270 } 271 } 272 273 snprintf(buf, len, "unknown CPU (ID = 0x%08x)", cpuid); 274 } 275 276 static void 277 cpu_identify(device_t self, struct cpu_info *ci) 278 { 279 char model[128]; 280 const char *m; 281 282 identify_aarch64_model(ci->ci_id.ac_midr, model, sizeof(model)); 283 284 aprint_naive("\n"); 285 aprint_normal(": %s, id 0x%lx\n", model, ci->ci_cpuid); 286 aprint_normal_dev(ci->ci_dev, "package %u, core %u, smt %u, numa %u\n", 287 ci->ci_package_id, ci->ci_core_id, ci->ci_smt_id, ci->ci_numa_id); 288 289 if (ci->ci_index == 0) { 290 m = cpu_getmodel(); 291 if (m == NULL || *m == 0) 292 cpu_setmodel("%s", model); 293 294 if (CPU_ID_ERRATA_CAVIUM_THUNDERX_1_1_P(ci->ci_id.ac_midr)) 295 aprint_normal("WARNING: ThunderX Pass 1.1 detected.\n" 296 "This has known hardware bugs that may cause the " 297 "incorrect operation of atomic operations.\n"); 298 } 299 } 300 301 static void 302 cpu_identify1(device_t self, struct cpu_info *ci) 303 { 304 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 305 uint64_t sctlr = ci->ci_sctlr_el1; 306 307 if (sctlr & SCTLR_I) 308 aprint_verbose_dev(self, "IC enabled"); 309 else 310 aprint_verbose_dev(self, "IC disabled"); 311 312 if (sctlr & SCTLR_C) 313 aprint_verbose(", DC enabled"); 314 else 315 aprint_verbose(", DC disabled"); 316 317 if (sctlr & SCTLR_A) 318 aprint_verbose(", Alignment check enabled\n"); 319 else { 320 switch (sctlr & (SCTLR_SA | SCTLR_SA0)) { 321 case SCTLR_SA | SCTLR_SA0: 322 aprint_verbose( 323 ", EL0/EL1 stack Alignment check enabled\n"); 324 break; 325 case SCTLR_SA: 326 aprint_verbose(", EL1 stack Alignment check enabled\n"); 327 break; 328 case SCTLR_SA0: 329 aprint_verbose(", EL0 stack Alignment check enabled\n"); 330 break; 331 case 0: 332 aprint_verbose(", Alignment check disabled\n"); 333 break; 334 } 335 } 336 337 /* 338 * CTR - Cache Type Register 339 */ 340 const uint64_t ctr = id->ac_ctr; 341 const uint64_t clidr = id->ac_clidr; 342 aprint_verbose_dev(self, "Cache Writeback Granule %" PRIu64 "B," 343 " Exclusives Reservation Granule %" PRIu64 "B\n", 344 __SHIFTOUT(ctr, CTR_EL0_CWG_LINE) * 4, 345 __SHIFTOUT(ctr, CTR_EL0_ERG_LINE) * 4); 346 347 aprint_verbose_dev(self, "Dcache line %ld, Icache line %ld" 348 ", DIC=%lu, IDC=%lu, LoUU=%lu, LoC=%lu, LoUIS=%lu\n", 349 sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_DMIN_LINE), 350 sizeof(int) << __SHIFTOUT(ctr, CTR_EL0_IMIN_LINE), 351 __SHIFTOUT(ctr, CTR_EL0_DIC), 352 __SHIFTOUT(ctr, CTR_EL0_IDC), 353 __SHIFTOUT(clidr, CLIDR_LOUU), 354 __SHIFTOUT(clidr, CLIDR_LOC), 355 __SHIFTOUT(clidr, CLIDR_LOUIS)); 356 } 357 358 359 /* 360 * identify vfp, etc. 361 */ 362 static void 363 cpu_identify2(device_t self, struct cpu_info *ci) 364 { 365 struct aarch64_sysctl_cpu_id * const id = &ci->ci_id; 366 367 aprint_debug_dev(self, "midr=0x%" PRIx64 " mpidr=0x%" PRIx64 "\n", 368 id->ac_midr, id->ac_mpidr); 369 aprint_verbose_dev(self, "revID=0x%" PRIx64, id->ac_revidr); 370 371 /* ID_AA64DFR0_EL1 */ 372 switch (__SHIFTOUT(id->ac_aa64dfr0, ID_AA64DFR0_EL1_PMUVER)) { 373 case ID_AA64DFR0_EL1_PMUVER_V3: 374 aprint_verbose(", PMUv3"); 375 break; 376 case ID_AA64DFR0_EL1_PMUVER_V3P1: 377 aprint_verbose(", PMUv3p1"); 378 break; 379 case ID_AA64DFR0_EL1_PMUVER_V3P4: 380 aprint_verbose(", PMUv3p4"); 381 break; 382 case ID_AA64DFR0_EL1_PMUVER_V3P5: 383 aprint_verbose(", PMUv3p5"); 384 break; 385 case ID_AA64DFR0_EL1_PMUVER_V3P7: 386 aprint_verbose(", PMUv3p7"); 387 break; 388 case ID_AA64DFR0_EL1_PMUVER_V3P8: 389 aprint_verbose(", PMUv3p8"); 390 break; 391 } 392 393 /* ID_AA64MMFR0_EL1 */ 394 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN4)) { 395 case ID_AA64MMFR0_EL1_TGRAN4_4KB: 396 aprint_verbose(", 4k table"); 397 break; 398 } 399 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN16)) { 400 case ID_AA64MMFR0_EL1_TGRAN16_16KB: 401 aprint_verbose(", 16k table"); 402 break; 403 } 404 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_TGRAN64)) { 405 case ID_AA64MMFR0_EL1_TGRAN64_64KB: 406 aprint_verbose(", 64k table"); 407 break; 408 } 409 410 switch (__SHIFTOUT(id->ac_aa64mmfr0, ID_AA64MMFR0_EL1_ASIDBITS)) { 411 case ID_AA64MMFR0_EL1_ASIDBITS_8BIT: 412 aprint_verbose(", 8bit ASID"); 413 break; 414 case ID_AA64MMFR0_EL1_ASIDBITS_16BIT: 415 aprint_verbose(", 16bit ASID"); 416 break; 417 } 418 aprint_verbose("\n"); 419 420 aprint_verbose_dev(self, "auxID=0x%" PRIx64, ci->ci_id.ac_aa64isar0); 421 422 /* PFR0 */ 423 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV3)) { 424 case ID_AA64PFR0_EL1_CSV3_IMPL: 425 aprint_verbose(", CSV3"); 426 break; 427 } 428 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_CSV2)) { 429 case ID_AA64PFR0_EL1_CSV2_IMPL: 430 aprint_verbose(", CSV2"); 431 break; 432 } 433 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_GIC)) { 434 case ID_AA64PFR0_EL1_GIC_CPUIF_EN: 435 aprint_verbose(", GICv3"); 436 break; 437 } 438 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_FP)) { 439 case ID_AA64PFR0_EL1_FP_NONE: 440 break; 441 default: 442 aprint_verbose(", FP"); 443 break; 444 } 445 446 /* ISAR0 */ 447 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_CRC32)) { 448 case ID_AA64ISAR0_EL1_CRC32_CRC32X: 449 aprint_verbose(", CRC32"); 450 break; 451 } 452 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA1)) { 453 case ID_AA64ISAR0_EL1_SHA1_SHA1CPMHSU: 454 aprint_verbose(", SHA1"); 455 break; 456 } 457 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_SHA2)) { 458 case ID_AA64ISAR0_EL1_SHA2_SHA256HSU: 459 aprint_verbose(", SHA256"); 460 break; 461 } 462 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { 463 case ID_AA64ISAR0_EL1_AES_AES: 464 aprint_verbose(", AES"); 465 break; 466 case ID_AA64ISAR0_EL1_AES_PMUL: 467 aprint_verbose(", AES+PMULL"); 468 break; 469 } 470 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { 471 case ID_AA64ISAR0_EL1_RNDR_RNDRRS: 472 aprint_verbose(", RNDRRS"); 473 break; 474 } 475 476 /* PFR0:DIT -- data-independent timing support */ 477 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_DIT)) { 478 case ID_AA64PFR0_EL1_DIT_IMPL: 479 aprint_verbose(", DIT"); 480 break; 481 } 482 483 /* PFR0:AdvSIMD */ 484 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { 485 case ID_AA64PFR0_EL1_ADV_SIMD_NONE: 486 break; 487 default: 488 aprint_verbose(", NEON"); 489 break; 490 } 491 492 /* MVFR0/MVFR1 */ 493 switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPROUND)) { 494 case MVFR0_FPROUND_ALL: 495 aprint_verbose(", rounding"); 496 break; 497 } 498 switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_FPTRAP)) { 499 case MVFR0_FPTRAP_TRAP: 500 aprint_verbose(", exceptions"); 501 break; 502 } 503 switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPDNAN)) { 504 case MVFR1_FPDNAN_NAN: 505 aprint_verbose(", NaN propagation"); 506 break; 507 } 508 switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_FPFTZ)) { 509 case MVFR1_FPFTZ_DENORMAL: 510 aprint_verbose(", denormals"); 511 break; 512 } 513 switch (__SHIFTOUT(id->ac_mvfr0, MVFR0_SIMDREG)) { 514 case MVFR0_SIMDREG_16x64: 515 aprint_verbose(", 16x64bitRegs"); 516 break; 517 case MVFR0_SIMDREG_32x64: 518 aprint_verbose(", 32x64bitRegs"); 519 break; 520 } 521 switch (__SHIFTOUT(id->ac_mvfr1, MVFR1_SIMDFMAC)) { 522 case MVFR1_SIMDFMAC_FMAC: 523 aprint_verbose(", Fused Multiply-Add"); 524 break; 525 } 526 527 aprint_verbose("\n"); 528 } 529 530 /* 531 * Enable the performance counter, then estimate frequency for 532 * the current PE and store the result in cpu_cc_freq. 533 */ 534 static void 535 cpu_init_counter(struct cpu_info *ci) 536 { 537 const uint64_t dfr0 = reg_id_aa64dfr0_el1_read(); 538 const u_int pmuver = __SHIFTOUT(dfr0, ID_AA64DFR0_EL1_PMUVER); 539 if (pmuver == ID_AA64DFR0_EL1_PMUVER_NONE) { 540 /* Performance Monitors Extension not implemented. */ 541 return; 542 } 543 if (pmuver == ID_AA64DFR0_EL1_PMUVER_IMPL) { 544 /* Non-standard Performance Monitors are not supported. */ 545 return; 546 } 547 548 reg_pmcr_el0_write(PMCR_E | PMCR_C | PMCR_LC); 549 reg_pmintenclr_el1_write(PMINTEN_C | PMINTEN_P); 550 reg_pmcntenset_el0_write(PMCNTEN_C); 551 552 const uint32_t prev = cpu_counter32(); 553 delay(100000); 554 ci->ci_data.cpu_cc_freq = (cpu_counter32() - prev) * 10; 555 } 556 557 /* 558 * Fill in this CPUs id data. Must be called on all cpus. 559 */ 560 void __noasan 561 cpu_setup_id(struct cpu_info *ci) 562 { 563 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 564 565 /* SCTLR - System Control Register */ 566 ci->ci_sctlr_el1 = reg_sctlr_el1_read(); 567 568 memset(id, 0, sizeof *id); 569 570 id->ac_midr = reg_midr_el1_read(); 571 id->ac_revidr = reg_revidr_el1_read(); 572 id->ac_mpidr = reg_mpidr_el1_read(); 573 574 id->ac_aa64dfr0 = reg_id_aa64dfr0_el1_read(); 575 id->ac_aa64dfr1 = reg_id_aa64dfr1_el1_read(); 576 577 id->ac_aa64isar0 = reg_id_aa64isar0_el1_read(); 578 id->ac_aa64isar1 = reg_id_aa64isar1_el1_read(); 579 580 id->ac_aa64mmfr0 = reg_id_aa64mmfr0_el1_read(); 581 id->ac_aa64mmfr1 = reg_id_aa64mmfr1_el1_read(); 582 id->ac_aa64mmfr2 = reg_id_aa64mmfr2_el1_read(); 583 584 id->ac_mvfr0 = reg_mvfr0_el1_read(); 585 id->ac_mvfr1 = reg_mvfr1_el1_read(); 586 id->ac_mvfr2 = reg_mvfr2_el1_read(); 587 588 id->ac_clidr = reg_clidr_el1_read(); 589 id->ac_ctr = reg_ctr_el0_read(); 590 591 /* Only in ARMv8.2. */ 592 id->ac_aa64zfr0 = 0 /* reg_id_aa64zfr0_el1_read() */; 593 594 id->ac_aa64pfr0 = reg_id_aa64pfr0_el1_read(); 595 id->ac_aa64pfr1 = reg_id_aa64pfr1_el1_read(); 596 } 597 598 /* 599 * setup the per-cpu sysctl tree. 600 */ 601 static void 602 cpu_setup_sysctl(device_t dv, struct cpu_info *ci) 603 { 604 const struct sysctlnode *cpunode = NULL; 605 606 sysctl_createv(NULL, 0, NULL, &cpunode, 607 CTLFLAG_PERMANENT, 608 CTLTYPE_NODE, device_xname(dv), NULL, 609 NULL, 0, NULL, 0, 610 CTL_MACHDEP, 611 CTL_CREATE, CTL_EOL); 612 613 if (cpunode == NULL) 614 return; 615 616 sysctl_createv(NULL, 0, &cpunode, NULL, 617 CTLFLAG_PERMANENT, 618 CTLTYPE_STRUCT, "cpu_id", NULL, 619 NULL, 0, &ci->ci_id, sizeof(ci->ci_id), 620 CTL_CREATE, CTL_EOL); 621 } 622 623 static struct krndsource rndrrs_source; 624 625 static void 626 rndrrs_get(size_t nbytes, void *cookie) 627 { 628 /* Entropy bits per data byte, wild-arse guess. */ 629 const unsigned bpb = 4; 630 size_t nbits = nbytes*NBBY; 631 uint64_t x; 632 int error, bound; 633 634 bound = curlwp_bind(); /* bind to CPU for rndrrs_fail evcnt */ 635 while (nbits) { 636 /* 637 * x := random 64-bit sample 638 * error := Z bit, set to 1 if sample is bad 639 * 640 * XXX This should be done by marking the function 641 * __attribute__((target("arch=armv8.5-a+rng"))) and 642 * using `mrs %0, rndrrs', but: 643 * 644 * (a) the version of gcc we use doesn't support that, 645 * and 646 * (b) clang doesn't seem to like `rndrrs' itself. 647 * 648 * So we use the numeric encoding for now. 649 */ 650 __asm __volatile("" 651 "mrs %0, s3_3_c2_c4_1\n" 652 "cset %w1, eq" 653 : "=r"(x), "=r"(error)); 654 if (error) { 655 DTRACE_PROBE(rndrrs_fail); 656 curcpu()->ci_rndrrs_fail.ev_count++; 657 break; 658 } 659 rnd_add_data_sync(&rndrrs_source, &x, sizeof(x), 660 bpb*sizeof(x)); 661 nbits -= MIN(nbits, bpb*sizeof(x)); 662 } 663 curlwp_bindx(bound); 664 665 explicit_memset(&x, 0, sizeof x); 666 } 667 668 /* 669 * setup the RNDRRS entropy source 670 */ 671 static void 672 cpu_setup_rng(device_t dv, struct cpu_info *ci) 673 { 674 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 675 676 /* Verify that it is supported. */ 677 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_RNDR)) { 678 case ID_AA64ISAR0_EL1_RNDR_RNDRRS: 679 break; 680 default: 681 return; 682 } 683 684 /* Attach event counter for RNDRRS failure. */ 685 evcnt_attach_dynamic(&ci->ci_rndrrs_fail, EVCNT_TYPE_MISC, NULL, 686 ci->ci_cpuname, "rndrrs fail"); 687 688 /* 689 * On the primary CPU, attach random source -- this only 690 * happens once globally. 691 */ 692 if (!CPU_IS_PRIMARY(ci)) 693 return; 694 rndsource_setcb(&rndrrs_source, rndrrs_get, NULL); 695 rnd_attach_source(&rndrrs_source, "rndrrs", RND_TYPE_RNG, 696 RND_FLAG_DEFAULT|RND_FLAG_HASCB); 697 } 698 699 /* 700 * setup the AES implementation 701 */ 702 static void 703 cpu_setup_aes(device_t dv, struct cpu_info *ci) 704 { 705 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 706 707 /* Check for ARMv8.0-AES support. */ 708 switch (__SHIFTOUT(id->ac_aa64isar0, ID_AA64ISAR0_EL1_AES)) { 709 case ID_AA64ISAR0_EL1_AES_AES: 710 case ID_AA64ISAR0_EL1_AES_PMUL: 711 aes_md_init(&aes_armv8_impl); 712 return; 713 default: 714 break; 715 } 716 717 /* Failing that, check for SIMD support. */ 718 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { 719 case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: 720 aes_md_init(&aes_neon_impl); 721 return; 722 default: 723 break; 724 } 725 } 726 727 /* 728 * setup the ChaCha implementation 729 */ 730 static void 731 cpu_setup_chacha(device_t dv, struct cpu_info *ci) 732 { 733 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 734 735 /* Check for SIMD support. */ 736 switch (__SHIFTOUT(id->ac_aa64pfr0, ID_AA64PFR0_EL1_ADVSIMD)) { 737 case ID_AA64PFR0_EL1_ADV_SIMD_IMPL: 738 chacha_md_init(&chacha_neon_impl); 739 return; 740 default: 741 break; 742 } 743 } 744 745 #ifdef MULTIPROCESSOR 746 /* 747 * Initialise a secondary processor. 748 * 749 * printf isn't available as kmutex(9) relies on curcpu which isn't setup yet. 750 * 751 */ 752 void __noasan 753 cpu_init_secondary_processor(int cpuindex) 754 { 755 struct cpu_info * ci = &cpu_info_store[cpuindex]; 756 struct aarch64_sysctl_cpu_id *id = &ci->ci_id; 757 758 aarch64_setcpufuncs(ci); 759 760 /* Sets ci->ci_{sctlr,midr,mpidr}, etc */ 761 cpu_setup_id(ci); 762 763 arm_cpu_topology_set(ci, id->ac_mpidr); 764 aarch64_getcacheinfo(ci); 765 766 cpu_set_hatched(cpuindex); 767 768 /* 769 * return to assembly to wait for cpu_boot_secondary_processors 770 */ 771 } 772 773 774 /* 775 * When we are called, the MMU and caches are on and we are running on the stack 776 * of the idlelwp for this cpu. 777 */ 778 void 779 cpu_hatch(struct cpu_info *ci) 780 { 781 KASSERT(curcpu() == ci); 782 KASSERT((reg_tcr_el1_read() & TCR_EPD0) != 0); 783 784 #ifdef DDB 785 db_machdep_cpu_init(); 786 #endif 787 788 cpu_init_counter(ci); 789 790 intr_cpu_init(ci); 791 792 #ifdef FDT 793 arm_fdt_cpu_hatch(ci); 794 #endif 795 796 /* 797 * clear my bit of arm_cpu_mbox to tell cpu_boot_secondary_processors(). 798 * there are cpu0,1,2,3, and if cpu2 is unresponsive, 799 * ci_index are each cpu0=0, cpu1=1, cpu2=undef, cpu3=2. 800 * therefore we have to use device_unit instead of ci_index for mbox. 801 */ 802 803 cpu_clr_mbox(device_unit(ci->ci_dev)); 804 } 805 #endif /* MULTIPROCESSOR */ 806