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