1 /* $NetBSD: machdep.c,v 1.213 2024/01/19 20:55:42 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1982, 1986, 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: Utah $Hdr: machdep.c 1.74 92/12/20$
37 *
38 * @(#)machdep.c 8.10 (Berkeley) 4/20/94
39 */
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.213 2024/01/19 20:55:42 thorpej Exp $");
43
44 #include "opt_ddb.h"
45 #include "opt_kgdb.h"
46 #include "opt_compat_netbsd.h"
47 #include "opt_fpu_emulate.h"
48 #include "opt_m060sp.h"
49 #include "opt_modular.h"
50 #include "opt_panicbutton.h"
51 #include "opt_extmem.h"
52 #include "opt_m68k_arch.h"
53
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/callout.h>
57 #include <sys/signalvar.h>
58 #include <sys/kauth.h>
59 #include <sys/kernel.h>
60 #include <sys/proc.h>
61 #include <sys/buf.h>
62 #include <sys/reboot.h>
63 #include <sys/conf.h>
64 #include <sys/file.h>
65 #include <sys/mbuf.h>
66 #include <sys/msgbuf.h>
67 #include <sys/ioctl.h>
68 #include <sys/tty.h>
69 #include <sys/mount.h>
70 #include <sys/exec.h>
71 #include <sys/exec_aout.h> /* for MID_* */
72 #include <sys/vnode.h>
73 #include <sys/syscallargs.h>
74 #include <sys/core.h>
75 #include <sys/kcore.h>
76 #include <sys/ksyms.h>
77 #include <sys/module.h>
78 #include <sys/cpu.h>
79 #include <sys/sysctl.h>
80 #include <sys/device.h>
81
82 #include "ksyms.h"
83
84 #if NKSYMS || defined(DDB) || defined(MODULAR)
85 #include <sys/exec_elf.h>
86 #endif
87
88 #include <machine/db_machdep.h>
89 #include <ddb/db_sym.h>
90 #include <ddb/db_extern.h>
91
92 #include <m68k/cacheops.h>
93 #include <machine/reg.h>
94 #include <machine/pcb.h>
95 #include <machine/psl.h>
96 #include <machine/pte.h>
97 #include <machine/kcore.h>
98
99 #include <dev/cons.h>
100 #include <dev/mm.h>
101
102 #define MAXMEM 64*1024 /* XXX - from cmap.h */
103 #include <uvm/uvm.h>
104 #include <uvm/uvm_physseg.h>
105
106 #include <machine/bus.h>
107 #include <machine/autoconf.h>
108 #include <arch/x68k/dev/intiovar.h>
109 #include <arch/x68k/x68k/iodevice.h>
110
111 extern void doboot(void) __attribute__((__noreturn__));
112
113 /* the following is used externally (sysctl_hw) */
114 char machine[] = MACHINE; /* from <machine/param.h> */
115
116 /* Our exported CPU info; we can have only one. */
117 struct cpu_info cpu_info_store;
118
119 struct vm_map *phys_map = NULL;
120
121 extern paddr_t avail_start, avail_end;
122 extern u_int lowram;
123 extern int end, *esym;
124
125 int maxmem; /* max memory per process */
126
127 /* prototypes for local functions */
128 void identifycpu(void);
129 static int check_emulator(char *, int);
130 void initcpu(void);
131 int cpu_dumpsize(void);
132 int cpu_dump(int (*)(dev_t, daddr_t, void *, size_t), daddr_t *);
133 void cpu_init_kcore_hdr(void);
134
135 /* functions called from locore.s */
136 void x68k_init(void);
137 void dumpsys(void);
138 void straytrap(int, u_short);
139 void nmihand(struct frame);
140 void intrhand(int);
141
142 /* memory probe function called from locore.s */
143 void setmemrange(void);
144 #ifdef EXTENDED_MEMORY
145 static bool mem_exists(paddr_t, paddr_t);
146 #endif
147
148 typedef struct {
149 paddr_t start;
150 paddr_t end;
151 } phys_seg_t;
152
153 static int basemem;
154 static phys_seg_t phys_basemem_seg;
155 #ifdef EXTENDED_MEMORY
156 #define EXTMEM_SEGS (VM_PHYSSEG_MAX - 1)
157 static phys_seg_t phys_extmem_seg[EXTMEM_SEGS];
158 #endif
159
160 /*
161 * On the 68020/68030, the value of delay_divisor is roughly
162 * 2048 / cpuspeed (where cpuspeed is in MHz).
163 *
164 * On the 68040, the value of delay_divisor is roughly
165 * 759 / cpuspeed (where cpuspeed is in MHz).
166 *
167 * On the 68060, the value of delay_divisor is reported to be
168 * 128 / cpuspeed (where cpuspeed is in MHz).
169 */
170 int delay_divisor = 140; /* assume some reasonable value to start */
171 static int cpuspeed; /* MPU clock (in MHz) */
172
173 /*
174 * Machine-dependent crash dump header info.
175 */
176 cpu_kcore_hdr_t cpu_kcore_hdr;
177
178 static callout_t candbtimer_ch;
179
180 void
x68k_init(void)181 x68k_init(void)
182 {
183 u_int i;
184 paddr_t msgbuf_pa;
185 paddr_t s, e;
186
187 /*
188 * Most m68k ports allocate msgbuf at the end of available memory
189 * (i.e. just after avail_end), but on x68k we allocate msgbuf
190 * at the end of main memory for compatibility.
191 */
192 msgbuf_pa = phys_basemem_seg.end - m68k_round_page(MSGBUFSIZE);
193
194 /*
195 * Tell the VM system about available physical memory.
196 */
197 /* load the main memory region */
198 s = avail_start;
199 e = msgbuf_pa;
200 uvm_page_physload(atop(s), atop(e), atop(s), atop(e),
201 VM_FREELIST_MAINMEM);
202
203 #ifdef EXTENDED_MEMORY
204 /* load extended memory regions */
205 for (i = 0; i < EXTMEM_SEGS; i++) {
206 if (phys_extmem_seg[i].start == phys_extmem_seg[i].end)
207 continue;
208 uvm_page_physload(atop(phys_extmem_seg[i].start),
209 atop(phys_extmem_seg[i].end),
210 atop(phys_extmem_seg[i].start),
211 atop(phys_extmem_seg[i].end),
212 VM_FREELIST_HIGHMEM);
213 }
214 #endif
215
216 /*
217 * Initialize error message buffer (at end of core).
218 */
219 for (i = 0; i < btoc(MSGBUFSIZE); i++)
220 pmap_kenter_pa((vaddr_t)msgbufaddr + i * PAGE_SIZE,
221 msgbuf_pa + i * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, 0);
222 pmap_update(pmap_kernel());
223 initmsgbuf(msgbufaddr, m68k_round_page(MSGBUFSIZE));
224 }
225
226 /*
227 * Console initialization: called early on from main,
228 * before vm init or startup. Do enough configuration
229 * to choose and initialize a console.
230 */
231 void
consinit(void)232 consinit(void)
233 {
234
235 /*
236 * bring graphics layer up.
237 */
238 config_console();
239
240 /*
241 * Initialize the console before we print anything out.
242 */
243 cninit();
244
245 #ifdef KGDB
246 zs_kgdb_init(); /* XXX */
247 #endif
248 #if NKSYMS || defined(DDB) || defined(MODULAR)
249 ksyms_addsyms_elf((int)esym - (int)&end - sizeof(Elf32_Ehdr),
250 (void *)&end, esym);
251 #endif
252 #ifdef DDB
253 if (boothowto & RB_KDB)
254 Debugger();
255 #endif
256 }
257
258 /*
259 * cpu_startup: allocate memory for variable-sized tables,
260 * initialize cpu, and do autoconfiguration.
261 */
262 void
cpu_startup(void)263 cpu_startup(void)
264 {
265 vaddr_t minaddr, maxaddr;
266 char pbuf[9];
267 #ifdef DEBUG
268 extern int pmapdebug;
269 int opmapdebug = pmapdebug;
270
271 pmapdebug = 0;
272 #endif
273
274 if (fputype != FPU_NONE)
275 m68k_make_fpu_idle_frame();
276
277 /*
278 * Initialize the kernel crash dump header.
279 */
280 cpu_init_kcore_hdr();
281
282 /*
283 * Good {morning,afternoon,evening,night}.
284 */
285 printf("%s%s", copyright, version);
286 identifycpu();
287 format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
288 printf("total memory = %s\n", pbuf);
289
290 minaddr = 0;
291
292 /*
293 * Allocate a submap for physio
294 */
295 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
296 VM_PHYS_SIZE, 0, false, NULL);
297
298 #ifdef DEBUG
299 pmapdebug = opmapdebug;
300 #endif
301 format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
302 printf("avail memory = %s\n", pbuf);
303
304 /*
305 * Set up CPU-specific registers, cache, etc.
306 */
307 initcpu();
308
309 callout_init(&candbtimer_ch, 0);
310 }
311
312 static const char *fpu_descr[] = {
313 #ifdef FPU_EMULATE
314 ", emulator FPU", /* 0 */
315 #else
316 ", no math support", /* 0 */
317 #endif
318 ", m68881 FPU", /* 1 */
319 ", m68882 FPU", /* 2 */
320 "/FPU", /* 3 */
321 "/FPU", /* 4 */
322 };
323
324 void
identifycpu(void)325 identifycpu(void)
326 {
327 /* there's alot of XXX in here... */
328 const char *cpu_type, *mach, *mmu, *fpu;
329 char clock[20];
330 char emubuf[20];
331 char cpubuf[16];
332 uint32_t pcr;
333
334 /*
335 * check machine type constant
336 */
337 switch (intio_get_sysport_mpustat()) {
338 case 0xdc:
339 /*
340 * CPU Type == 68030, Clock == 25MHz
341 */
342 mach = "030";
343 break;
344 case 0xfe:
345 /*
346 * CPU Type == 68000, Clock == 16MHz
347 */
348 mach = "000XVI";
349 break;
350 case 0xff:
351 /*
352 * CPU Type == 68000, Clock == 10MHz
353 */
354 mach = "000/ACE/PRO/EXPERT/SUPER";
355 break;
356 default:
357 /*
358 * unknown type
359 */
360 mach = "000?(unknown model)";
361 break;
362 }
363
364 clock[0] = '\0';
365 emubuf[0] = '\0';
366 check_emulator(emubuf, sizeof(emubuf));
367
368 switch (cputype) {
369 case CPU_68060:
370 /* from amiga */
371 __asm(".word 0x4e7a,0x0808; movl %%d0,%0"
372 : "=d"(pcr) : : "d0");
373 snprintf(cpubuf, sizeof(cpubuf), "m68%s060 rev.%d",
374 (pcr & 0x10000) ? "LC/EC" : "", (pcr >> 8) & 0xff);
375 cpu_type = cpubuf;
376 mmu = "/MMU";
377 /*
378 * This delay_divisor method cannot get accurate cpuspeed
379 * for 68060.
380 */
381 clock[0] = '\0';
382 break;
383 case CPU_68040:
384 cpu_type = "m68040";
385 mmu = "/MMU";
386 cpuspeed = 759 / delay_divisor;
387 snprintf(clock, sizeof(clock), ", %d/%dMHz clock",
388 cpuspeed*2, cpuspeed);
389 break;
390 case CPU_68030:
391 cpu_type = "m68030";
392 mmu = "/MMU";
393 cpuspeed = 2048 / delay_divisor;
394 snprintf(clock, sizeof(clock), ", %dMHz clock", cpuspeed);
395 break;
396 case CPU_68020:
397 cpu_type = "m68020";
398 mmu = ", m68851 MMU";
399 cpuspeed = 2048 / delay_divisor;
400 snprintf(clock, sizeof(clock), ", %dMHz clock", cpuspeed);
401 break;
402 default:
403 cpu_type = "unknown";
404 mmu = ", unknown MMU";
405 break;
406 }
407 if (fputype >= 0 && fputype < sizeof(fpu_descr)/sizeof(fpu_descr[0]))
408 fpu = fpu_descr[fputype];
409 else
410 fpu = ", unknown FPU";
411 cpu_setmodel("X68%s (%s CPU%s%s%s)%s%s",
412 mach, cpu_type, mmu, fpu, clock,
413 emubuf[0] ? " on " : "", emubuf);
414 printf("%s\n", cpu_getmodel());
415 }
416
417 /*
418 * If it is an emulator, store the name in buf and return 1.
419 * Otherwise return 0.
420 */
421 static int
check_emulator(char * buf,int bufsize)422 check_emulator(char *buf, int bufsize)
423 {
424 int xm6major;
425 int xm6minor;
426 int xm6imark;
427 int xm6imajor;
428 int xm6iminor;
429
430 /* XM6 and its family */
431 intio_set_sysport_sramwp('X');
432 if (intio_get_sysport_sramwp() == '6') {
433 xm6major = intio_get_sysport_sramwp();
434 xm6minor = intio_get_sysport_sramwp();
435 xm6imark = intio_get_sysport_sramwp();
436 switch (xm6imark) {
437 case 0xff: /* Original XM6 or unknown compatibles */
438 snprintf(buf, bufsize, "XM6 v%x.%02x",
439 xm6major, xm6minor);
440 break;
441
442 case 'i': /* XM6i */
443 xm6imajor = intio_get_sysport_sramwp();
444 xm6iminor = intio_get_sysport_sramwp();
445 snprintf(buf, bufsize, "XM6i v%d.%02d",
446 xm6imajor, xm6iminor);
447 break;
448
449 case 'g': /* XM6 TypeG */
450 snprintf(buf, bufsize, "XM6 TypeG v%x.%02x",
451 xm6major, xm6minor);
452 break;
453
454 default: /* Other XM6 compatibles? */
455 /* XXX what should I do? */
456 return 0;
457 }
458 return 1;
459 }
460
461 return 0;
462 }
463
464 /*
465 * machine dependent system variables.
466 */
467 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
468 {
469
470 sysctl_createv(clog, 0, NULL, NULL,
471 CTLFLAG_PERMANENT,
472 CTLTYPE_NODE, "machdep", NULL,
473 NULL, 0, NULL, 0,
474 CTL_MACHDEP, CTL_EOL);
475
476 sysctl_createv(clog, 0, NULL, NULL,
477 CTLFLAG_PERMANENT,
478 CTLTYPE_STRUCT, "console_device", NULL,
479 sysctl_consdev, 0, NULL, sizeof(dev_t),
480 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
481 }
482
483 int waittime = -1;
484
485 void
cpu_reboot(int howto,char * bootstr)486 cpu_reboot(int howto, char *bootstr)
487 {
488 struct pcb *pcb = lwp_getpcb(curlwp);
489
490 /* take a snap shot before clobbering any registers */
491 if (pcb != NULL)
492 savectx(pcb);
493
494 boothowto = howto;
495 if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
496 waittime = 0;
497 vfs_shutdown();
498 /*
499 * If we've been adjusting the clock, the todr
500 * will be out of synch; adjust it now.
501 */
502 /*resettodr();*/
503 }
504
505 /* Disable interrupts. */
506 splhigh();
507
508 if (howto & RB_DUMP)
509 dumpsys();
510
511 /* Run any shutdown hooks. */
512 doshutdownhooks();
513
514 pmf_system_shutdown(boothowto);
515
516 #if defined(PANICWAIT) && !defined(DDB)
517 if ((howto & RB_HALT) == 0 && panicstr) {
518 printf("hit any key to reboot...\n");
519 cnpollc(1);
520 (void)cngetc();
521 cnpollc(0);
522 printf("\n");
523 }
524 #endif
525
526 /* Finally, halt/reboot the system. */
527 /* a) RB_POWERDOWN
528 * a1: the power switch is still on
529 * Power cannot be removed; simply halt the system (b)
530 * a2: the power switch is off
531 * Remove the power
532 * b) RB_HALT
533 * call cngetc
534 * c) otherwise
535 * Reboot
536 */
537 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
538 printf("powering off...\n");
539 delay(1000000);
540
541 /* Turn off the alarm signal of RTC */
542 IODEVbase->io_rtc.bank0.reset = 0x0c;
543
544 intio_set_sysport_powoff(0x00);
545 intio_set_sysport_powoff(0x0f);
546 intio_set_sysport_powoff(0x0f);
547 delay(1000000);
548 }
549 if ((howto & RB_HALT) != 0) {
550 printf("System halted. Hit any key to reboot.\n\n");
551 cnpollc(1);
552 (void)cngetc();
553 cnpollc(0);
554 }
555
556 printf("rebooting...\n");
557 DELAY(1000000);
558 doboot();
559 /* NOTREACHED */
560 }
561
562 /*
563 * Initialize the kernel crash dump header.
564 */
565 void
cpu_init_kcore_hdr(void)566 cpu_init_kcore_hdr(void)
567 {
568 cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
569 struct m68k_kcore_hdr *m = &h->un._m68k;
570 psize_t size;
571 #ifdef EXTENDED_MEMORY
572 int i, seg;
573 #endif
574
575 memset(&cpu_kcore_hdr, 0, sizeof(cpu_kcore_hdr));
576
577 /*
578 * Initialize the `dispatcher' portion of the header.
579 */
580 strcpy(h->name, machine);
581 h->page_size = PAGE_SIZE;
582 h->kernbase = KERNBASE;
583
584 /*
585 * Fill in information about our MMU configuration.
586 */
587 m->mmutype = mmutype;
588 m->sg_v = SG_V;
589 m->sg_frame = SG_FRAME;
590 m->sg_ishift = SG_ISHIFT;
591 m->sg_pmask = SG_PMASK;
592 m->sg40_shift1 = SG4_SHIFT1;
593 m->sg40_mask2 = SG4_MASK2;
594 m->sg40_shift2 = SG4_SHIFT2;
595 m->sg40_mask3 = SG4_MASK3;
596 m->sg40_shift3 = SG4_SHIFT3;
597 m->sg40_addr1 = SG4_ADDR1;
598 m->sg40_addr2 = SG4_ADDR2;
599 m->pg_v = PG_V;
600 m->pg_frame = PG_FRAME;
601
602 /*
603 * Initialize pointer to kernel segment table.
604 */
605 m->sysseg_pa = (uint32_t)(pmap_kernel()->pm_stpa);
606
607 /*
608 * Initialize relocation value such that:
609 *
610 * pa = (va - KERNBASE) + reloc
611 */
612 m->reloc = lowram;
613
614 /*
615 * Define the end of the relocatable range.
616 */
617 m->relocend = (uint32_t)&end;
618
619 /*
620 * X68k has multiple RAM segments on some models.
621 */
622 size = phys_basemem_seg.end - phys_basemem_seg.start;
623 m->ram_segs[0].start = phys_basemem_seg.start;
624 m->ram_segs[0].size = size;
625 #ifdef EXTENDED_MEMORY
626 seg = 1;
627 for (i = 0; i < EXTMEM_SEGS; i++) {
628 size = phys_extmem_seg[i].end - phys_extmem_seg[i].start;
629 if (size == 0)
630 continue;
631 m->ram_segs[seg].start = phys_extmem_seg[i].start;
632 m->ram_segs[seg].size = size;
633 seg++;
634 }
635 #endif
636 }
637
638 /*
639 * Compute the size of the machine-dependent crash dump header.
640 * Returns size in disk blocks.
641 */
642
643 #define CHDRSIZE (ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)))
644 #define MDHDRSIZE roundup(CHDRSIZE, dbtob(1))
645
646 int
cpu_dumpsize(void)647 cpu_dumpsize(void)
648 {
649
650 return btodb(MDHDRSIZE);
651 }
652
653 /*
654 * Called by dumpsys() to dump the machine-dependent header.
655 */
656 int
cpu_dump(int (* dump)(dev_t,daddr_t,void *,size_t),daddr_t * blknop)657 cpu_dump(int (*dump)(dev_t, daddr_t, void *, size_t), daddr_t *blknop)
658 {
659 int buf[MDHDRSIZE / sizeof(int)];
660 cpu_kcore_hdr_t *chdr;
661 kcore_seg_t *kseg;
662 int error;
663
664 kseg = (kcore_seg_t *)buf;
665 chdr = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(kcore_seg_t)) /
666 sizeof(int)];
667
668 /* Create the segment header. */
669 CORE_SETMAGIC(*kseg, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
670 kseg->c_size = MDHDRSIZE - ALIGN(sizeof(kcore_seg_t));
671
672 memcpy(chdr, &cpu_kcore_hdr, sizeof(cpu_kcore_hdr_t));
673 error = (*dump)(dumpdev, *blknop, (void *)buf, sizeof(buf));
674 *blknop += btodb(sizeof(buf));
675 return (error);
676 }
677
678 /*
679 * These variables are needed by /sbin/savecore
680 */
681 uint32_t dumpmag = 0x8fca0101; /* magic number */
682 int dumpsize = 0; /* pages */
683 long dumplo = 0; /* blocks */
684
685 /*
686 * This is called by main to set dumplo and dumpsize.
687 * Dumps always skip the first PAGE_SIZE of disk space in
688 * case there might be a disk label stored there. If there
689 * is extra space, put dump at the end to reduce the chance
690 * that swapping trashes it.
691 */
692 void
cpu_dumpconf(void)693 cpu_dumpconf(void)
694 {
695 cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
696 struct m68k_kcore_hdr *m = &h->un._m68k;
697 int chdrsize; /* size of dump header */
698 int nblks; /* size of dump area */
699 int i;
700
701 if (dumpdev == NODEV)
702 return;
703 nblks = bdev_size(dumpdev);
704 chdrsize = cpu_dumpsize();
705
706 dumpsize = 0;
707 for (i = 0; i < M68K_NPHYS_RAM_SEGS && m->ram_segs[i].size; i++)
708 dumpsize += btoc(m->ram_segs[i].size);
709 /*
710 * Check to see if we will fit. Note we always skip the
711 * first PAGE_SIZE in case there is a disk label there.
712 */
713 if (nblks < (ctod(dumpsize) + chdrsize + ctod(1))) {
714 dumpsize = 0;
715 dumplo = -1;
716 return;
717 }
718
719 /*
720 * Put dump at the end of the partition.
721 */
722 dumplo = (nblks - 1) - ctod(dumpsize) - chdrsize;
723 }
724
725 void
dumpsys(void)726 dumpsys(void)
727 {
728 cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
729 struct m68k_kcore_hdr *m = &h->un._m68k;
730 const struct bdevsw *bdev;
731 daddr_t blkno; /* current block to write */
732 /* dump routine */
733 int (*dump)(dev_t, daddr_t, void *, size_t);
734 int pg; /* page being dumped */
735 paddr_t maddr; /* PA being dumped */
736 int seg; /* RAM segment being dumped */
737 int error; /* error code from (*dump)() */
738
739 /* XXX initialized here because of gcc lossage */
740 seg = 0;
741 maddr = m->ram_segs[seg].start;
742 pg = 0;
743
744 /* Make sure dump device is valid. */
745 if (dumpdev == NODEV)
746 return;
747 bdev = bdevsw_lookup(dumpdev);
748 if (bdev == NULL)
749 return;
750 if (dumpsize == 0) {
751 cpu_dumpconf();
752 if (dumpsize == 0)
753 return;
754 }
755 if (dumplo <= 0) {
756 printf("\ndump to dev %u,%u not possible\n",
757 major(dumpdev), minor(dumpdev));
758 return;
759 }
760 dump = bdev->d_dump;
761 blkno = dumplo;
762
763 printf("\ndumping to dev %u,%u offset %ld\n",
764 major(dumpdev), minor(dumpdev), dumplo);
765
766 printf("dump ");
767
768 /* Write the dump header. */
769 error = cpu_dump(dump, &blkno);
770 if (error)
771 goto bad;
772
773 for (pg = 0; pg < dumpsize; pg++) {
774 #define NPGMB (1024*1024/PAGE_SIZE)
775 /* print out how many MBs we have dumped */
776 if (pg && (pg % NPGMB) == 0)
777 printf_nolog("%d ", pg / NPGMB);
778 #undef NPGMB
779 if (maddr == 0) {
780 /* Skip first page */
781 maddr += PAGE_SIZE;
782 blkno += btodb(PAGE_SIZE);
783 continue;
784 }
785 while (maddr >=
786 (m->ram_segs[seg].start + m->ram_segs[seg].size)) {
787 if (++seg >= M68K_NPHYS_RAM_SEGS ||
788 m->ram_segs[seg].size == 0) {
789 error = EINVAL; /* XXX ?? */
790 goto bad;
791 }
792 maddr = m->ram_segs[seg].start;
793 }
794 pmap_enter(pmap_kernel(), (vaddr_t)vmmap, maddr,
795 VM_PROT_READ, VM_PROT_READ|PMAP_WIRED);
796 pmap_update(pmap_kernel());
797
798 error = (*dump)(dumpdev, blkno, vmmap, PAGE_SIZE);
799 bad:
800 switch (error) {
801 case 0:
802 maddr += PAGE_SIZE;
803 blkno += btodb(PAGE_SIZE);
804 break;
805
806 case ENXIO:
807 printf("device bad\n");
808 return;
809
810 case EFAULT:
811 printf("device not ready\n");
812 return;
813
814 case EINVAL:
815 printf("area improper\n");
816 return;
817
818 case EIO:
819 printf("i/o error\n");
820 return;
821
822 case EINTR:
823 printf("aborted from console\n");
824 return;
825
826 default:
827 printf("error %d\n", error);
828 return;
829 }
830 }
831 printf("succeeded\n");
832 }
833
834 void
initcpu(void)835 initcpu(void)
836 {
837 /* XXX should init '40 vecs here, too */
838 #if defined(M68060)
839 extern void *vectab[256];
840 #if defined(M060SP)
841 extern uint8_t I_CALL_TOP[];
842 extern uint8_t FP_CALL_TOP[];
843 #else
844 extern uint8_t illinst;
845 #endif
846 extern uint8_t fpfault;
847 #endif
848
849 #if defined(M68060)
850 if (cputype == CPU_68060) {
851 #if defined(M060SP)
852 /* integer support */
853 vectab[61] = &I_CALL_TOP[128 + 0x00];
854
855 /* floating point support */
856 vectab[11] = &FP_CALL_TOP[128 + 0x30];
857 vectab[55] = &FP_CALL_TOP[128 + 0x38];
858 vectab[60] = &FP_CALL_TOP[128 + 0x40];
859
860 vectab[54] = &FP_CALL_TOP[128 + 0x00];
861 vectab[52] = &FP_CALL_TOP[128 + 0x08];
862 vectab[53] = &FP_CALL_TOP[128 + 0x10];
863 vectab[51] = &FP_CALL_TOP[128 + 0x18];
864 vectab[50] = &FP_CALL_TOP[128 + 0x20];
865 vectab[49] = &FP_CALL_TOP[128 + 0x28];
866 #else
867 vectab[61] = &illinst;
868 #endif
869 vectab[48] = &fpfault;
870 }
871 DCIS();
872 #endif
873 }
874
875 void
straytrap(int pc,u_short evec)876 straytrap(int pc, u_short evec)
877 {
878
879 printf("unexpected trap (vector offset %x) from %x\n",
880 evec & 0xFFF, pc);
881 #if defined(DDB)
882 Debugger();
883 #endif
884 }
885
886 int *nofault;
887
888 int
badaddr(volatile void * addr)889 badaddr(volatile void* addr)
890 {
891 int i;
892 label_t faultbuf;
893
894 nofault = (int *)&faultbuf;
895 if (setjmp((label_t *)nofault)) {
896 nofault = NULL;
897 return 1;
898 }
899 i = *(volatile short *)addr;
900 __USE(i);
901 nofault = NULL;
902 return 0;
903 }
904
905 int
badbaddr(volatile void * addr)906 badbaddr(volatile void *addr)
907 {
908 int i;
909 label_t faultbuf;
910
911 nofault = (int *)&faultbuf;
912 if (setjmp((label_t *)nofault)) {
913 nofault = NULL;
914 return 1;
915 }
916 i = *(volatile char *)addr;
917 __USE(i);
918 nofault = NULL;
919 return 0;
920 }
921
922 void
intrhand(int sr)923 intrhand(int sr)
924 {
925
926 printf("intrhand: unexpected sr 0x%x\n", sr);
927 }
928
929 const uint16_t ipl2psl_table[NIPL] = {
930 [IPL_NONE] = PSL_S | PSL_IPL0,
931 [IPL_SOFTCLOCK] = PSL_S | PSL_IPL1,
932 [IPL_SOFTBIO] = PSL_S | PSL_IPL1,
933 [IPL_SOFTNET] = PSL_S | PSL_IPL1,
934 [IPL_SOFTSERIAL] = PSL_S | PSL_IPL1,
935 [IPL_VM] = PSL_S | PSL_IPL5,
936 [IPL_SCHED] = PSL_S | PSL_IPL7,
937 [IPL_HIGH] = PSL_S | PSL_IPL7,
938 };
939
940 #if (defined(DDB) || defined(DEBUG)) && !defined(PANICBUTTON)
941 #define PANICBUTTON
942 #endif
943
944 #ifdef PANICBUTTON
945 int panicbutton = 1; /* non-zero if panic buttons are enabled */
946 int crashandburn = 0;
947 int candbdelay = 50; /* give em half a second */
948 void candbtimer(void *);
949
950 void
candbtimer(void * arg)951 candbtimer(void *arg)
952 {
953
954 crashandburn = 0;
955 }
956 #endif
957
958 /*
959 * Level 7 interrupts can be caused by the NMI button.
960 */
961 void
nmihand(struct frame frame)962 nmihand(struct frame frame)
963 {
964
965 intio_set_sysport_keyctrl(intio_get_sysport_keyctrl() | 0x04);
966
967 if (1) {
968 #ifdef PANICBUTTON
969 static int innmihand = 0;
970
971 /*
972 * Attempt to reduce the window of vulnerability for recursive
973 * NMIs (e.g. someone holding down the keyboard reset button).
974 */
975 if (innmihand == 0) {
976 innmihand = 1;
977 printf("NMI button pressed\n");
978 innmihand = 0;
979 }
980 #ifdef DDB
981 Debugger();
982 #else
983 if (panicbutton) {
984 if (crashandburn) {
985 crashandburn = 0;
986 panic(panicstr ?
987 "forced crash, nosync" : "forced crash");
988 }
989 crashandburn++;
990 callout_reset(&candbtimer_ch, candbdelay,
991 candbtimer, NULL);
992 }
993 #endif /* DDB */
994 #endif /* PANICBUTTON */
995 return;
996 }
997 /* panic?? */
998 printf("unexpected level 7 interrupt ignored\n");
999 }
1000
1001 /*
1002 * cpu_exec_aout_makecmds():
1003 * cpu-dependent a.out format hook for execve().
1004 *
1005 * Determine of the given exec package refers to something which we
1006 * understand and, if so, set up the vmcmds for it.
1007 *
1008 * XXX what are the special cases for the hp300?
1009 * XXX why is this COMPAT_NOMID? was something generating
1010 * hp300 binaries with an a_mid of 0? i thought that was only
1011 * done on little-endian machines... -- cgd
1012 */
1013 int
cpu_exec_aout_makecmds(struct lwp * l,struct exec_package * epp)1014 cpu_exec_aout_makecmds(struct lwp *l, struct exec_package *epp)
1015 {
1016 #if defined(COMPAT_NOMID) || defined(COMPAT_44)
1017 u_long midmag, magic;
1018 u_short mid;
1019 int error;
1020 struct exec *execp = epp->ep_hdr;
1021
1022 midmag = ntohl(execp->a_midmag);
1023 mid = (midmag >> 16) & 0xffff;
1024 magic = midmag & 0xffff;
1025
1026 midmag = mid << 16 | magic;
1027
1028 switch (midmag) {
1029 #ifdef COMPAT_NOMID
1030 case (MID_ZERO << 16) | ZMAGIC:
1031 error = exec_aout_prep_oldzmagic(l, epp);
1032 break;
1033 #endif
1034 #ifdef COMPAT_44
1035 case (MID_HP300 << 16) | ZMAGIC:
1036 error = exec_aout_prep_oldzmagic(l, epp);
1037 break;
1038 #endif
1039 default:
1040 error = ENOEXEC;
1041 }
1042
1043 return error;
1044 #else /* !(defined(COMPAT_NOMID) || defined(COMPAT_44)) */
1045 return ENOEXEC;
1046 #endif
1047 }
1048
1049 #ifdef MODULAR
1050 /*
1051 * Push any modules loaded by the bootloader etc.
1052 */
1053 void
module_init_md(void)1054 module_init_md(void)
1055 {
1056 }
1057 #endif
1058
1059 #ifdef EXTENDED_MEMORY
1060
1061 static const struct memlist {
1062 paddr_t exstart;
1063 psize_t minsize;
1064 psize_t maxsize;
1065 } memlist[] = {
1066 /* We define two extended memory regions for all possible settings. */
1067
1068 /*
1069 * The first region is at 0x01000000:
1070 *
1071 * TS-6BE16: 16MB at 0x01000000 (to 0x01FFFFFF)
1072 * XM6i: 4MB - 240MB at 0x01000000 (upto 0x0FFFFFFF)
1073 */
1074 { 0x01000000, 0x00400000, 0x0f000000 },
1075
1076 /*
1077 * The second region is at 0x10000000:
1078 *
1079 * 060turbo: 4MB - 128MB at 0x10000000 (upto 0x17FFFFFF)
1080 * XM6i: 4MB - 768MB at 0x10000000 (upto 0x3FFFFFFF)
1081 */
1082 { 0x10000000, 0x00400000, 0x30000000 },
1083 };
1084
1085 /* check each 4MB region */
1086 #define EXTMEM_RANGE (4 * 1024 * 1024)
1087
1088 /*
1089 * check memory existency
1090 */
1091 static bool
mem_exists(paddr_t mem,paddr_t basemax)1092 mem_exists(paddr_t mem, paddr_t basemax)
1093 {
1094 /* most variables must be register! */
1095 volatile unsigned char *m, *b;
1096 unsigned char save_m, save_b=0; /* XXX: shutup gcc */
1097 bool baseismem;
1098 bool exists = false;
1099 void *base;
1100 void *begin_check, *end_check;
1101 label_t faultbuf;
1102
1103 /*
1104 * In this function we assume:
1105 * - MMU is not enabled yet but PA == VA
1106 * (i.e. no RELOC() macro to convert PA to VA)
1107 * - bus error can be caught by setjmp()
1108 * (i.e. %vbr register is initialized properly)
1109 * - all memory cache is not enabled
1110 */
1111
1112 /* only 24bits are significant on normal X680x0 systems */
1113 base = (void *)(mem & 0x00FFFFFF);
1114
1115 m = (void *)mem;
1116 b = (void *)base;
1117
1118 /* This is somewhat paranoid -- avoid overwriting myself */
1119 __asm("lea %%pc@(begin_check_mem),%0" : "=a"(begin_check));
1120 __asm("lea %%pc@(end_check_mem),%0" : "=a"(end_check));
1121 if (base >= begin_check && base < end_check) {
1122 size_t off = (char *)end_check - (char *)begin_check;
1123
1124 m -= off;
1125 b -= off;
1126 }
1127
1128 nofault = (int *)&faultbuf;
1129 if (setjmp((label_t *)nofault)) {
1130 nofault = (int *)0;
1131 return false;
1132 }
1133
1134 (void)*m;
1135 /*
1136 * Can't check by writing if the corresponding
1137 * base address isn't memory.
1138 *
1139 * I hope this would be no harm....
1140 */
1141 baseismem = base < (void *)basemax;
1142
1143 __asm("begin_check_mem:");
1144 /* save original value (base must be saved first) */
1145 if (baseismem)
1146 save_b = *b;
1147 save_m = *m;
1148
1149 /*
1150 * stack and other data segment variables are unusable
1151 * til end_check_mem, because they may be clobbered.
1152 */
1153
1154 /*
1155 * check memory by writing/reading
1156 */
1157 if (baseismem)
1158 *b = 0x55;
1159 *m = 0xAA;
1160 if ((baseismem && *b != 0x55) || *m != 0xAA)
1161 goto out;
1162
1163 *m = 0x55;
1164 if (baseismem)
1165 *b = 0xAA;
1166 if (*m != 0x55 || (baseismem && *b != 0xAA))
1167 goto out;
1168
1169 exists = true;
1170 out:
1171 *m = save_m;
1172 if (baseismem)
1173 *b = save_b;
1174
1175 __asm("end_check_mem:");
1176
1177 nofault = (int *)0;
1178
1179 return exists;
1180 }
1181 #endif
1182
1183 void
setmemrange(void)1184 setmemrange(void)
1185 {
1186 #ifdef EXTENDED_MEMORY
1187 int i;
1188 paddr_t exstart, exend;
1189 psize_t size, minsize, maxsize;
1190 const struct memlist *mlist = memlist;
1191 paddr_t basemax = m68k_ptob(physmem);
1192 #endif
1193
1194 /*
1195 * VM system is not started yet, and even MMU is not enabled here.
1196 * We assume VA == PA and don't bother to use RELOC() macro
1197 * as pmap_bootstrap() does.
1198 */
1199
1200 /* save the original base memory range */
1201 basemem = physmem;
1202
1203 /*
1204 * XXX
1205 * Probably we should also probe the main memory region
1206 * for machines which might have a wrong value in a dead SRAM.
1207 */
1208 phys_basemem_seg.start = lowram;
1209 phys_basemem_seg.end = m68k_ptob(basemem) + lowram;
1210
1211 #ifdef EXTENDED_MEMORY
1212 /* discover extended memory */
1213 for (i = 0; i < __arraycount(memlist); i++) {
1214 exstart = mlist[i].exstart;
1215 minsize = mlist[i].minsize;
1216 maxsize = mlist[i].maxsize;
1217 /*
1218 * Normally, x68k hardware is NOT 32bit-clean.
1219 * But some type of extended memory is in 32bit address space.
1220 * Check whether.
1221 */
1222 if (!mem_exists(exstart, basemax))
1223 continue;
1224 exend = 0;
1225 /* range check */
1226 for (size = minsize; size <= maxsize; size += EXTMEM_RANGE) {
1227 if (!mem_exists(exstart + size - 4, basemax))
1228 break;
1229 exend = exstart + size;
1230 }
1231 if (exstart < exend) {
1232 phys_extmem_seg[i].start = exstart;
1233 phys_extmem_seg[i].end = exend;
1234 physmem += m68k_btop(exend - exstart);
1235 if (maxmem < m68k_btop(exend))
1236 maxmem = m68k_btop(exend);
1237 }
1238 }
1239 #endif
1240 }
1241
1242 volatile unsigned int intr_depth;
1243
1244 bool
cpu_intr_p(void)1245 cpu_intr_p(void)
1246 {
1247
1248 return intr_depth != 0;
1249 }
1250
1251 int
mm_md_physacc(paddr_t pa,vm_prot_t prot)1252 mm_md_physacc(paddr_t pa, vm_prot_t prot)
1253 {
1254 #ifdef EXTENDED_MEMORY
1255 int i;
1256 #endif
1257
1258 /* Main memory */
1259 if (phys_basemem_seg.start <= pa && pa < phys_basemem_seg.end)
1260 return 0;
1261
1262 #ifdef EXTENDED_MEMORY
1263 for (i = 0; i < EXTMEM_SEGS; i++) {
1264 if (phys_extmem_seg[i].start == phys_extmem_seg[i].end)
1265 continue;
1266 if (phys_extmem_seg[i].start <= pa &&
1267 pa < phys_extmem_seg[i].end) {
1268 return 0;
1269 }
1270 }
1271 #endif
1272
1273 /* I/O space */
1274 if (INTIOBASE <= pa && pa < INTIOTOP) {
1275 return kauth_authorize_machdep(kauth_cred_get(),
1276 KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL);
1277 }
1278
1279 return EFAULT;
1280 }
1281