xref: /netbsd/sys/arch/emips/stand/common/boot.c (revision 6550d01e)
1 /*	$NetBSD: boot.c,v 1.1 2011/01/26 01:18:54 pooka 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