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