main.c revision 1.7
1/* $NetBSD: main.c,v 1.7 2011/02/26 20:11:24 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	nnif = pcilookup(PCI_CLASS_ETH, lnif, 1);
129	nusb = pcilookup(PCI_CLASS_USB, lusb, 3);
130
131#ifdef DEBUG
132	if (nata == 0)
133		printf("No IDE/SATA found\n");
134	else for (n = 0; n < nata; n++) {
135		int b, d, f, bdf, pvd;
136		bdf = lata[n].bdf;
137		pvd = lata[n].pvd;
138		pcidecomposetag(bdf, &b, &d, &f);
139		printf("%04x.%04x DSK %02d:%02d:%02d\n",
140		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
141	}
142	if (nnif == 0)
143		printf("no NET found\n");
144	else {
145		int b, d, f, bdf, pvd;
146		bdf = lnif[0].bdf;
147		pvd = lnif[0].pvd;
148		pcidecomposetag(bdf, &b, &d, &f);
149		printf("%04x.%04x NET %02d:%02d:%02d\n",
150		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
151	}
152	if (nusb == 0)
153		printf("no USB found\n");
154	else for (n = 0; n < nusb; n++) {
155		int b, d, f, bdf, pvd;
156		bdf = lusb[0].bdf;
157		pvd = lusb[0].pvd;
158		pcidecomposetag(bdf, &b, &d, &f);
159		printf("%04x.%04x USB %02d:%02d:%02d\n",
160		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
161	}
162#endif
163
164	pcisetup();
165	pcifixup();
166
167	if (dskdv_init(&lata[0]) == 0
168	    || (nata == 2 && dskdv_init(&lata[1]) == 0))
169		printf("IDE/SATA device driver was not found\n");
170
171	if (netif_init(&lnif[0]) == 0)
172		printf("no NET device driver was found\n");
173
174	/*
175	 * When argc is too big then it is probably a pointer, which could
176	 * indicate that we were launched as a Linux kernel module using
177	 * "bootm".
178	 */
179	if (argc > MAX_ARGS) {
180		/* parse Linux bootargs */
181		argv = new_argv;
182		argc = parse_cmdline(argv, MAX_ARGS, bootargs_start,
183		    bootargs_end);
184	}
185
186	howto = RB_AUTOBOOT;		/* default is autoboot = 0 */
187
188	/* get boot options and determine bootname */
189	for (n = 1; n < argc; n++) {
190		for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) {
191			if (strncasecmp(argv[n], bootargs[i].name,
192			    strlen(bootargs[i].name)) == 0) {
193				howto |= bootargs[i].value;
194				break;
195			}
196		}
197		if (i >= sizeof(bootargs) / sizeof(bootargs[0]))
198			break;	/* break on first unknown string */
199	}
200	if (n >= argc)
201		bname = BNAME_DEFAULT;
202	else {
203		bname = argv[n];
204		if (check_bootname(bname) == 0) {
205			printf("%s not a valid bootname\n", bname);
206			goto loadfail;
207		}
208	}
209
210	if ((fd = open(bname, 0)) < 0) {
211		if (errno == ENOENT)
212			printf("\"%s\" not found\n", bi_path.bootpath);
213		goto loadfail;
214	}
215	printf("loading \"%s\" ", bi_path.bootpath);
216	marks[MARK_START] = 0;
217	if (fdloadfile(fd, marks, LOAD_KERNEL) < 0)
218		goto loadfail;
219	close(fd);
220
221	printf("entry=%p, ssym=%p, esym=%p\n",
222	    (void *)marks[MARK_ENTRY],
223	    (void *)marks[MARK_SYM],
224	    (void *)marks[MARK_END]);
225
226	bootinfo = (void *)0x4000;
227	bi_init(bootinfo);
228	bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons));
229	bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem));
230	bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk));
231	bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
232	bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
233	bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
234	if (brdtype == BRD_SYNOLOGY) {
235		/* need to set MAC address for Marvell-SKnet */
236		bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
237	}
238
239	if (modules_enabled) {
240		module_add(fsmod);
241		if (fsmod2 != NULL && strcmp(fsmod, fsmod2) != 0)
242			module_add(fsmod2);
243		kmodloadp = marks[MARK_END];
244		btinfo_modulelist = NULL;
245		module_load(bname);
246		if (btinfo_modulelist != NULL && btinfo_modulelist->num > 0)
247			bi_add(btinfo_modulelist, BTINFO_MODULELIST,
248			    btinfo_modulelist_size);
249	}
250
251	__syncicache((void *)marks[MARK_ENTRY],
252	    (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]);
253
254	run((void *)marks[MARK_SYM], (void *)marks[MARK_END],
255	    (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]);
256
257	/* should never come here */
258	printf("exec returned. Restarting...\n");
259	_rtt();
260
261  loadfail:
262	printf("load failed. Restarting...\n");
263	_rtt();
264}
265
266void
267bi_init(void *addr)
268{
269	struct btinfo_magic bi_magic;
270
271	memset(addr, 0, BOOTINFO_MAXSIZE);
272	bi_next = (char *)addr;
273	bi_size = 0;
274
275	bi_magic.magic = BOOTINFO_MAGIC;
276	bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
277}
278
279void
280bi_add(void *new, int type, int size)
281{
282	struct btinfo_common *bi;
283
284	if (bi_size + size > BOOTINFO_MAXSIZE)
285		return;				/* XXX error? */
286
287	bi = new;
288	bi->next = size;
289	bi->type = type;
290	memcpy(bi_next, new, size);
291	bi_next += size;
292}
293
294void
295module_add(char *name)
296{
297	struct boot_module *bm, *bmp;
298
299	while (*name == ' ' || *name == '\t')
300		++name;
301
302	bm = alloc(sizeof(struct boot_module) + strlen(name) + 1);
303	if (bm == NULL) {
304		printf("couldn't allocate module %s\n", name);
305		return;
306	}
307
308	bm->bm_kmod = (char *)(bm + 1);
309	bm->bm_len = -1;
310	bm->bm_next = NULL;
311	strcpy(bm->bm_kmod, name);
312	if ((bmp = boot_modules) == NULL)
313		boot_modules = bm;
314	else {
315		while (bmp->bm_next != NULL)
316			bmp = bmp->bm_next;
317		bmp->bm_next = bm;
318	}
319}
320
321#define PAGE_SIZE	4096
322#define alignpg(x)	(((x)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
323
324void
325module_load(char *kernel_path)
326{
327	struct boot_module *bm;
328	struct bi_modulelist_entry *bi;
329	struct stat st;
330	char *p;
331	int size, fd;
332
333	strcpy(module_base, kernel_path);
334	if ((p = strchr(module_base, ':')) == NULL)
335		return; /* eeh?! */
336	p += 1;
337	size = sizeof(module_base) - (p - module_base);
338
339	if (netbsd_version / 1000000 % 100 == 99) {
340		/* -current */
341		snprintf(p, size,
342		    "/stand/sandpoint/%d.%d.%d/modules",
343		    netbsd_version / 100000000,
344		    netbsd_version / 1000000 % 100,
345		    netbsd_version / 100 % 100);
346	}
347	 else if (netbsd_version != 0) {
348		/* release */
349		snprintf(p, size,
350		    "/stand/sandpoint/%d.%d/modules",
351		    netbsd_version / 100000000,
352		    netbsd_version / 1000000 % 100);
353	}
354
355	/*
356	 * 1st pass; determine module existence
357	 */
358	size = 0;
359	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
360		fd = module_open(bm);
361		if (fd == -1)
362			continue;
363		if (fstat(fd, &st) == -1 || st.st_size == -1) {
364			printf("WARNING: couldn't stat %s\n", bm->bm_kmod);
365			close(fd);
366			continue;
367		}
368		bm->bm_len = (int)st.st_size;
369		close(fd);
370		size += sizeof(struct bi_modulelist_entry);
371	}
372	if (size == 0)
373		return;
374
375	size += sizeof(struct btinfo_modulelist);
376	btinfo_modulelist = alloc(size);
377	if (btinfo_modulelist == NULL) {
378		printf("WARNING: couldn't allocate module list\n");
379		return;
380	}
381	btinfo_modulelist_size = size;
382	btinfo_modulelist->num = 0;
383
384	/*
385	 * 2nd pass; load modules into memory
386	 */
387	kmodloadp = alignpg(kmodloadp);
388	bi = (struct bi_modulelist_entry *)(btinfo_modulelist + 1);
389	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
390		if (bm->bm_len == -1)
391			continue; /* already found unavailable */
392		fd = module_open(bm);
393		printf("module \"%s\" ", bm->bm_kmod);
394		size = read(fd, (char *)kmodloadp, SSIZE_MAX);
395		if (size < bm->bm_len)
396			printf("WARNING: couldn't load");
397		else {
398			snprintf(bi->kmod, sizeof(bi->kmod), bm->bm_kmod);
399			bi->type = BI_MODULE_ELF;
400			bi->len = size;
401			bi->base = kmodloadp;
402			btinfo_modulelist->num += 1;
403			printf("loaded at 0x%08x size 0x%x", kmodloadp, size);
404			kmodloadp += alignpg(size);
405			bi += 1;
406		}
407		printf("\n");
408		close(fd);
409	}
410	btinfo_modulelist->endpa = kmodloadp;
411}
412
413int
414module_open(struct boot_module *bm)
415{
416	char path[80];
417	int fd;
418
419	snprintf(path, sizeof(path),
420	    "%s/%s/%s.kmod", module_base, bm->bm_kmod, bm->bm_kmod);
421	fd = open(path, 0);
422	return fd;
423}
424
425#if 0
426static const char *cmdln[] = {
427	"console=ttyS0,115200 root=/dev/sda1 rw initrd=0x200000,2M",
428	"console=ttyS0,115200 root=/dev/nfs ip=dhcp"
429};
430
431void
432mkatagparams(unsigned addr, char *kcmd)
433{
434	struct tag {
435		unsigned siz;
436		unsigned tag;
437		unsigned val[1];
438	};
439	struct tag *p;
440#define ATAG_CORE 	0x54410001
441#define ATAG_MEM	0x54410002
442#define ATAG_INITRD	0x54410005
443#define ATAG_CMDLINE	0x54410009
444#define ATAG_NONE	0x00000000
445#define tagnext(p) (struct tag *)((unsigned *)(p) + (p)->siz)
446#define tagsize(n) (2 + (n))
447
448	p = (struct tag *)addr;
449	p->tag = ATAG_CORE;
450	p->siz = tagsize(3);
451	p->val[0] = 0;		/* flags */
452	p->val[1] = 0;		/* pagesize */
453	p->val[2] = 0;		/* rootdev */
454	p = tagnext(p);
455	p->tag = ATAG_MEM;
456	p->siz = tagsize(2);
457	p->val[0] = 64 * 1024 * 1024;
458	p->val[1] = 0;		/* start */
459	p = tagnext(p);
460	if (kcmd != NULL) {
461		p = tagnext(p);
462		p->tag = ATAG_CMDLINE;
463		p->siz = tagsize((strlen(kcmd) + 1 + 3) >> 2);
464		strcpy((void *)p->val, kcmd);
465	}
466	p = tagnext(p);
467	p->tag = ATAG_NONE;
468	p->siz = 0;
469}
470#endif
471
472void *
473allocaligned(size_t size, size_t align)
474{
475	uint32_t p;
476
477	if (align-- < 2)
478		return alloc(size);
479	p = (uint32_t)alloc(size + align);
480	return (void *)((p + align) & ~align);
481}
482
483static int
484check_bootname(char *s)
485{
486	/*
487	 * nfs:
488	 * nfs:<bootfile>
489	 * tftp:
490	 * tftp:<bootfile>
491	 * wd[N[P]]:<bootfile>
492	 *
493	 * net is a synonym of nfs.
494	 */
495	if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0)
496		return 1;
497	if (strncmp(s, "tftp:", 5) == 0)
498		return 1;
499	if (s[0] == 'w' && s[1] == 'd') {
500		s += 2;
501		if (*s != ':' && *s >= '0' && *s <= '3') {
502			++s;
503			if (*s != ':' && *s >= 'a' && *s <= 'p')
504				++s;
505		}
506		return *s == ':';
507	}
508	return 0;
509}
510
511static int
512parse_cmdline(char **argv, int maxargc, char *p, char *end)
513{
514	int argc;
515
516	argv[0] = "";
517	for (argc = 1; argc < maxargc && p < end; argc++) {
518		while (is_space(*p))
519			p++;
520		if (p >= end)
521			break;
522		argv[argc] = p;
523		while (!is_space(*p) && p < end)
524			p++;
525		*p++ = '\0';
526	}
527
528	return argc;
529}
530
531static int
532is_space(char c)
533{
534	return c > '\0' && c <= ' ';
535}
536