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