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