main.c revision 1.8
1/* $NetBSD: main.c,v 1.8 2011/03/06 13:55:12 phx Exp $ */
2
3/*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33#include <sys/reboot.h>
34
35#include <lib/libsa/stand.h>
36#include <lib/libsa/loadfile.h>
37#include <lib/libkern/libkern.h>
38
39#include <machine/bootinfo.h>
40
41#include "globals.h"
42
43static const struct bootarg {
44	const char *name;
45	int value;
46} bootargs[] = {
47	{ "multi",	RB_AUTOBOOT },
48	{ "auto",	RB_AUTOBOOT },
49	{ "ask",	RB_ASKNAME },
50	{ "single",	RB_SINGLE },
51	{ "ddb",	RB_KDB },
52	{ "userconf",	RB_USERCONF },
53	{ "norm",	AB_NORMAL },
54	{ "quiet",	AB_QUIET },
55	{ "verb",	AB_VERBOSE },
56	{ "silent",	AB_SILENT },
57	{ "debug",	AB_DEBUG }
58};
59
60void *bootinfo; /* low memory reserved to pass bootinfo structures */
61int bi_size;	/* BOOTINFO_MAXSIZE */
62char *bi_next;
63
64void bi_init(void *);
65void bi_add(void *, int, int);
66
67struct btinfo_memory bi_mem;
68struct btinfo_console bi_cons;
69struct btinfo_clock bi_clk;
70struct btinfo_prodfamily bi_fam;
71struct btinfo_bootpath bi_path;
72struct btinfo_rootdevice bi_rdev;
73struct btinfo_net bi_net;
74struct btinfo_modulelist *btinfo_modulelist;
75size_t btinfo_modulelist_size;
76
77struct boot_module {
78	char *bm_kmod;
79	ssize_t bm_len;
80	struct boot_module *bm_next;
81};
82struct boot_module *boot_modules;
83char module_base[80];
84uint32_t kmodloadp;
85int modules_enabled = 0;
86
87void module_add(char *);
88void module_load(char *);
89int module_open(struct boot_module *);
90
91void main(int, char **, char *, char *);
92extern char bootprog_name[], bootprog_rev[];
93
94struct pcidev lata[2];
95struct pcidev lnif[1];
96struct pcidev lusb[3];
97int nata, nnif, nusb;
98
99int brdtype;
100uint32_t busclock, cpuclock;
101
102static int check_bootname(char *);
103static int parse_cmdline(char **, int, char *, char *);
104static int is_space(char);
105
106#define	BNAME_DEFAULT "nfs:"
107#define MAX_ARGS 10
108
109void
110main(int argc, char *argv[], char *bootargs_start, char *bootargs_end)
111{
112	struct brdprop *brdprop;
113	unsigned long marks[MARK_MAX];
114	char *new_argv[MAX_ARGS];
115	int n, i, fd, howto;
116	char *bname;
117
118	printf("\n");
119	printf(">> %s altboot, revision %s\n", bootprog_name, bootprog_rev);
120
121	brdprop = brd_lookup(brdtype);
122	printf(">> %s, cpu %u MHz, bus %u MHz, %dMB SDRAM\n", brdprop->verbose,
123	    cpuclock / 1000000, busclock / 1000000, bi_mem.memsize >> 20);
124
125	nata = pcilookup(PCI_CLASS_IDE, lata, 2);
126	if (nata == 0)
127		nata = pcilookup(PCI_CLASS_MISCSTORAGE, lata, 2);
128	if (nata == 0)
129		nata = pcilookup(PCI_CLASS_SCSI, lata, 2);
130	nnif = pcilookup(PCI_CLASS_ETH, lnif, 1);
131	nusb = pcilookup(PCI_CLASS_USB, lusb, 3);
132
133#ifdef DEBUG
134	if (nata == 0)
135		printf("No IDE/SATA found\n");
136	else for (n = 0; n < nata; n++) {
137		int b, d, f, bdf, pvd;
138		bdf = lata[n].bdf;
139		pvd = lata[n].pvd;
140		pcidecomposetag(bdf, &b, &d, &f);
141		printf("%04x.%04x DSK %02d:%02d:%02d\n",
142		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
143	}
144	if (nnif == 0)
145		printf("no NET found\n");
146	else {
147		int b, d, f, bdf, pvd;
148		bdf = lnif[0].bdf;
149		pvd = lnif[0].pvd;
150		pcidecomposetag(bdf, &b, &d, &f);
151		printf("%04x.%04x NET %02d:%02d:%02d\n",
152		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
153	}
154	if (nusb == 0)
155		printf("no USB found\n");
156	else for (n = 0; n < nusb; n++) {
157		int b, d, f, bdf, pvd;
158		bdf = lusb[0].bdf;
159		pvd = lusb[0].pvd;
160		pcidecomposetag(bdf, &b, &d, &f);
161		printf("%04x.%04x USB %02d:%02d:%02d\n",
162		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
163	}
164#endif
165
166	pcisetup();
167	pcifixup();
168
169	if (dskdv_init(&lata[0]) == 0
170	    || (nata == 2 && dskdv_init(&lata[1]) == 0))
171		printf("IDE/SATA device driver was not found\n");
172
173	if (netif_init(&lnif[0]) == 0)
174		printf("no NET device driver was found\n");
175
176	/*
177	 * When argc is too big then it is probably a pointer, which could
178	 * indicate that we were launched as a Linux kernel module using
179	 * "bootm".
180	 */
181	if (argc > MAX_ARGS) {
182		/* parse Linux bootargs */
183		argv = new_argv;
184		argc = parse_cmdline(argv, MAX_ARGS, bootargs_start,
185		    bootargs_end);
186	}
187
188	howto = RB_AUTOBOOT;		/* default is autoboot = 0 */
189
190	/* get boot options and determine bootname */
191	for (n = 1; n < argc; n++) {
192		for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) {
193			if (strncasecmp(argv[n], bootargs[i].name,
194			    strlen(bootargs[i].name)) == 0) {
195				howto |= bootargs[i].value;
196				break;
197			}
198		}
199		if (i >= sizeof(bootargs) / sizeof(bootargs[0]))
200			break;	/* break on first unknown string */
201	}
202	if (n >= argc)
203		bname = BNAME_DEFAULT;
204	else {
205		bname = argv[n];
206		if (check_bootname(bname) == 0) {
207			printf("%s not a valid bootname\n", bname);
208			goto loadfail;
209		}
210	}
211
212	if ((fd = open(bname, 0)) < 0) {
213		if (errno == ENOENT)
214			printf("\"%s\" not found\n", bi_path.bootpath);
215		goto loadfail;
216	}
217	printf("loading \"%s\" ", bi_path.bootpath);
218	marks[MARK_START] = 0;
219	if (fdloadfile(fd, marks, LOAD_KERNEL) < 0)
220		goto loadfail;
221	close(fd);
222
223	printf("entry=%p, ssym=%p, esym=%p\n",
224	    (void *)marks[MARK_ENTRY],
225	    (void *)marks[MARK_SYM],
226	    (void *)marks[MARK_END]);
227
228	bootinfo = (void *)0x4000;
229	bi_init(bootinfo);
230	bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons));
231	bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem));
232	bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk));
233	bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
234	bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
235	bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
236	if (brdtype == BRD_SYNOLOGY || brdtype == BRD_DLINKDSM) {
237		/* need to set this MAC address in kernel driver later */
238		bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
239	}
240
241	if (modules_enabled) {
242		module_add(fsmod);
243		if (fsmod2 != NULL && strcmp(fsmod, fsmod2) != 0)
244			module_add(fsmod2);
245		kmodloadp = marks[MARK_END];
246		btinfo_modulelist = NULL;
247		module_load(bname);
248		if (btinfo_modulelist != NULL && btinfo_modulelist->num > 0)
249			bi_add(btinfo_modulelist, BTINFO_MODULELIST,
250			    btinfo_modulelist_size);
251	}
252
253	__syncicache((void *)marks[MARK_ENTRY],
254	    (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]);
255
256	run((void *)marks[MARK_SYM], (void *)marks[MARK_END],
257	    (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]);
258
259	/* should never come here */
260	printf("exec returned. Restarting...\n");
261	_rtt();
262
263  loadfail:
264	printf("load failed. Restarting...\n");
265	_rtt();
266}
267
268void
269bi_init(void *addr)
270{
271	struct btinfo_magic bi_magic;
272
273	memset(addr, 0, BOOTINFO_MAXSIZE);
274	bi_next = (char *)addr;
275	bi_size = 0;
276
277	bi_magic.magic = BOOTINFO_MAGIC;
278	bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
279}
280
281void
282bi_add(void *new, int type, int size)
283{
284	struct btinfo_common *bi;
285
286	if (bi_size + size > BOOTINFO_MAXSIZE)
287		return;				/* XXX error? */
288
289	bi = new;
290	bi->next = size;
291	bi->type = type;
292	memcpy(bi_next, new, size);
293	bi_next += size;
294}
295
296void
297module_add(char *name)
298{
299	struct boot_module *bm, *bmp;
300
301	while (*name == ' ' || *name == '\t')
302		++name;
303
304	bm = alloc(sizeof(struct boot_module) + strlen(name) + 1);
305	if (bm == NULL) {
306		printf("couldn't allocate module %s\n", name);
307		return;
308	}
309
310	bm->bm_kmod = (char *)(bm + 1);
311	bm->bm_len = -1;
312	bm->bm_next = NULL;
313	strcpy(bm->bm_kmod, name);
314	if ((bmp = boot_modules) == NULL)
315		boot_modules = bm;
316	else {
317		while (bmp->bm_next != NULL)
318			bmp = bmp->bm_next;
319		bmp->bm_next = bm;
320	}
321}
322
323#define PAGE_SIZE	4096
324#define alignpg(x)	(((x)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
325
326void
327module_load(char *kernel_path)
328{
329	struct boot_module *bm;
330	struct bi_modulelist_entry *bi;
331	struct stat st;
332	char *p;
333	int size, fd;
334
335	strcpy(module_base, kernel_path);
336	if ((p = strchr(module_base, ':')) == NULL)
337		return; /* eeh?! */
338	p += 1;
339	size = sizeof(module_base) - (p - module_base);
340
341	if (netbsd_version / 1000000 % 100 == 99) {
342		/* -current */
343		snprintf(p, size,
344		    "/stand/sandpoint/%d.%d.%d/modules",
345		    netbsd_version / 100000000,
346		    netbsd_version / 1000000 % 100,
347		    netbsd_version / 100 % 100);
348	}
349	 else if (netbsd_version != 0) {
350		/* release */
351		snprintf(p, size,
352		    "/stand/sandpoint/%d.%d/modules",
353		    netbsd_version / 100000000,
354		    netbsd_version / 1000000 % 100);
355	}
356
357	/*
358	 * 1st pass; determine module existence
359	 */
360	size = 0;
361	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
362		fd = module_open(bm);
363		if (fd == -1)
364			continue;
365		if (fstat(fd, &st) == -1 || st.st_size == -1) {
366			printf("WARNING: couldn't stat %s\n", bm->bm_kmod);
367			close(fd);
368			continue;
369		}
370		bm->bm_len = (int)st.st_size;
371		close(fd);
372		size += sizeof(struct bi_modulelist_entry);
373	}
374	if (size == 0)
375		return;
376
377	size += sizeof(struct btinfo_modulelist);
378	btinfo_modulelist = alloc(size);
379	if (btinfo_modulelist == NULL) {
380		printf("WARNING: couldn't allocate module list\n");
381		return;
382	}
383	btinfo_modulelist_size = size;
384	btinfo_modulelist->num = 0;
385
386	/*
387	 * 2nd pass; load modules into memory
388	 */
389	kmodloadp = alignpg(kmodloadp);
390	bi = (struct bi_modulelist_entry *)(btinfo_modulelist + 1);
391	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
392		if (bm->bm_len == -1)
393			continue; /* already found unavailable */
394		fd = module_open(bm);
395		printf("module \"%s\" ", bm->bm_kmod);
396		size = read(fd, (char *)kmodloadp, SSIZE_MAX);
397		if (size < bm->bm_len)
398			printf("WARNING: couldn't load");
399		else {
400			snprintf(bi->kmod, sizeof(bi->kmod), bm->bm_kmod);
401			bi->type = BI_MODULE_ELF;
402			bi->len = size;
403			bi->base = kmodloadp;
404			btinfo_modulelist->num += 1;
405			printf("loaded at 0x%08x size 0x%x", kmodloadp, size);
406			kmodloadp += alignpg(size);
407			bi += 1;
408		}
409		printf("\n");
410		close(fd);
411	}
412	btinfo_modulelist->endpa = kmodloadp;
413}
414
415int
416module_open(struct boot_module *bm)
417{
418	char path[80];
419	int fd;
420
421	snprintf(path, sizeof(path),
422	    "%s/%s/%s.kmod", module_base, bm->bm_kmod, bm->bm_kmod);
423	fd = open(path, 0);
424	return fd;
425}
426
427#if 0
428static const char *cmdln[] = {
429	"console=ttyS0,115200 root=/dev/sda1 rw initrd=0x200000,2M",
430	"console=ttyS0,115200 root=/dev/nfs ip=dhcp"
431};
432
433void
434mkatagparams(unsigned addr, char *kcmd)
435{
436	struct tag {
437		unsigned siz;
438		unsigned tag;
439		unsigned val[1];
440	};
441	struct tag *p;
442#define ATAG_CORE 	0x54410001
443#define ATAG_MEM	0x54410002
444#define ATAG_INITRD	0x54410005
445#define ATAG_CMDLINE	0x54410009
446#define ATAG_NONE	0x00000000
447#define tagnext(p) (struct tag *)((unsigned *)(p) + (p)->siz)
448#define tagsize(n) (2 + (n))
449
450	p = (struct tag *)addr;
451	p->tag = ATAG_CORE;
452	p->siz = tagsize(3);
453	p->val[0] = 0;		/* flags */
454	p->val[1] = 0;		/* pagesize */
455	p->val[2] = 0;		/* rootdev */
456	p = tagnext(p);
457	p->tag = ATAG_MEM;
458	p->siz = tagsize(2);
459	p->val[0] = 64 * 1024 * 1024;
460	p->val[1] = 0;		/* start */
461	p = tagnext(p);
462	if (kcmd != NULL) {
463		p = tagnext(p);
464		p->tag = ATAG_CMDLINE;
465		p->siz = tagsize((strlen(kcmd) + 1 + 3) >> 2);
466		strcpy((void *)p->val, kcmd);
467	}
468	p = tagnext(p);
469	p->tag = ATAG_NONE;
470	p->siz = 0;
471}
472#endif
473
474void *
475allocaligned(size_t size, size_t align)
476{
477	uint32_t p;
478
479	if (align-- < 2)
480		return alloc(size);
481	p = (uint32_t)alloc(size + align);
482	return (void *)((p + align) & ~align);
483}
484
485static int
486check_bootname(char *s)
487{
488	/*
489	 * nfs:
490	 * nfs:<bootfile>
491	 * tftp:
492	 * tftp:<bootfile>
493	 * wd[N[P]]:<bootfile>
494	 *
495	 * net is a synonym of nfs.
496	 */
497	if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0)
498		return 1;
499	if (strncmp(s, "tftp:", 5) == 0)
500		return 1;
501	if (s[0] == 'w' && s[1] == 'd') {
502		s += 2;
503		if (*s != ':' && *s >= '0' && *s <= '3') {
504			++s;
505			if (*s != ':' && *s >= 'a' && *s <= 'p')
506				++s;
507		}
508		return *s == ':';
509	}
510	return 0;
511}
512
513static int
514parse_cmdline(char **argv, int maxargc, char *p, char *end)
515{
516	int argc;
517
518	argv[0] = "";
519	for (argc = 1; argc < maxargc && p < end; argc++) {
520		while (is_space(*p))
521			p++;
522		if (p >= end)
523			break;
524		argv[argc] = p;
525		while (!is_space(*p) && p < end)
526			p++;
527		*p++ = '\0';
528	}
529
530	return argc;
531}
532
533static int
534is_space(char c)
535{
536	return c > '\0' && c <= ' ';
537}
538