xref: /netbsd-src/sys/arch/arm/arm32/cpu.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: cpu.c,v 1.51 2003/06/23 11:01:06 martin Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Mark Brinicombe.
5  * Copyright (c) 1995 Brini.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by Brini.
19  * 4. The name of the company nor the name of the author may be used to
20  *    endorse or promote products derived from this software without specific
21  *    prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * RiscBSD kernel project
36  *
37  * cpu.c
38  *
39  * Probing and configuration for the master cpu
40  *
41  * Created      : 10/10/95
42  */
43 
44 #include "opt_armfpe.h"
45 #include "opt_multiprocessor.h"
46 
47 #include <sys/param.h>
48 
49 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.51 2003/06/23 11:01:06 martin Exp $");
50 
51 #include <sys/systm.h>
52 #include <sys/malloc.h>
53 #include <sys/device.h>
54 #include <sys/proc.h>
55 #include <sys/conf.h>
56 #include <uvm/uvm_extern.h>
57 #include <machine/cpu.h>
58 
59 #include <arm/cpuconf.h>
60 #include <arm/undefined.h>
61 
62 #ifdef ARMFPE
63 #include <machine/bootconfig.h> /* For boot args */
64 #include <arm/fpe-arm/armfpe.h>
65 #endif
66 
67 char cpu_model[256];
68 
69 /* Prototypes */
70 void identify_arm_cpu(struct device *dv, struct cpu_info *);
71 
72 /*
73  * Identify the master (boot) CPU
74  */
75 
76 void
77 cpu_attach(struct device *dv)
78 {
79 	int usearmfpe;
80 
81 	usearmfpe = 1;	/* when compiled in, its enabled by default */
82 
83 	curcpu()->ci_dev = dv;
84 
85 	evcnt_attach_dynamic(&curcpu()->ci_arm700bugcount, EVCNT_TYPE_MISC,
86 	    NULL, dv->dv_xname, "arm700swibug");
87 
88 	/* Get the cpu ID from coprocessor 15 */
89 
90 	curcpu()->ci_arm_cpuid = cpu_id();
91 	curcpu()->ci_arm_cputype = curcpu()->ci_arm_cpuid & CPU_ID_CPU_MASK;
92 	curcpu()->ci_arm_cpurev =
93 	    curcpu()->ci_arm_cpuid & CPU_ID_REVISION_MASK;
94 
95 	identify_arm_cpu(dv, curcpu());
96 
97 	if (curcpu()->ci_arm_cputype == CPU_ID_SA110 &&
98 	    curcpu()->ci_arm_cpurev < 3) {
99 		aprint_normal("%s: SA-110 with bugged STM^ instruction\n",
100 		       dv->dv_xname);
101 	}
102 
103 #ifdef CPU_ARM8
104 	if ((curcpu()->ci_arm_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
105 		int clock = arm8_clock_config(0, 0);
106 		char *fclk;
107 		aprint_normal("%s: ARM810 cp15=%02x", dv->dv_xname, clock);
108 		aprint_normal(" clock:%s", (clock & 1) ? " dynamic" : "");
109 		aprint_normal("%s", (clock & 2) ? " sync" : "");
110 		switch ((clock >> 2) & 3) {
111 		case 0:
112 			fclk = "bus clock";
113 			break;
114 		case 1:
115 			fclk = "ref clock";
116 			break;
117 		case 3:
118 			fclk = "pll";
119 			break;
120 		default:
121 			fclk = "illegal";
122 			break;
123 		}
124 		aprint_normal(" fclk source=%s\n", fclk);
125  	}
126 #endif
127 
128 #ifdef ARMFPE
129 	/*
130 	 * Ok now we test for an FPA
131 	 * At this point no floating point emulator has been installed.
132 	 * This means any FP instruction will cause undefined exception.
133 	 * We install a temporay coproc 1 handler which will modify
134 	 * undefined_test if it is called.
135 	 * We then try to read the FP status register. If undefined_test
136 	 * has been decremented then the instruction was not handled by
137 	 * an FPA so we know the FPA is missing. If undefined_test is
138 	 * still 1 then we know the instruction was handled by an FPA.
139 	 * We then remove our test handler and look at the
140 	 * FP status register for identification.
141 	 */
142 
143 	/*
144 	 * Ok if ARMFPE is defined and the boot options request the
145 	 * ARM FPE then it will be installed as the FPE.
146 	 * This is just while I work on integrating the new FPE.
147 	 * It means the new FPE gets installed if compiled int (ARMFPE
148 	 * defined) and also gives me a on/off option when I boot in
149 	 * case the new FPE is causing panics.
150 	 */
151 
152 
153 	if (boot_args)
154 		get_bootconf_option(boot_args, "armfpe",
155 		    BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
156 	if (usearmfpe)
157 		initialise_arm_fpe();
158 #endif
159 }
160 
161 enum cpu_class {
162 	CPU_CLASS_NONE,
163 	CPU_CLASS_ARM2,
164 	CPU_CLASS_ARM2AS,
165 	CPU_CLASS_ARM3,
166 	CPU_CLASS_ARM6,
167 	CPU_CLASS_ARM7,
168 	CPU_CLASS_ARM7TDMI,
169 	CPU_CLASS_ARM8,
170 	CPU_CLASS_ARM9TDMI,
171 	CPU_CLASS_ARM9ES,
172 	CPU_CLASS_SA1,
173 	CPU_CLASS_XSCALE,
174 	CPU_CLASS_ARM10E
175 };
176 
177 static const char * const generic_steppings[16] = {
178 	"rev 0",	"rev 1",	"rev 2",	"rev 3",
179 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
180 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
181 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
182 };
183 
184 static const char * const sa110_steppings[16] = {
185 	"rev 0",	"step J",	"step K",	"step S",
186 	"step T",	"rev 5",	"rev 6",	"rev 7",
187 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
188 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
189 };
190 
191 static const char * const sa1100_steppings[16] = {
192 	"rev 0",	"step B",	"step C",	"rev 3",
193 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
194 	"step D",	"step E",	"rev 10"	"step G",
195 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
196 };
197 
198 static const char * const sa1110_steppings[16] = {
199 	"step A-0",	"rev 1",	"rev 2",	"rev 3",
200 	"step B-0",	"step B-1",	"step B-2",	"step B-3",
201 	"step B-4",	"step B-5",	"rev 10",	"rev 11",
202 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
203 };
204 
205 static const char * const ixp12x0_steppings[16] = {
206 	"(IXP1200 step A)",		"(IXP1200 step B)",
207 	"rev 2",			"(IXP1200 step C)",
208 	"(IXP1200 step D)",		"(IXP1240/1250 step A)",
209 	"(IXP1240 step B)",		"(IXP1250 step B)",
210 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
211 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
212 };
213 
214 static const char * const xscale_steppings[16] = {
215 	"step A-0",	"step A-1",	"step B-0",	"step C-0",
216 	"step D-0",	"rev 5",	"rev 6",	"rev 7",
217 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
218 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
219 };
220 
221 static const char * const i80321_steppings[16] = {
222 	"step A-0",	"step B-0",	"rev 2",	"rev 3",
223 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
224 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
225 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
226 };
227 
228 static const char * const pxa2x0_steppings[16] = {
229 	"step A-0",	"step A-1",	"step B-0",	"step B-1",
230 	"step B-2",	"step C-0",	"rev 6",	"rev 7",
231 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
232 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
233 };
234 
235 static const char * const ixp425_steppings[16] = {
236 	"step 0",	"rev 1",	"rev 2",	"rev 3",
237 	"rev 4",	"rev 5",	"rev 6",	"rev 7",
238 	"rev 8",	"rev 9",	"rev 10",	"rev 11",
239 	"rev 12",	"rev 13",	"rev 14",	"rev 15",
240 };
241 
242 struct cpuidtab {
243 	u_int32_t	cpuid;
244 	enum		cpu_class cpu_class;
245 	const char	*cpu_name;
246 	const char * const *cpu_steppings;
247 };
248 
249 const struct cpuidtab cpuids[] = {
250 	{ CPU_ID_ARM2,		CPU_CLASS_ARM2,		"ARM2",
251 	  generic_steppings },
252 	{ CPU_ID_ARM250,	CPU_CLASS_ARM2AS,	"ARM250",
253 	  generic_steppings },
254 
255 	{ CPU_ID_ARM3,		CPU_CLASS_ARM3,		"ARM3",
256 	  generic_steppings },
257 
258 	{ CPU_ID_ARM600,	CPU_CLASS_ARM6,		"ARM600",
259 	  generic_steppings },
260 	{ CPU_ID_ARM610,	CPU_CLASS_ARM6,		"ARM610",
261 	  generic_steppings },
262 	{ CPU_ID_ARM620,	CPU_CLASS_ARM6,		"ARM620",
263 	  generic_steppings },
264 
265 	{ CPU_ID_ARM700,	CPU_CLASS_ARM7,		"ARM700",
266 	  generic_steppings },
267 	{ CPU_ID_ARM710,	CPU_CLASS_ARM7,		"ARM710",
268 	  generic_steppings },
269 	{ CPU_ID_ARM7500,	CPU_CLASS_ARM7,		"ARM7500",
270 	  generic_steppings },
271 	{ CPU_ID_ARM710A,	CPU_CLASS_ARM7,		"ARM710a",
272 	  generic_steppings },
273 	{ CPU_ID_ARM7500FE,	CPU_CLASS_ARM7,		"ARM7500FE",
274 	  generic_steppings },
275 	{ CPU_ID_ARM710T,	CPU_CLASS_ARM7TDMI,	"ARM710T",
276 	  generic_steppings },
277 	{ CPU_ID_ARM720T,	CPU_CLASS_ARM7TDMI,	"ARM720T",
278 	  generic_steppings },
279 	{ CPU_ID_ARM740T8K,	CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
280 	  generic_steppings },
281 	{ CPU_ID_ARM740T4K,	CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
282 	  generic_steppings },
283 
284 	{ CPU_ID_ARM810,	CPU_CLASS_ARM8,		"ARM810",
285 	  generic_steppings },
286 
287 	{ CPU_ID_ARM920T,	CPU_CLASS_ARM9TDMI,	"ARM920T",
288 	  generic_steppings },
289 	{ CPU_ID_ARM922T,	CPU_CLASS_ARM9TDMI,	"ARM922T",
290 	  generic_steppings },
291 	{ CPU_ID_ARM940T,	CPU_CLASS_ARM9TDMI,	"ARM940T",
292 	  generic_steppings },
293 	{ CPU_ID_ARM946ES,	CPU_CLASS_ARM9ES,	"ARM946E-S",
294 	  generic_steppings },
295 	{ CPU_ID_ARM966ES,	CPU_CLASS_ARM9ES,	"ARM966E-S",
296 	  generic_steppings },
297 	{ CPU_ID_ARM966ESR1,	CPU_CLASS_ARM9ES,	"ARM966E-S",
298 	  generic_steppings },
299 
300 	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
301 	  sa110_steppings },
302 	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
303 	  sa1100_steppings },
304 	{ CPU_ID_SA1110,	CPU_CLASS_SA1,		"SA-1110",
305 	  sa1110_steppings },
306 
307 	{ CPU_ID_IXP1200,	CPU_CLASS_SA1,		"IXP1200",
308 	  ixp12x0_steppings },
309 
310 	{ CPU_ID_80200,		CPU_CLASS_XSCALE,	"i80200",
311 	  xscale_steppings },
312 
313 	{ CPU_ID_80321_400,	CPU_CLASS_XSCALE,	"i80321 400MHz",
314 	  i80321_steppings },
315 	{ CPU_ID_80321_600,	CPU_CLASS_XSCALE,	"i80321 600MHz",
316 	  i80321_steppings },
317 	{ CPU_ID_80321_400_B0,	CPU_CLASS_XSCALE,	"i80321 400MHz",
318 	  i80321_steppings },
319 	{ CPU_ID_80321_600_B0,	CPU_CLASS_XSCALE,	"i80321 600MHz",
320 	  i80321_steppings },
321 
322 	{ CPU_ID_PXA250A,	CPU_CLASS_XSCALE,	"PXA250",
323 	  pxa2x0_steppings },
324 	{ CPU_ID_PXA210A,	CPU_CLASS_XSCALE,	"PXA210",
325 	  pxa2x0_steppings },
326 	{ CPU_ID_PXA250B,	CPU_CLASS_XSCALE,	"PXA250",
327 	  pxa2x0_steppings },
328 	{ CPU_ID_PXA210B,	CPU_CLASS_XSCALE,	"PXA210",
329 	  pxa2x0_steppings },
330 	{ CPU_ID_PXA250C, 	CPU_CLASS_XSCALE,	"PXA250",
331 	  pxa2x0_steppings },
332 	{ CPU_ID_PXA210C, 	CPU_CLASS_XSCALE,	"PXA210",
333 	  pxa2x0_steppings },
334 
335 	{ CPU_ID_IXP425_533,	CPU_CLASS_XSCALE,	"IXP425 533MHz",
336 	  ixp425_steppings },
337 	{ CPU_ID_IXP425_400,	CPU_CLASS_XSCALE,	"IXP425 400MHz",
338 	  ixp425_steppings },
339 	{ CPU_ID_IXP425_266,	CPU_CLASS_XSCALE,	"IXP425 266MHz",
340 	  ixp425_steppings },
341 
342 	{ CPU_ID_ARM1022ES,	CPU_CLASS_ARM10E,	"ARM1022ES",
343 	  generic_steppings },
344 
345 	{ 0, CPU_CLASS_NONE, NULL, NULL }
346 };
347 
348 struct cpu_classtab {
349 	const char	*class_name;
350 	const char	*class_option;
351 };
352 
353 const struct cpu_classtab cpu_classes[] = {
354 	{ "unknown",	NULL },			/* CPU_CLASS_NONE */
355 	{ "ARM2",	"CPU_ARM2" },		/* CPU_CLASS_ARM2 */
356 	{ "ARM2as",	"CPU_ARM250" },		/* CPU_CLASS_ARM2AS */
357 	{ "ARM3",	"CPU_ARM3" },		/* CPU_CLASS_ARM3 */
358 	{ "ARM6",	"CPU_ARM6" },		/* CPU_CLASS_ARM6 */
359 	{ "ARM7",	"CPU_ARM7" },		/* CPU_CLASS_ARM7 */
360 	{ "ARM7TDMI",	"CPU_ARM7TDMI" },	/* CPU_CLASS_ARM7TDMI */
361 	{ "ARM8",	"CPU_ARM8" },		/* CPU_CLASS_ARM8 */
362 	{ "ARM9TDMI",	NULL },			/* CPU_CLASS_ARM9TDMI */
363 	{ "ARM9E-S",	NULL },			/* CPU_CLASS_ARM9ES */
364 	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
365 	{ "XScale",	"CPU_XSCALE_..." },	/* CPU_CLASS_XSCALE */
366 	{ "ARM10E",	NULL },			/* CPU_CLASS_ARM10E */
367 };
368 
369 /*
370  * Report the type of the specified arm processor. This uses the generic and
371  * arm specific information in the cpu structure to identify the processor.
372  * The remaining fields in the cpu structure are filled in appropriately.
373  */
374 
375 static const char * const wtnames[] = {
376 	"write-through",
377 	"write-back",
378 	"write-back",
379 	"**unknown 3**",
380 	"**unknown 4**",
381 	"write-back-locking",		/* XXX XScale-specific? */
382 	"write-back-locking-A",
383 	"write-back-locking-B",
384 	"**unknown 8**",
385 	"**unknown 9**",
386 	"**unknown 10**",
387 	"**unknown 11**",
388 	"**unknown 12**",
389 	"**unknown 13**",
390 	"**unknown 14**",
391 	"**unknown 15**",
392 };
393 
394 void
395 identify_arm_cpu(struct device *dv, struct cpu_info *ci)
396 {
397 	u_int cpuid;
398 	enum cpu_class cpu_class;
399 	int i;
400 
401 	cpuid = ci->ci_arm_cpuid;
402 
403 	if (cpuid == 0) {
404 		aprint_error("Processor failed probe - no CPU ID\n");
405 		return;
406 	}
407 
408 	for (i = 0; cpuids[i].cpuid != 0; i++)
409 		if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
410 			cpu_class = cpuids[i].cpu_class;
411 			sprintf(cpu_model, "%s %s (%s core)",
412 			    cpuids[i].cpu_name,
413 			    cpuids[i].cpu_steppings[cpuid &
414 						    CPU_ID_REVISION_MASK],
415 			    cpu_classes[cpu_class].class_name);
416 			break;
417 		}
418 
419 	if (cpuids[i].cpuid == 0)
420 		sprintf(cpu_model, "unknown CPU (ID = 0x%x)", cpuid);
421 
422 	aprint_naive(": %s\n", cpu_model);
423 	aprint_normal(": %s\n", cpu_model);
424 
425 	aprint_normal("%s:", dv->dv_xname);
426 
427 	switch (cpu_class) {
428 	case CPU_CLASS_ARM6:
429 	case CPU_CLASS_ARM7:
430 	case CPU_CLASS_ARM7TDMI:
431 	case CPU_CLASS_ARM8:
432 		if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
433 			aprint_normal(" IDC disabled");
434 		else
435 			aprint_normal(" IDC enabled");
436 		break;
437 	case CPU_CLASS_ARM9TDMI:
438 	case CPU_CLASS_SA1:
439 	case CPU_CLASS_XSCALE:
440 		if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
441 			aprint_normal(" DC disabled");
442 		else
443 			aprint_normal(" DC enabled");
444 		if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
445 			aprint_normal(" IC disabled");
446 		else
447 			aprint_normal(" IC enabled");
448 		break;
449 	default:
450 		break;
451 	}
452 	if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
453 		aprint_normal(" WB disabled");
454 	else
455 		aprint_normal(" WB enabled");
456 
457 	if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
458 		aprint_normal(" LABT");
459 	else
460 		aprint_normal(" EABT");
461 
462 	if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
463 		aprint_normal(" branch prediction enabled");
464 
465 	aprint_normal("\n");
466 
467 	/* Print cache info. */
468 	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
469 		goto skip_pcache;
470 
471 	if (arm_pcache_unified) {
472 		aprint_normal("%s: %dKB/%dB %d-way %s unified cache\n",
473 		    dv->dv_xname, arm_pdcache_size / 1024,
474 		    arm_pdcache_line_size, arm_pdcache_ways,
475 		    wtnames[arm_pcache_type]);
476 	} else {
477 		aprint_normal("%s: %dKB/%dB %d-way Instruction cache\n",
478 		    dv->dv_xname, arm_picache_size / 1024,
479 		    arm_picache_line_size, arm_picache_ways);
480 		aprint_normal("%s: %dKB/%dB %d-way %s Data cache\n",
481 		    dv->dv_xname, arm_pdcache_size / 1024,
482 		    arm_pdcache_line_size, arm_pdcache_ways,
483 		    wtnames[arm_pcache_type]);
484 	}
485 
486  skip_pcache:
487 
488 	switch (cpu_class) {
489 #ifdef CPU_ARM2
490 	case CPU_CLASS_ARM2:
491 #endif
492 #ifdef CPU_ARM250
493 	case CPU_CLASS_ARM2AS:
494 #endif
495 #ifdef CPU_ARM3
496 	case CPU_CLASS_ARM3:
497 #endif
498 #ifdef CPU_ARM6
499 	case CPU_CLASS_ARM6:
500 #endif
501 #ifdef CPU_ARM7
502 	case CPU_CLASS_ARM7:
503 #endif
504 #ifdef CPU_ARM7TDMI
505 	case CPU_CLASS_ARM7TDMI:
506 #endif
507 #ifdef CPU_ARM8
508 	case CPU_CLASS_ARM8:
509 #endif
510 #ifdef CPU_ARM9
511 	case CPU_CLASS_ARM9TDMI:
512 #endif
513 #if defined(CPU_SA110) || defined(CPU_SA1100) || \
514     defined(CPU_SA1110) || defined(CPU_IXP12X0)
515 	case CPU_CLASS_SA1:
516 #endif
517 #if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
518     defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
519 	case CPU_CLASS_XSCALE:
520 #endif
521 		break;
522 	default:
523 		if (cpu_classes[cpu_class].class_option != NULL)
524 			aprint_error("%s: %s does not fully support this CPU."
525 			       "\n", dv->dv_xname, ostype);
526 		else {
527 			aprint_error("%s: This kernel does not fully support "
528 			       "this CPU.\n", dv->dv_xname);
529 			aprint_normal("%s: Recompile with \"options %s\" to "
530 			       "correct this.\n", dv->dv_xname,
531 			       cpu_classes[cpu_class].class_option);
532 		}
533 		break;
534 	}
535 
536 }
537 #ifdef MULTIPROCESSOR
538 int
539 cpu_alloc_idlepcb(struct cpu_info *ci)
540 {
541 	vaddr_t uaddr;
542 	struct pcb *pcb;
543 	struct trapframe *tf;
544 	int error;
545 
546 	/*
547 	 * Generate a kernel stack and PCB (in essence, a u-area) for the
548 	 * new CPU.
549 	 */
550 	if (uvm_uarea_alloc(&uaddr)) {
551 		error = uvm_fault_wire(kernel_map, uaddr, uaddr + USPACE,
552 		    VM_FAULT_WIRE, VM_PROT_READ | VM_PROT_WRITE);
553 		if (error)
554 			return error;
555 	}
556 	ci->ci_idlepcb = pcb = (struct pcb *)uaddr;
557 
558 	/*
559 	 * This code is largely derived from cpu_fork(), with which it
560 	 * should perhaps be shared.
561 	 */
562 
563 	/* Copy the pcb */
564 	*pcb = proc0.p_addr->u_pcb;
565 
566 	/* Set up the undefined stack for the process. */
567 	pcb->pcb_un.un_32.pcb32_und_sp = uaddr + USPACE_UNDEF_STACK_TOP;
568 	pcb->pcb_un.un_32.pcb32_sp = uaddr + USPACE_SVC_STACK_TOP;
569 
570 #ifdef STACKCHECKS
571 	/* Fill the undefined stack with a known pattern */
572 	memset(((u_char *)uaddr) + USPACE_UNDEF_STACK_BOTTOM, 0xdd,
573 	    (USPACE_UNDEF_STACK_TOP - USPACE_UNDEF_STACK_BOTTOM));
574 	/* Fill the kernel stack with a known pattern */
575 	memset(((u_char *)uaddr) + USPACE_SVC_STACK_BOTTOM, 0xdd,
576 	    (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM));
577 #endif	/* STACKCHECKS */
578 
579 	pcb->pcb_tf = tf =
580 	    (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
581 	*tf = *proc0.p_addr->u_pcb.pcb_tf;
582 	return 0;
583 }
584 #endif /* MULTIPROCESSOR */
585 
586 /* End of cpu.c */
587