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