Home | History | Annotate | Line # | Download | only in sun3x
      1 /*	$NetBSD: machdep.c,v 1.154 2026/04/28 03:29:11 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  *	from: @(#)machdep.c	8.10 (Berkeley) 4/20/94
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.154 2026/04/28 03:29:11 thorpej Exp $");
     42 
     43 #include "opt_ddb.h"
     44 #include "opt_kgdb.h"
     45 #include "opt_modular.h"
     46 
     47 #include <sys/param.h>
     48 #include <sys/systm.h>
     49 #include <sys/kernel.h>
     50 #include <sys/proc.h>
     51 #include <sys/buf.h>
     52 #include <sys/reboot.h>
     53 #include <sys/conf.h>
     54 #include <sys/file.h>
     55 #include <sys/device.h>
     56 #include <sys/mbuf.h>
     57 #include <sys/msgbuf.h>
     58 #include <sys/ioctl.h>
     59 #include <sys/tty.h>
     60 #include <sys/mount.h>
     61 #include <sys/exec.h>
     62 #include <sys/core.h>
     63 #include <sys/kcore.h>
     64 #include <sys/vnode.h>
     65 #include <sys/syscallargs.h>
     66 #include <sys/ksyms.h>
     67 #include <sys/module.h>
     68 #include <sys/cpu.h>
     69 #ifdef	KGDB
     70 #include <sys/kgdb.h>
     71 #endif
     72 
     73 #include <uvm/uvm_extern.h>
     74 
     75 #include <sys/sysctl.h>
     76 
     77 #include <dev/cons.h>
     78 #include <dev/mm.h>
     79 
     80 #include <machine/cpu.h>
     81 #include <machine/dvma.h>
     82 #include <machine/idprom.h>
     83 #include <machine/kcore.h>
     84 #include <machine/reg.h>
     85 #include <machine/pcb.h>
     86 #include <machine/psl.h>
     87 #include <machine/pte.h>
     88 #include <machine/mon.h>
     89 
     90 #if defined(DDB)
     91 #include <machine/db_machdep.h>
     92 #include <ddb/db_sym.h>
     93 #include <ddb/db_extern.h>
     94 #endif
     95 
     96 #include <sun3/sun3/machdep.h>
     97 
     98 #include "ksyms.h"
     99 
    100 /* Defined in locore.s */
    101 extern char kernel_text[];
    102 /* Defined by the linker */
    103 extern char etext[];
    104 
    105 /* kernel_arch specific values required by module(9) */
    106 const vaddr_t kernbase = KERNBASE3X;
    107 const vaddr_t kern_end = KERN_END3X;
    108 
    109 extern void *msgbufaddr;
    110 
    111 /* Virtual page frame for /dev/mem (see mem.c) */
    112 vaddr_t vmmap;
    113 
    114 u_char cpu_machine_id = 0;
    115 const char *cpu_string = NULL;
    116 int cpu_has_vme = 0;
    117 int has_iocache = 0;
    118 
    119 vaddr_t dumppage;
    120 
    121 int	delay_divisor = delay_divisor_est(33); /* assume fastest 33Hz */
    122 char	kernel_arch[16] = "sun3x";	/* XXX needs a sysctl node */
    123 
    124 static void initcpu(void);
    125 
    126 /*
    127  * Console initialization: called early on from main,
    128  * before vm init or cpu_startup.  This system is able
    129  * to use the console for output immediately (via PROM)
    130  * but can not use it for input until after this point.
    131  */
    132 void
    133 consinit(void)
    134 {
    135 
    136 	/*
    137 	 * Switch from the PROM console (output only)
    138 	 * to our own console driver.
    139 	 */
    140 	cninit();
    141 
    142 #if NKSYMS || defined(DDB) || defined(MODULAR)
    143 	{
    144 		extern int nsym;
    145 		extern char *ssym, *esym;
    146 
    147 		ksyms_addsyms_elf(nsym, ssym, esym);
    148 	}
    149 #endif	/* DDB */
    150 
    151 	/*
    152 	 * Now that the console can do input as well as
    153 	 * output, consider stopping for a debugger.
    154 	 */
    155 	if (boothowto & RB_KDB) {
    156 #ifdef KGDB
    157 		/* XXX - Ask on console for kgdb_dev? */
    158 		/* Note: this will just return if kgdb_dev==NODEV */
    159 		kgdb_connect(1);
    160 #else	/* KGDB */
    161 		/* Either DDB or no debugger (just PROM). */
    162 		Debugger();
    163 #endif	/* KGDB */
    164 	}
    165 }
    166 
    167 /*
    168  * cpu_startup: allocate memory for variable-sized tables,
    169  * initialize CPU, and do autoconfiguration.
    170  *
    171  * This is called early in init_main.c:main(), after the
    172  * kernel memory allocator is ready for use, but before
    173  * the creation of processes 1,2, and mountroot, etc.
    174  */
    175 void
    176 cpu_startup(void)
    177 {
    178 	/* Set the FPU bit in the "system enable register" */
    179 	enable_fpu(1);
    180 
    181 	/*
    182 	 * Get scratch page for dumpsys().
    183 	 */
    184 	dumppage = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_WIRED);
    185 	if (dumppage == 0)
    186 		panic("startup: alloc dumppage");
    187 
    188 	cpu_startup_common();
    189 
    190 	/*
    191 	 * Allocate a virtual page (for use by /dev/mem)
    192 	 * This page is handed to pmap_enter() therefore
    193 	 * it has to be in the normal kernel VA range.
    194 	 */
    195 	vmmap = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
    196 	    UVM_KMF_VAONLY | UVM_KMF_WAITVA);
    197 
    198 	/*
    199 	 * Create the DVMA maps.
    200 	 */
    201 	dvma_init();
    202 
    203 	/*
    204 	 * Set up CPU-specific registers, cache, etc.
    205 	 */
    206 	initcpu();
    207 
    208 	if (fputype == FPU_NONE) {
    209 		/* Might as well turn the enable bit back off. */
    210 		enable_fpu(0);
    211 	}
    212 }
    213 
    214 void
    215 machine_set_model(void)
    216 {
    217 	u_char machtype = identity_prom.idp_machtype;
    218 	if ((machtype & IDM_ARCH_MASK) != IDM_ARCH_SUN3X) {
    219 		printf("Bad IDPROM arch!\n");
    220 		sunmon_abort();
    221 	}
    222 
    223 	cpu_machine_id = machtype;
    224 	switch (cpu_machine_id) {
    225 
    226 	case ID_SUN3X_80:
    227 		cpu_string = "80";  	/* Hydra */
    228 		cpuspeed_khz = 20000;
    229 		delay_divisor = delay_divisor_est(20);
    230 		cpu_has_vme = false;
    231 		break;
    232 
    233 	case ID_SUN3X_470:
    234 		cpu_string = "470"; 	/* Pegasus */
    235 		cpuspeed_khz = 33000;
    236 		delay_divisor = delay_divisor_est(33);
    237 		cpu_has_vme = true;
    238 		break;
    239 
    240 	default:
    241 		printf("unknown sun3x model\n");
    242 		sunmon_abort();
    243 	}
    244 
    245 	sun68k_set_model();
    246 }
    247 
    248 /*
    249  * machine dependent system variables.
    250  */
    251 #if 0   /* XXX - Not yet... */
    252 static int
    253 sysctl_machdep_root_device(SYSCTLFN_ARGS)
    254 {
    255 	struct sysctlnode node = *rnode;
    256 
    257 	node.sysctl_data = some permutation on root_device;
    258 	node.sysctl_size = strlen(root_device) + 1;
    259 	return (sysctl_lookup(SYSCTLFN_CALL(&node)));
    260 }
    261 
    262 static int
    263 sysctl_machdep_booted_kernel(SYSCTLFN_ARGS)
    264 {
    265 	struct sysctlnode node = *rnode;
    266 
    267 	node.sysctl_data = some permutation on booted_kernel;
    268 	node.sysctl_size = strlen(booted_kernel) + 1;
    269 	return (sysctl_lookup(SYSCTLFN_CALL(&node)));
    270 }
    271 #endif
    272 
    273 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
    274 {
    275 
    276 	sysctl_createv(clog, 0, NULL, NULL,
    277 		       CTLFLAG_PERMANENT,
    278 		       CTLTYPE_NODE, "machdep", NULL,
    279 		       NULL, 0, NULL, 0,
    280 		       CTL_MACHDEP, CTL_EOL);
    281 
    282 	sysctl_createv(clog, 0, NULL, NULL,
    283 		       CTLFLAG_PERMANENT,
    284 		       CTLTYPE_STRUCT, "console_device", NULL,
    285 		       sysctl_consdev, 0, NULL, sizeof(dev_t),
    286 		       CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
    287 #if 0 /* XXX - Not yet... */
    288 	sysctl_createv(clog, 0, NULL, NULL,
    289 		       CTLFLAG_PERMANENT,
    290 		       CTLTYPE_STRING, "root_device", NULL,
    291 		       sysctl_machdep_root_device, 0, NULL, 0,
    292 		       CTL_MACHDEP, CPU_ROOT_DEVICE, CTL_EOL);
    293 	sysctl_createv(clog, 0, NULL, NULL,
    294 		       CTLFLAG_PERMANENT,
    295 		       CTLTYPE_STRING, "booted_kernel", NULL,
    296 		       sysctl_machdep_booted_kernel, 0, NULL, 0,
    297 		       CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL);
    298 #endif
    299 }
    300 
    301 void
    302 machine_halt(void)
    303 {
    304 	sunmon_halt();
    305 }
    306 
    307 void
    308 machine_reboot(int howto, char *user_bootstr)
    309 {
    310 	static char bootstr[128];	/* N.B. MUST BE STATIC */
    311 	char *p;
    312 
    313 	if (user_bootstr != NULL) {
    314 		strlcpy(bootstr, user_bootstr, sizeof(bootstr));
    315 	} else {
    316 		/*
    317 		 * Build our own boot string with an empty
    318 		 * boot device/file and (maybe) some flags.
    319 		 * The PROM will supply the device/file name.
    320 		 */
    321 		p = bootstr;
    322 		*p = '\0';
    323 
    324 		if (howto & (RB_KDB|RB_ASKNAME|RB_SINGLE)) {
    325 			/* Append the boot flags. */
    326 			*p++ = ' ';
    327 			*p++ = '-';
    328 			if (howto & RB_KDB)
    329 				*p++ = 'd';
    330 			if (howto & RB_ASKNAME)
    331 				*p++ = 'a';
    332 			if (howto & RB_SINGLE)
    333 				*p++ = 's';
    334 			*p = '\0';
    335 		}
    336 	}
    337 	sunmon_reboot(bootstr);
    338 }
    339 
    340 /*
    341  * These variables are needed by /sbin/savecore
    342  */
    343 uint32_t dumpmag = 0x8fca0101;	/* magic number */
    344 int 	dumpsize = 0;		/* pages */
    345 long	dumplo = 0; 		/* blocks */
    346 
    347 #define DUMP_EXTRA	1	/* CPU-dependent extra pages */
    348 
    349 /*
    350  * This is called by main to set dumplo, dumpsize.
    351  * Dumps always skip the first PAGE_SIZE of disk space
    352  * in case there might be a disk label stored there.
    353  * If there is extra space, put dump at the end to
    354  * reduce the chance that swapping trashes it.
    355  */
    356 void
    357 cpu_dumpconf(void)
    358 {
    359 	int devblks;	/* size of dump device in blocks */
    360 	int dumpblks;	/* size of dump image in blocks */
    361 
    362 	if (dumpdev == NODEV)
    363 		return;
    364 
    365 	devblks = bdev_size(dumpdev);
    366 	if (devblks <= ctod(1))
    367 		return;
    368 	devblks &= ~(ctod(1) - 1);
    369 
    370 	/*
    371 	 * Note: savecore expects dumpsize to be the
    372 	 * number of pages AFTER the dump header.
    373 	 */
    374 	dumpsize = physmem; 	/* pages */
    375 
    376 	/* Position dump image near end of space, page aligned. */
    377 	dumpblks = ctod(physmem + DUMP_EXTRA);
    378 	dumplo = devblks - dumpblks;
    379 
    380 	/* If it does not fit, truncate it by moving dumplo. */
    381 	/* Note: Must force signed comparison. */
    382 	if (dumplo < ((long)ctod(1))) {
    383 		dumplo = ctod(1);
    384 		dumpsize = dtoc(devblks - dumplo) - DUMP_EXTRA;
    385 	}
    386 }
    387 
    388 /* Note: gdb looks for "dumppcb" in a kernel crash dump. */
    389 struct pcb dumppcb;
    390 
    391 /*
    392  * Write a crash dump.  The format while in swap is:
    393  *   kcore_seg_t cpu_hdr;
    394  *   cpu_kcore_hdr_t cpu_data;
    395  *   padding (PAGE_SIZE-sizeof(kcore_seg_t))
    396  *   pagemap (2*PAGE_SIZE)
    397  *   physical memory...
    398  */
    399 void
    400 dumpsys(void)
    401 {
    402 	const struct bdevsw *dsw;
    403 	kcore_seg_t *kseg_p;
    404 	cpu_kcore_hdr_t *chdr_p;
    405 	struct sun3x_kcore_hdr *sh;
    406 	phys_ram_seg_t *crs_p;
    407 	char *vaddr;
    408 	paddr_t paddr;
    409 	int psize, todo, seg, segsz;
    410 	daddr_t blkno;
    411 	int error = 0;
    412 
    413 	if (dumpdev == NODEV)
    414 		return;
    415 	dsw = bdevsw_lookup(dumpdev);
    416 	if (dsw == NULL || dsw->d_psize == NULL)
    417 		return;
    418 
    419 	/*
    420 	 * For dumps during autoconfiguration,
    421 	 * if dump device has already configured...
    422 	 */
    423 	if (dumpsize == 0)
    424 		cpu_dumpconf();
    425 	if (dumplo <= 0) {
    426 		printf("\ndump to dev %u,%u not possible\n",
    427 		    major(dumpdev), minor(dumpdev));
    428 		return;
    429 	}
    430 	savectx(&dumppcb);
    431 
    432 	psize = bdev_size(dumpdev);
    433 	if (psize == -1) {
    434 		printf("dump area unavailable\n");
    435 		return;
    436 	}
    437 
    438 	printf("\ndumping to dev %u,%u offset %ld\n",
    439 	    major(dumpdev), minor(dumpdev), dumplo);
    440 
    441 	/*
    442 	 * Prepare the dump header
    443 	 */
    444 	blkno = dumplo;
    445 	todo = dumpsize;	/* pages */
    446 	vaddr = (char *)dumppage;
    447 	memset(vaddr, 0, PAGE_SIZE);
    448 
    449 	/* Set pointers to all three parts. */
    450 	kseg_p = (kcore_seg_t *)vaddr;
    451 	chdr_p = (cpu_kcore_hdr_t *)(kseg_p + 1);
    452 	sh = &chdr_p->un._sun3x;
    453 
    454 	/* Fill in kcore_seg_t part. */
    455 	CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
    456 	kseg_p->c_size = (ctob(DUMP_EXTRA) - sizeof(*kseg_p));
    457 
    458 	/* Fill in cpu_kcore_hdr_t part. */
    459 	strncpy(chdr_p->name, kernel_arch, sizeof(chdr_p->name));
    460 	chdr_p->page_size = PAGE_SIZE;
    461 	chdr_p->kernbase = KERNBASE3X;
    462 
    463 	/* Fill in the sun3x_kcore_hdr part. */
    464 	pmap_kcore_hdr(sh);
    465 
    466 	/* Write out the dump header. */
    467 	error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE);
    468 	if (error)
    469 		goto fail;
    470 	blkno += btodb(PAGE_SIZE);
    471 
    472 	/*
    473 	 * Now dump physical memory.  Note that physical memory
    474 	 * might NOT be contiguous, so do it by segments.
    475 	 */
    476 
    477 	vaddr = (char *)vmmap;	/* Borrow /dev/mem VA */
    478 
    479 	for (seg = 0; seg < SUN3X_NPHYS_RAM_SEGS; seg++) {
    480 		crs_p = &sh->ram_segs[seg];
    481 		paddr = crs_p->start;
    482 		segsz = crs_p->size;
    483 
    484 		while (todo && (segsz > 0)) {
    485 
    486 			/* Print pages left after every 16. */
    487 			if ((todo & 0xf) == 0)
    488 				printf_nolog("\r%4d", todo);
    489 
    490 			/* Make a temporary mapping for the page. */
    491 			pmap_kenter_pa(vmmap, paddr | PMAP_NC, VM_PROT_READ, 0);
    492 			pmap_update(pmap_kernel());
    493 			error = (*dsw->d_dump)(dumpdev, blkno, vaddr,
    494 					       PAGE_SIZE);
    495 			pmap_kremove(vmmap, PAGE_SIZE);
    496 			pmap_update(pmap_kernel());
    497 			if (error)
    498 				goto fail;
    499 			paddr += PAGE_SIZE;
    500 			segsz -= PAGE_SIZE;
    501 			blkno += btodb(PAGE_SIZE);
    502 			todo--;
    503 		}
    504 	}
    505 	printf("\rdump succeeded\n");
    506 	return;
    507 fail:
    508 	printf(" dump error=%d\n", error);
    509 }
    510 
    511 static void
    512 initcpu(void)
    513 {
    514 	/* XXX: Enable RAM parity/ECC checking? */
    515 	/* XXX: parityenable(); */
    516 
    517 #ifdef	HAVECACHE
    518 	cache_enable();
    519 #endif
    520 }
    521 
    522 /* straptrap() in trap.c */
    523 
    524 /* from hp300: badaddr() */
    525 /* peek_byte(), peek_word() moved to bus_subr.c */
    526 
    527 /* XXX: parityenable() ? */
    528 /* regdump() moved to regdump.c */
    529 
    530 bool
    531 mm_md_direct_mapped_phys(paddr_t paddr, vaddr_t *vaddr)
    532 {
    533 	extern paddr_t avail_start;
    534 
    535 	if (paddr >= avail_start)
    536 		return false;
    537 	*vaddr = KERNBASE3X + paddr;
    538 	return true;
    539 }
    540 
    541 /*
    542  * Allow access to the PROM mapping similar to uvm_kernacc().
    543  */
    544 int
    545 mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled)
    546 {
    547 
    548 	if ((vaddr_t)ptr < SUN3X_PROM_BASE || (vaddr_t)ptr > SUN3X_MONEND) {
    549 		*handled = false;
    550 		return 0;
    551 	}
    552 
    553 	*handled = true;
    554 	/* Read in the PROM itself is OK. */
    555 	if ((prot & VM_PROT_WRITE) == 0)
    556 		return 0;
    557 
    558 	/* PROM data page is OK for read/write. */
    559 	if ((vaddr_t)ptr >= SUN3X_MONDATA &&
    560 	    (vaddr_t)ptr < SUN3X_MONDATA + PAGE_SIZE)
    561 		return 0;
    562 	return EFAULT;
    563 }
    564