1 /* $NetBSD: boot.c,v 1.19 2009/03/18 17:06:47 cegger Exp $ */
4 * Copyright (c) 1997, 1999 Eduardo E. Horvath. All rights reserved.
5 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
6 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7 * Copyright (C) 1995, 1996 TooLs GmbH.
10 * ELF support derived from NetBSD/alpha's boot loader, written
11 * by Christopher G. Demetriou.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by TooLs GmbH.
24 * 4. The name of TooLs GmbH may not be used to endorse or promote products
25 * derived from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * First try for the boot code
43 * [promdev[{:|,}partition]]/[filename] [flags]
46 #include <lib/libsa/stand.h>
47 #include <lib/libsa/loadfile.h>
48 #include <lib/libkern/libkern.h>
50 #include <sys/param.h>
51 #include <sys/reboot.h>
52 #include <sys/disklabel.h>
53 #include <sys/boot_flag.h>
55 #include <machine/cpu.h>
56 #include <machine/promlib.h>
57 #include <machine/bootinfo.h>
64 #define COMPAT_BOOT(marks) (marks[MARK_START] == marks[MARK_ENTRY])
67 typedef void (*entry_t
)(long o0
, long bootargs
, long bootsize
, long o3
,
71 * Boot device is derived from ROM provided information, or if there is none,
72 * this list is used in sequence, to find a kernel.
74 const char *kernelnames
[] = {
91 char bootdev
[PROM_MAX_PATH
];
104 for (cp
= dev
; *cp
; cp
++)
114 bootoptions(const char *ap
, char *loaddev
, char *kernel
, char *options
)
117 const char *start1
= NULL
, *end1
= NULL
, *start2
= NULL
, *end2
= NULL
;
134 while (*ap
!= '\0' && *ap
!= ' ') {
139 while (*ap
!= '\0' && *ap
== ' ') {
145 while (*ap
!= '\0' && *ap
!= ' ') {
149 while (*ap
!= '\0' && *ap
== ' ') {
154 if (end2
== start2
) {
155 start2
= end2
= NULL
;
157 if (end1
== start1
) {
158 start1
= end1
= NULL
;
161 if (start1
== NULL
) {
163 } else if (start2
== NULL
) {
164 memcpy(kernel
, start1
, (end1
- start1
));
165 kernel
[end1
- start1
] = '\0';
166 path
= filename(kernel
, &partition
);
168 strcpy(loaddev
, kernel
);
170 } else if (path
!= kernel
) {
171 /* copy device part */
172 memcpy(loaddev
, kernel
, path
-kernel
);
173 loaddev
[path
-kernel
] = '\0';
175 pp
= loaddev
+ strlen(loaddev
);
180 /* and kernel path */
181 strcpy(kernel
, path
);
184 memcpy(loaddev
, start1
, (end1
-start1
));
185 loaddev
[end1
-start1
] = '\0';
186 memcpy(kernel
, start2
, (end2
- start2
));
187 kernel
[end2
- start2
] = '\0';
191 while (*ap
!= '\0' && *ap
!= ' ' && *ap
!= '\t' && *ap
!= '\n') {
205 if (((v
& RB_KDB
) != 0) && (debug
== 0)) {
209 DPRINTF(("bootoptions: device='%s', kernel='%s', options='%s'\n",
210 loaddev
, kernel
, options
));
215 * The older (those relying on ofwboot v1.8 and earlier) kernels can't handle
216 * ksyms information unless it resides in a dedicated memory allocated from
217 * PROM and aligned on NBPG boundary. This is because the kernels calculate
218 * their ends on their own, they use address of 'end[]' reference which follows
219 * text segment. Ok, allocate some memory from PROM and copy symbol information
223 ksyms_copyout(void **ssym
, void **esym
)
226 int kssize
= (int)(long)(*esym
- *ssym
+ 1);
228 DPRINTF(("ksyms_copyout(): ssym = %p, esym = %p, kssize = %d\n",
229 *ssym
, *esym
, kssize
));
231 if ( (addr
= OF_claim(0, kssize
, NBPG
)) == (void *)-1) {
232 panic("ksyms_copyout(): no space for symbol table");
235 memcpy(addr
, *ssym
, kssize
);
237 *esym
= addr
+ kssize
- 1;
239 DPRINTF(("ksyms_copyout(): ssym = %p, esym = %p\n", *ssym
, *esym
));
243 * Prepare boot information and jump directly to the kernel.
246 jump_to_kernel(u_long
*marks
, char *kernel
, char *args
, void *ofw
)
253 struct btinfo_symtab bi_sym
;
254 struct btinfo_kernend bi_kend
;
256 char bootline
[PROM_MAX_PATH
* 2];
258 /* Compose kernel boot line. */
259 strncpy(bootline
, kernel
, sizeof(bootline
));
260 cp
= bootline
+ strlen(bootline
);
263 strncpy(bootline
, args
, sizeof(bootline
) - (cp
- bootline
));
265 *cp
= 0; args
= bootline
;
267 /* Record symbol information in the bootinfo. */
268 bootinfo
= bi_init(marks
[MARK_END
]);
269 bi_sym
.nsym
= marks
[MARK_NSYM
];
270 bi_sym
.ssym
= marks
[MARK_SYM
];
271 bi_sym
.esym
= marks
[MARK_END
];
272 bi_add(&bi_sym
, BTINFO_SYMTAB
, sizeof(bi_sym
));
273 bi_kend
.addr
= bootinfo
+ BOOTINFO_SIZE
;
274 bi_add(&bi_kend
, BTINFO_KERNEND
, sizeof(bi_kend
));
275 sparc64_finalize_tlb(marks
[MARK_DATA
]);
278 ssym
= (void*)(long)marks
[MARK_SYM
];
279 esym
= (void*)(long)marks
[MARK_END
];
281 DPRINTF(("jump_to_kernel(): ssym = %p, esym = %p\n", ssym
, esym
));
283 /* Adjust ksyms pointers, if needed. */
284 if (COMPAT_BOOT(marks
) || compatmode
) {
285 ksyms_copyout(&ssym
, &esym
);
290 * When we come in args consists of a pointer to the boot
291 * string. We need to fix it so it takes into account
292 * other params such as romp.
296 * Stash pointer to end of symbol table after the argument
299 l
= strlen(args
) + 1;
300 memcpy(args
+ l
, &esym
, sizeof(esym
));
304 * Tell the kernel we're an OpenFirmware system.
306 machine_tag
= SPARC_MACHINE_OPENFIRMWARE
;
307 memcpy(args
+ l
, &machine_tag
, sizeof(machine_tag
));
308 l
+= sizeof(machine_tag
);
311 * Since we don't need the boot string (we can get it from /chosen)
312 * we won't pass it in. Just pass in esym and magic #
314 newargs
[0] = SPARC_MACHINE_OPENFIRMWARE
;
315 newargs
[1] = (long)esym
;
316 newargs
[2] = (long)ssym
;
317 newargs
[3] = (long)(void*)bootinfo
;
318 args
= (char *)newargs
;
321 /* if -D is set then pause in the PROM. */
322 if (debug
> 1) callrom();
325 * Jump directly to the kernel. Solaris kernel and Sun PROM
326 * flash updates expect ROMP vector in %o0, so we do. Format
327 * of other parameters and their order reflect OF_chain()
328 * symantics since this is what older NetBSD kernels rely on.
329 * (see sparc64/include/bootinfo.h for specification).
331 DPRINTF(("jump_to_kernel(%lx, %lx, %lx, %lx, %lx) @ %p\n", (long)ofw
,
332 (long)args
, (long)l
, (long)ofw
, (long)ofw
,
333 (void*)marks
[MARK_ENTRY
]));
334 (*(entry_t
)marks
[MARK_ENTRY
])((long)ofw
, (long)args
, (long)l
, (long)ofw
,
336 printf("Returned from kernel entry point!\n");
340 start_kernel(char *kernel
, char *bootline
, void *ofw
)
343 u_long marks
[MARK_MAX
];
346 * First, load headers using default allocator and check whether kernel
347 * entry address matches kernel text load address. If yes, this is the
348 * old kernel designed for ofwboot v1.8 and therefore it must be mapped
349 * by PROM. Otherwise, map the kernel with 4MB permanent pages.
351 loadfile_set_allocator(LOADFILE_NOP_ALLOCATOR
);
352 if ( (fd
= loadfile(kernel
, marks
, LOAD_HDR
|COUNT_TEXT
)) != -1) {
353 if (COMPAT_BOOT(marks
) || compatmode
) {
354 (void)printf("[c] ");
355 loadfile_set_allocator(LOADFILE_OFW_ALLOCATOR
);
357 loadfile_set_allocator(LOADFILE_MMU_ALLOCATOR
);
359 (void)printf("Loading %s: ", kernel
);
361 if (fdloadfile(fd
, marks
, LOAD_ALL
) != -1) {
362 jump_to_kernel(marks
, kernel
, bootline
, ofw
);
365 (void)printf("Failed to load '%s'.\n", kernel
);
371 printf( "enter a special command\n"
374 " to return to OpenFirmware\n"
377 " to display this message\n"
378 "or a boot specification:\n"
379 " [device] [kernel] [options]\n"
382 " disk:a netbsd -s\n");
388 int boothowto
, i
= 0;
390 char kernel
[PROM_MAX_PATH
];
391 char bootline
[PROM_MAX_PATH
];
393 /* Initialize OpenFirmware */
397 printf("\r>> %s, Revision %s\n", bootprog_name
, bootprog_rev
);
398 DPRINTF((">> (%s, %s)\n", bootprog_maker
, bootprog_date
));
400 /* Figure boot arguments */
401 strncpy(bootdev
, prom_getbootpath(), sizeof(bootdev
) - 1);
402 boothowto
= bootoptions(prom_getbootargs(), bootdev
, kernel
, bootline
);
404 for (;; *kernel
= '\0') {
405 if (boothowto
& RB_ASKNAME
) {
406 char *cp
, cmdline
[PROM_MAX_PATH
];
411 if (!strcmp(cmdline
,"exit") ||
412 !strcmp(cmdline
,"halt")) {
414 } else if (!strcmp(cmdline
, "?") ||
415 !strcmp(cmdline
, "help")) {
420 boothowto
= bootoptions(cmdline
, bootdev
, kernel
,
422 boothowto
|= RB_ASKNAME
;
426 if (*kernel
== '\0') {
427 if (kernelnames
[i
] == NULL
) {
428 boothowto
|= RB_ASKNAME
;
431 strncpy(kernel
, kernelnames
[i
++], PROM_MAX_PATH
);
434 * Kernel name was passed via command line -- ask user
435 * again if requested image fails to boot.
437 boothowto
|= RB_ASKNAME
;
440 start_kernel(kernel
, bootline
, ofw
);
443 * Try next name from kernel name list if not in askname mode,
444 * enter askname on reaching list's end.
446 if ((boothowto
& RB_ASKNAME
) == 0 && (kernelnames
[i
] != NULL
)) {
447 printf(": trying %s...\n", kernelnames
[i
]);
450 boothowto
|= RB_ASKNAME
;
454 (void)printf("Boot failed! Exiting to the Firmware.\n");