xref: /netbsd-src/sys/arch/x68k/x68k/machdep.c (revision a7c95ef528cdc69beba8a7ca7bd0dfa555e1f4bd)
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