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