boot.c revision 1.14 1 1.14 martin /* $NetBSD: boot.c,v 1.14 2007/06/05 08:52:20 martin Exp $ */
2 1.12 cdi
3 1.1 mrg /*
4 1.1 mrg * Copyright (c) 1997, 1999 Eduardo E. Horvath. All rights reserved.
5 1.1 mrg * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
6 1.1 mrg * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7 1.1 mrg * Copyright (C) 1995, 1996 TooLs GmbH.
8 1.1 mrg * All rights reserved.
9 1.1 mrg *
10 1.1 mrg * ELF support derived from NetBSD/alpha's boot loader, written
11 1.1 mrg * by Christopher G. Demetriou.
12 1.1 mrg *
13 1.1 mrg * Redistribution and use in source and binary forms, with or without
14 1.1 mrg * modification, are permitted provided that the following conditions
15 1.1 mrg * are met:
16 1.1 mrg * 1. Redistributions of source code must retain the above copyright
17 1.1 mrg * notice, this list of conditions and the following disclaimer.
18 1.1 mrg * 2. Redistributions in binary form must reproduce the above copyright
19 1.1 mrg * notice, this list of conditions and the following disclaimer in the
20 1.1 mrg * documentation and/or other materials provided with the distribution.
21 1.1 mrg * 3. All advertising materials mentioning features or use of this software
22 1.1 mrg * must display the following acknowledgement:
23 1.1 mrg * This product includes software developed by TooLs GmbH.
24 1.1 mrg * 4. The name of TooLs GmbH may not be used to endorse or promote products
25 1.1 mrg * derived from this software without specific prior written permission.
26 1.1 mrg *
27 1.1 mrg * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
28 1.1 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 1.1 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 1.1 mrg * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 1.1 mrg * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 1.1 mrg * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33 1.1 mrg * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34 1.1 mrg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 1.1 mrg * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 1.1 mrg * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 1.1 mrg */
38 1.1 mrg
39 1.1 mrg /*
40 1.1 mrg * First try for the boot code
41 1.1 mrg *
42 1.1 mrg * Input syntax is:
43 1.1 mrg * [promdev[{:|,}partition]]/[filename] [flags]
44 1.1 mrg */
45 1.1 mrg
46 1.1 mrg #include <lib/libsa/stand.h>
47 1.12 cdi #include <lib/libsa/loadfile.h>
48 1.1 mrg #include <lib/libkern/libkern.h>
49 1.1 mrg
50 1.1 mrg #include <sys/param.h>
51 1.1 mrg #include <sys/reboot.h>
52 1.1 mrg #include <sys/disklabel.h>
53 1.2 jdolecek #include <sys/boot_flag.h>
54 1.1 mrg
55 1.1 mrg #include <machine/cpu.h>
56 1.12 cdi #include <machine/promlib.h>
57 1.12 cdi #include <machine/bootinfo.h>
58 1.1 mrg
59 1.12 cdi #include "boot.h"
60 1.1 mrg #include "ofdev.h"
61 1.1 mrg #include "openfirm.h"
62 1.1 mrg
63 1.12 cdi
64 1.12 cdi #define COMPAT_BOOT(marks) (marks[MARK_START] == marks[MARK_ENTRY])
65 1.12 cdi
66 1.12 cdi
67 1.12 cdi typedef void (*entry_t)(long o0, long bootargs, long bootsize, long o3,
68 1.12 cdi long ofw);
69 1.1 mrg
70 1.1 mrg /*
71 1.1 mrg * Boot device is derived from ROM provided information, or if there is none,
72 1.1 mrg * this list is used in sequence, to find a kernel.
73 1.1 mrg */
74 1.12 cdi const char *kernelnames[] = {
75 1.12 cdi "netbsd",
76 1.12 cdi "netbsd.gz",
77 1.12 cdi "netbsd.old",
78 1.12 cdi "netbsd.old.gz",
79 1.12 cdi "onetbsd",
80 1.12 cdi "onetbsd.gz",
81 1.1 mrg "vmunix ",
82 1.1 mrg #ifdef notyet
83 1.1 mrg "netbsd.pl ",
84 1.1 mrg "netbsd.pl.gz ",
85 1.1 mrg "netbsd.el ",
86 1.1 mrg "netbsd.el.gz ",
87 1.1 mrg #endif
88 1.1 mrg NULL
89 1.1 mrg };
90 1.1 mrg
91 1.12 cdi char bootdev[PROM_MAX_PATH];
92 1.1 mrg
93 1.12 cdi int debug = 0;
94 1.12 cdi int compatmode = 0;
95 1.1 mrg
96 1.1 mrg #if 0
97 1.1 mrg static void
98 1.13 uwe prom2boot(char *dev)
99 1.1 mrg {
100 1.1 mrg char *cp, *lp = 0;
101 1.1 mrg int handle;
102 1.1 mrg char devtype[16];
103 1.1 mrg
104 1.1 mrg for (cp = dev; *cp; cp++)
105 1.1 mrg if (*cp == ':')
106 1.1 mrg lp = cp;
107 1.1 mrg if (!lp)
108 1.1 mrg lp = cp;
109 1.1 mrg *lp = 0;
110 1.1 mrg }
111 1.1 mrg #endif
112 1.1 mrg
113 1.12 cdi static int
114 1.12 cdi bootoptions(const char *ap, char *kernel, char *options)
115 1.1 mrg {
116 1.12 cdi int v = 0;
117 1.12 cdi const char *cp;
118 1.12 cdi
119 1.12 cdi *kernel = '\0';
120 1.12 cdi *options = '\0';
121 1.12 cdi
122 1.12 cdi if (ap == NULL) {
123 1.12 cdi return (0);
124 1.12 cdi }
125 1.12 cdi
126 1.12 cdi while (*ap == ' ') {
127 1.12 cdi ap++;
128 1.12 cdi }
129 1.12 cdi
130 1.12 cdi cp = ap;
131 1.12 cdi if (*ap != '-') {
132 1.12 cdi while (*ap != '\0' && *ap != ' ') {
133 1.12 cdi ap++;
134 1.12 cdi }
135 1.12 cdi
136 1.12 cdi memcpy(kernel, cp, (ap - cp));
137 1.12 cdi kernel[ap - cp] = '\0';
138 1.1 mrg
139 1.12 cdi while (*ap != '\0' && *ap == ' ') {
140 1.12 cdi ap++;
141 1.12 cdi }
142 1.1 mrg }
143 1.12 cdi
144 1.12 cdi strcpy(options, ap);
145 1.12 cdi while (*ap != '\0' && *ap != ' ' && *ap != '\t' && *ap != '\n') {
146 1.12 cdi BOOT_FLAG(*ap, v);
147 1.12 cdi switch(*ap++) {
148 1.1 mrg case 'D':
149 1.1 mrg debug = 2;
150 1.1 mrg break;
151 1.12 cdi case 'C':
152 1.12 cdi compatmode = 1;
153 1.12 cdi break;
154 1.2 jdolecek default:
155 1.1 mrg break;
156 1.1 mrg }
157 1.1 mrg }
158 1.12 cdi
159 1.12 cdi if (((v & RB_KDB) != 0) && (debug == 0)) {
160 1.12 cdi debug = 1;
161 1.12 cdi }
162 1.12 cdi
163 1.12 cdi DPRINTF(("bootoptions: kernel='%s', options='%s'\n", kernel, options));
164 1.12 cdi return (v);
165 1.1 mrg }
166 1.1 mrg
167 1.12 cdi /*
168 1.12 cdi * The older (those relying on ofwboot v1.8 and earlier) kernels can't handle
169 1.12 cdi * ksyms information unless it resides in a dedicated memory allocated from
170 1.12 cdi * PROM and aligned on NBPG boundary. This is because the kernels calculate
171 1.12 cdi * their ends on their own, they use address of 'end[]' reference which follows
172 1.12 cdi * text segment. Ok, allocate some memory from PROM and copy symbol information
173 1.12 cdi * over there.
174 1.12 cdi */
175 1.12 cdi static void
176 1.12 cdi ksyms_copyout(void **ssym, void **esym)
177 1.12 cdi {
178 1.12 cdi void *addr;
179 1.12 cdi int kssize = (int)(long)(*esym - *ssym + 1);
180 1.12 cdi
181 1.12 cdi DPRINTF(("ksyms_copyout(): ssym = %p, esym = %p, kssize = %d\n",
182 1.12 cdi *ssym, *esym, kssize));
183 1.1 mrg
184 1.12 cdi if ( (addr = OF_claim(0, kssize, NBPG)) == (void *)-1) {
185 1.12 cdi panic("ksyms_copyout(): no space for symbol table");
186 1.12 cdi }
187 1.12 cdi
188 1.12 cdi memcpy(addr, *ssym, kssize);
189 1.12 cdi *ssym = addr;
190 1.12 cdi *esym = addr + kssize - 1;
191 1.12 cdi
192 1.12 cdi DPRINTF(("ksyms_copyout(): ssym = %p, esym = %p\n", *ssym, *esym));
193 1.12 cdi }
194 1.12 cdi
195 1.12 cdi /*
196 1.12 cdi * Prepare boot information and jump directly to the kernel.
197 1.12 cdi */
198 1.1 mrg static void
199 1.12 cdi jump_to_kernel(u_long *marks, char *kernel, char *args, void *ofw)
200 1.1 mrg {
201 1.1 mrg extern char end[];
202 1.1 mrg int l, machine_tag;
203 1.12 cdi long newargs[4];
204 1.12 cdi void *ssym, *esym;
205 1.12 cdi vaddr_t bootinfo;
206 1.12 cdi struct btinfo_symtab bi_sym;
207 1.12 cdi struct btinfo_kernend bi_kend;
208 1.12 cdi char *cp;
209 1.12 cdi char bootline[PROM_MAX_PATH * 2];
210 1.1 mrg
211 1.12 cdi /* Compose kernel boot line. */
212 1.12 cdi strncpy(bootline, kernel, sizeof(bootline));
213 1.12 cdi cp = bootline + strlen(bootline);
214 1.12 cdi if (*args) {
215 1.12 cdi *cp++ = ' ';
216 1.12 cdi strncpy(bootline, args, sizeof(bootline) - (cp - bootline));
217 1.12 cdi }
218 1.12 cdi *cp = 0; args = bootline;
219 1.12 cdi
220 1.12 cdi /* Record symbol information in the bootinfo. */
221 1.12 cdi bootinfo = bi_init(marks[MARK_END]);
222 1.12 cdi bi_sym.nsym = marks[MARK_NSYM];
223 1.12 cdi bi_sym.ssym = marks[MARK_SYM];
224 1.12 cdi bi_sym.esym = marks[MARK_END];
225 1.12 cdi bi_add(&bi_sym, BTINFO_SYMTAB, sizeof(bi_sym));
226 1.12 cdi bi_kend.addr= bootinfo + BOOTINFO_SIZE;
227 1.12 cdi bi_add(&bi_kend, BTINFO_KERNEND, sizeof(bi_kend));
228 1.14 martin sparc64_finalize_tlb(marks[MARK_DATA]);
229 1.12 cdi sparc64_bi_add();
230 1.12 cdi
231 1.12 cdi ssym = (void*)(long)marks[MARK_SYM];
232 1.12 cdi esym = (void*)(long)marks[MARK_END];
233 1.12 cdi
234 1.12 cdi DPRINTF(("jump_to_kernel(): ssym = %p, esym = %p\n", ssym, esym));
235 1.12 cdi
236 1.12 cdi /* Adjust ksyms pointers, if needed. */
237 1.12 cdi if (COMPAT_BOOT(marks) || compatmode) {
238 1.12 cdi ksyms_copyout(&ssym, &esym);
239 1.12 cdi }
240 1.1 mrg
241 1.1 mrg freeall();
242 1.1 mrg /*
243 1.1 mrg * When we come in args consists of a pointer to the boot
244 1.1 mrg * string. We need to fix it so it takes into account
245 1.1 mrg * other params such as romp.
246 1.1 mrg */
247 1.1 mrg
248 1.1 mrg /*
249 1.1 mrg * Stash pointer to end of symbol table after the argument
250 1.1 mrg * strings.
251 1.1 mrg */
252 1.1 mrg l = strlen(args) + 1;
253 1.1 mrg bcopy(&esym, args + l, sizeof(esym));
254 1.1 mrg l += sizeof(esym);
255 1.1 mrg
256 1.1 mrg /*
257 1.1 mrg * Tell the kernel we're an OpenFirmware system.
258 1.1 mrg */
259 1.1 mrg machine_tag = SPARC_MACHINE_OPENFIRMWARE;
260 1.1 mrg bcopy(&machine_tag, args + l, sizeof(machine_tag));
261 1.1 mrg l += sizeof(machine_tag);
262 1.1 mrg
263 1.1 mrg /*
264 1.1 mrg * Since we don't need the boot string (we can get it from /chosen)
265 1.1 mrg * we won't pass it in. Just pass in esym and magic #
266 1.1 mrg */
267 1.1 mrg newargs[0] = SPARC_MACHINE_OPENFIRMWARE;
268 1.1 mrg newargs[1] = (long)esym;
269 1.1 mrg newargs[2] = (long)ssym;
270 1.12 cdi newargs[3] = (long)(void*)bootinfo;
271 1.1 mrg args = (char *)newargs;
272 1.1 mrg l = sizeof(newargs);
273 1.1 mrg
274 1.1 mrg /* if -D is set then pause in the PROM. */
275 1.12 cdi if (debug > 1) callrom();
276 1.12 cdi
277 1.12 cdi /*
278 1.12 cdi * Jump directly to the kernel. Solaris kernel and Sun PROM
279 1.12 cdi * flash updates expect ROMP vector in %o0, so we do. Format
280 1.12 cdi * of other parameters and their order reflect OF_chain()
281 1.12 cdi * symantics since this is what older NetBSD kernels rely on.
282 1.12 cdi * (see sparc64/include/bootinfo.h for specification).
283 1.12 cdi */
284 1.12 cdi DPRINTF(("jump_to_kernel(%lx, %lx, %lx, %lx, %lx) @ %p\n", (long)ofw,
285 1.12 cdi (long)args, (long)l, (long)ofw, (long)ofw,
286 1.12 cdi (void*)marks[MARK_ENTRY]));
287 1.12 cdi (*(entry_t)marks[MARK_ENTRY])((long)ofw, (long)args, (long)l, (long)ofw,
288 1.12 cdi (long)ofw);
289 1.12 cdi printf("Returned from kernel entry point!\n");
290 1.1 mrg }
291 1.1 mrg
292 1.12 cdi static void
293 1.12 cdi start_kernel(char *kernel, char *bootline, void *ofw)
294 1.1 mrg {
295 1.1 mrg int fd;
296 1.12 cdi u_long marks[MARK_MAX];
297 1.1 mrg
298 1.1 mrg /*
299 1.12 cdi * First, load headers using default allocator and check whether kernel
300 1.12 cdi * entry address matches kernel text load address. If yes, this is the
301 1.12 cdi * old kernel designed for ofwboot v1.8 and therefore it must be mapped
302 1.12 cdi * by PROM. Otherwise, map the kernel with 4MB permanent pages.
303 1.1 mrg */
304 1.12 cdi loadfile_set_allocator(LOADFILE_NOP_ALLOCATOR);
305 1.12 cdi if ( (fd = loadfile(kernel, marks, LOAD_HDR|COUNT_TEXT)) != -1) {
306 1.12 cdi if (COMPAT_BOOT(marks) || compatmode) {
307 1.12 cdi (void)printf("[c] ");
308 1.12 cdi loadfile_set_allocator(LOADFILE_OFW_ALLOCATOR);
309 1.12 cdi } else {
310 1.12 cdi loadfile_set_allocator(LOADFILE_MMU_ALLOCATOR);
311 1.12 cdi }
312 1.12 cdi (void)printf("Loading %s: ", kernel);
313 1.1 mrg
314 1.12 cdi if (fdloadfile(fd, marks, LOAD_ALL) != -1) {
315 1.12 cdi jump_to_kernel(marks, kernel, bootline, ofw);
316 1.1 mrg }
317 1.1 mrg }
318 1.12 cdi (void)printf("Failed to load '%s'.\n", kernel);
319 1.1 mrg }
320 1.1 mrg
321 1.12 cdi void
322 1.12 cdi main(void *ofw)
323 1.12 cdi {
324 1.12 cdi int boothowto, i = 0;
325 1.1 mrg
326 1.12 cdi char kernel[PROM_MAX_PATH];
327 1.12 cdi char bootline[PROM_MAX_PATH];
328 1.1 mrg
329 1.12 cdi /* Initialize OpenFirmware */
330 1.12 cdi romp = ofw;
331 1.12 cdi prom_init();
332 1.1 mrg
333 1.7 martin printf("\r>> %s, Revision %s\n", bootprog_name, bootprog_rev);
334 1.1 mrg printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
335 1.1 mrg
336 1.12 cdi /* Figure boot arguments */
337 1.12 cdi boothowto = bootoptions(prom_getbootargs(), kernel, bootline);
338 1.12 cdi strncpy(bootdev, prom_getbootpath(), sizeof(bootdev) - 1);
339 1.12 cdi strncpy(bootline, prom_getbootargs(), sizeof(bootline) - 1);
340 1.12 cdi
341 1.12 cdi for (;; *kernel = '\0') {
342 1.1 mrg if (boothowto & RB_ASKNAME) {
343 1.12 cdi char *cp, cmdline[PROM_MAX_PATH];
344 1.12 cdi
345 1.1 mrg printf("Boot: ");
346 1.12 cdi gets(cmdline);
347 1.12 cdi
348 1.12 cdi boothowto = bootoptions(cmdline, kernel, bootline);
349 1.12 cdi boothowto |= RB_ASKNAME;
350 1.12 cdi
351 1.12 cdi if (!strcmp(kernel,"exit") || !strcmp(kernel,"halt")) {
352 1.12 cdi prom_halt();
353 1.12 cdi }
354 1.1 mrg }
355 1.12 cdi
356 1.12 cdi if (*kernel == '\0') {
357 1.12 cdi if (kernelnames[i] == NULL) {
358 1.12 cdi boothowto |= RB_ASKNAME;
359 1.12 cdi continue;
360 1.12 cdi }
361 1.12 cdi strncpy(kernel, kernelnames[i++], PROM_MAX_PATH);
362 1.12 cdi } else if (i == 0) {
363 1.12 cdi /*
364 1.12 cdi * Kernel name was passed via command line -- ask user
365 1.12 cdi * again if requested image fails to boot.
366 1.12 cdi */
367 1.12 cdi boothowto |= RB_ASKNAME;
368 1.12 cdi }
369 1.12 cdi
370 1.12 cdi start_kernel(kernel, bootline, ofw);
371 1.12 cdi
372 1.1 mrg /*
373 1.12 cdi * Try next name from kernel name list if not in askname mode,
374 1.12 cdi * enter askname on reaching list's end.
375 1.1 mrg */
376 1.12 cdi if ((boothowto & RB_ASKNAME) == 0 && (kernelnames[i] != NULL)) {
377 1.12 cdi printf(": trying %s...\n", kernelnames[i]);
378 1.1 mrg } else {
379 1.1 mrg printf("\n");
380 1.1 mrg boothowto |= RB_ASKNAME;
381 1.1 mrg }
382 1.1 mrg }
383 1.1 mrg
384 1.12 cdi (void)printf("Boot failed! Exiting to the Firmware.\n");
385 1.12 cdi prom_halt();
386 1.1 mrg }
387