1 /* $NetBSD: boot.c,v 1.23 2006/07/13 20:03:34 uwe Exp $ */
4 * Copyright (c) 1982, 1986, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)boot.c 8.1 (Berkeley) 6/10/93
34 #include <sys/param.h>
35 #include <sys/reboot.h>
36 #include <sys/boot_flag.h>
39 #include <lib/libsa/stand.h>
40 #include <lib/libsa/loadfile.h>
41 #include <lib/libkern/libkern.h>
43 #include <machine/promlib.h>
44 #include <sparc/stand/common/promdev.h>
48 extern void prom_patch(void); /* prompatch.c */
50 static int bootoptions(const char *);
56 char fbuf
[80], dbuf
[128];
57 paddr_t bstart
, bend
; /* physical start & end address of the boot program */
59 int compatmode
= 0; /* For loading older kernels */
60 u_long loadaddrmask
= -1UL;
62 extern char bootprog_name
[], bootprog_rev
[], bootprog_date
[], bootprog_maker
[];
65 typedef void (*entry_t
)(void *, int, int, int, long, long);
68 * Boot device is derived from ROM provided information, or if there is none,
69 * this list is used in sequence, to find a kernel.
89 bootoptions(const char *ap
)
92 if (ap
== NULL
|| *ap
++ != '-')
95 while (*ap
!= '\0' && *ap
!= ' ' && *ap
!= '\t' && *ap
!= '\n') {
102 if ((v
& RB_KDB
) != 0)
109 getphysmem(u_long size
)
111 struct memarr
*pmemarr
; /* physical memory regions */
112 int npmemarr
; /* number of entries in pmemarr */
115 extern char start
[]; /* top of stack (see srt0.S) */
118 * Find the physical memory area that's in use by the boot loader.
119 * Our stack grows down from label `start'; assume we need no more
120 * than 16K of stack space.
121 * The top of the boot loader is the next 4MB boundary.
123 if (pmap_extract((vaddr_t
)start
- (16*1024), &bstart
) != 0)
124 return ((paddr_t
)-1);
126 bend
= roundup(bstart
, 0x400000);
129 * Get available physical memory from the prom.
131 npmemarr
= prom_makememarr(NULL
, 0, MEMARR_AVAILPHYS
);
132 pmemarr
= alloc(npmemarr
*sizeof(struct memarr
));
134 return ((paddr_t
)-1);
135 npmemarr
= prom_makememarr(pmemarr
, npmemarr
, MEMARR_AVAILPHYS
);
138 * Find a suitable loading address.
140 for (mp
= pmemarr
, i
= npmemarr
; --i
>= 0; mp
++) {
141 paddr_t pa
= (paddr_t
)pmemarr
[i
].addr
;
142 u_long len
= (u_long
)pmemarr
[i
].len
;
144 /* Check whether it will fit in front of us */
145 if (pa
< bstart
&& len
>= size
&& (bstart
- pa
) >= size
)
148 /* Skip the boot program memory */
151 /* Not large enough */
154 /* Shrink this segment */
159 /* Does it fit in the remainder of this segment? */
163 return ((paddr_t
)-1);
167 loadk(char *kernel
, u_long
*marks
)
174 if ((fd
= open(kernel
, 0)) < 0)
175 return (errno
? errno
: ENOENT
);
177 marks
[MARK_START
] = 0;
178 if ((error
= fdloadfile(fd
, marks
, COUNT_KERNEL
)) != 0)
181 size
= marks
[MARK_END
] - marks
[MARK_START
];
183 /* We want that leading 16K in front of the kernel image */
184 size
+= PROM_LOADADDR
;
185 va
= marks
[MARK_START
] - PROM_LOADADDR
;
188 * Extra space for bootinfo and kernel bootstrap.
189 * In compat mode, we get to re-use the space occupied by the
190 * boot program. Traditionally, we've silently assumed that
191 * is enough for the kernel to work with.
193 size
+= BOOTINFO_SIZE
;
197 /* Get a physical load address */
198 pa
= getphysmem(size
);
199 if (pa
== (paddr_t
)-1) {
204 if (boothowto
& AB_VERBOSE
)
205 printf("Loading at physical address %lx\n", pa
);
206 if (pmap_map(va
, pa
, size
) != 0) {
211 /* XXX - to do: inspect kernel image and set compat mode */
213 /* Double-map at VA 0 for compatibility */
214 if (pa
+ size
>= bstart
) {
215 printf("%s: too large for compat mode\n", kernel
);
220 if (pa
!= 0 && pmap_map(0, pa
, size
) != 0) {
224 loadaddrmask
= 0x07ffffffUL
;
227 marks
[MARK_START
] = 0;
228 error
= fdloadfile(fd
, marks
, LOAD_KERNEL
);
238 char kernel
[MAX_PROM_PATH
];
240 u_long marks
[MARK_MAX
], bootinfo
;
241 struct btinfo_symtab bi_sym
;
247 setheap((void *)ALIGN(end
), (void *)0xffffffff);
253 printf(">> %s, Revision %s\n", bootprog_name
, bootprog_rev
);
254 printf(">> (%s, %s)\n", bootprog_maker
, bootprog_date
);
256 /* massage machine prom */
260 * get default kernel.
262 k
= prom_getbootfile();
263 if (k
!= NULL
&& *k
!= '\0') {
264 i
= -1; /* not using the kernels */
268 strcpy(kernel
, kernels
[i
]);
271 k
= prom_getbootpath();
273 strcpy(prom_bootdevice
, k
);
274 boothowto
= bootoptions(prom_getbootargs());
278 * ask for a kernel first ..
280 if (boothowto
& RB_ASKNAME
) {
281 printf("device[%s] (\"halt\" to halt): ",
284 if (strcmp(dbuf
, "halt") == 0)
287 strcpy(prom_bootdevice
, dbuf
);
288 printf("boot (press RETURN to try default list): ");
291 strcpy(kernel
, fbuf
);
293 boothowto
&= ~RB_ASKNAME
;
295 strcpy(kernel
, kernels
[i
]);
299 printf("Booting %s\n", kernel
);
300 if ((error
= loadk(kernel
, marks
)) == 0)
303 if (error
!= ENOENT
) {
304 printf("Cannot load %s: error=%d\n", kernel
, error
);
305 boothowto
|= RB_ASKNAME
;
309 * if we have are not in askname mode, and we aren't using the
310 * prom bootfile, try the next one (if it exits). otherwise,
311 * go into askname mode.
313 if ((boothowto
& RB_ASKNAME
) == 0 &&
314 i
!= -1 && kernels
[++i
]) {
315 strcpy(kernel
, kernels
[i
]);
316 printf(": trying %s...\n", kernel
);
319 boothowto
|= RB_ASKNAME
;
323 marks
[MARK_END
] = (((u_long
)marks
[MARK_END
] + sizeof(u_long
) - 1)) &
325 arg
= (prom_version() == PROM_OLDMON
) ? (void *)PROM_LOADADDR
: romp
;
327 /* Setup boot info structure at the end of the kernel image */
328 bootinfo
= bi_init(marks
[MARK_END
] & loadaddrmask
);
330 /* Add kernel symbols to bootinfo */
331 bi_sym
.nsym
= marks
[MARK_NSYM
] & loadaddrmask
;
332 bi_sym
.ssym
= marks
[MARK_SYM
] & loadaddrmask
;
333 bi_sym
.esym
= marks
[MARK_END
] & loadaddrmask
;
334 bi_add(&bi_sym
, BTINFO_SYMTAB
, sizeof(bi_sym
));
336 /* Add kernel path to bootinfo */
337 i
= sizeof(struct btinfo_common
) + strlen(kernel
) + 1;
338 /* Impose limit (somewhat arbitrary) */
339 if (i
< BOOTINFO_SIZE
/ 2) {
341 struct btinfo_kernelfile bi_file
;
344 strcpy(U
.bi_file
.name
, kernel
);
345 bi_add(&U
.bi_file
, BTINFO_KERNELFILE
, i
);
348 (*(entry_t
)marks
[MARK_ENTRY
])(arg
, 0, 0, 0, bootinfo
, DDB_MAGIC2
);