xref: /freebsd/sys/powerpc/powerpc/machdep.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3  * Copyright (C) 1995, 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*
32  * Copyright (C) 2001 Benno Rice
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  *
44  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
45  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
49  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
50  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
52  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
53  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  *	$NetBSD: machdep.c,v 1.74.2.1 2000/11/01 16:13:48 tv Exp $
55  */
56 
57 #ifndef lint
58 static const char rcsid[] =
59   "$FreeBSD$";
60 #endif /* not lint */
61 
62 #include "opt_ddb.h"
63 #include "opt_compat.h"
64 #include "opt_msgbuf.h"
65 
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/eventhandler.h>
69 #include <sys/sysproto.h>
70 #include <sys/mutex.h>
71 #include <sys/ktr.h>
72 #include <sys/signalvar.h>
73 #include <sys/kernel.h>
74 #include <sys/proc.h>
75 #include <sys/lock.h>
76 #include <sys/malloc.h>
77 #include <sys/reboot.h>
78 #include <sys/bio.h>
79 #include <sys/buf.h>
80 #include <sys/bus.h>
81 #include <sys/mbuf.h>
82 #include <sys/vmmeter.h>
83 #include <sys/msgbuf.h>
84 #include <sys/exec.h>
85 #include <sys/sysctl.h>
86 #include <sys/uio.h>
87 #include <sys/linker.h>
88 #include <sys/cons.h>
89 #include <net/netisr.h>
90 #include <vm/vm.h>
91 #include <vm/vm_kern.h>
92 #include <vm/vm_page.h>
93 #include <vm/vm_map.h>
94 #include <vm/vm_extern.h>
95 #include <vm/vm_object.h>
96 #include <vm/vm_pager.h>
97 #include <sys/user.h>
98 #include <sys/ptrace.h>
99 #include <machine/bat.h>
100 #include <machine/clock.h>
101 #include <machine/md_var.h>
102 #include <machine/reg.h>
103 #include <machine/fpu.h>
104 #include <machine/globaldata.h>
105 #include <machine/vmparam.h>
106 #include <machine/elf.h>
107 #include <machine/trap.h>
108 #include <machine/powerpc.h>
109 #include <dev/ofw/openfirm.h>
110 #include <ddb/ddb.h>
111 #include <sys/vnode.h>
112 #include <fs/procfs/procfs.h>
113 #include <machine/sigframe.h>
114 
115 int cold = 1;
116 
117 struct mtx	sched_lock;
118 struct mtx	Giant;
119 
120 struct user	*proc0paddr;
121 
122 char		machine[] = "powerpc";
123 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
124 
125 static char	model[128];
126 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, "");
127 
128 char		bootpath[256];
129 
130 #ifdef DDB
131 /* start and end of kernel symbol table */
132 void		*ksym_start, *ksym_end;
133 #endif /* DDB */
134 
135 static void	cpu_startup(void *);
136 SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL)
137 
138 void		powerpc_init(u_int, u_int, u_int, char *);
139 
140 int		save_ofw_mapping(void);
141 int		restore_ofw_mapping(void);
142 
143 void		install_extint(void (*)(void));
144 
145 void		osendsig(sig_t, int, sigset_t *, u_long);
146 
147 struct msgbuf	*msgbufp = 0;
148 
149 int		bootverbose = 0, Maxmem = 0;
150 long		dumplo;
151 
152 vm_offset_t	phys_avail[10];
153 
154 static int	chosen;
155 
156 struct pmap	ofw_pmap;
157 extern int	ofmsr;
158 
159 struct bat	battable[16];
160 
161 static void	identifycpu(void);
162 
163 static vm_offset_t	buffer_sva, buffer_eva;
164 vm_offset_t		clean_sva, clean_eva;
165 static vm_offset_t	pager_sva, pager_eva;
166 
167 static void
168 powerpc_ofw_shutdown(void *junk, int howto)
169 {
170 	if (howto & RB_HALT) {
171 		OF_exit();
172 	}
173 }
174 
175 static void
176 cpu_startup(void *dummy)
177 {
178 	unsigned int	i;
179 	caddr_t		v;
180 	vm_offset_t	maxaddr;
181 	vm_size_t	size;
182 	vm_offset_t	firstaddr;
183 	vm_offset_t	minaddr;
184 
185 	size = 0;
186 
187 	/*
188 	 * Good {morning,afternoon,evening,night}.
189 	 */
190 	identifycpu();
191 
192 	/* startrtclock(); */
193 #ifdef PERFMON
194 	perfmon_init();
195 #endif
196 	printf("real memory  = %ld (%ldK bytes)\n", ptoa(Maxmem),
197 	    ptoa(Maxmem) / 1024);
198 
199 	/*
200 	 * Display any holes after the first chunk of extended memory.
201 	 */
202 	if (bootverbose) {
203 		int indx;
204 
205 		printf("Physical memory chunk(s):\n");
206 		for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) {
207 			int size1 = phys_avail[indx + 1] - phys_avail[indx];
208 
209 			printf("0x%08x - 0x%08x, %d bytes (%d pages)\n",
210 			    phys_avail[indx], phys_avail[indx + 1] - 1, size1,
211 			    size1 / PAGE_SIZE);
212 		}
213 	}
214 
215 	/*
216 	 * Calculate callout wheel size
217 	 */
218 	for (callwheelsize = 1, callwheelbits = 0;
219 	     callwheelsize < ncallout;
220 	     callwheelsize <<= 1, ++callwheelbits)
221 		;
222 	callwheelmask = callwheelsize - 1;
223 
224 	/*
225 	 * Allocate space for system data structures.
226 	 * The first available kernel virtual address is in "v".
227 	 * As pages of kernel virtual memory are allocated, "v" is incremented.
228 	 * As pages of memory are allocated and cleared,
229 	 * "firstaddr" is incremented.
230 	 * An index into the kernel page table corresponding to the
231 	 * virtual memory address maintained in "v" is kept in "mapaddr".
232 	 */
233 
234 	/*
235 	 * Make two passes.  The first pass calculates how much memory is
236 	 * needed and allocates it.  The second pass assigns virtual
237 	 * addresses to the various data structures.
238 	 */
239 	firstaddr = 0;
240 again:
241 	v = (caddr_t)firstaddr;
242 
243 #define	valloc(name, type, num) \
244 	    (name) = (type *)v; v = (caddr_t)((name)+(num))
245 #define	valloclim(name, type, num, lim) \
246 	    (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
247 
248 	valloc(callout, struct callout, ncallout);
249 	valloc(callwheel, struct callout_tailq, callwheelsize);
250 
251 	/*
252 	 * The nominal buffer size (and minimum KVA allocation) is BKVASIZE.
253 	 * For the first 64MB of ram nominally allocate sufficient buffers to
254 	 * cover 1/4 of our ram.  Beyond the first 64MB allocate additional
255 	 * buffers to cover 1/20 of our ram over 64MB.
256 	 */
257 
258 	if (nbuf == 0) {
259 		int factor;
260 
261 		factor = 4 * BKVASIZE / PAGE_SIZE;
262 		nbuf = 50;
263 		if (Maxmem > 1024)
264 			nbuf += min((Maxmem - 1024) / factor, 16384 / factor);
265 		if (Maxmem > 16384)
266 			nbuf += (Maxmem - 16384) * 2 / (factor * 5);
267 	}
268 	nswbuf = max(min(nbuf/4, 64), 16);
269 
270 	valloc(swbuf, struct buf, nswbuf);
271 	valloc(buf, struct buf, nbuf);
272 	v = bufhashinit(v);
273 
274 	/*
275 	 * End of first pass, size has been calculated so allocate memory
276 	 */
277 	if (firstaddr == 0) {
278 		size = (vm_size_t)(v - firstaddr);
279 		firstaddr = (vm_offset_t)kmem_alloc(kernel_map,
280 		    round_page(size));
281 		if (firstaddr == 0)
282 			panic("startup: no room for tables");
283 		goto again;
284 	}
285 
286 	/*
287 	 * End of second pass, addresses have been assigned
288 	 */
289 	if ((vm_size_t)(v - firstaddr) != size)
290 		panic("startup: table size inconsistency");
291 
292 	clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva,
293 	    (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size);
294 	buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva,
295 	    (nbuf*BKVASIZE));
296 	pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva,
297 	    (nswbuf*MAXPHYS) + pager_map_size);
298 	pager_map->system_map = 1;
299 	exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
300 	    (16*(ARG_MAX+(PAGE_SIZE*3))));
301 
302 	/*
303 	 * XXX: Mbuf system machine-specific initializations should
304 	 *      go here, if anywhere.
305 	 */
306 
307 	/*
308 	 * Initialize callouts
309 	 */
310 	SLIST_INIT(&callfree);
311 	for (i = 0; i < ncallout; i++) {
312 		callout_init(&callout[i], 0);
313 		callout[i].c_flags = CALLOUT_LOCAL_ALLOC;
314 		SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle);
315 	}
316 
317 	for (i = 0; i < callwheelsize; i++) {
318 		TAILQ_INIT(&callwheel[i]);
319 	}
320 
321 	mtx_init(&callout_lock, "callout", MTX_SPIN);
322 
323 #if defined(USERCONFIG)
324 #if defined(USERCONFIG_BOOT)
325 	if (1)
326 #else
327         if (boothowto & RB_CONFIG)
328 #endif
329 	{
330 		userconfig();
331 		cninit();	/* the preferred console may have changed */
332 	}
333 #endif
334 
335 	printf("avail memory = %ld (%ldK bytes)\n", ptoa(cnt.v_free_count),
336 	    ptoa(cnt.v_free_count) / 1024);
337 
338 	/*
339 	 * Set up buffers, so they can be used to read disk labels.
340 	 */
341 	bufinit();
342 	vm_pager_bufferinit();
343 	EVENTHANDLER_REGISTER(shutdown_final, powerpc_ofw_shutdown, 0,
344 	    SHUTDOWN_PRI_LAST);
345 
346 #ifdef SMP
347 	/*
348 	 * OK, enough kmem_alloc/malloc state should be up, lets get on with it!
349 	 */
350 	mp_start();			/* fire up the secondaries */
351 	mp_announce();
352 #endif  /* SMP */
353 }
354 
355 void
356 identifycpu()
357 {
358 	unsigned int pvr, version, revision;
359 
360 	/*
361 	 * Find cpu type (Do it by OpenFirmware?)
362 	 */
363 	__asm ("mfpvr %0" : "=r"(pvr));
364 	version = pvr >> 16;
365 	revision = pvr & 0xffff;
366 	switch (version) {
367 	case 0x0001:
368 		sprintf(model, "601");
369 		break;
370 	case 0x0003:
371 		sprintf(model, "603 (Wart)");
372 		break;
373 	case 0x0004:
374 		sprintf(model, "604 (Zephyr)");
375 		break;
376 	case 0x0005:
377 		sprintf(model, "602 (Galahad)");
378 		break;
379 	case 0x0006:
380 		sprintf(model, "603e (Stretch)");
381 		break;
382 	case 0x0007:
383 		if ((revision && 0xf000) == 0x0000)
384 			sprintf(model, "603ev (Valiant)");
385 		else
386 			sprintf(model, "603r (Goldeneye)");
387 		break;
388 	case 0x0008:
389 		if ((revision && 0xf000) == 0x0000)
390 			sprintf(model, "G3 / 750 (Arthur)");
391 		else
392 			sprintf(model, "G3 / 755 (Goldfinger)");
393 		break;
394 	case 0x0009:
395 		if ((revision && 0xf000) == 0x0000)
396 			sprintf(model, "604e (Sirocco)");
397 		else
398 			sprintf(model, "604r (Mach V)");
399 		break;
400 	case 0x000a:
401 		sprintf(model, "604r (Mach V)");
402 		break;
403 	case 0x000c:
404 		sprintf(model, "G4 / 7400 (Max)");
405 		break;
406 	case 0x0014:
407 		sprintf(model, "620 (Red October)");
408 		break;
409 	case 0x0081:
410 		sprintf(model, "8240 (Kahlua)");
411 		break;
412 	case 0x8000:
413 		sprintf(model, "G4 / 7450 (V'ger)");
414 		break;
415 	case 0x800c:
416 		sprintf(model, "G4 / 7410 (Nitro)");
417 		break;
418 	case 0x8081:
419 		sprintf(model, "8245 (Kahlua II)");
420 		break;
421 	default:
422 		sprintf(model, "Version %x", version);
423 		break;
424 	}
425 	sprintf(model + strlen(model), " (Revision %x)", revision);
426 	printf("CPU: PowerPC %s\n", model);
427 }
428 
429 extern char	kernel_text[], _end[];
430 
431 extern void	*trapcode, *trapsize;
432 extern void	*alitrap, *alisize;
433 extern void	*dsitrap, *dsisize;
434 extern void	*isitrap, *isisize;
435 extern void	*decrint, *decrsize;
436 extern void	*tlbimiss, *tlbimsize;
437 extern void	*tlbdlmiss, *tlbdlmsize;
438 extern void	*tlbdsmiss, *tlbdsmsize;
439 
440 #if 0 /* XXX: interrupt handler.  We'll get to this later */
441 extern void	ext_intr(void);
442 #endif
443 
444 #ifdef DDB
445 extern		ddblow, ddbsize;
446 #endif
447 #ifdef IPKDB
448 extern		ipkdblow, ipkdbsize;
449 #endif
450 
451 static struct globaldata	tmpglobal;
452 
453 void
454 powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, char *args)
455 {
456 	unsigned int		exc, scratch;
457 	struct mem_region	*allmem, *availmem, *mp;
458 	struct globaldata	*globalp;
459 
460 	/*
461 	 * Set up BAT0 to only map the lowest 256 MB area
462 	 */
463 	battable[0].batl = BATL(0x00000000, BAT_M, BAT_PP_RW);
464 	battable[0].batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs);
465 
466 	/*
467 	 * Map PCI memory space.
468 	 */
469 	battable[0x8].batl = BATL(0x80000000, BAT_I, BAT_PP_RW);
470 	battable[0x8].batu = BATU(0x80000000, BAT_BL_256M, BAT_Vs);
471 
472 	battable[0x9].batl = BATL(0x90000000, BAT_I, BAT_PP_RW);
473 	battable[0x9].batu = BATU(0x90000000, BAT_BL_256M, BAT_Vs);
474 
475 	battable[0xa].batl = BATL(0xa0000000, BAT_I, BAT_PP_RW);
476 	battable[0xa].batu = BATU(0xa0000000, BAT_BL_256M, BAT_Vs);
477 
478 	/*
479 	 * Map obio devices.
480 	 */
481 	battable[0xf].batl = BATL(0xf0000000, BAT_I, BAT_PP_RW);
482 	battable[0xf].batu = BATU(0xf0000000, BAT_BL_256M, BAT_Vs);
483 
484 	/*
485 	 * Now setup fixed bat registers
486 	 *
487 	 * Note that we still run in real mode, and the BAT
488 	 * registers were cleared above.
489 	 */
490 	/* BAT0 used for initial 256 MB segment */
491 	__asm __volatile ("mtibatl 0,%0; mtibatu 0,%1;"
492 		          "mtdbatl 0,%0; mtdbatu 0,%1;"
493 		          :: "r"(battable[0].batl), "r"(battable[0].batu));
494 	/*
495 	 * Set up battable to map all RAM regions.
496 	 * This is here because mem_regions() call needs bat0 set up.
497 	 */
498 	mem_regions(&allmem, &availmem);
499 	for (mp = allmem; mp->size; mp++) {
500 		vm_offset_t	pa = mp->start & 0xf0000000;
501 		vm_offset_t	end = mp->start + mp->size;
502 
503 		do {
504 			u_int n = pa >> 28;
505 
506 			battable[n].batl = BATL(pa, BAT_M, BAT_PP_RW);
507 			battable[n].batu = BATU(pa, BAT_BL_256M, BAT_Vs);
508 			pa += 0x10000000;
509 		} while (pa < end);
510 	}
511 
512 	chosen = OF_finddevice("/chosen");
513 	save_ofw_mapping();
514 
515 	proc0.p_addr = proc0paddr;
516 	bzero(proc0.p_addr, sizeof *proc0.p_addr);
517 
518 	LIST_INIT(&proc0.p_contested);
519 
520 /* XXX: NetBSDism I _think_.  Not sure yet. */
521 #if 0
522 	curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = kernel_pmap;
523 #endif
524 
525 	/*
526 	 * Initialise some mutexes.
527 	 */
528 	mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE);
529 	mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE);
530 	mtx_init(&proc0.p_mtx, "process lock", MTX_DEF);
531 
532 	/*
533 	 * Initialise console.
534 	 */
535 	cninit();
536 
537 	mtx_lock(&Giant);
538 
539 #ifdef	__notyet__		/* Needs some rethinking regarding real/virtual OFW */
540 	OF_set_callback(callback);
541 #endif
542 
543 	/*
544 	 * Set up trap vectors
545 	 */
546 	for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100) {
547 		switch (exc) {
548 		default:
549 			bcopy(&trapcode, (void *)exc, (size_t)&trapsize);
550 			break;
551 		case EXC_DECR:
552 			bcopy(&decrint, (void *)EXC_DECR, (size_t)&decrsize);
553 			break;
554 #if 0 /* XXX: Not enabling these traps yet. */
555 		case EXC_EXI:
556 			/*
557 			 * This one is (potentially) installed during autoconf
558 			 */
559 			break;
560 		case EXC_ALI:
561 			bcopy(&alitrap, (void *)EXC_ALI, (size_t)&alisize);
562 			break;
563 		case EXC_DSI:
564 			bcopy(&dsitrap, (void *)EXC_DSI, (size_t)&dsisize);
565 			break;
566 		case EXC_ISI:
567 			bcopy(&isitrap, (void *)EXC_ISI, (size_t)&isisize);
568 			break;
569 		case EXC_IMISS:
570 			bcopy(&tlbimiss, (void *)EXC_IMISS, (size_t)&tlbimsize);
571 			break;
572 		case EXC_DLMISS:
573 			bcopy(&tlbdlmiss, (void *)EXC_DLMISS, (size_t)&tlbdlmsize);
574 			break;
575 		case EXC_DSMISS:
576 			bcopy(&tlbdsmiss, (void *)EXC_DSMISS, (size_t)&tlbdsmsize);
577 			break;
578 #if defined(DDB) || defined(IPKDB)
579 		case EXC_TRC:
580 		case EXC_PGM:
581 		case EXC_BPT:
582 #if defined(DDB)
583 			bcopy(&ddblow, (void *)exc, (size_t)&ddbsize);
584 #else
585 			bcopy(&ipkdblow, (void *)exc, (size_t)&ipkdbsize);
586 #endif
587 			break;
588 #endif /* DDB || IPKDB */
589 #endif
590 		}
591 	}
592 
593 #if 0 /* XXX: coming soon... */
594 	/*
595 	 * external interrupt handler install
596 	 */
597 	install_extint(ext_intr);
598 #endif
599 
600 	__syncicache((void *)EXC_RST, EXC_LAST - EXC_RST + 0x100);
601 
602 	/*
603 	 * Now enable translation (and machine checks/recoverable interrupts).
604 	 */
605 	__asm ("mfmsr %0" : "=r"(scratch));
606 	scratch |= PSL_IR | PSL_DR | PSL_ME | PSL_RI;
607 	__asm ("mtmsr %0" :: "r"(scratch));
608 
609 	ofmsr &= ~PSL_IP;
610 
611 	/*
612 	 * Parse arg string.
613 	 */
614 #ifdef DDB
615 	bcopy(args + strlen(args) + 1, &startsym, sizeof(startsym));
616 	bcopy(args + strlen(args) + 5, &endsym, sizeof(endsym));
617 	if (startsym == NULL || endsym == NULL)
618 		startsym = endsym = NULL;
619 #endif
620 
621 	strcpy(bootpath, args);
622 	args = bootpath;
623 	while (*++args && *args != ' ');
624 	if (*args) {
625 		*args++ = 0;
626 		while (*args) {
627 			switch (*args++) {
628 			case 'a':
629 				boothowto |= RB_ASKNAME;
630 				break;
631 			case 's':
632 				boothowto |= RB_SINGLE;
633 				break;
634 			case 'd':
635 				boothowto |= RB_KDB;
636 				break;
637 			case 'v':
638 				boothowto |= RB_VERBOSE;
639 				break;
640 			}
641 		}
642 	}
643 
644 #ifdef DDB
645 	ddb_init((int)((u_int)endsym - (u_int)startsym), startsym, endsym);
646 #endif
647 #ifdef IPKDB
648 	/*
649 	 * Now trap to IPKDB
650 	 */
651 	ipkdb_init();
652 	if (boothowto & RB_KDB)
653 		ipkdb_connect(0);
654 #endif
655 
656 	/*
657 	 * Set the page size.
658 	 */
659 #if 0
660 	vm_set_page_size();
661 #endif
662 
663 	/*
664 	 * Initialize pmap module.
665 	 */
666 	pmap_bootstrap(startkernel, endkernel);
667 
668 	restore_ofw_mapping();
669 
670 	/*
671 	 * Setup the global data for the bootstrap cpu.
672 	 */
673 	globalp = (struct globaldata *) &tmpglobal;
674 
675 	/*
676 	 * XXX: Pass 0 as CPU id.  This is bad.  We need to work out
677 	 * XXX: which CPU we are somehow.
678 	 */
679 	globaldata_init(globalp, 0, sizeof(struct globaldata));
680 	__asm ("mtsprg 0, %0" :: "r"(globalp));
681 
682 	PCPU_GET(next_asn) = 1;	/* 0 used for proc0 pmap */
683 	PCPU_SET(curproc, &proc0);
684 	PCPU_SET(spinlocks, NULL);
685 }
686 
687 static int N_mapping;
688 static struct {
689 	vm_offset_t	va;
690 	int		len;
691 	vm_offset_t	pa;
692 	int		mode;
693 } ofw_mapping[256];
694 
695 int
696 save_ofw_mapping()
697 {
698 	int	mmui, mmu;
699 
700 	OF_getprop(chosen, "mmu", &mmui, 4);
701 	mmu = OF_instance_to_package(mmui);
702 
703 	bzero(ofw_mapping, sizeof(ofw_mapping));
704 
705 	N_mapping =
706 	    OF_getprop(mmu, "translations", ofw_mapping, sizeof(ofw_mapping));
707 	N_mapping /= sizeof(ofw_mapping[0]);
708 
709 	return 0;
710 }
711 
712 int
713 restore_ofw_mapping()
714 {
715 	int		i;
716 	struct vm_page	pg;
717 
718 	pmap_pinit(&ofw_pmap);
719 
720 	ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT;
721 
722 	for (i = 0; i < N_mapping; i++) {
723 		vm_offset_t	pa = ofw_mapping[i].pa;
724 		vm_offset_t	va = ofw_mapping[i].va;
725 		int		size = ofw_mapping[i].len;
726 
727 		if (va < 0x90000000)			/* XXX */
728 			continue;
729 
730 		while (size > 0) {
731 			pg.phys_addr = pa;
732 			pmap_enter(&ofw_pmap, va, &pg, VM_PROT_ALL,
733 			    VM_PROT_ALL);
734 			pa += PAGE_SIZE;
735 			va += PAGE_SIZE;
736 			size -= PAGE_SIZE;
737 		}
738 	}
739 
740 	return 0;
741 }
742 
743 void
744 bzero(void *buf, size_t len)
745 {
746 	caddr_t	p;
747 
748 	p = buf;
749 
750 	while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) {
751 		*p++ = 0;
752 		len--;
753 	}
754 
755 	while (len >= sizeof(u_long) * 8) {
756 		*(u_long*) p = 0;
757 		*((u_long*) p + 1) = 0;
758 		*((u_long*) p + 2) = 0;
759 		*((u_long*) p + 3) = 0;
760 		len -= sizeof(u_long) * 8;
761 		*((u_long*) p + 4) = 0;
762 		*((u_long*) p + 5) = 0;
763 		*((u_long*) p + 6) = 0;
764 		*((u_long*) p + 7) = 0;
765 		p += sizeof(u_long) * 8;
766 	}
767 
768 	while (len >= sizeof(u_long)) {
769 		*(u_long*) p = 0;
770 		len -= sizeof(u_long);
771 		p += sizeof(u_long);
772 	}
773 
774 	while (len) {
775 		*p++ = 0;
776 		len--;
777 	}
778 }
779 
780 #if 0
781 void
782 delay(unsigned n)
783 {
784 	u_long tb;
785 
786 	do {
787 		__asm __volatile("mftb %0" : "=r" (tb));
788 	} while (n > (int)(tb & 0xffffffff));
789 }
790 #endif
791 
792 void
793 osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
794 {
795 
796 	/* XXX: To be done */
797 	return;
798 }
799 
800 void
801 sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
802 {
803 
804 	/* XXX: To be done */
805 	return;
806 }
807 
808 int
809 osigreturn(struct proc *p, struct osigreturn_args *uap)
810 {
811 
812 	/* XXX: To be done */
813 	return(ENOSYS);
814 }
815 
816 int
817 sigreturn(struct proc *p, struct sigreturn_args *uap)
818 {
819 
820 	/* XXX: To be done */
821 	return(ENOSYS);
822 }
823 
824 void
825 cpu_boot(int howto)
826 {
827 }
828 
829 /*
830  * Shutdown the CPU as much as possible.
831  */
832 void
833 cpu_halt(void)
834 {
835 
836 	OF_exit();
837 }
838 
839 /*
840  * Set set up registers on exec.
841  */
842 void
843 setregs(struct proc *p, u_long entry, u_long stack, u_long ps_strings)
844 {
845 	struct trapframe	*tf;
846 	struct ps_strings	arginfo;
847 
848 	tf = trapframe(p);
849 
850 	bzero(tf, sizeof *tf);
851 	tf->fixreg[1] = -roundup(-stack + 8, 16);
852 
853 	/*
854 	 * XXX Machine-independent code has already copied arguments and
855 	 * XXX environment to userland.  Get them back here.
856 	 */
857 	(void)copyin((char *)PS_STRINGS, &arginfo, sizeof(arginfo));
858 
859 	/*
860 	 * Set up arguments for _start():
861 	 *	_start(argc, argv, envp, obj, cleanup, ps_strings);
862 	 *
863 	 * Notes:
864 	 *	- obj and cleanup are the auxilliary and termination
865 	 *	  vectors.  They are fixed up by ld.elf_so.
866 	 *	- ps_strings is a NetBSD extention, and will be
867 	 * 	  ignored by executables which are strictly
868 	 *	  compliant with the SVR4 ABI.
869 	 *
870 	 * XXX We have to set both regs and retval here due to different
871 	 * XXX calling convention in trap.c and init_main.c.
872 	 */
873 	tf->fixreg[3] = arginfo.ps_nargvstr;
874 	tf->fixreg[4] = (register_t)arginfo.ps_argvstr;
875 	tf->fixreg[5] = (register_t)arginfo.ps_envstr;
876 	tf->fixreg[6] = 0;			/* auxillary vector */
877 	tf->fixreg[7] = 0;			/* termination vector */
878 	tf->fixreg[8] = (register_t)PS_STRINGS;	/* NetBSD extension */
879 
880 	tf->srr0 = entry;
881 	tf->srr1 = PSL_MBO | PSL_USERSET | PSL_FE_DFLT;
882 	p->p_addr->u_pcb.pcb_flags = 0;
883 }
884 
885 extern void	*extint, *extsize;
886 extern u_long	extint_call;
887 
888 void
889 install_extint(void (*handler)(void))
890 {
891 	u_long	offset;
892 	int	omsr, msr;
893 
894 	offset = (u_long)handler - (u_long)&extint_call;
895 
896 #ifdef	DIAGNOSTIC
897 	if (offset > 0x1ffffff)
898 		panic("install_extint: too far away");
899 #endif
900 
901 	msr = mfmsr();
902 	mtmsr(msr & ~PSL_EE);
903 
904 	extint_call = (extint_call & 0xfc000003) | offset;
905 	bcopy(&extint, (void *)EXC_EXI, (size_t)&extsize);
906 	__syncicache((void *)&extint_call, sizeof extint_call);
907 	__syncicache((void *)EXC_EXI, (int)&extsize);
908 
909 	mtmsr(msr);
910 }
911 
912 #if !defined(DDB)
913 void
914 Debugger(const char *msg)
915 {
916 
917 	printf("Debugger(\"%s\") called.\n", msg);
918 }
919 #endif /* !defined(DDB) */
920 
921 /* XXX: dummy {fill,set}_[fp]regs */
922 int
923 fill_regs(struct proc *p, struct reg *regs)
924 {
925 
926 	return (ENOSYS);
927 }
928 
929 int
930 fill_fpregs(struct proc *p, struct fpreg *fpregs)
931 {
932 
933 	return (ENOSYS);
934 }
935 
936 int
937 set_regs(struct proc *p, struct reg *regs)
938 {
939 
940 	return (ENOSYS);
941 }
942 
943 int
944 set_fpregs(struct proc *p, struct fpreg *fpregs)
945 {
946 
947 	return (ENOSYS);
948 }
949 
950 int
951 ptrace_set_pc(struct proc *p, unsigned long addr)
952 {
953 
954 	/* XXX: coming soon... */
955 	return (ENOSYS);
956 }
957 
958 int
959 ptrace_single_step(struct proc *p)
960 {
961 
962 	/* XXX: coming soon... */
963 	return (ENOSYS);
964 }
965 
966 int
967 ptrace_write_u(struct proc *p, vm_offset_t off, long data)
968 {
969 
970 	/* XXX: coming soon... */
971 	return (ENOSYS);
972 }
973 
974 int
975 ptrace_read_u_check(struct proc *p, vm_offset_t addr, size_t len)
976 {
977 
978 	/* XXX: coming soon... */
979 	return (ENOSYS);
980 }
981 
982 int
983 ptrace_clear_single_step(struct proc *p)
984 {
985 
986 	/* XXX: coming soon... */
987 	return (ENOSYS);
988 }
989 
990 /*
991  * Initialise a struct globaldata.
992  */
993 void
994 globaldata_init(struct globaldata *globaldata, int cpuid, size_t sz)
995 {
996 
997         bzero(globaldata, sz);
998         globaldata->gd_cpuid = cpuid;
999         globaldata->gd_next_asn = 0;
1000         globaldata->gd_current_asngen = 1;
1001 }
1002