xref: /netbsd/sys/arch/ofppc/ofppc/machdep.c (revision bf9ec67e)
1 /*	$NetBSD: machdep.c,v 1.75 2002/05/13 07:12:21 matt Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
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 TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "opt_compat_netbsd.h"
35 #include "opt_ddb.h"
36 
37 #include <sys/param.h>
38 #include <sys/buf.h>
39 #include <sys/exec.h>
40 #include <sys/malloc.h>
41 #include <sys/map.h>
42 #include <sys/mbuf.h>
43 #include <sys/mount.h>
44 #include <sys/msgbuf.h>
45 #include <sys/proc.h>
46 #include <sys/reboot.h>
47 #include <sys/syscallargs.h>
48 #include <sys/syslog.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/user.h>
52 #include <sys/boot_flag.h>
53 
54 #include <uvm/uvm_extern.h>
55 
56 #include <net/netisr.h>
57 
58 #include <machine/db_machdep.h>
59 #include <ddb/db_extern.h>
60 
61 #include <dev/ofw/openfirm.h>
62 
63 #include <machine/autoconf.h>
64 #include <machine/bat.h>
65 #include <machine/pmap.h>
66 #include <machine/powerpc.h>
67 #include <machine/trap.h>
68 
69 #include <machine/platform.h>
70 
71 #include <dev/cons.h>
72 
73 /*
74  * Global variables used here and there
75  */
76 struct vm_map *exec_map = NULL;
77 struct vm_map *mb_map = NULL;
78 struct vm_map *phys_map = NULL;
79 
80 struct pcb *curpcb;
81 struct pmap *curpm;
82 struct proc *fpuproc;
83 
84 extern struct user *proc0paddr;
85 
86 struct bat battable[16];
87 
88 char *bootpath;
89 
90 paddr_t msgbuf_paddr;
91 vaddr_t msgbuf_vaddr;
92 
93 int	lcsplx(int);			/* called from locore.S */
94 
95 static int fake_spl __P((int));
96 static void fake_splx __P((int));
97 static void fake_setsoft __P((int));
98 static void fake_clock_return __P((struct clockframe *, int));
99 static void *fake_intr_establish __P((int, int, int, int (*)(void *), void *));
100 static void fake_intr_disestablish __P((void *));
101 
102 struct machvec machine_interface = {
103 	fake_spl,
104 	fake_spl,
105 	fake_splx,
106 	fake_setsoft,
107 	fake_clock_return,
108 	fake_intr_establish,
109 	fake_intr_disestablish,
110 };
111 
112 void	ofppc_bootstrap_console(void);
113 
114 void
115 initppc(startkernel, endkernel, args)
116 	u_int startkernel, endkernel;
117 	char *args;
118 {
119 	extern int trapcode, trapsize;
120 	extern int alitrap, alisize;
121 	extern int dsitrap, dsisize;
122 	extern int isitrap, isisize;
123 	extern int decrint, decrsize;
124 	extern int tlbimiss, tlbimsize;
125 	extern int tlbdlmiss, tlbdlmsize;
126 	extern int tlbdsmiss, tlbdsmsize;
127 #ifdef DDB
128 	extern int ddblow, ddbsize;
129 	extern void *startsym, *endsym;
130 #endif
131 #ifdef IPKDB
132 	extern int ipkdblow, ipkdbsize;
133 #endif
134 	int exc, scratch;
135 
136 	/* Initialize the bootstrap console. */
137 	ofppc_bootstrap_console();
138 
139 	/*
140 	 * Initialize BAT registers to unmapped to not generate
141 	 * overlapping mappings below.
142 	 */
143 	asm volatile ("mtibatu 0,%0" :: "r"(0));
144 	asm volatile ("mtibatu 1,%0" :: "r"(0));
145 	asm volatile ("mtibatu 2,%0" :: "r"(0));
146 	asm volatile ("mtibatu 3,%0" :: "r"(0));
147 	asm volatile ("mtdbatu 0,%0" :: "r"(0));
148 	asm volatile ("mtdbatu 1,%0" :: "r"(0));
149 	asm volatile ("mtdbatu 2,%0" :: "r"(0));
150 	asm volatile ("mtdbatu 3,%0" :: "r"(0));
151 
152 	/*
153 	 * Set up initial BAT table to only map the lowest 256 MB area
154 	 */
155 	battable[0].batl = BATL(0x00000000, BAT_M, BAT_PP_RW);
156 	battable[0].batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs);
157 
158 	/*
159 	 * Now setup fixed bat registers
160 	 *
161 	 * Note that we still run in real mode, and the BAT
162 	 * registers were cleared above.
163 	 */
164 	/* IBAT0 used for initial 256 MB segment */
165 	asm volatile ("mtibatl 0,%0; mtibatu 0,%1"
166 		      :: "r"(battable[0].batl), "r"(battable[0].batu));
167 	/* DBAT0 used similar */
168 	asm volatile ("mtdbatl 0,%0; mtdbatu 0,%1"
169 		      :: "r"(battable[0].batl), "r"(battable[0].batu));
170 
171 	/*
172 	 * Initialize the platform structure.  This may add entries
173 	 * to the BAT table.
174 	 */
175 	platform_init();
176 
177 	proc0.p_addr = proc0paddr;
178 	memset(proc0.p_addr, 0, sizeof *proc0.p_addr);
179 
180 	curpcb = &proc0paddr->u_pcb;
181 
182 	curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = pmap_kernel();
183 
184 #ifdef __notyet__	/* Needs some rethinking regarding real/virtual OFW */
185 	OF_set_callback(callback);
186 #endif
187 
188 	/*
189 	 * Set up trap vectors
190 	 */
191 	for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100)
192 		switch (exc) {
193 		default:
194 			memcpy((void *)exc, &trapcode, (size_t)&trapsize);
195 			break;
196 		case EXC_EXI:
197 			/*
198 			 * This one is (potentially) installed during autoconf
199 			 */
200 			break;
201 		case EXC_ALI:
202 			memcpy((void *)EXC_ALI, &alitrap, (size_t)&alisize);
203 			break;
204 		case EXC_DSI:
205 			memcpy((void *)EXC_DSI, &dsitrap, (size_t)&dsisize);
206 			break;
207 		case EXC_ISI:
208 			memcpy((void *)EXC_ISI, &isitrap, (size_t)&isisize);
209 			break;
210 		case EXC_DECR:
211 			memcpy((void *)EXC_DECR, &decrint, (size_t)&decrsize);
212 			break;
213 		case EXC_IMISS:
214 			memcpy((void *)EXC_IMISS, &tlbimiss, (size_t)&tlbimsize);
215 			break;
216 		case EXC_DLMISS:
217 			memcpy((void *)EXC_DLMISS, &tlbdlmiss, (size_t)&tlbdlmsize);
218 			break;
219 		case EXC_DSMISS:
220 			memcpy((void *)EXC_DSMISS, &tlbdsmiss, (size_t)&tlbdsmsize);
221 			break;
222 #if defined(DDB) || defined(IPKDB)
223 		case EXC_PGM:
224 		case EXC_TRC:
225 		case EXC_BPT:
226 #if defined(DDB)
227 			memcpy((void *)exc, &ddblow, (size_t)&ddbsize);
228 #else
229 			memcpy((void *)exc, &ipkdblow, (size_t)&ipkdbsize);
230 #endif
231 			break;
232 #endif /* DDB || IPKDB */
233 		}
234 
235 	__syncicache((void *)EXC_RST, EXC_LAST - EXC_RST + 0x100);
236 
237 	/*
238 	 * Now enable translation (and machine checks/recoverable interrupts).
239 	 */
240 	asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0; isync"
241 		      : "=r"(scratch) : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));
242 
243 	/*
244 	 * Now that translation is enabled (and we can access bus space),
245 	 * initialize the console.
246 	 */
247 	(*platform.cons_init)();
248 
249 	/*
250 	 * Parse arg string.
251 	 */
252 	bootpath = args;
253 	while (*++args && *args != ' ');
254 	if (*args) {
255 		for(*args++ = 0; *args; args++)
256 			BOOT_FLAG(*args, boothowto);
257 	}
258 
259 	/*
260 	 * Set the page size.
261 	 */
262 	uvm_setpagesize();
263 
264 	/*
265 	 * Initialize pmap module.
266 	 */
267 	pmap_bootstrap(startkernel, endkernel, NULL);
268 
269 #ifdef DDB
270 	ddb_init((int)((u_int)endsym - (u_int)startsym), startsym, endsym);
271 	if (boothowto & RB_KDB)
272 		Debugger();
273 #endif
274 #ifdef IPKDB
275 	/*
276 	 * Now trap to IPKDB
277 	 */
278 	ipkdb_init();
279 	if (boothowto & RB_KDB)
280 		ipkdb_connect(0);
281 #endif
282 }
283 
284 /*
285  * This should probably be in autoconf!				XXX
286  */
287 char machine[] = MACHINE;		/* from <machine/param.h> */
288 char machine_arch[] = MACHINE_ARCH;	/* from <machine/param.h> */
289 
290 void
291 install_extint(handler)
292 	void (*handler) __P((void));
293 {
294 	extern int extint, extsize;
295 	extern u_long extint_call;
296 	u_long offset = (u_long)handler - (u_long)&extint_call;
297 	int omsr, msr;
298 
299 #ifdef	DIAGNOSTIC
300 	if (offset > 0x1ffffff)
301 		panic("install_extint: too far away");
302 #endif
303 	asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
304 		      : "=r"(omsr), "=r"(msr) : "K"((u_short)~PSL_EE));
305 	extint_call = (extint_call & 0xfc000003) | offset;
306 	memcpy((void *)EXC_EXI, &extint, (size_t)&extsize);
307 	__syncicache((void *)&extint_call, sizeof extint_call);
308 	__syncicache((void *)EXC_EXI, (int)&extsize);
309 	asm volatile ("mtmsr %0" :: "r"(omsr));
310 }
311 
312 /*
313  * Machine dependent startup code.
314  */
315 void
316 cpu_startup()
317 {
318 	int sz, i;
319 	caddr_t v;
320 	paddr_t minaddr, maxaddr;
321 	int base, residual;
322 	char pbuf[9];
323 
324 	proc0.p_addr = proc0paddr;
325 	v = (caddr_t)proc0paddr + USPACE;
326 
327 	/*
328 	 * Initialize error message buffer (at end of core).
329 	 */
330 	if (!(msgbuf_vaddr = uvm_km_alloc(kernel_map, round_page(MSGBUFSIZE))))
331 		panic("startup: no room for message buffer");
332 	for (i = 0; i < btoc(MSGBUFSIZE); i++)
333 		pmap_enter(pmap_kernel(), msgbuf_vaddr + i * NBPG,
334 		    msgbuf_paddr + i * NBPG, VM_PROT_READ|VM_PROT_WRITE,
335 		    VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
336 	pmap_update(pmap_kernel());
337 	initmsgbuf((caddr_t)msgbuf_vaddr, round_page(MSGBUFSIZE));
338 
339 	printf("%s", version);
340 	cpu_identify(NULL, 0);
341 
342 	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
343 	printf("total memory = %s\n", pbuf);
344 
345 	/*
346 	 * Find out how much space we need, allocate it,
347 	 * and then give everything true virtual addresses.
348 	 */
349 	sz = (int)allocsys(NULL, NULL);
350 	if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0)
351 		panic("startup: no room for tables");
352 	if (allocsys(v, NULL) - v != sz)
353 		panic("startup: table size inconsistency");
354 
355 	/*
356 	 * Now allocate buffers proper.  They are different than the above
357 	 * in that they usually occupy more virtual memory than physical.
358 	 */
359 	sz = MAXBSIZE * nbuf;
360 	if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(sz),
361 		    NULL, UVM_UNKNOWN_OFFSET, 0,
362 		    UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
363 				UVM_ADV_NORMAL, 0)) != 0)
364 		panic("startup: cannot allocate VM for buffers");
365 	minaddr = (vaddr_t)buffers;
366 	base = bufpages / nbuf;
367 	residual = bufpages % nbuf;
368 	if (base >= MAXBSIZE) {
369 		/* Don't want to alloc more physical mem than ever needed */
370 		base = MAXBSIZE;
371 		residual = 0;
372 	}
373 	for (i = 0; i < nbuf; i++) {
374 		vsize_t curbufsize;
375 		vaddr_t curbuf;
376 		struct vm_page *pg;
377 
378 		/*
379 		 * Each buffer has MAXBSIZE bytes of VM space allocated.  Of
380 		 * that MAXBSIZE space, we allocate and map (base+1) pages
381 		 * for the first "residual" buffers, and then we allocate
382 		 * "base" pages for the rest.
383 		 */
384 		curbuf = (vaddr_t) buffers + (i * MAXBSIZE);
385 		curbufsize = NBPG * ((i < residual) ? (base+1) : base);
386 
387 		while (curbufsize) {
388 			pg = uvm_pagealloc(NULL, 0, NULL, 0);
389 			if (pg == NULL)
390 				panic("startup: not enough memory for "
391 					"buffer cache");
392 			pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
393 			    VM_PROT_READ | VM_PROT_WRITE);
394 			curbuf += PAGE_SIZE;
395 			curbufsize -= PAGE_SIZE;
396 		}
397 	}
398 	pmap_update(kernel_map->pmap);
399 
400 	/*
401 	 * Allocate a submap for exec arguments.  This map effectively
402 	 * limits the number of processes exec'ing at any time.
403 	 */
404 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
405 				 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
406 
407 	/*
408 	 * Allocate a submap for physio
409 	 */
410 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
411 				 VM_PHYS_SIZE, 0, FALSE, NULL);
412 
413 	/*
414 	 * No need to allocate an mbuf cluster submap.  Mbuf clusters
415 	 * are allocated via the pool allocator, and we use direct-mapped
416 	 * pool pages.
417 	 */
418 
419 	format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
420 	printf("avail memory = %s\n", pbuf);
421 	format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG);
422 	printf("using %d buffers containing %s of memory\n", nbuf, pbuf);
423 
424 	/*
425 	 * Set up the buffers.
426 	 */
427 	bufinit();
428 
429 	/*
430 	 * Now allow hardware interrupts.
431 	 */
432 	{
433 		int msr;
434 
435 		splhigh();
436 		asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
437 			      : "=r"(msr) : "K"((u_short)(PSL_EE|PSL_RI)));
438 	}
439 }
440 
441 void
442 consinit()
443 {
444 
445 	/* Nothing to do; console is already initialized. */
446 }
447 
448 int	ofppc_cngetc(dev_t);
449 void	ofppc_cnputc(dev_t, int);
450 
451 struct consdev ofppc_bootcons = {
452 	NULL, NULL, ofppc_cngetc, ofppc_cnputc, nullcnpollc, NULL,
453 	    makedev(0,0), 1,
454 };
455 
456 int	ofppc_stdin_ihandle, ofppc_stdout_ihandle;
457 int	ofppc_stdin_phandle, ofppc_stdout_phandle;
458 
459 void
460 ofppc_bootstrap_console(void)
461 {
462 	int chosen;
463 	char data[4];
464 
465 	chosen = OF_finddevice("/chosen");
466 
467 	if (OF_getprop(chosen, "stdin", data, sizeof(data)) != sizeof(int))
468 		goto nocons;
469 	ofppc_stdin_ihandle = of_decode_int(data);
470 	ofppc_stdin_phandle = OF_instance_to_package(ofppc_stdin_ihandle);
471 
472 	if (OF_getprop(chosen, "stdout", data, sizeof(data)) != sizeof(int))
473 		goto nocons;
474 	ofppc_stdout_ihandle = of_decode_int(data);
475 	ofppc_stdout_phandle = OF_instance_to_package(ofppc_stdout_ihandle);
476 
477 	cn_tab = &ofppc_bootcons;
478 
479  nocons:
480 	return;
481 }
482 
483 int
484 ofppc_cngetc(dev_t dev)
485 {
486 	u_char ch = '\0';
487 	int l;
488 
489 	while ((l = OF_read(ofppc_stdin_ihandle, &ch, 1)) != 1)
490 		if (l != -2 && l != 0)
491 			return (-1);
492 
493 	return (ch);
494 }
495 
496 void
497 ofppc_cnputc(dev_t dev, int c)
498 {
499 	char ch = c;
500 
501 	OF_write(ofppc_stdout_ihandle, &ch, 1);
502 }
503 
504 /*
505  * Crash dump handling.
506  */
507 
508 void
509 dumpsys()
510 {
511 	printf("dumpsys: TBD\n");
512 }
513 
514 /*
515  * Soft networking interrupts.
516  */
517 void
518 softnet()
519 {
520 	int isr = netisr;
521 
522 	netisr = 0;
523 
524 #define DONETISR(bit, fn) do {		\
525 	if (isr & (1 << bit))		\
526 		fn();			\
527 } while (0)
528 
529 #include <net/netisr_dispatch.h>
530 
531 #undef DONETISR
532 }
533 
534 /*
535  * Stray interrupts.
536  */
537 void
538 strayintr(irq)
539 	int irq;
540 {
541 	log(LOG_ERR, "stray interrupt %d\n", irq);
542 }
543 
544 /*
545  * Halt or reboot the machine after syncing/dumping according to howto.
546  */
547 void
548 cpu_reboot(howto, what)
549 	int howto;
550 	char *what;
551 {
552 	static int syncing;
553 	static char str[256];
554 	char *ap = str, *ap1 = ap;
555 
556 	boothowto = howto;
557 	if (!cold && !(howto & RB_NOSYNC) && !syncing) {
558 		syncing = 1;
559 		vfs_shutdown();		/* sync */
560 		resettodr();		/* set wall clock */
561 	}
562 	splhigh();
563 	if (howto & RB_HALT) {
564 		doshutdownhooks();
565 		printf("halted\n\n");
566 		ppc_exit();
567 	}
568 	if (!cold && (howto & RB_DUMP))
569 		dumpsys();
570 	doshutdownhooks();
571 	printf("rebooting\n\n");
572 	if (what && *what) {
573 		if (strlen(what) > sizeof str - 5)
574 			printf("boot string too large, ignored\n");
575 		else {
576 			strcpy(str, what);
577 			ap1 = ap = str + strlen(str);
578 			*ap++ = ' ';
579 		}
580 	}
581 	*ap++ = '-';
582 	if (howto & RB_SINGLE)
583 		*ap++ = 's';
584 	if (howto & RB_KDB)
585 		*ap++ = 'd';
586 	*ap++ = 0;
587 	if (ap[-2] == '-')
588 		*ap1 = 0;
589 	ppc_boot(str);
590 }
591 
592 #ifdef notyet
593 /*
594  * OpenFirmware callback routine
595  */
596 void
597 callback(p)
598 	void *p;
599 {
600 	panic("callback");	/* for now			XXX */
601 }
602 #endif
603 
604 /*
605  * Perform an `splx()' for locore.
606  */
607 int
608 lcsplx(int ipl)
609 {
610 
611 	return (_spllower(ipl));
612 }
613 
614 /*
615  * Initial Machine Interface.
616  */
617 static int
618 fake_spl(int new)
619 {
620 	int scratch;
621 
622 	asm volatile ("mfmsr %0; andi. %0,%0,%1; mtmsr %0; isync"
623 	    : "=r"(scratch) : "K"((u_short)~(PSL_EE|PSL_ME)));
624 	return (-1);
625 }
626 
627 static void
628 fake_setsoft(int ipl)
629 {
630 	/* Do nothing */
631 }
632 
633 static void
634 fake_splx(new)
635 	int new;
636 {
637 
638 	(void) fake_spl(0);
639 }
640 
641 static void
642 fake_clock_return(frame, nticks)
643 	struct clockframe *frame;
644 	int nticks;
645 {
646 	/* Do nothing */
647 }
648 
649 static void *
650 fake_intr_establish(irq, level, ist, handler, arg)
651 	int irq, level, ist;
652 	int (*handler) __P((void *));
653 	void *arg;
654 {
655 
656 	panic("fake_intr_establish");
657 }
658 
659 static void
660 fake_intr_disestablish(cookie)
661 	void *cookie;
662 {
663 
664 	panic("fake_intr_disestablish");
665 }
666