Home | History | Annotate | Line # | Download | only in atari
      1 /*	$NetBSD: machdep.c,v 1.209 2026/04/28 03:29:09 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 University of Utah.
      5  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
      6  * 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.63 91/04/24$
     37  *
     38  *	@(#)machdep.c	7.16 (Berkeley) 6/3/91
     39  */
     40 
     41 #include <sys/cdefs.h>
     42 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.209 2026/04/28 03:29:09 thorpej Exp $");
     43 
     44 #include "opt_ddb.h"
     45 #include "opt_mbtype.h"
     46 #include "opt_modular.h"
     47 #include "opt_panicbutton.h"
     48 
     49 #include <sys/param.h>
     50 #include <sys/systm.h>
     51 #include <sys/signalvar.h>
     52 #include <sys/kernel.h>
     53 #include <sys/proc.h>
     54 #include <sys/buf.h>
     55 #include <sys/reboot.h>
     56 #include <sys/conf.h>
     57 #include <sys/file.h>
     58 #include <sys/device.h>
     59 #include <sys/kmem.h>
     60 #include <sys/mbuf.h>
     61 #include <sys/msgbuf.h>
     62 #include <sys/vnode.h>
     63 #include <sys/queue.h>
     64 #include <sys/mount.h>
     65 #include <sys/syscallargs.h>
     66 #include <sys/ksyms.h>
     67 #include <sys/module.h>
     68 #include <sys/intr.h>
     69 #include <sys/exec.h>
     70 #include <sys/cpu.h>
     71 #include <sys/exec_elf.h>
     72 #include <sys/bus.h>
     73 
     74 #include <uvm/uvm_extern.h>
     75 
     76 #include <sys/sysctl.h>
     77 
     78 #include <machine/db_machdep.h>
     79 #include <ddb/db_sym.h>
     80 #include <ddb/db_extern.h>
     81 
     82 #include <machine/reg.h>
     83 #include <machine/psl.h>
     84 #include <machine/pte.h>
     85 
     86 #include <m68k/pcr.h>
     87 
     88 #include <dev/cons.h>
     89 #include <dev/mm.h>
     90 
     91 #include "ksyms.h"
     92 #include "nvr.h"
     93 
     94 #define	DEV_NVRAM	11	/* Nvram minor-number */
     95 
     96 static void call_sicallbacks(void);
     97 void	straymfpint(int, u_short);
     98 
     99 #ifdef _MILANHW_
    100 void	nmihandler(void);
    101 #endif
    102 
    103 extern  int   freebufspace;
    104 extern	u_int lowram;
    105 
    106 struct pmap_bootmap machine_bootmap[] = {
    107 	/* XXX */
    108 	{ .pmbm_vaddr = -1 },
    109 };
    110 
    111 /*
    112  * Console initialization: called early on from main,
    113  * before vm init or startup.  Do enough configuration
    114  * to choose and initialize a console.
    115  */
    116 void
    117 consinit(void)
    118 {
    119 	int i;
    120 
    121 	/*
    122 	 * Initialize error message buffer. pmap_bootstrap() has
    123 	 * positioned this at the end of kernel memory segment - map
    124 	 * and initialize it now.
    125 	 */
    126 	extern paddr_t msgbufpa;
    127 	for (i = 0; i < btoc(MSGBUFSIZE); i++)
    128 		pmap_kenter_pa((vaddr_t)msgbufaddr + i * PAGE_SIZE,
    129 		    msgbufpa + i * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, 0);
    130 	pmap_update(pmap_kernel());
    131 	initmsgbuf(msgbufaddr, m68k_round_page(MSGBUFSIZE));
    132 
    133 	/*
    134 	 * Initialize hardware that support various console types like
    135 	 * the grf and PCI busses.
    136 	 */
    137 	config_console();
    138 
    139 	/*
    140 	 * Now pick the best console candidate.
    141 	 */
    142 	cninit();
    143 
    144 #if NKSYMS || defined(DDB) || defined(MODULAR)
    145 	{
    146 		extern int end;
    147 		extern int *esym;
    148 
    149 		ksyms_addsyms_elf((int)esym - (int)&end - sizeof(Elf32_Ehdr),
    150 		    (void *)&end, esym);
    151 	}
    152 #endif
    153 #if defined (DDB)
    154 	if (boothowto & RB_KDB)
    155 		Debugger();
    156 #endif
    157 }
    158 
    159 vsize_t		mem_size;
    160 
    161 void
    162 machine_set_model(void)
    163 {
    164 	const char *mach;
    165 
    166 	switch (machineid & ATARI_ANYMACH) {
    167 	case ATARI_TT:
    168 		mach = "Atari TT";
    169 		break;
    170 	case ATARI_FALCON:
    171 		mach = "Atari Falcon";
    172 		break;
    173 	case ATARI_HADES:
    174 		mach = "Atari Hades";
    175 		break;
    176 	case ATARI_MILAN:
    177 		mach = "Atari Milan";
    178 		break;
    179 	default:
    180 		mach = "Atari UNKNOWN";
    181 		break;
    182 	}
    183 
    184 	cpu_setmodel("%s", mach);
    185 }
    186 
    187 /*
    188  * machine dependent system variables.
    189  */
    190 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
    191 {
    192 
    193 	sysctl_createv(clog, 0, NULL, NULL,
    194 		       CTLFLAG_PERMANENT,
    195 		       CTLTYPE_NODE, "machdep", NULL,
    196 		       NULL, 0, NULL, 0,
    197 		       CTL_MACHDEP, CTL_EOL);
    198 
    199 	sysctl_createv(clog, 0, NULL, NULL,
    200 		       CTLFLAG_PERMANENT,
    201 		       CTLTYPE_STRUCT, "console_device", NULL,
    202 		       sysctl_consdev, 0, NULL, sizeof(dev_t),
    203 		       CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
    204 }
    205 
    206 static vaddr_t	dumpspace;	/* Virt. space to map dumppages	*/
    207 
    208 /*
    209  * Reserve _virtual_ memory to map in the page to be dumped
    210  */
    211 vaddr_t
    212 reserve_dumppages(vaddr_t p)
    213 {
    214 
    215 	dumpspace = p;
    216 	return p + PAGE_SIZE;
    217 }
    218 
    219 uint32_t	dumpmag  = 0x8fca0101;	/* magic number for savecore	*/
    220 int		dumpsize = 0;		/* also for savecore (pages)	*/
    221 long		dumplo   = 0;		/* (disk blocks)		*/
    222 
    223 void
    224 cpu_dumpconf(void)
    225 {
    226 	int	nblks, i;
    227 
    228 	for (i = dumpsize = 0; i < NMEM_SEGS; i++) {
    229 		if (boot_segs[i].start == boot_segs[i].end)
    230 			break;
    231 		dumpsize += boot_segs[i].end - boot_segs[i].start;
    232 	}
    233 	dumpsize = btoc(dumpsize);
    234 
    235 	if (dumpdev != NODEV) {
    236 		nblks = bdev_size(dumpdev);
    237 		if (nblks > 0) {
    238 			if (dumpsize > btoc(dbtob(nblks - dumplo)))
    239 				dumpsize = btoc(dbtob(nblks - dumplo));
    240 			else if (dumplo == 0)
    241 				dumplo = nblks - btodb(ctob(dumpsize));
    242 		}
    243 	}
    244 	dumplo -= cpu_dumpsize();
    245 
    246 	/*
    247 	 * Don't dump on the first PAGE_SIZE (why PAGE_SIZE?)
    248 	 * in case the dump device includes a disk label.
    249 	 */
    250 	if (dumplo < btodb(PAGE_SIZE))
    251 		dumplo = btodb(PAGE_SIZE);
    252 }
    253 
    254 /*
    255  * Doadump comes here after turning off memory management and
    256  * getting on the dump stack, either when called above, or by
    257  * the auto-restart code.
    258  */
    259 void
    260 dumpsys(void)
    261 {
    262 	const struct bdevsw *bdev;
    263 	daddr_t	blkno;		/* Current block to write	*/
    264 	int	(*dump)(dev_t, daddr_t, void *, size_t);
    265 				/* Dumping function		*/
    266 	u_long	maddr;		/* PA being dumped		*/
    267 	int	segbytes;	/* Number of bytes in this seg.	*/
    268 	int	segnum;		/* Segment we are dumping	*/
    269 	int	nbytes;		/* Bytes left to dump		*/
    270 	int	i, n, error;
    271 
    272 	error = segnum = 0;
    273 	if (dumpdev == NODEV)
    274 		return;
    275 	bdev = bdevsw_lookup(dumpdev);
    276 	if (bdev == NULL)
    277 		return;
    278 	/*
    279 	 * For dumps during autoconfiguration,
    280 	 * if dump device has already configured...
    281 	 */
    282 	if (dumpsize == 0)
    283 		cpu_dumpconf();
    284 	if (dumplo <= 0) {
    285 		printf("\ndump to dev %u,%u not possible\n",
    286 		    major(dumpdev), minor(dumpdev));
    287 		return;
    288 	}
    289 	printf("\ndumping to dev %u,%u offset %ld\n",
    290 	    major(dumpdev), minor(dumpdev), dumplo);
    291 
    292 #if defined(DDB) || defined(PANICWAIT)
    293 	printf("Do you want to dump memory? [y]");
    294 	cnpollc(true);
    295 	i = cngetc();
    296 	cnpollc(false);
    297 	cnputc(i);
    298 	switch (i) {
    299 	case 'n':
    300 	case 'N':
    301 		return;
    302 	case '\n':
    303 		break;
    304 	default :
    305 		cnputc('\n');
    306 	}
    307 #endif /* defined(DDB) || defined(PANICWAIT) */
    308 
    309 	maddr    = 0;
    310 	segbytes = boot_segs[0].end;
    311 	blkno    = dumplo;
    312 	dump     = bdev->d_dump;
    313 	nbytes   = dumpsize * PAGE_SIZE;
    314 
    315 	printf("dump ");
    316 
    317 	error = cpu_dump(dump, &blkno);
    318 	if (!error) {
    319 		for (i = 0; i < nbytes; i += n, segbytes -= n) {
    320 			/*
    321 			 * Skip the hole
    322 			 */
    323 			if (segbytes == 0) {
    324 				segnum++;
    325 				maddr    = boot_segs[segnum].start;
    326 				segbytes = boot_segs[segnum].end -
    327 				    boot_segs[segnum].start;
    328 			}
    329 			/*
    330 			 * Print Mb's to go
    331 			 */
    332 			n = nbytes - i;
    333 			if (n && (n % (1024 * 1024)) == 0)
    334 				printf_nolog("%d ", n / (1024 * 1024));
    335 
    336 			/*
    337 			 * Limit transfer to PAGE_SIZE
    338 			 */
    339 			if (n > PAGE_SIZE)
    340 				n = PAGE_SIZE;
    341 
    342 			/*
    343 			 * Map to a VA and write it
    344 			 */
    345 			if (maddr != 0) { /* XXX kvtop chokes on this	*/
    346 				pmap_enter(pmap_kernel(), dumpspace, maddr,
    347 				    VM_PROT_READ, VM_PROT_READ|PMAP_WIRED);
    348 				pmap_update(pmap_kernel());
    349 				error = (*dump)(dumpdev, blkno,
    350 				    (void *)dumpspace, n);
    351 				if (error)
    352 					break;
    353 			}
    354 
    355 			maddr += n;
    356 			blkno += btodb(n);
    357 		}
    358 	}
    359 	switch (error) {
    360 
    361 	case ENXIO:
    362 		printf("device bad\n");
    363 		break;
    364 
    365 	case EFAULT:
    366 		printf("device not ready\n");
    367 		break;
    368 
    369 	case EINVAL:
    370 		printf("area improper\n");
    371 		break;
    372 
    373 	case EIO:
    374 		printf("i/o error\n");
    375 		break;
    376 
    377 	default:
    378 		printf("succeeded\n");
    379 		break;
    380 	}
    381 	printf("\n\n");
    382 	delay(5000000);		/* 5 seconds */
    383 }
    384 
    385 void
    386 straymfpint(int pc, u_short evec)
    387 {
    388 
    389 	printf("unexpected mfp-interrupt (vector offset 0x%x) from 0x%x\n",
    390 	       evec & 0xFFF, pc);
    391 }
    392 
    393 /*
    394  * this is a handy package to have asynchronously executed
    395  * function calls executed at very low interrupt priority.
    396  * Example for use is keyboard repeat, where the repeat
    397  * handler running at splclock() triggers such a (hardware
    398  * aided) software interrupt.
    399  * Note: the installed functions are currently called in a
    400  * LIFO fashion, might want to change this to FIFO
    401  * later.
    402  *
    403  * XXX: Some of functions which use this callback should be rewritten
    404  * XXX: to use MI softintr(9) directly.
    405  */
    406 struct si_callback {
    407 	struct si_callback *next;
    408 	void (*function)(void *rock1, void *rock2);
    409 	void *rock1, *rock2;
    410 };
    411 static void *si_callback_cookie;
    412 static struct si_callback *si_callbacks;
    413 static struct si_callback *si_free;
    414 #ifdef DIAGNOSTIC
    415 static int ncbd;	/* number of callback blocks dynamically allocated */
    416 #endif
    417 
    418 void
    419 init_sicallback(void)
    420 {
    421 
    422 	si_callback_cookie = softint_establish(SOFTINT_NET,
    423 	    (void (*)(void *))call_sicallbacks, NULL);
    424 }
    425 
    426 void
    427 add_sicallback(void (*function)(void *, void *), void *rock1, void *rock2)
    428 {
    429 	struct si_callback *si;
    430 	int s;
    431 
    432 	/*
    433 	 * this function may be called from high-priority interrupt handlers.
    434 	 * We may NOT block for  memory-allocation in here!.
    435 	 */
    436 	s = splhigh();
    437 	if ((si = si_free) != NULL)
    438 		si_free = si->next;
    439 	splx(s);
    440 
    441 	if (si == NULL) {
    442 		si = kmem_intr_alloc(sizeof(*si), KM_NOSLEEP);
    443 #ifdef DIAGNOSTIC
    444 		if (si)
    445 			++ncbd;		/* count # dynamically allocated */
    446 #endif
    447 		if (si == NULL)
    448 			return;
    449 	}
    450 
    451 	si->function = function;
    452 	si->rock1    = rock1;
    453 	si->rock2    = rock2;
    454 
    455 	s = splhigh();
    456 	si->next     = si_callbacks;
    457 	si_callbacks = si;
    458 	splx(s);
    459 
    460 	/*
    461 	 * and cause a software interrupt (spl1). This interrupt might
    462 	 * happen immediately, or after returning to a safe enough level.
    463 	 *
    464 	 * XXX:
    465 	 * According to <machine/scu.h> and lev1intr() handler in locore.s,
    466 	 * at least _ATARIHW_ machines (ATARITT and HADES?) seem to have
    467 	 * some hardware support which can initiate real hardware interrupt
    468 	 * at ipl 1 for software interrupt. But as per <machine/mtpr.h>,
    469 	 * this feature was not used at all on setsoft*() calls and
    470 	 * traditional hp300 derived ssir (simulated software interrupt
    471 	 * request) on VAX REI emulation in locore.s is used.
    472 	 */
    473 	softint_schedule(si_callback_cookie);
    474 }
    475 
    476 void
    477 rem_sicallback(void (*function)(void *rock1, void *rock2))
    478 {
    479 	struct si_callback *si, *psi, *nsi;
    480 	int s;
    481 
    482 	s = splhigh();
    483 	for (psi = 0, si = si_callbacks; si; ) {
    484 		nsi = si->next;
    485 
    486 		if (si->function != function)
    487 			psi = si;
    488 		else {
    489 			si->next = si_free;
    490 			si_free  = si;
    491 			if (psi != NULL)
    492 				psi->next = nsi;
    493 			else
    494 				si_callbacks = nsi;
    495 		}
    496 		si = nsi;
    497 	}
    498 	splx(s);
    499 }
    500 
    501 /* purge the list */
    502 static void
    503 call_sicallbacks(void)
    504 {
    505 	struct si_callback *si;
    506 	int s;
    507 	void *rock1, *rock2;
    508 	void (*function)(void *, void *);
    509 
    510 	do {
    511 		s = splhigh();
    512 		if ((si = si_callbacks) != NULL)
    513 			si_callbacks = si->next;
    514 		splx(s);
    515 
    516 		if (si != NULL) {
    517 			function = si->function;
    518 			rock1    = si->rock1;
    519 			rock2    = si->rock2;
    520 			s = splhigh();
    521 			if (si_callbacks)
    522 				softint_schedule(si_callback_cookie);
    523 			si->next = si_free;
    524 			si_free  = si;
    525 			splx(s);
    526 
    527 			/*
    528 			 * Raise spl for BASEPRI() checks to see
    529 			 * nested interrupts in some drivers using callbacks
    530 			 * since modern MI softint(9) doesn't seem to do it
    531 			 * in !__HAVE_FAST_SOFTINTS case.
    532 			 *
    533 			 * XXX: This is just a workaround hack.
    534 			 *      Each driver should raise spl in its handler
    535 			 *      to avoid nested interrupts if necessary.
    536 			 */
    537 			s = splsoftnet();	/* XXX */
    538 			function(rock1, rock2);
    539 			splx(s);
    540 		}
    541 	} while (si != NULL);
    542 #ifdef DIAGNOSTIC
    543 	if (ncbd) {
    544 #ifdef DEBUG
    545 		printf("call_sicallback: %d more dynamic structures\n", ncbd);
    546 #endif
    547 		ncbd = 0;
    548 	}
    549 #endif
    550 }
    551 
    552 #if defined(DEBUG) && !defined(PANICBUTTON)
    553 #define PANICBUTTON
    554 #endif
    555 
    556 #ifdef PANICBUTTON
    557 int panicbutton = 1;	/* non-zero if panic buttons are enabled */
    558 int crashandburn = 0;
    559 int candbdelay = 50;	/* give em half a second */
    560 
    561 void candbtimer(void);
    562 
    563 void
    564 candbtimer(void)
    565 {
    566 
    567 	crashandburn = 0;
    568 }
    569 #endif
    570 
    571 #ifdef _MILANHW_
    572 
    573 /*
    574  * Currently the only source of NMI interrupts on the Milan is the PLX9080.
    575  * On access errors to the PCI bus, an NMI is generated. This NMI is shorted
    576  * in locore in case of a PCI config cycle to a non-existing address to allow
    577  * for probes. On other occasions, it ShouldNotHappen(TM).
    578  * Note: The handler in locore clears the errors, to make further PCI access
    579  * possible.
    580  */
    581 void
    582 nmihandler(void)
    583 {
    584 	extern unsigned long	plx_status;
    585 
    586 	printf("nmihandler: plx_status = 0x%08lx\n", plx_status);
    587 }
    588 #endif
    589 
    590 int
    591 mm_md_physacc(paddr_t pa, vm_prot_t prot)
    592 {
    593 	struct memseg *ms;
    594 
    595 	for (ms = boot_segs; ms->start != ms->end; ms++) {
    596 		if ((pa >= ms->start) && (pa < ms->end))
    597 			return 0;
    598 	}
    599 	return EFAULT;
    600 }
    601 
    602 int
    603 mm_md_readwrite(dev_t dev, struct uio *uio)
    604 {
    605 	switch (minor(dev)) {
    606 	case DEV_NVRAM:
    607 #if NNVR > 0
    608 		return nvram_uio(uio);
    609 #else
    610 		return ENXIO;
    611 #endif
    612 	default:
    613 		return ENXIO;
    614 	}
    615 }
    616