1 /* $NetBSD: boot.c,v 1.4 2015/12/13 18:24:50 christos 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
loadit(char * name,u_long * marks)67 static int loadit(char *name, u_long *marks)
68 {
69 printf("Loading: %s\n", name);
70 memset(marks, 0, sizeof(*marks) * MARK_MAX);
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
main(char * stack_top)79 main(char *stack_top)
80 {
81 int autoboot = 1, win;
82 char *name, **namep, *dev, *kernel;
83 char bootpath[PATH_MAX], options[OPT_MAX];
84 uint32_t entry;
85 u_long marks[MARK_MAX];
86 struct btinfo_symtab bi_syms;
87 struct btinfo_bootpath bi_bpath;
88
89 /* Init all peripherals, esp USART for printf and memory */
90 init_board();
91
92 /* On account of compression, we need a fairly large heap.
93 * To keep things simple, take one meg just below the 16 meg mark.
94 * That allows for a large kernel, and a 16MB configuration still works.
95 */
96 setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000);
97
98 /* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete
99 * and switching the serial line to PuTTY as console. Get a char to pause.
100 * This delay is also the practice on PCs so.
101 */
102 Delay(200000);
103 printf("Hit any char to boot..");
104 (void)GetChar();
105
106 /* print a banner */
107 printf("\n");
108 printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n",
109 bootprog_rev);
110
111 /* initialise bootinfo structure early */
112 bi_init(BOOTINFO_ADDR);
113
114 /* Default is to auto-boot from the first disk */
115 dev = "0/ace(0,0)/";
116 kernel = kernelnames[0];
117 options[0] = 0;
118
119 win = 0;
120 for (;!win;) {
121 strcpy(bootpath, dev);
122 strcat(bootpath, kernel);
123 name = getboot(bootpath,options);
124
125 if (name != NULL) {
126 win = (loadit(name, marks) == 0);
127 } else if (autoboot)
128 break;
129 autoboot = 0;
130 }
131
132 if (!win) {
133 for (namep = kernelnames, win = 0; *namep != NULL && !win;
134 namep++) {
135 kernel = *namep;
136 strcpy(bootpath, dev);
137 strcat(bootpath, kernel);
138 win = (loadit(bootpath, marks) == 0);
139 if (win) {
140 name = bootpath;
141 }
142 }
143 }
144 if (!win)
145 goto fail;
146
147 strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN);
148 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
149
150 entry = marks[MARK_ENTRY];
151 bi_syms.nsym = marks[MARK_NSYM];
152 bi_syms.ssym = marks[MARK_SYM];
153 bi_syms.esym = marks[MARK_END];
154 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
155
156 printf("Starting at 0x%x\n\n", entry);
157 call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo);
158 (void)printf("KERNEL RETURNED!\n");
159
160 fail:
161 (void)printf("Boot failed! Halting...\n");
162 }
163
164 static inline int
parse(char * cmd,char * kname,char * optarg)165 parse(char *cmd, char *kname, char *optarg)
166 {
167 char *arg = cmd;
168 char *ep, *p;
169 int c, i;
170
171 while ((c = *arg++)) {
172 /* skip leading blanks */
173 if (c == ' ' || c == '\t' || c == '\n')
174 continue;
175 /* find separator, or eol */
176 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
177 ep = p;
178 /* trim if separator */
179 if (*p)
180 *p++ = 0;
181 /* token is either "-opts" or "kernelname" */
182 if (c == '-') {
183 /* no overflow because whole line same length as optarg anyways */
184 while ((c = *arg++)) {
185 *optarg++ = c;
186 }
187 *optarg = 0;
188 } else {
189 arg--;
190 if ((i = ep - arg)) {
191 if ((size_t)i >= PATH_MAX)
192 return -1;
193 memcpy(kname, arg, i + 1);
194 }
195 }
196 arg = p;
197 }
198 return 0;
199 }
200
201 /* String returned is zero-terminated and at most PATH_MAX chars */
202 static inline void
getstr(char * cmd,int c)203 getstr(char *cmd, int c)
204 {
205 char *s;
206
207 s = cmd;
208 if (c == 0)
209 c = GetChar();
210 for (;;) {
211 switch (c) {
212 case 0:
213 break;
214 case '\177':
215 case '\b':
216 if (s > cmd) {
217 s--;
218 printf("\b \b");
219 }
220 break;
221 case '\n':
222 case '\r':
223 *s = 0;
224 return;
225 default:
226 if ((s - cmd) < (PATH_MAX - 1))
227 *s++ = c;
228 xputchar(c);
229 }
230 c = GetChar();
231 }
232 }
233
getboot(char * kname,char * optarg)234 char *getboot(char *kname, char* optarg)
235 {
236 char c = 0;
237 char cmd[PATH_MAX];
238
239 printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname);
240 if ((c = GetChar()) == -1)
241 return NULL;
242
243 cmd[0] = 0;
244 getstr(cmd,c);
245 xputchar('\n');
246 if (parse(cmd,kname,optarg))
247 xputchar('\a');
248 else if (devcanon(kname) == 0)
249 return kname;
250 return NULL;
251 }
252
253 /*
254 * Make bootpath canonical, provides defaults when missing
255 */
256 static int
devcanon(char * fname)257 devcanon(char *fname)
258 {
259 int ctlr = 0, unit = 0, part = 0;
260 int c;
261 char device_name[20];
262 char file_name[PATH_MAX];
263 const char *cp;
264 char *ncp;
265
266 //printf("devcanon(%s)\n",fname);
267
268 cp = fname;
269 ncp = device_name;
270
271 /* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file
272 * Defaults: ctrl=0, name='ace', unit=0, part=0, file=<none>
273 */
274
275 /* get controller number */
276 if ((c = *cp) >= '0' && c <= '9') {
277 ctlr = c - '0';
278 c = *++cp;
279 if (c != '/')
280 return (ENXIO);
281 c = *++cp;
282 }
283
284 /* get device name */
285 while ((c = *cp) != '\0') {
286 if ((c == '(') || (c == '/')) {
287 cp++;
288 break;
289 }
290 if (ncp < device_name + sizeof(device_name) - 1)
291 *ncp++ = c;
292 cp++;
293 }
294 /* set default if missing */
295 if (ncp == device_name) {
296 strcpy(device_name,"ace");
297 ncp += 3;
298 }
299
300 /* get device number */
301 if ((c = *cp) >= '0' && c <= '9') {
302 unit = c - '0';
303 c = *++cp;
304 }
305
306 if (c == ',') {
307 /* get partition number */
308 if ((c = *++cp) >= '0' && c <= '9') {
309 part = c - '0';
310 c = *++cp;
311 }
312 }
313
314 if (c == ')')
315 c = *++cp;
316 if (c == '/')
317 cp++;
318
319 *ncp = '\0';
320
321 /* Copy kernel name before we overwrite, then do it */
322 strcpy(file_name, (*cp) ? cp : kernelnames[0]);
323 snprintf(fname, PATH_MAX, "%c/%s(%c,%c)/%s",
324 ctlr + '0', device_name, unit + '0', part + '0', file_name);
325
326 //printf("devcanon -> %s\n",fname);
327
328 return (0);
329 }
330