Home | History | Annotate | Line # | Download | only in altboot
main.c revision 1.9
      1 /* $NetBSD: main.c,v 1.9 2011/03/06 18:22:13 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 
     43 static 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 
     60 void *bootinfo; /* low memory reserved to pass bootinfo structures */
     61 int bi_size;	/* BOOTINFO_MAXSIZE */
     62 char *bi_next;
     63 
     64 void bi_init(void *);
     65 void bi_add(void *, int, int);
     66 
     67 struct btinfo_memory bi_mem;
     68 struct btinfo_console bi_cons;
     69 struct btinfo_clock bi_clk;
     70 struct btinfo_prodfamily bi_fam;
     71 struct btinfo_bootpath bi_path;
     72 struct btinfo_rootdevice bi_rdev;
     73 struct btinfo_net bi_net;
     74 struct btinfo_modulelist *btinfo_modulelist;
     75 size_t btinfo_modulelist_size;
     76 
     77 struct boot_module {
     78 	char *bm_kmod;
     79 	ssize_t bm_len;
     80 	struct boot_module *bm_next;
     81 };
     82 struct boot_module *boot_modules;
     83 char module_base[80];
     84 uint32_t kmodloadp;
     85 int modules_enabled = 0;
     86 
     87 void module_add(char *);
     88 void module_load(char *);
     89 int module_open(struct boot_module *);
     90 
     91 void main(int, char **, char *, char *);
     92 extern char bootprog_name[], bootprog_rev[];
     93 
     94 struct pcidev lata[2];
     95 struct pcidev lnif[1];
     96 struct pcidev lusb[3];
     97 int nata, nnif, nusb;
     98 
     99 int brdtype;
    100 uint32_t busclock, cpuclock;
    101 
    102 static int check_bootname(char *);
    103 static int parse_cmdline(char **, int, char *, char *);
    104 static int is_space(char);
    105 
    106 #define	BNAME_DEFAULT "nfs:"
    107 #define MAX_ARGS 10
    108 
    109 void
    110 main(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 
    268 void
    269 bi_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 
    281 void
    282 bi_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 
    296 void
    297 module_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 
    326 void
    327 module_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 
    415 int
    416 module_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
    428 static 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 
    433 void
    434 mkatagparams(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 
    474 void *
    475 allocaligned(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 
    485 static int hex2nibble(char c)
    486 {
    487 
    488 	if (c >= 'a')
    489 		c &= ~0x20;
    490 	if (c >= 'A' && c <= 'F')
    491 		c -= 'A' - ('9' + 1);
    492 	else if (c < '0' || c > '9')
    493 		return -1;
    494 
    495 	return c - '0';
    496 }
    497 
    498 uint32_t
    499 read_hex(const char *s)
    500 {
    501 	int n;
    502 	uint32_t val;
    503 
    504 	val = 0;
    505 	while ((n = hex2nibble(*s++)) >= 0)
    506 		val = (val << 4) | n;
    507 	return val;
    508 }
    509 
    510 static int
    511 check_bootname(char *s)
    512 {
    513 	/*
    514 	 * nfs:
    515 	 * nfs:<bootfile>
    516 	 * tftp:
    517 	 * tftp:<bootfile>
    518 	 * wd[N[P]]:<bootfile>
    519 	 * mem:<address>
    520 	 *
    521 	 * net is a synonym of nfs.
    522 	 */
    523 	if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0 ||
    524 	    strncmp(s, "tftp:", 5) == 0 || strncmp(s, "mem:", 4) == 0)
    525 		return 1;
    526 	if (s[0] == 'w' && s[1] == 'd') {
    527 		s += 2;
    528 		if (*s != ':' && *s >= '0' && *s <= '3') {
    529 			++s;
    530 			if (*s != ':' && *s >= 'a' && *s <= 'p')
    531 				++s;
    532 		}
    533 		return *s == ':';
    534 	}
    535 	return 0;
    536 }
    537 
    538 static int
    539 parse_cmdline(char **argv, int maxargc, char *p, char *end)
    540 {
    541 	int argc;
    542 
    543 	argv[0] = "";
    544 	for (argc = 1; argc < maxargc && p < end; argc++) {
    545 		while (is_space(*p))
    546 			p++;
    547 		if (p >= end)
    548 			break;
    549 		argv[argc] = p;
    550 		while (!is_space(*p) && p < end)
    551 			p++;
    552 		*p++ = '\0';
    553 	}
    554 
    555 	return argc;
    556 }
    557 
    558 static int
    559 is_space(char c)
    560 {
    561 	return c > '\0' && c <= ' ';
    562 }
    563