Home | History | Annotate | Line # | Download | only in sun3
      1 /*	$NetBSD: locore2.c,v 1.109 2026/04/23 02:54:40 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Adam Glass and Gordon W. Ross.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: locore2.c,v 1.109 2026/04/23 02:54:40 thorpej Exp $");
     34 
     35 #include "opt_ddb.h"
     36 #include "opt_modular.h"
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/proc.h>
     41 #include <sys/reboot.h>
     42 #define ELFSIZE 32
     43 #include <sys/exec_elf.h>
     44 
     45 #include <uvm/uvm_extern.h>
     46 
     47 #include <dev/cons.h>
     48 
     49 #include <machine/cpu.h>
     50 #include <machine/db_machdep.h>
     51 #include <machine/dvma.h>
     52 #include <machine/fcode.h>
     53 #include <machine/idprom.h>
     54 #include <machine/leds.h>
     55 #include <machine/mon.h>
     56 #include <machine/pmap.h>
     57 #include <machine/pte.h>
     58 #include <machine/vectors.h>
     59 
     60 #include <sun3/sun3/control.h>
     61 #include <sun3/sun3/interreg.h>
     62 #include <sun3/sun3/machdep.h>
     63 #include <sun3/sun3/obmem.h>
     64 
     65 #include "ksyms.h"
     66 
     67 /* This is defined in locore.s */
     68 extern char kernel_text[];
     69 
     70 /* These are defined by the linker */
     71 extern char etext[], edata[], end[];
     72 int nsym;
     73 char *ssym, *esym;
     74 
     75 /* Basically a flag: "Do we have a VAC?" */
     76 int cache_size;
     77 
     78 /*
     79  * XXX: m68k common code needs these...
     80  * ... but this port does not need to deal with anything except
     81  * an mc68020, so these two variables are always ignored.
     82  */
     83 int cputype = CPU_68020;
     84 int mmutype = MMU_SUN;
     85 
     86 /*
     87  * Now our own stuff.
     88  */
     89 
     90 u_char cpu_machine_id = 0;
     91 const char *cpu_string;
     92 int cpu_has_vme = 0;
     93 
     94 int delay_divisor = delay_divisor_est(25); /* assume the fastest (3/260) */
     95 
     96 extern struct pcb *curpcb;
     97 
     98 /* First C code called by locore.s */
     99 void *_bootstrap(void);
    100 
    101 #if NKSYMS || defined(DDB) || defined(MODULAR)
    102 /*
    103  * Preserve DDB symbols and strings by setting esym.
    104  */
    105 static void
    106 _save_symtab(void)
    107 {
    108 	int i;
    109 	Elf_Ehdr *ehdr;
    110 	Elf_Shdr *shp;
    111 	vaddr_t minsym, maxsym;
    112 
    113 	/*
    114 	 * Check the ELF headers.
    115 	 */
    116 
    117 	ehdr = (void *)end;
    118 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 ||
    119 	    ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
    120 		mon_printf("_save_symtab: bad ELF magic\n");
    121 		return;
    122 	}
    123 
    124 	/*
    125 	 * Find the end of the symbols and strings.
    126 	 */
    127 
    128 	maxsym = 0;
    129 	minsym = ~maxsym;
    130 	shp = (Elf_Shdr *)(end + ehdr->e_shoff);
    131 	for (i = 0; i < ehdr->e_shnum; i++) {
    132 		if (shp[i].sh_type != SHT_SYMTAB &&
    133 		    shp[i].sh_type != SHT_STRTAB) {
    134 			continue;
    135 		}
    136 		minsym = uimin(minsym, (vaddr_t)end + shp[i].sh_offset);
    137 		maxsym = uimax(maxsym, (vaddr_t)end + shp[i].sh_offset +
    138 			     shp[i].sh_size);
    139 	}
    140 
    141 	/*
    142 	 * The Sun3/50 has further restrictions on the
    143 	 * size of the kernel boot image.  If preserving
    144 	 * the symbol table would take us over the limit,
    145 	 * then just ignore the symbols.
    146 	 */
    147 
    148 	if ((cpu_machine_id == ID_SUN3_50) &&
    149 	    ((vaddr_t)maxsym > (KERNBASE3 + OBMEM_BW50_ADDR - USPACE))) {
    150 		mon_printf("_save_symtab: too large for 3/50");
    151 		return;
    152 	}
    153 
    154 	nsym = 1;
    155 	ssym = (char *)ehdr;
    156 	esym = (char *)maxsym;
    157 }
    158 #endif	/* DDB */
    159 
    160 /*
    161  * This function is called from _bootstrap() to initialize
    162  * pre-vm-system virtual memory.  All this really does is to
    163  * set virtual_avail to the first page following preloaded
    164  * data (i.e. the kernel and its symbol table) and special
    165  * things that may be needed very early (lwp0 upages).
    166  * Once that is done, pmap_bootstrap() is called to do the
    167  * usual preparations for our use of the MMU.
    168  *
    169  * Returns the new kernel %sp value for lwp0.
    170  */
    171 static void *
    172 _vm_init(void)
    173 {
    174 	vaddr_t nextva;
    175 	paddr_t nextpa;
    176 
    177 	/*
    178 	 * First preserve our symbol table, which might have been
    179 	 * loaded after our BSS area by the boot loader.  However,
    180 	 * if DDB is not part of this kernel, ignore the symbols.
    181 	 */
    182 	esym = end + 4;
    183 #if NKSYMS || defined(DDB) || defined(MODULAR)
    184 	/* This will advance esym past the symbols. */
    185 	_save_symtab();
    186 #endif
    187 
    188 	/*
    189 	 * Steal some special-purpose, already mapped pages.
    190 	 * Note: msgbuf is setup in machdep.c:cpu_startup()
    191 	 */
    192 	nextva = m68k_round_page(esym);
    193 
    194 	/*
    195 	 * Setup the u-area pages (stack, etc.) for lwp0.
    196 	 * This is done very early (here) to make sure the
    197 	 * fault handler works in case we hit an early bug.
    198 	 * (The fault handler may reference lwp0 stuff.)
    199 	 */
    200 	memset((void *)nextva, 0, USPACE);
    201 	uvm_lwp_setuarea(&lwp0, nextva);
    202 	curlwp = &lwp0;
    203 	curpcb = lwp_getpcb(&lwp0);
    204 
    205 	/* Create a fake exception frame so that cpu_lwp_fork() can copy it. */
    206 	struct trapframe *tf = (struct trapframe *)(nextva + USPACE) - 1;
    207 	tf->tf_sr = PSL_USER;
    208 	lwp0.l_md.md_regs = (int *)tf;
    209 
    210 	nextva += USPACE;
    211 
    212 	/* This does most of the real work. */
    213 	nextpa = pmap_bootstrap(nextva);
    214 
    215 	machine_init_common(nextpa);
    216 
    217 	return tf;
    218 }
    219 
    220 /*
    221  * Determine which Sun3 model we are running on.
    222  * We have to do this very early on the Sun3 because
    223  * pmap_bootstrap() needs to know if it should avoid
    224  * the video memory on the Sun3/50.
    225  *
    226  * XXX: Just save idprom.idp_machtype here, and
    227  * XXX: move the rest of this to identifycpu().
    228  * XXX: Move cache_size stuff to cache.c.
    229  */
    230 static void
    231 _verify_hardware(void)
    232 {
    233 	unsigned char machtype;
    234 	int cpu_match = 0;
    235 
    236 	machtype = identity_prom.idp_machtype;
    237 	if ((machtype & IDM_ARCH_MASK) != IDM_ARCH_SUN3) {
    238 		mon_printf("Bad IDPROM arch!\n");
    239 		sunmon_abort();
    240 	}
    241 
    242 	/*
    243 	 * XXX Should really calibrate the delay_divisor against a
    244 	 * XXX timer, but it's been this way for a long time.
    245 	 */
    246 
    247 	cpu_machine_id = machtype;
    248 	switch (cpu_machine_id) {
    249 
    250 	case ID_SUN3_50 :
    251 		cpu_match++;
    252 		cpu_string = "50";
    253 		cpuspeed_khz = 16000;
    254 		delay_divisor = delay_divisor_est(16);
    255 		break;
    256 
    257 	case ID_SUN3_60 :
    258 		cpu_match++;
    259 		cpu_string = "60";
    260 		cpuspeed_khz = 20000;
    261 		delay_divisor = delay_divisor_est(20);
    262 		break;
    263 
    264 	case ID_SUN3_110:
    265 		cpu_match++;
    266 		cpu_string = "110";
    267 		cpuspeed_khz = 16670;
    268 		delay_divisor = delay_divisor_est(17);
    269 		cpu_has_vme = true;
    270 		break;
    271 
    272 	case ID_SUN3_160:
    273 		cpu_match++;
    274 		cpu_string = "160";
    275 		cpuspeed_khz = 16670;
    276 		delay_divisor = delay_divisor_est(17);
    277 		cpu_has_vme = true;
    278 		break;
    279 
    280 	case ID_SUN3_260:
    281 		cpu_match++;
    282 		cpu_string = "260";
    283 		cpuspeed_khz = 25000;
    284 		delay_divisor = delay_divisor_est(25);
    285 		cpu_has_vme = true;
    286 #ifdef	HAVECACHE
    287 		cache_size = 0x10000;	/* 64K */
    288 #endif
    289 		break;
    290 
    291 	case ID_SUN3_E  :
    292 		cpu_match++;
    293 		cpu_string = "E";
    294 		cpuspeed_khz = 20000;
    295 		delay_divisor = delay_divisor_est(20); /* XXX 20MHz correct? */
    296 		cpu_has_vme = true;
    297 		break;
    298 
    299 	default:
    300 		mon_printf("unknown sun3 model\n");
    301 		sunmon_abort();
    302 	}
    303 	if (!cpu_match) {
    304 		mon_printf("kernel not configured for the Sun 3 model\n");
    305 		sunmon_abort();
    306 	}
    307 }
    308 
    309 /*
    310  * This is called from locore.s just after the kernel is remapped
    311  * to its proper address, but before the call to main().  The work
    312  * done here corresponds to various things done in locore.s on the
    313  * hp300 port (and other m68k) but which we prefer to do in C code.
    314  * Also do setup specific to the Sun PROM monitor and IDPROM here.
    315  */
    316 void *
    317 _bootstrap(void)
    318 {
    319 	extern struct consdev consdev_prom;	/* XXX */
    320 
    321 	/* First, Clear BSS. */
    322 	memset(edata, 0, end - edata);
    323 
    324 	/* Set v_handler, get boothowto. */
    325 	sunmon_init();
    326 
    327 	/*
    328 	 * Initialize console to point to the PROM (output only) table
    329 	 * for early printf calls.
    330 	 */
    331 	cn_tab = &consdev_prom;
    332 
    333 	/* Copy the IDPROM from control space. */
    334 	idprom_init();
    335 
    336 	/* Validate the Sun3 model (from IDPROM). */
    337 	_verify_hardware();
    338 
    339 	/* Handle kernel mapping, pmap_bootstrap(), etc. */
    340 	void *ksp = _vm_init();
    341 
    342 	/*
    343 	 * Find and save OBIO mappings needed early,
    344 	 * and call some init functions.
    345 	 */
    346 	obio_init();
    347 
    348 	/*
    349 	 * Point interrupts/exceptions to our vector table.
    350 	 * (Until now, we use the one setup by the PROM.)
    351 	 *
    352 	 * This is done after obio_init() / intreg_init() finds
    353 	 * the interrupt register and disables the NMI clock so
    354 	 * it will not cause "spurrious level 7" complaints.
    355 	 * Done after _vm_init so the PROM can debug that.
    356 	 */
    357 	vec_init();
    358 	/* Interrupts are enabled later, after autoconfig. */
    359 
    360 	/*
    361 	 * Turn on the LEDs so we know power is on.
    362 	 * Needs idprom_init and obio_init earlier.
    363 	 */
    364 	leds_init();
    365 
    366 	/*
    367 	 * Initialize the source/destination control registers for
    368 	 * movs.
    369 	 */
    370 	setsfc(FC_USERD);
    371 	setdfc(FC_USERD);
    372 
    373 	return ksp;
    374 }
    375