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