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