xref: /netbsd-src/sys/arch/emips/stand/common/boot.c (revision 5a2e6e9910724937b05d363046d346368ea4b294)
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