1 /* $NetBSD: locore2.c,v 1.34 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, Gordon W. Ross, and Matthew Fredette. 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.34 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/promlib.h> 56 #include <machine/pmap.h> 57 #include <machine/pte.h> 58 #include <machine/vectors.h> 59 60 #include <sun2/sun2/control.h> 61 #include <sun2/sun2/machdep.h> 62 63 #include "ksyms.h" 64 65 /* This is defined in locore.s */ 66 extern char kernel_text[]; 67 68 /* These are defined by the linker */ 69 extern char etext[], edata[], end[]; 70 int nsym; 71 char *ssym, *esym; 72 73 /* 74 * XXX: m68k common code needs these... 75 * ... but this port does not need to deal with anything except 76 * an mc68010, so these two variables are always ignored. 77 */ 78 int cputype = CPU_68010; 79 int mmutype = MMU_SUN; 80 81 /* 82 * Now our own stuff. 83 */ 84 85 u_char cpu_machine_id = 0; 86 const char *cpu_string = NULL; 87 int cpu_has_multibus = 0; 88 int cpu_has_vme = 0; 89 90 /* XXX This is probably overkill. */ 91 int delay_divisor = delay_divisor_est(25); 92 93 extern struct pcb *curpcb; 94 95 /* First C code called by locore.s */ 96 void *_bootstrap(void); 97 98 #if NKSYMS || defined(DDB) || defined(MODULAR) 99 /* 100 * Preserve symbols and strings by setting esym. 101 */ 102 static void 103 _save_symtab(void) 104 { 105 int i; 106 Elf_Ehdr *ehdr; 107 Elf_Shdr *shp; 108 vaddr_t minsym, maxsym; 109 110 /* 111 * Check the ELF headers. 112 */ 113 114 ehdr = (void *)end; 115 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 || 116 ehdr->e_ident[EI_CLASS] != ELFCLASS32) { 117 prom_printf("_save_symtab: bad ELF magic\n"); 118 return; 119 } 120 121 /* 122 * Find the end of the symbols and strings. 123 */ 124 125 maxsym = 0; 126 minsym = ~maxsym; 127 shp = (Elf_Shdr *)(end + ehdr->e_shoff); 128 for (i = 0; i < ehdr->e_shnum; i++) { 129 if (shp[i].sh_type != SHT_SYMTAB && 130 shp[i].sh_type != SHT_STRTAB) { 131 continue; 132 } 133 minsym = uimin(minsym, (vaddr_t)end + shp[i].sh_offset); 134 maxsym = uimax(maxsym, (vaddr_t)end + shp[i].sh_offset + 135 shp[i].sh_size); 136 } 137 138 nsym = 1; 139 ssym = (char *)ehdr; 140 esym = (char *)maxsym; 141 } 142 #endif /* DDB */ 143 144 /* 145 * This function is called from _bootstrap() to initialize 146 * pre-vm-system virtual memory. All this really does is to 147 * set virtual_avail to the first page following preloaded 148 * data (i.e. the kernel and its symbol table) and special 149 * things that may be needed very early (lwp0 upages). 150 * Once that is done, pmap_bootstrap() is called to do the 151 * usual preparations for our use of the MMU. 152 * 153 * Returns the new kernel %sp value for lwp0. 154 */ 155 static void * 156 _vm_init(void) 157 { 158 vaddr_t nextva; 159 paddr_t nextpa; 160 161 /* 162 * First preserve our symbol table, which might have been 163 * loaded after our BSS area by the boot loader. However, 164 * if DDB is not part of this kernel, ignore the symbols. 165 */ 166 esym = end + 4; 167 #if NKSYMS || defined(DDB) || defined(MODULAR) 168 /* This will advance esym past the symbols. */ 169 _save_symtab(); 170 #endif 171 172 /* 173 * Steal some special-purpose, already mapped pages. 174 * Note: msgbuf is setup in machdep.c:cpu_startup() 175 */ 176 nextva = m68k_round_page(esym); 177 178 /* 179 * Setup the u-area pages (stack, etc.) for lwp0. 180 * This is done very early (here) to make sure the 181 * fault handler works in case we hit an early bug. 182 * (The fault handler may reference lwp0 stuff.) 183 */ 184 uvm_lwp_setuarea(&lwp0, nextva); 185 memset((void *)nextva, 0, USPACE); 186 curlwp = &lwp0; 187 curpcb = lwp_getpcb(&lwp0); 188 189 /* Create a fake exception frame so that cpu_lwp_fork() can copy it. */ 190 struct trapframe *tf = (struct trapframe *)(nextva + USPACE) - 1; 191 tf->tf_sr = PSL_USER; 192 lwp0.l_md.md_regs = (int *)tf; 193 194 nextva += USPACE; 195 196 /* This does most of the real work. */ 197 nextpa = pmap_bootstrap(nextva); 198 199 machine_init_common(nextpa); 200 201 return tf; 202 } 203 204 /* 205 * Determine which Sun2 model we are running on. 206 * 207 * XXX: Just save idprom.idp_machtype here, and 208 * XXX: move the rest of this to identifycpu(). 209 * XXX: Move cache_size stuff to cache.c. 210 */ 211 static void 212 _verify_hardware(void) 213 { 214 unsigned char machtype; 215 int cpu_match = 0; 216 217 machtype = identity_prom.idp_machtype; 218 if ((machtype & IDM_ARCH_MASK) != IDM_ARCH_SUN2) { 219 prom_printf("Bad IDPROM arch!\n"); 220 prom_abort(); 221 } 222 223 cpu_machine_id = machtype; 224 switch (cpu_machine_id) { 225 226 case ID_SUN2_120 : 227 cpu_match++; 228 cpu_string = "{120,170}"; 229 cpuspeed_khz = 10000; 230 delay_divisor = delay_divisor_est(10); 231 cpu_has_multibus = true; 232 break; 233 234 case ID_SUN2_50 : 235 cpu_match++; 236 cpu_string = "50"; 237 cpuspeed_khz = 10000; 238 delay_divisor = delay_divisor_est(10); 239 cpu_has_vme = true; 240 break; 241 242 default: 243 prom_printf("unknown sun2 model\n"); 244 prom_abort(); 245 } 246 if (!cpu_match) { 247 prom_printf("kernel not configured for the Sun 2 model\n"); 248 prom_abort(); 249 } 250 } 251 252 /* 253 * This is called from locore.s just after the kernel is remapped 254 * to its proper address, but before the call to main(). The work 255 * done here corresponds to various things done in locore.s on the 256 * hp300 port (and other m68k) but which we prefer to do in C code. 257 * Also do setup specific to the Sun PROM monitor and IDPROM here. 258 */ 259 void * 260 _bootstrap(void) 261 { 262 extern struct consdev consdev_prom; /* XXX */ 263 vaddr_t va; 264 265 /* First, Clear BSS. */ 266 memset(edata, 0, end - edata); 267 268 /* Initialize the PROM. */ 269 prom_init(); 270 271 /* 272 * Initialize console to point to the PROM (output only) table 273 * for early printf calls. 274 */ 275 cn_tab = &consdev_prom; 276 277 /* Copy the IDPROM from control space. */ 278 idprom_init(); 279 280 /* Validate the Sun2 model (from IDPROM). */ 281 _verify_hardware(); 282 283 /* Handle kernel mapping, pmap_bootstrap(), etc. */ 284 void *ksp = _vm_init(); 285 286 /* 287 * Point interrupts/exceptions to our vector table. 288 * (Until now, we use the one setup by the PROM.) 289 */ 290 vec_init(); 291 /* Interrupts are enabled later, after autoconfig. */ 292 293 /* 294 * Now unmap the PROM's physical/virtual pages zero through three. 295 */ 296 for(va = 0; va < PAGE_SIZE * 4; va += PAGE_SIZE) 297 set_pte(va, PG_INVAL); 298 299 /* 300 * Turn on the LEDs so we know power is on. 301 * Needs idprom_init and obio_init earlier. 302 */ 303 leds_init(); 304 305 /* 306 * Initialize the source/destination control registers for 307 * movs. 308 */ 309 setsfc(FC_USERD); 310 setdfc(FC_USERD); 311 312 return ksp; 313 } 314