machdep.c revision 1.59 1 /* $NetBSD: machdep.c,v 1.59 2000/09/24 12:32:37 jdolecek 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/bat.h>
59 #include <machine/pmap.h>
60 #include <machine/powerpc.h>
61 #include <machine/trap.h>
62
63 /* Our exported CPU info; we can have only one. */
64 struct cpu_info cpu_info_store;
65
66 /*
67 * Global variables used here and there
68 */
69 vm_map_t exec_map = NULL;
70 vm_map_t mb_map = NULL;
71 vm_map_t phys_map = NULL;
72
73 struct pcb *curpcb;
74 struct pmap *curpm;
75 struct proc *fpuproc;
76
77 extern struct user *proc0paddr;
78
79 struct bat battable[16];
80
81 int astpending;
82
83 char *bootpath;
84
85 paddr_t msgbuf_paddr;
86 vaddr_t msgbuf_vaddr;
87
88 static int fake_spl __P((void));
89 static int fake_splx __P((int));
90 static void fake_setsoft __P((void));
91 static void fake_clock_return __P((struct clockframe *, int));
92 static void fake_irq_establish __P((int, int, void (*)(void *), void *));
93
94 struct machvec machine_interface = {
95 fake_spl,
96 fake_spl,
97 fake_spl,
98 fake_spl,
99 fake_spl,
100 fake_spl,
101 fake_spl,
102 fake_spl,
103 fake_spl,
104 fake_spl,
105 fake_splx,
106 fake_setsoft,
107 fake_setsoft,
108 fake_clock_return,
109 fake_irq_establish,
110 };
111
112 void
113 initppc(startkernel, endkernel, args)
114 u_int startkernel, endkernel;
115 char *args;
116 {
117 int phandle, qhandle;
118 char name[32];
119 struct machvec *mp;
120 extern trapcode, trapsize;
121 extern alitrap, alisize;
122 extern dsitrap, dsisize;
123 extern isitrap, isisize;
124 extern decrint, decrsize;
125 extern tlbimiss, tlbimsize;
126 extern tlbdlmiss, tlbdlmsize;
127 extern tlbdsmiss, tlbdsmsize;
128 #ifdef DDB
129 extern ddblow, ddbsize;
130 extern void *startsym, *endsym;
131 #endif
132 #ifdef IPKDB
133 extern ipkdblow, ipkdbsize;
134 #endif
135 extern void consinit __P((void));
136 extern void callback __P((void *));
137 int exc, scratch;
138
139 proc0.p_addr = proc0paddr;
140 bzero(proc0.p_addr, sizeof *proc0.p_addr);
141
142 curpcb = &proc0paddr->u_pcb;
143
144 curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = pmap_kernel();
145
146 /*
147 * i386 port says, that this shouldn't be here,
148 * but I really think the console should be initialized
149 * as early as possible.
150 */
151 consinit();
152
153 #ifdef __notyet__ /* Needs some rethinking regarding real/virtual OFW */
154 OF_set_callback(callback);
155 #endif
156 /*
157 * Initialize BAT registers to unmapped to not generate
158 * overlapping mappings below.
159 */
160 asm volatile ("mtibatu 0,%0" :: "r"(0));
161 asm volatile ("mtibatu 1,%0" :: "r"(0));
162 asm volatile ("mtibatu 2,%0" :: "r"(0));
163 asm volatile ("mtibatu 3,%0" :: "r"(0));
164 asm volatile ("mtdbatu 0,%0" :: "r"(0));
165 asm volatile ("mtdbatu 1,%0" :: "r"(0));
166 asm volatile ("mtdbatu 2,%0" :: "r"(0));
167 asm volatile ("mtdbatu 3,%0" :: "r"(0));
168
169 /*
170 * Set up initial BAT table to only map the lowest 256 MB area
171 */
172 battable[0].batl = BATL(0x00000000, BAT_M, BAT_PP_RW);
173 battable[0].batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs);
174
175 /*
176 * Now setup fixed bat registers
177 *
178 * Note that we still run in real mode, and the BAT
179 * registers were cleared above.
180 */
181 /* IBAT0 used for initial 256 MB segment */
182 asm volatile ("mtibatl 0,%0; mtibatu 0,%1"
183 :: "r"(battable[0].batl), "r"(battable[0].batu));
184 /* DBAT0 used similar */
185 asm volatile ("mtdbatl 0,%0; mtdbatu 0,%1"
186 :: "r"(battable[0].batl), "r"(battable[0].batu));
187
188 /*
189 * Set up trap vectors
190 */
191 for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100)
192 switch (exc) {
193 default:
194 bcopy(&trapcode, (void *)exc, (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 bcopy(&alitrap, (void *)EXC_ALI, (size_t)&alisize);
203 break;
204 case EXC_DSI:
205 bcopy(&dsitrap, (void *)EXC_DSI, (size_t)&dsisize);
206 break;
207 case EXC_ISI:
208 bcopy(&isitrap, (void *)EXC_ISI, (size_t)&isisize);
209 break;
210 case EXC_DECR:
211 bcopy(&decrint, (void *)EXC_DECR, (size_t)&decrsize);
212 break;
213 case EXC_IMISS:
214 bcopy(&tlbimiss, (void *)EXC_IMISS, (size_t)&tlbimsize);
215 break;
216 case EXC_DLMISS:
217 bcopy(&tlbdlmiss, (void *)EXC_DLMISS, (size_t)&tlbdlmsize);
218 break;
219 case EXC_DSMISS:
220 bcopy(&tlbdsmiss, (void *)EXC_DSMISS, (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 bcopy(&ddblow, (void *)exc, (size_t)&ddbsize);
228 #else
229 bcopy(&ipkdblow, (void *)exc, (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 * Parse arg string.
245 */
246 bootpath = args;
247 while (*++args && *args != ' ');
248 if (*args) {
249 for(*args++ = 0; *args; args++)
250 BOOT_FLAG(*args, boothowto);
251 }
252
253 #ifdef DDB
254 /* ddb_init((int)(endsym - startsym), startsym, endsym); */
255 #endif
256 #ifdef IPKDB
257 /*
258 * Now trap to IPKDB
259 */
260 ipkdb_init();
261 if (boothowto & RB_KDB)
262 ipkdb_connect(0);
263 #endif
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
276 /*
277 * This should probably be in autoconf! XXX
278 */
279 int cpu;
280 char cpu_model[80];
281 char machine[] = MACHINE; /* from <machine/param.h> */
282 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */
283
284 void
285 identifycpu()
286 {
287 int phandle, pvr;
288 char name[32];
289
290 /*
291 * Find cpu type (Do it by OpenFirmware?)
292 */
293 asm ("mfpvr %0" : "=r"(pvr));
294 cpu = pvr >> 16;
295 switch (cpu) {
296 case 1:
297 sprintf(cpu_model, "601");
298 break;
299 case 3:
300 sprintf(cpu_model, "603");
301 break;
302 case 4:
303 sprintf(cpu_model, "604");
304 break;
305 case 5:
306 sprintf(cpu_model, "602");
307 break;
308 case 6:
309 sprintf(cpu_model, "603e");
310 break;
311 case 7:
312 sprintf(cpu_model, "603ev");
313 break;
314 case 9:
315 sprintf(cpu_model, "604ev");
316 break;
317 case 20:
318 sprintf(cpu_model, "620");
319 break;
320 default:
321 sprintf(cpu_model, "Version %x", cpu);
322 break;
323 }
324 sprintf(cpu_model + strlen(cpu_model), " (Revision %x)", pvr & 0xffff);
325 printf("CPU: %s\n", cpu_model);
326 }
327
328 void
329 install_extint(handler)
330 void (*handler) __P((void));
331 {
332 extern extint, extsize;
333 extern u_long extint_call;
334 u_long offset = (u_long)handler - (u_long)&extint_call;
335 int omsr, msr;
336
337 #ifdef DIAGNOSTIC
338 if (offset > 0x1ffffff)
339 panic("install_extint: too far away");
340 #endif
341 asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1"
342 : "=r"(omsr), "=r"(msr) : "K"((u_short)~PSL_EE));
343 extint_call = (extint_call & 0xfc000003) | offset;
344 bcopy(&extint, (void *)EXC_EXI, (size_t)&extsize);
345 __syncicache((void *)&extint_call, sizeof extint_call);
346 __syncicache((void *)EXC_EXI, (int)&extsize);
347 asm volatile ("mtmsr %0" :: "r"(omsr));
348 }
349
350 /*
351 * Machine dependent startup code.
352 */
353 void
354 cpu_startup()
355 {
356 int sz, i;
357 caddr_t v;
358 paddr_t minaddr, maxaddr;
359 int base, residual;
360 char pbuf[9];
361
362 proc0.p_addr = proc0paddr;
363 v = (caddr_t)proc0paddr + USPACE;
364
365 /*
366 * Initialize error message buffer (at end of core).
367 */
368 if (!(msgbuf_vaddr = uvm_km_alloc(kernel_map, round_page(MSGBUFSIZE))))
369 panic("startup: no room for message buffer");
370 for (i = 0; i < btoc(MSGBUFSIZE); i++)
371 pmap_enter(pmap_kernel(), msgbuf_vaddr + i * NBPG,
372 msgbuf_paddr + i * NBPG, VM_PROT_READ|VM_PROT_WRITE,
373 VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
374 initmsgbuf((caddr_t)msgbuf_vaddr, round_page(MSGBUFSIZE));
375
376 printf("%s", version);
377 identifycpu();
378
379 format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
380 printf("total memory = %s\n", pbuf);
381
382 /*
383 * Find out how much space we need, allocate it,
384 * and then give everything true virtual addresses.
385 */
386 sz = (int)allocsys(NULL, NULL);
387 if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0)
388 panic("startup: no room for tables");
389 if (allocsys(v, NULL) - v != sz)
390 panic("startup: table size inconsistency");
391
392 /*
393 * Now allocate buffers proper. They are different than the above
394 * in that they usually occupy more virtual memory than physical.
395 */
396 sz = MAXBSIZE * nbuf;
397 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(sz),
398 NULL, UVM_UNKNOWN_OFFSET, 0,
399 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
400 UVM_ADV_NORMAL, 0)) != KERN_SUCCESS)
401 panic("startup: cannot allocate VM for buffers");
402 minaddr = (vaddr_t)buffers;
403 base = bufpages / nbuf;
404 residual = bufpages % nbuf;
405 if (base >= MAXBSIZE) {
406 /* Don't want to alloc more physical mem than ever needed */
407 base = MAXBSIZE;
408 residual = 0;
409 }
410 for (i = 0; i < nbuf; i++) {
411 vsize_t curbufsize;
412 vaddr_t curbuf;
413 struct vm_page *pg;
414
415 /*
416 * Each buffer has MAXBSIZE bytes of VM space allocated. Of
417 * that MAXBSIZE space, we allocate and map (base+1) pages
418 * for the first "residual" buffers, and then we allocate
419 * "base" pages for the rest.
420 */
421 curbuf = (vaddr_t) buffers + (i * MAXBSIZE);
422 curbufsize = NBPG * ((i < residual) ? (base+1) : base);
423
424 while (curbufsize) {
425 pg = uvm_pagealloc(NULL, 0, NULL, 0);
426 if (pg == NULL)
427 panic("startup: not enough memory for "
428 "buffer cache");
429 pmap_enter(kernel_map->pmap, curbuf,
430 VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE,
431 VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
432 curbuf += PAGE_SIZE;
433 curbufsize -= PAGE_SIZE;
434 }
435 }
436
437 /*
438 * Allocate a submap for exec arguments. This map effectively
439 * limits the number of processes exec'ing at any time.
440 */
441 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
442 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
443
444 /*
445 * Allocate a submap for physio
446 */
447 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
448 VM_PHYS_SIZE, 0, FALSE, NULL);
449
450 /*
451 * No need to allocate an mbuf cluster submap. Mbuf clusters
452 * are allocated via the pool allocator, and we use direct-mapped
453 * pool pages.
454 */
455
456 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
457 printf("avail memory = %s\n", pbuf);
458 format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG);
459 printf("using %d buffers containing %s of memory\n", nbuf, pbuf);
460
461 /*
462 * Set up the buffers.
463 */
464 bufinit();
465
466 /*
467 * For now, use soft spl handling.
468 */
469 {
470 extern struct machvec soft_machvec;
471
472 machine_interface = soft_machvec;
473 }
474
475 /*
476 * Now allow hardware interrupts.
477 */
478 {
479 int msr;
480
481 splhigh();
482 asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
483 : "=r"(msr) : "K"((u_short)(PSL_EE|PSL_RI)));
484 }
485 }
486
487 /*
488 * consinit
489 * Initialize system console.
490 */
491 void
492 consinit()
493 {
494 static int initted;
495
496 if (initted)
497 return;
498 initted = 1;
499 cninit();
500 }
501
502 /*
503 * Set set up registers on exec.
504 */
505 void
506 setregs(p, pack, stack)
507 struct proc *p;
508 struct exec_package *pack;
509 u_long stack;
510 {
511 struct trapframe *tf = trapframe(p);
512 struct ps_strings arginfo;
513
514 bzero(tf, sizeof *tf);
515 tf->fixreg[1] = -roundup(-stack + 8, 16);
516
517 /*
518 * XXX Machine-independent code has already copied arguments and
519 * XXX environment to userland. Get them back here.
520 */
521 (void)copyin((char *)PS_STRINGS, &arginfo, sizeof (arginfo));
522
523 /*
524 * Set up arguments for _start():
525 * _start(argc, argv, envp, obj, cleanup, ps_strings);
526 *
527 * Notes:
528 * - obj and cleanup are the auxilliary and termination
529 * vectors. They are fixed up by ld.elf_so.
530 * - ps_strings is a NetBSD extention, and will be
531 * ignored by executables which are strictly
532 * compliant with the SVR4 ABI.
533 *
534 * XXX We have to set both regs and retval here due to different
535 * XXX calling convention in trap.c and init_main.c.
536 */
537 tf->fixreg[3] = arginfo.ps_nargvstr;
538 tf->fixreg[4] = (register_t)arginfo.ps_argvstr;
539 tf->fixreg[5] = (register_t)arginfo.ps_envstr;
540 tf->fixreg[6] = 0; /* auxillary vector */
541 tf->fixreg[7] = 0; /* termination vector */
542 tf->fixreg[8] = (register_t)PS_STRINGS; /* NetBSD extension */
543
544 tf->srr0 = pack->ep_entry;
545 tf->srr1 = PSL_MBO | PSL_USERSET | PSL_FE_DFLT;
546 p->p_addr->u_pcb.pcb_flags = 0;
547 }
548
549 /*
550 * Machine dependent system variables.
551 */
552 int
553 cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
554 int *name;
555 u_int namelen;
556 void *oldp;
557 size_t *oldlenp;
558 void *newp;
559 size_t newlen;
560 struct proc *p;
561 {
562 /* all sysctl names at this level are terminal */
563 if (namelen != 1)
564 return (ENOTDIR);
565
566 switch (name[0]) {
567 case CPU_CACHELINE:
568 return sysctl_rdint(oldp, oldlenp, newp, CACHELINESIZE);
569 default:
570 return (EOPNOTSUPP);
571 }
572 }
573
574 /*
575 * Crash dump handling.
576 */
577 u_long dumpmag = 0x8fca0101; /* magic number */
578 int dumpsize = 0; /* size of dump in pages */
579 long dumplo = -1; /* blocks */
580
581 void
582 dumpsys()
583 {
584 printf("dumpsys: TBD\n");
585 }
586
587 /*
588 * Soft networking interrupts.
589 */
590 void
591 softnet()
592 {
593 int isr = netisr;
594
595 netisr = 0;
596
597 #define DONETISR(bit, fn) do { \
598 if (isr & (1 << bit)) \
599 fn(); \
600 } while (0)
601
602 #include <net/netisr_dispatch.h>
603
604 #undef DONETISR
605 }
606
607 /*
608 * Stray interrupts.
609 */
610 void
611 strayintr(irq)
612 int irq;
613 {
614 log(LOG_ERR, "stray interrupt %d\n", irq);
615 }
616
617 /*
618 * Halt or reboot the machine after syncing/dumping according to howto.
619 */
620 void
621 cpu_reboot(howto, what)
622 int howto;
623 char *what;
624 {
625 static int syncing;
626 static char str[256];
627 char *ap = str, *ap1 = ap;
628
629 boothowto = howto;
630 if (!cold && !(howto & RB_NOSYNC) && !syncing) {
631 syncing = 1;
632 vfs_shutdown(); /* sync */
633 resettodr(); /* set wall clock */
634 }
635 splhigh();
636 if (howto & RB_HALT) {
637 doshutdownhooks();
638 printf("halted\n\n");
639 ppc_exit();
640 }
641 if (!cold && (howto & RB_DUMP))
642 dumpsys();
643 doshutdownhooks();
644 printf("rebooting\n\n");
645 if (what && *what) {
646 if (strlen(what) > sizeof str - 5)
647 printf("boot string too large, ignored\n");
648 else {
649 strcpy(str, what);
650 ap1 = ap = str + strlen(str);
651 *ap++ = ' ';
652 }
653 }
654 *ap++ = '-';
655 if (howto & RB_SINGLE)
656 *ap++ = 's';
657 if (howto & RB_KDB)
658 *ap++ = 'd';
659 *ap++ = 0;
660 if (ap[-2] == '-')
661 *ap1 = 0;
662 ppc_boot(str);
663 }
664
665 /*
666 * OpenFirmware callback routine
667 */
668 void
669 callback(p)
670 void *p;
671 {
672 panic("callback"); /* for now XXX */
673 }
674
675 /*
676 * Initial Machine Interface.
677 */
678 static int
679 fake_spl()
680 {
681 int scratch;
682
683 asm volatile ("mfmsr %0; andi. %0,%0,%1; mtmsr %0; isync"
684 : "=r"(scratch) : "K"((u_short)~(PSL_EE|PSL_ME)));
685 return (-1);
686 }
687
688 static void
689 fake_setsoft()
690 {
691 /* Do nothing */
692 }
693
694 static int
695 fake_splx(new)
696 int new;
697 {
698 return (fake_spl());
699 }
700
701 static void
702 fake_clock_return(frame, nticks)
703 struct clockframe *frame;
704 int nticks;
705 {
706 /* Do nothing */
707 }
708
709 static void
710 fake_irq_establish(irq, level, handler, arg)
711 int irq, level;
712 void (*handler) __P((void *));
713 void *arg;
714 {
715 panic("fake_irq_establish");
716 }
717