boot.c revision 1.1.4.2 1 1.1.4.2 rmind /* $NetBSD: boot.c,v 1.1.4.2 2011/03/05 20:50:01 rmind Exp $ */
2 1.1.4.2 rmind
3 1.1.4.2 rmind /*-
4 1.1.4.2 rmind * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 1.1.4.2 rmind * Copyright (c) 1999 The NetBSD Foundation, Inc.
6 1.1.4.2 rmind * All rights reserved.
7 1.1.4.2 rmind *
8 1.1.4.2 rmind * This code was written by Alessandro Forin and Neil Pittman
9 1.1.4.2 rmind * at Microsoft Research and contributed to The NetBSD Foundation
10 1.1.4.2 rmind * by Microsoft Corporation.
11 1.1.4.2 rmind *
12 1.1.4.2 rmind * Redistribution and use in source and binary forms, with or without
13 1.1.4.2 rmind * modification, are permitted provided that the following conditions
14 1.1.4.2 rmind * are met:
15 1.1.4.2 rmind * 1. Redistributions of source code must retain the above copyright
16 1.1.4.2 rmind * notice, this list of conditions and the following disclaimer.
17 1.1.4.2 rmind * 2. Redistributions in binary form must reproduce the above copyright
18 1.1.4.2 rmind * notice, this list of conditions and the following disclaimer in the
19 1.1.4.2 rmind * documentation and/or other materials provided with the distribution.
20 1.1.4.2 rmind *
21 1.1.4.2 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 1.1.4.2 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.1.4.2 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.1.4.2 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 1.1.4.2 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 1.1.4.2 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 1.1.4.2 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 1.1.4.2 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.1.4.2 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.1.4.2 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1.4.2 rmind * POSSIBILITY OF SUCH DAMAGE.
32 1.1.4.2 rmind */
33 1.1.4.2 rmind
34 1.1.4.2 rmind #include <lib/libsa/stand.h>
35 1.1.4.2 rmind #include <lib/libsa/loadfile.h>
36 1.1.4.2 rmind #include <lib/libkern/libkern.h>
37 1.1.4.2 rmind
38 1.1.4.2 rmind #include <sys/param.h>
39 1.1.4.2 rmind #include <sys/exec.h>
40 1.1.4.2 rmind #include <sys/exec_elf.h>
41 1.1.4.2 rmind
42 1.1.4.2 rmind #include "common.h"
43 1.1.4.2 rmind #include "bootinfo.h"
44 1.1.4.2 rmind #include "start.h"
45 1.1.4.2 rmind
46 1.1.4.2 rmind /*
47 1.1.4.2 rmind * We won't go overboard with gzip'd kernel names. After all we can
48 1.1.4.2 rmind * still boot a gzip'd kernel called "netbsd.emips" - it doesn't need
49 1.1.4.2 rmind * the .gz suffix.
50 1.1.4.2 rmind */
51 1.1.4.2 rmind char *kernelnames[] = {
52 1.1.4.2 rmind "netbsd", "netbsd.gz",
53 1.1.4.2 rmind "netbsd.old",
54 1.1.4.2 rmind "onetbsd",
55 1.1.4.2 rmind "gennetbsd",
56 1.1.4.2 rmind "nfsnetbsd",
57 1.1.4.2 rmind NULL
58 1.1.4.2 rmind };
59 1.1.4.2 rmind
60 1.1.4.2 rmind
61 1.1.4.2 rmind void main (char *);
62 1.1.4.2 rmind char *getboot(char *, char*);
63 1.1.4.2 rmind static int devcanon(char *);
64 1.1.4.2 rmind
65 1.1.4.2 rmind #define OPT_MAX PATH_MAX /* way overkill */
66 1.1.4.2 rmind
67 1.1.4.2 rmind static int loadit(char *name, u_long marks[MARK_MAX])
68 1.1.4.2 rmind {
69 1.1.4.2 rmind printf("Loading: %s\n", name);
70 1.1.4.2 rmind memset(marks, 0, sizeof marks);
71 1.1.4.2 rmind return (loadfile(name, marks, LOAD_ALL));
72 1.1.4.2 rmind }
73 1.1.4.2 rmind
74 1.1.4.2 rmind /*
75 1.1.4.2 rmind * The locore in start.S calls us with an 8KB stack carved after _end.
76 1.1.4.2 rmind *
77 1.1.4.2 rmind */
78 1.1.4.2 rmind void
79 1.1.4.2 rmind main(char *stack_top)
80 1.1.4.2 rmind {
81 1.1.4.2 rmind int argc;
82 1.1.4.2 rmind int autoboot = 1, win;
83 1.1.4.2 rmind char *name, **namep, *dev, *kernel;
84 1.1.4.2 rmind char bootname[PATH_MAX], bootpath[PATH_MAX], options[OPT_MAX];
85 1.1.4.2 rmind uint32_t entry;
86 1.1.4.2 rmind u_long marks[MARK_MAX];
87 1.1.4.2 rmind struct btinfo_symtab bi_syms;
88 1.1.4.2 rmind struct btinfo_bootpath bi_bpath;
89 1.1.4.2 rmind
90 1.1.4.2 rmind /* Init all peripherals, esp USART for printf and memory */
91 1.1.4.2 rmind init_board();
92 1.1.4.2 rmind
93 1.1.4.2 rmind /* On account of compression, we need a fairly large heap.
94 1.1.4.2 rmind * To keep things simple, take one meg just below the 16 meg mark.
95 1.1.4.2 rmind * That allows for a large kernel, and a 16MB configuration still works.
96 1.1.4.2 rmind */
97 1.1.4.2 rmind setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000);
98 1.1.4.2 rmind
99 1.1.4.2 rmind /* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete
100 1.1.4.2 rmind * and switching the serial line to PuTTY as console. Get a char to pause.
101 1.1.4.2 rmind * This delay is also the practice on PCs so.
102 1.1.4.2 rmind */
103 1.1.4.2 rmind Delay(200000);
104 1.1.4.2 rmind printf("Hit any char to boot..");
105 1.1.4.2 rmind argc = GetChar();
106 1.1.4.2 rmind
107 1.1.4.2 rmind /* print a banner */
108 1.1.4.2 rmind printf("\n");
109 1.1.4.2 rmind printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n",
110 1.1.4.2 rmind bootprog_rev);
111 1.1.4.2 rmind
112 1.1.4.2 rmind /* initialise bootinfo structure early */
113 1.1.4.2 rmind bi_init(BOOTINFO_ADDR);
114 1.1.4.2 rmind
115 1.1.4.2 rmind /* Default is to auto-boot from the first disk */
116 1.1.4.2 rmind dev = "0/ace(0,0)/";
117 1.1.4.2 rmind kernel = kernelnames[0];
118 1.1.4.2 rmind options[0] = 0;
119 1.1.4.2 rmind
120 1.1.4.2 rmind win = 0;
121 1.1.4.2 rmind for (;!win;) {
122 1.1.4.2 rmind strcpy(bootpath, dev);
123 1.1.4.2 rmind strcat(bootpath, kernel);
124 1.1.4.2 rmind name = getboot(bootpath,options);
125 1.1.4.2 rmind
126 1.1.4.2 rmind if (name != NULL) {
127 1.1.4.2 rmind win = (loadit(name, marks) == 0);
128 1.1.4.2 rmind } else if (autoboot)
129 1.1.4.2 rmind break;
130 1.1.4.2 rmind autoboot = 0;
131 1.1.4.2 rmind }
132 1.1.4.2 rmind
133 1.1.4.2 rmind if (!win) {
134 1.1.4.2 rmind for (namep = kernelnames, win = 0; *namep != NULL && !win;
135 1.1.4.2 rmind namep++) {
136 1.1.4.2 rmind kernel = *namep;
137 1.1.4.2 rmind strcpy(bootpath, dev);
138 1.1.4.2 rmind strcat(bootpath, kernel);
139 1.1.4.2 rmind win = (loadit(bootpath, marks) == 0);
140 1.1.4.2 rmind if (win) {
141 1.1.4.2 rmind name = bootpath;
142 1.1.4.2 rmind }
143 1.1.4.2 rmind }
144 1.1.4.2 rmind }
145 1.1.4.2 rmind if (!win)
146 1.1.4.2 rmind goto fail;
147 1.1.4.2 rmind
148 1.1.4.2 rmind strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN);
149 1.1.4.2 rmind bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
150 1.1.4.2 rmind
151 1.1.4.2 rmind entry = marks[MARK_ENTRY];
152 1.1.4.2 rmind bi_syms.nsym = marks[MARK_NSYM];
153 1.1.4.2 rmind bi_syms.ssym = marks[MARK_SYM];
154 1.1.4.2 rmind bi_syms.esym = marks[MARK_END];
155 1.1.4.2 rmind bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
156 1.1.4.2 rmind
157 1.1.4.2 rmind printf("Starting at 0x%x\n\n", entry);
158 1.1.4.2 rmind call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo);
159 1.1.4.2 rmind (void)printf("KERNEL RETURNED!\n");
160 1.1.4.2 rmind
161 1.1.4.2 rmind fail:
162 1.1.4.2 rmind (void)printf("Boot failed! Halting...\n");
163 1.1.4.2 rmind }
164 1.1.4.2 rmind
165 1.1.4.2 rmind static inline int
166 1.1.4.2 rmind parse(char *cmd, char *kname, char *optarg)
167 1.1.4.2 rmind {
168 1.1.4.2 rmind char *arg = cmd;
169 1.1.4.2 rmind char *ep, *p;
170 1.1.4.2 rmind int c, i;
171 1.1.4.2 rmind
172 1.1.4.2 rmind while ((c = *arg++)) {
173 1.1.4.2 rmind /* skip leading blanks */
174 1.1.4.2 rmind if (c == ' ' || c == '\t' || c == '\n')
175 1.1.4.2 rmind continue;
176 1.1.4.2 rmind /* find separator, or eol */
177 1.1.4.2 rmind for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
178 1.1.4.2 rmind ep = p;
179 1.1.4.2 rmind /* trim if separator */
180 1.1.4.2 rmind if (*p)
181 1.1.4.2 rmind *p++ = 0;
182 1.1.4.2 rmind /* token is either "-opts" or "kernelname" */
183 1.1.4.2 rmind if (c == '-') {
184 1.1.4.2 rmind /* no overflow because whole line same length as optarg anyways */
185 1.1.4.2 rmind while ((c = *arg++)) {
186 1.1.4.2 rmind *optarg++ = c;
187 1.1.4.2 rmind }
188 1.1.4.2 rmind *optarg = 0;
189 1.1.4.2 rmind } else {
190 1.1.4.2 rmind arg--;
191 1.1.4.2 rmind if ((i = ep - arg)) {
192 1.1.4.2 rmind if ((size_t)i >= PATH_MAX)
193 1.1.4.2 rmind return -1;
194 1.1.4.2 rmind memcpy(kname, arg, i + 1);
195 1.1.4.2 rmind }
196 1.1.4.2 rmind }
197 1.1.4.2 rmind arg = p;
198 1.1.4.2 rmind }
199 1.1.4.2 rmind return 0;
200 1.1.4.2 rmind }
201 1.1.4.2 rmind
202 1.1.4.2 rmind /* String returned is zero-terminated and at most PATH_MAX chars */
203 1.1.4.2 rmind static inline void
204 1.1.4.2 rmind getstr(char *cmd, int c)
205 1.1.4.2 rmind {
206 1.1.4.2 rmind char *s;
207 1.1.4.2 rmind
208 1.1.4.2 rmind s = cmd;
209 1.1.4.2 rmind if (c == 0)
210 1.1.4.2 rmind c = GetChar();
211 1.1.4.2 rmind for (;;) {
212 1.1.4.2 rmind switch (c) {
213 1.1.4.2 rmind case 0:
214 1.1.4.2 rmind break;
215 1.1.4.2 rmind case '\177':
216 1.1.4.2 rmind case '\b':
217 1.1.4.2 rmind if (s > cmd) {
218 1.1.4.2 rmind s--;
219 1.1.4.2 rmind printf("\b \b");
220 1.1.4.2 rmind }
221 1.1.4.2 rmind break;
222 1.1.4.2 rmind case '\n':
223 1.1.4.2 rmind case '\r':
224 1.1.4.2 rmind *s = 0;
225 1.1.4.2 rmind return;
226 1.1.4.2 rmind default:
227 1.1.4.2 rmind if ((s - cmd) < (PATH_MAX - 1))
228 1.1.4.2 rmind *s++ = c;
229 1.1.4.2 rmind xputchar(c);
230 1.1.4.2 rmind }
231 1.1.4.2 rmind c = GetChar();
232 1.1.4.2 rmind }
233 1.1.4.2 rmind }
234 1.1.4.2 rmind
235 1.1.4.2 rmind char *getboot(char *kname, char* optarg)
236 1.1.4.2 rmind {
237 1.1.4.2 rmind char c = 0;
238 1.1.4.2 rmind char cmd[PATH_MAX];
239 1.1.4.2 rmind
240 1.1.4.2 rmind printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname);
241 1.1.4.2 rmind if ((c = GetChar()) == -1)
242 1.1.4.2 rmind return NULL;
243 1.1.4.2 rmind
244 1.1.4.2 rmind cmd[0] = 0;
245 1.1.4.2 rmind getstr(cmd,c);
246 1.1.4.2 rmind xputchar('\n');
247 1.1.4.2 rmind if (parse(cmd,kname,optarg))
248 1.1.4.2 rmind xputchar('\a');
249 1.1.4.2 rmind else if (devcanon(kname) == 0)
250 1.1.4.2 rmind return kname;
251 1.1.4.2 rmind return NULL;
252 1.1.4.2 rmind }
253 1.1.4.2 rmind
254 1.1.4.2 rmind /*
255 1.1.4.2 rmind * Make bootpath canonical, provides defaults when missing
256 1.1.4.2 rmind */
257 1.1.4.2 rmind static int
258 1.1.4.2 rmind devcanon(char *fname)
259 1.1.4.2 rmind {
260 1.1.4.2 rmind int ctlr = 0, unit = 0, part = 0;
261 1.1.4.2 rmind int c, rc;
262 1.1.4.2 rmind char device_name[20];
263 1.1.4.2 rmind char file_name[PATH_MAX];
264 1.1.4.2 rmind const char *cp;
265 1.1.4.2 rmind char *ncp;
266 1.1.4.2 rmind
267 1.1.4.2 rmind //printf("devcanon(%s)\n",fname);
268 1.1.4.2 rmind
269 1.1.4.2 rmind cp = fname;
270 1.1.4.2 rmind ncp = device_name;
271 1.1.4.2 rmind
272 1.1.4.2 rmind /* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file
273 1.1.4.2 rmind * Defaults: ctrl=0, name='ace', unit=0, part=0, file=<none>
274 1.1.4.2 rmind */
275 1.1.4.2 rmind
276 1.1.4.2 rmind /* get controller number */
277 1.1.4.2 rmind if ((c = *cp) >= '0' && c <= '9') {
278 1.1.4.2 rmind ctlr = c - '0';
279 1.1.4.2 rmind c = *++cp;
280 1.1.4.2 rmind if (c != '/')
281 1.1.4.2 rmind return (ENXIO);
282 1.1.4.2 rmind c = *++cp;
283 1.1.4.2 rmind }
284 1.1.4.2 rmind
285 1.1.4.2 rmind /* get device name */
286 1.1.4.2 rmind while ((c = *cp) != '\0') {
287 1.1.4.2 rmind if ((c == '(') || (c == '/')) {
288 1.1.4.2 rmind cp++;
289 1.1.4.2 rmind break;
290 1.1.4.2 rmind }
291 1.1.4.2 rmind if (ncp < device_name + sizeof(device_name) - 1)
292 1.1.4.2 rmind *ncp++ = c;
293 1.1.4.2 rmind cp++;
294 1.1.4.2 rmind }
295 1.1.4.2 rmind /* set default if missing */
296 1.1.4.2 rmind if (ncp == device_name) {
297 1.1.4.2 rmind strcpy(device_name,"ace");
298 1.1.4.2 rmind ncp += 3;
299 1.1.4.2 rmind }
300 1.1.4.2 rmind
301 1.1.4.2 rmind /* get device number */
302 1.1.4.2 rmind if ((c = *cp) >= '0' && c <= '9') {
303 1.1.4.2 rmind unit = c - '0';
304 1.1.4.2 rmind c = *++cp;
305 1.1.4.2 rmind }
306 1.1.4.2 rmind
307 1.1.4.2 rmind if (c == ',') {
308 1.1.4.2 rmind /* get partition number */
309 1.1.4.2 rmind if ((c = *++cp) >= '0' && c <= '9') {
310 1.1.4.2 rmind part = c - '0';
311 1.1.4.2 rmind c = *++cp;
312 1.1.4.2 rmind }
313 1.1.4.2 rmind }
314 1.1.4.2 rmind
315 1.1.4.2 rmind if (c == ')')
316 1.1.4.2 rmind c = *++cp;
317 1.1.4.2 rmind if (c == '/')
318 1.1.4.2 rmind cp++;
319 1.1.4.2 rmind
320 1.1.4.2 rmind *ncp = '\0';
321 1.1.4.2 rmind
322 1.1.4.2 rmind /* Copy kernel name before we overwrite, then do it */
323 1.1.4.2 rmind strcpy(file_name, (*cp) ? cp : kernelnames[0]);
324 1.1.4.2 rmind sprintf(fname,"%c/%s(%c,%c)/%s",
325 1.1.4.2 rmind ctlr + '0', device_name, unit + '0', part + '0', file_name);
326 1.1.4.2 rmind
327 1.1.4.2 rmind //printf("devcanon -> %s\n",fname);
328 1.1.4.2 rmind
329 1.1.4.2 rmind return (0);
330 1.1.4.2 rmind }
331