machdep.c revision 1.70 1 /* $NetBSD: machdep.c,v 1.70 2001/10/22 16:44:03 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 <dev/ofw/openfirm.h>
59
60 #include <machine/autoconf.h>
61 #include <machine/bat.h>
62 #include <machine/pmap.h>
63 #include <machine/powerpc.h>
64 #include <machine/trap.h>
65
66 #include <dev/cons.h>
67
68 /*
69 * Global variables used here and there
70 */
71 struct vm_map *exec_map = NULL;
72 struct vm_map *mb_map = NULL;
73 struct vm_map *phys_map = NULL;
74
75 struct pcb *curpcb;
76 struct pmap *curpm;
77 struct proc *fpuproc;
78
79 extern struct user *proc0paddr;
80
81 struct bat battable[16];
82
83 int astpending;
84
85 char *bootpath;
86
87 paddr_t msgbuf_paddr;
88 vaddr_t msgbuf_vaddr;
89
90 int lcsplx(int); /* called from locore.S */
91
92 static int fake_spl __P((void));
93 static int fake_splx __P((int));
94 static void fake_setsoft __P((void));
95 static void fake_clock_return __P((struct clockframe *, int));
96 static void fake_irq_establish __P((int, int, void (*)(void *), void *));
97
98 struct machvec machine_interface = {
99 fake_spl,
100 fake_spl,
101 fake_spl,
102 fake_spl,
103 fake_spl,
104 fake_spl,
105 fake_spl,
106 fake_spl,
107 fake_spl,
108 fake_spl,
109 fake_splx,
110 fake_setsoft,
111 fake_setsoft,
112 fake_clock_return,
113 fake_irq_establish,
114 };
115
116 char platform_name[64];
117
118 void
119 initppc(startkernel, endkernel, args)
120 u_int startkernel, endkernel;
121 char *args;
122 {
123 extern int trapcode, trapsize;
124 extern int alitrap, alisize;
125 extern int dsitrap, dsisize;
126 extern int isitrap, isisize;
127 extern int decrint, decrsize;
128 extern int tlbimiss, tlbimsize;
129 extern int tlbdlmiss, tlbdlmsize;
130 extern int tlbdsmiss, tlbdsmsize;
131 #ifdef DDB
132 extern int ddblow, ddbsize;
133 /* extern void *startsym, *endsym; */
134 #endif
135 #ifdef IPKDB
136 extern int ipkdblow, ipkdbsize;
137 #endif
138 int exc, scratch, node;
139
140 proc0.p_addr = proc0paddr;
141 memset(proc0.p_addr, 0, sizeof *proc0.p_addr);
142
143 curpcb = &proc0paddr->u_pcb;
144
145 curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = pmap_kernel();
146
147 /*
148 * Fetch the platform name from the root of the OFW tree.
149 */
150 node = OF_peer(0);
151 OF_getprop(node, "name", platform_name, sizeof(platform_name));
152
153 /*
154 * i386 port says, that this shouldn't be here,
155 * but I really think the console should be initialized
156 * as early as possible.
157 */
158 consinit();
159
160 #ifdef __notyet__ /* Needs some rethinking regarding real/virtual OFW */
161 OF_set_callback(callback);
162 #endif
163 /*
164 * Initialize BAT registers to unmapped to not generate
165 * overlapping mappings below.
166 */
167 asm volatile ("mtibatu 0,%0" :: "r"(0));
168 asm volatile ("mtibatu 1,%0" :: "r"(0));
169 asm volatile ("mtibatu 2,%0" :: "r"(0));
170 asm volatile ("mtibatu 3,%0" :: "r"(0));
171 asm volatile ("mtdbatu 0,%0" :: "r"(0));
172 asm volatile ("mtdbatu 1,%0" :: "r"(0));
173 asm volatile ("mtdbatu 2,%0" :: "r"(0));
174 asm volatile ("mtdbatu 3,%0" :: "r"(0));
175
176 /*
177 * Set up initial BAT table to only map the lowest 256 MB area
178 */
179 battable[0].batl = BATL(0x00000000, BAT_M, BAT_PP_RW);
180 battable[0].batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs);
181
182 /*
183 * Now setup fixed bat registers
184 *
185 * Note that we still run in real mode, and the BAT
186 * registers were cleared above.
187 */
188 /* IBAT0 used for initial 256 MB segment */
189 asm volatile ("mtibatl 0,%0; mtibatu 0,%1"
190 :: "r"(battable[0].batl), "r"(battable[0].batu));
191 /* DBAT0 used similar */
192 asm volatile ("mtdbatl 0,%0; mtdbatu 0,%1"
193 :: "r"(battable[0].batl), "r"(battable[0].batu));
194
195 /*
196 * Set up trap vectors
197 */
198 for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100)
199 switch (exc) {
200 default:
201 memcpy((void *)exc, &trapcode, (size_t)&trapsize);
202 break;
203 case EXC_EXI:
204 /*
205 * This one is (potentially) installed during autoconf
206 */
207 break;
208 case EXC_ALI:
209 memcpy((void *)EXC_ALI, &alitrap, (size_t)&alisize);
210 break;
211 case EXC_DSI:
212 memcpy((void *)EXC_DSI, &dsitrap, (size_t)&dsisize);
213 break;
214 case EXC_ISI:
215 memcpy((void *)EXC_ISI, &isitrap, (size_t)&isisize);
216 break;
217 case EXC_DECR:
218 memcpy((void *)EXC_DECR, &decrint, (size_t)&decrsize);
219 break;
220 case EXC_IMISS:
221 memcpy((void *)EXC_IMISS, &tlbimiss, (size_t)&tlbimsize);
222 break;
223 case EXC_DLMISS:
224 memcpy((void *)EXC_DLMISS, &tlbdlmiss, (size_t)&tlbdlmsize);
225 break;
226 case EXC_DSMISS:
227 memcpy((void *)EXC_DSMISS, &tlbdsmiss, (size_t)&tlbdsmsize);
228 break;
229 #if defined(DDB) || defined(IPKDB)
230 case EXC_PGM:
231 case EXC_TRC:
232 case EXC_BPT:
233 #if defined(DDB)
234 memcpy((void *)exc, &ddblow, (size_t)&ddbsize);
235 #else
236 memcpy((void *)exc, &ipkdblow, (size_t)&ipkdbsize);
237 #endif
238 break;
239 #endif /* DDB || IPKDB */
240 }
241
242 __syncicache((void *)EXC_RST, EXC_LAST - EXC_RST + 0x100);
243
244 /*
245 * Now enable translation (and machine checks/recoverable interrupts).
246 */
247 asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0; isync"
248 : "=r"(scratch) : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI));
249
250 /*
251 * Parse arg string.
252 */
253 bootpath = args;
254 while (*++args && *args != ' ');
255 if (*args) {
256 for(*args++ = 0; *args; args++)
257 BOOT_FLAG(*args, boothowto);
258 }
259
260 #ifdef DDB
261 /* ddb_init((int)(endsym - startsym), startsym, endsym); */
262 #endif
263 #ifdef IPKDB
264 /*
265 * Now trap to IPKDB
266 */
267 ipkdb_init();
268 if (boothowto & RB_KDB)
269 ipkdb_connect(0);
270 #endif
271
272 /*
273 * Set the page size.
274 */
275 uvm_setpagesize();
276
277 /*
278 * Initialize pmap module.
279 */
280 pmap_bootstrap(startkernel, endkernel);
281 }
282
283 /*
284 * This should probably be in autoconf! XXX
285 */
286 int cpu;
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 * For now, use soft spl handling.
431 */
432 {
433 extern struct machvec soft_machvec;
434
435 machine_interface = soft_machvec;
436 }
437
438 /*
439 * Now allow hardware interrupts.
440 */
441 {
442 int msr;
443
444 splhigh();
445 asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
446 : "=r"(msr) : "K"((u_short)(PSL_EE|PSL_RI)));
447 }
448 }
449
450 /*
451 * consinit
452 * Initialize system console.
453 */
454 void
455 consinit()
456 {
457 static int initted;
458
459 if (initted)
460 return;
461 initted = 1;
462 cninit();
463 }
464
465 /*
466 * Crash dump handling.
467 */
468
469 void
470 dumpsys()
471 {
472 printf("dumpsys: TBD\n");
473 }
474
475 /*
476 * Soft networking interrupts.
477 */
478 void
479 softnet()
480 {
481 int isr = netisr;
482
483 netisr = 0;
484
485 #define DONETISR(bit, fn) do { \
486 if (isr & (1 << bit)) \
487 fn(); \
488 } while (0)
489
490 #include <net/netisr_dispatch.h>
491
492 #undef DONETISR
493 }
494
495 /*
496 * Stray interrupts.
497 */
498 void
499 strayintr(irq)
500 int irq;
501 {
502 log(LOG_ERR, "stray interrupt %d\n", irq);
503 }
504
505 /*
506 * Halt or reboot the machine after syncing/dumping according to howto.
507 */
508 void
509 cpu_reboot(howto, what)
510 int howto;
511 char *what;
512 {
513 static int syncing;
514 static char str[256];
515 char *ap = str, *ap1 = ap;
516
517 boothowto = howto;
518 if (!cold && !(howto & RB_NOSYNC) && !syncing) {
519 syncing = 1;
520 vfs_shutdown(); /* sync */
521 resettodr(); /* set wall clock */
522 }
523 splhigh();
524 if (howto & RB_HALT) {
525 doshutdownhooks();
526 printf("halted\n\n");
527 ppc_exit();
528 }
529 if (!cold && (howto & RB_DUMP))
530 dumpsys();
531 doshutdownhooks();
532 printf("rebooting\n\n");
533 if (what && *what) {
534 if (strlen(what) > sizeof str - 5)
535 printf("boot string too large, ignored\n");
536 else {
537 strcpy(str, what);
538 ap1 = ap = str + strlen(str);
539 *ap++ = ' ';
540 }
541 }
542 *ap++ = '-';
543 if (howto & RB_SINGLE)
544 *ap++ = 's';
545 if (howto & RB_KDB)
546 *ap++ = 'd';
547 *ap++ = 0;
548 if (ap[-2] == '-')
549 *ap1 = 0;
550 ppc_boot(str);
551 }
552
553 #ifdef notyet
554 /*
555 * OpenFirmware callback routine
556 */
557 void
558 callback(p)
559 void *p;
560 {
561 panic("callback"); /* for now XXX */
562 }
563 #endif
564
565 /*
566 * Perform an `splx()' for locore.
567 */
568 int
569 lcsplx(int ipl)
570 {
571
572 return (splx(ipl));
573 }
574
575 /*
576 * Initial Machine Interface.
577 */
578 static int
579 fake_spl()
580 {
581 int scratch;
582
583 asm volatile ("mfmsr %0; andi. %0,%0,%1; mtmsr %0; isync"
584 : "=r"(scratch) : "K"((u_short)~(PSL_EE|PSL_ME)));
585 return (-1);
586 }
587
588 static void
589 fake_setsoft()
590 {
591 /* Do nothing */
592 }
593
594 static int
595 fake_splx(new)
596 int new;
597 {
598 return (fake_spl());
599 }
600
601 static void
602 fake_clock_return(frame, nticks)
603 struct clockframe *frame;
604 int nticks;
605 {
606 /* Do nothing */
607 }
608
609 static void
610 fake_irq_establish(irq, level, handler, arg)
611 int irq, level;
612 void (*handler) __P((void *));
613 void *arg;
614 {
615 panic("fake_irq_establish");
616 }
617