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