boot.c revision 1.4
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 */
51char *kernelnames[] = {
52	"netbsd",	"netbsd.gz",
53	"netbsd.old",
54	"onetbsd",
55	"gennetbsd",
56	"nfsnetbsd",
57	NULL
58};
59
60
61void main (char *);
62char *getboot(char *, char*);
63static int devcanon(char *);
64
65#define OPT_MAX PATH_MAX /* way overkill */
66
67static 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 */
78void
79main(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
160fail:
161	(void)printf("Boot failed!  Halting...\n");
162}
163
164static inline int
165parse(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 */
202static inline void
203getstr(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
234char *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 */
256static int
257devcanon(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