boot2.c revision 329183
1/*- 2 * Copyright (c) 2013-2014 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * Copyright (c) 1998 Robert Nordier 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms are freely 34 * permitted provided that the above copyright notice and this 35 * paragraph and the following disclaimer are duplicated in all 36 * such forms. 37 * 38 * This software is provided "AS IS" and without any express or 39 * implied warranties, including, without limitation, the implied 40 * warranties of merchantability and fitness for a particular 41 * purpose. 42 */ 43 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: stable/11/stand/mips/beri/boot2/boot2.c 329183 2018-02-12 20:51:28Z kevans $"); 46 47#include <sys/param.h> 48#include <sys/disklabel.h> 49#include <sys/diskmbr.h> 50#include <sys/dirent.h> 51#include <sys/endian.h> 52#include <sys/reboot.h> 53 54#include <machine/bootinfo.h> 55#include <machine/elf.h> 56 57#include <stand.h> 58#include <stdarg.h> 59#include <string.h> 60 61#include <beri.h> 62#include <cfi.h> 63#include <cons.h> 64#include <mips.h> 65#include <sdcard.h> 66 67#include "paths.h" 68#include "rbx.h" 69 70static int beri_argc; 71static const char **beri_argv, **beri_envv; 72static uint64_t beri_memsize; 73 74#define IO_KEYBOARD 1 75#define IO_SERIAL 2 76 77#define SECOND 1 /* Circa that many ticks in a second. */ 78 79#define ARGS 0x900 80#define NOPT 14 81#define MEM_BASE 0x12 82#define MEM_EXT 0x15 83 84/* 85 * XXXRW: I think this has to do with whether boot2 expects a partition 86 * table? 87 */ 88#define DRV_HARD 0x80 89#define DRV_MASK 0x7f 90 91/* Default to using CFI flash. */ 92#define TYPE_DEFAULT BOOTINFO_DEV_TYPE_SDCARD 93 94/* Hard-coded assumption about location of JTAG-loaded kernel. */ 95#define DRAM_KERNEL_ADDR ((void *)mips_phys_to_cached(0x20000)) 96 97extern uint32_t _end; 98 99static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 100static const unsigned char flags[NOPT] = { 101 RBX_DUAL, 102 RBX_SERIAL, 103 RBX_ASKNAME, 104 RBX_CDROM, 105 RBX_CONFIG, 106 RBX_KDB, 107 RBX_GDB, 108 RBX_MUTE, 109 RBX_NOINTR, 110 RBX_PAUSE, 111 RBX_QUIET, 112 RBX_DFLTROOT, 113 RBX_SINGLE, 114 RBX_VERBOSE 115}; 116 117/* These must match BOOTINFO_DEV_TYPE constants. */ 118static const char *const dev_nm[] = {"dram", "cfi", "sdcard"}; 119static const u_int dev_nm_count = nitems(dev_nm); 120 121static struct dsk { 122 unsigned type; /* BOOTINFO_DEV_TYPE_x object type. */ 123 uintptr_t unitptr; /* Unit number or pointer to object. */ 124 uint8_t slice; 125 uint8_t part; 126#if 0 127 unsigned start; 128 int init; 129#endif 130} dsk; 131static char cmd[512], cmddup[512], knamebuf[1024]; 132static const char *kname; 133uint32_t opts; 134#if 0 135static int comspeed = SIOSPD; 136#endif 137struct bootinfo bootinfo; 138static uint8_t ioctrl = IO_KEYBOARD; 139 140void putchar(int); 141static void boot_fromdram(void); 142static void boot_fromfs(void); 143static void load(void); 144static int parse(void); 145static int dskread(void *, unsigned, unsigned); 146static int xputc(int); 147static int xgetc(int); 148 149#define UFS_SMALL_CGBASE 150#include "ufsread.c" 151 152static struct dmadat __dmadat; 153 154static inline int 155xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 156{ 157 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 158 printf("Invalid %s\n", "format"); 159 return -1; 160 } 161 return 0; 162} 163 164static inline void 165getstr(void) 166{ 167 char *s; 168 int c; 169 170 s = cmd; 171 for (;;) { 172 switch (c = xgetc(0)) { 173 case 0: 174 break; 175 case '\177': 176 case '\b': 177 if (s > cmd) { 178 s--; 179 printf("\b \b"); 180 } 181 break; 182 case '\n': 183 case '\r': 184 putchar('\n'); 185 *s = 0; 186 return; 187 default: 188 if (s - cmd < sizeof(cmd) - 1) 189 *s++ = c; 190 putchar(c); 191 } 192 } 193} 194 195int 196main(u_int argc, const char *argv[], const char *envv[], uint64_t memsize) 197{ 198 uint8_t autoboot; 199 ufs_ino_t ino; 200 size_t nbyte; 201 202 /* Arguments from Miniboot. */ 203 beri_argc = argc; 204 beri_argv = argv; 205 beri_envv = envv; 206 beri_memsize = memsize; 207 208 dmadat = &__dmadat; 209#if 0 210 /* XXXRW: more here. */ 211 v86.ctl = V86_FLAGS; 212 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 213 dsk.drive = *(uint8_t *)PTOV(ARGS); 214#endif 215 dsk.type = TYPE_DEFAULT; 216#if 0 217 dsk.unit = dsk.drive & DRV_MASK; 218 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 219#endif 220 bootinfo.bi_version = BOOTINFO_VERSION; 221 bootinfo.bi_size = sizeof(bootinfo); 222 223 /* Process configuration file */ 224 225 autoboot = 1; 226 227 if ((ino = lookup(PATH_CONFIG)) || 228 (ino = lookup(PATH_DOTCONFIG))) { 229 nbyte = fsread(ino, cmd, sizeof(cmd) - 1); 230 cmd[nbyte] = '\0'; 231 } 232 233 if (*cmd) { 234 memcpy(cmddup, cmd, sizeof(cmd)); 235 if (parse()) 236 autoboot = 0; 237 if (!OPT_CHECK(RBX_QUIET)) 238 printf("%s: %s", PATH_CONFIG, cmddup); 239 /* Do not process this command twice */ 240 *cmd = 0; 241 } 242 243 /* 244 * Try to exec stage 3 boot loader. If interrupted by a keypress, 245 * or in case of failure, try to load a kernel directly instead. 246 */ 247 248 if (!kname) { 249 kname = PATH_LOADER; 250 if (autoboot && !keyhit(3*SECOND)) { 251 boot_fromfs(); 252 kname = PATH_KERNEL; 253 } 254 } 255 256 /* Present the user with the boot2 prompt. */ 257 258 for (;;) { 259 if (!autoboot || !OPT_CHECK(RBX_QUIET)) 260 printf("\nFreeBSD/mips boot\n" 261 "Default: %s%ju:%s\n" 262 "boot: ", 263 dev_nm[dsk.type], dsk.unitptr, kname); 264#if 0 265 if (ioctrl & IO_SERIAL) 266 sio_flush(); 267#endif 268 if (!autoboot || keyhit(3*SECOND)) 269 getstr(); 270 else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 271 putchar('\n'); 272 autoboot = 0; 273 if (parse()) 274 putchar('\a'); 275 else 276 load(); 277 } 278} 279 280static void 281boot(void *entryp, int argc, const char *argv[], const char *envv[]) 282{ 283 284 bootinfo.bi_kernelname = (bi_ptr_t)kname; 285 bootinfo.bi_boot2opts = opts & RBX_MASK; 286 bootinfo.bi_boot_dev_type = dsk.type; 287 bootinfo.bi_boot_dev_unitptr = dsk.unitptr; 288 bootinfo.bi_memsize = beri_memsize; 289#if 0 290 /* 291 * XXXRW: A possible future way to distinguish Miniboot passing a memory 292 * size vs DTB..? 293 */ 294 if (beri_memsize <= BERI_MEMVSDTB) 295 bootinfo.bi_memsize = beri_memsize; 296 else 297 bootinfo.bi_dtb = beri_memsize; 298#endif 299 ((void(*)(int, const char **, const char **, void *))entryp)(argc, argv, 300 envv, &bootinfo); 301} 302 303/* 304 * Boot a kernel that has mysteriously (i.e., by JTAG) appeared in DRAM; 305 * assume that it is already properly relocated, etc, and invoke its entry 306 * address without question or concern. 307 */ 308static void 309boot_fromdram(void) 310{ 311 void *kaddr = DRAM_KERNEL_ADDR; /* XXXRW: Something better here. */ 312 Elf64_Ehdr *ehp = kaddr; 313 314 if (!IS_ELF(*ehp)) { 315 printf("Invalid %s\n", "format"); 316 return; 317 } 318 boot((void *)ehp->e_entry, beri_argc, beri_argv, beri_envv); 319} 320 321static void 322boot_fromfs(void) 323{ 324 union { 325 Elf64_Ehdr eh; 326 } hdr; 327 static Elf64_Phdr ep[2]; 328#if 0 329 static Elf64_Shdr es[2]; 330#endif 331 caddr_t p; 332 ufs_ino_t ino; 333 uint64_t addr; 334 int i, j; 335 336 if (!(ino = lookup(kname))) { 337 if (!ls) 338 printf("No %s\n", kname); 339 return; 340 } 341 if (xfsread(ino, &hdr, sizeof(hdr))) 342 return; 343 344 if (IS_ELF(hdr.eh)) { 345 fs_off = hdr.eh.e_phoff; 346 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 347 if (xfsread(ino, ep + j, sizeof(ep[0]))) 348 return; 349 if (ep[j].p_type == PT_LOAD) 350 j++; 351 } 352 for (i = 0; i < 2; i++) { 353 p = (caddr_t)ep[i].p_paddr; 354 fs_off = ep[i].p_offset; 355 if (xfsread(ino, p, ep[i].p_filesz)) 356 return; 357 } 358 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 359#if 0 360 bootinfo.bi_symtab = VTOP(p); 361 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 362 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 363 (hdr.eh.e_shstrndx + 1); 364 if (xfsread(ino, &es, sizeof(es))) 365 return; 366 for (i = 0; i < 2; i++) { 367 *(Elf32_Word *)p = es[i].sh_size; 368 p += sizeof(es[i].sh_size); 369 fs_off = es[i].sh_offset; 370 if (xfsread(ino, p, es[i].sh_size)) 371 return; 372 p += es[i].sh_size; 373 } 374 } 375#endif 376 addr = hdr.eh.e_entry; 377#if 0 378 bootinfo.bi_esymtab = VTOP(p); 379#endif 380 } else { 381 printf("Invalid %s\n", "format"); 382 return; 383 } 384 boot((void *)addr, beri_argc, beri_argv, beri_envv); 385} 386 387static void 388load(void) 389{ 390 391 switch (dsk.type) { 392 case BOOTINFO_DEV_TYPE_DRAM: 393 boot_fromdram(); 394 break; 395 396 default: 397 boot_fromfs(); 398 break; 399 } 400} 401 402static int 403parse() 404{ 405 char *arg = cmd; 406 char *ep, *p, *q; 407 char unit; 408 size_t len; 409 const char *cp; 410#if 0 411 int c, i, j; 412#else 413 int c, i; 414#endif 415 416 while ((c = *arg++)) { 417 if (c == ' ' || c == '\t' || c == '\n') 418 continue; 419 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 420 ep = p; 421 if (*p) 422 *p++ = 0; 423 if (c == '-') { 424 while ((c = *arg++)) { 425 if (c == 'P') { 426 cp = "yes"; 427#if 0 428 } else { 429 opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 430 cp = "no"; 431 } 432#endif 433 printf("Keyboard: %s\n", cp); 434 continue; 435#if 0 436 } else if (c == 'S') { 437 j = 0; 438 while ((unsigned int)(i = *arg++ - '0') <= 9) 439 j = j * 10 + i; 440 if (j > 0 && i == -'0') { 441 comspeed = j; 442 break; 443 } 444 /* Fall through to error below ('S' not in optstr[]). */ 445#endif 446 } 447 for (i = 0; c != optstr[i]; i++) 448 if (i == NOPT - 1) 449 return -1; 450 opts ^= OPT_SET(flags[i]); 451 } 452 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 453 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 454#if 0 455 if (ioctrl & IO_SERIAL) { 456 if (sio_init(115200 / comspeed) != 0) 457 ioctrl &= ~IO_SERIAL; 458 } 459#endif 460 } else { 461 /*- 462 * Parse a device/kernel name. Format(s): 463 * 464 * path 465 * deviceX:path 466 * 467 * NB: Utterly incomprehensible but space-efficient ARM/i386 468 * parsing removed in favour of larger but easier-to-read C. This 469 * is still not great, however -- e.g., relating to unit handling. 470 * 471 * TODO: it would be nice if a DRAM pointer could be specified 472 * here. 473 * 474 * XXXRW: Pick up pieces here. 475 */ 476 477 /* 478 * Search for a parens; if none, then it's just a path. 479 * Otherwise, it's a devicename. 480 */ 481 arg--; 482 q = strsep(&arg, ":"); 483 if (arg != NULL) { 484 len = strlen(q); 485 if (len < 2) { 486 printf("Invalid device: name too short\n"); 487 return (-1); 488 } 489 490 /* 491 * First, handle one-digit unit. 492 */ 493 unit = q[len-1]; 494 if (unit < '0' || unit > '9') { 495 printf("Invalid device: invalid unit %c\n", 496 unit); 497 return (-1); 498 } 499 unit -= '0'; 500 q[len-1] = '\0'; 501 502 /* 503 * Next, find matching device. 504 */ 505 for (i = 0; i < dev_nm_count; i++) { 506 if (strcmp(q, dev_nm[i]) == 0) 507 break; 508 } 509 if (i == dev_nm_count) { 510 printf("Invalid device: no driver match\n"); 511 return (-1); 512 } 513 dsk.type = i; 514 dsk.unitptr = unit; /* Someday: also a DRAM pointer? */ 515 } else 516 arg = q; 517 if ((i = ep - arg)) { 518 if ((size_t)i >= sizeof(knamebuf)) 519 return -1; 520 memcpy(knamebuf, arg, i + 1); 521 kname = knamebuf; 522 } 523 } 524 arg = p; 525 } 526 return 0; 527} 528 529static int 530drvread(void *buf, unsigned lba, unsigned nblk) 531{ 532 533 /* XXXRW: eventually, we may want to pass 'drive' and 'unit' here. */ 534 switch (dsk.type) { 535 case BOOTINFO_DEV_TYPE_CFI: 536 return (cfi_read(buf, lba, nblk)); 537 538 case BOOTINFO_DEV_TYPE_SDCARD: 539 return (altera_sdcard_read(buf, lba, nblk)); 540 541 default: 542 return (-1); 543 } 544} 545 546static int 547dskread(void *buf, unsigned lba, unsigned nblk) 548{ 549#if 0 550 /* 551 * XXXRW: For now, assume no partition table around the file system; it's 552 * just in raw flash. 553 */ 554 struct dos_partition *dp; 555 struct disklabel *d; 556 char *sec; 557 unsigned i; 558 uint8_t sl; 559 560 if (!dsk_meta) { 561 sec = dmadat->secbuf; 562 dsk.start = 0; 563 if (drvread(sec, DOSBBSECTOR, 1)) 564 return -1; 565 dp = (void *)(sec + DOSPARTOFF); 566 sl = dsk.slice; 567 if (sl < BASE_SLICE) { 568 for (i = 0; i < NDOSPART; i++) 569 if (dp[i].dp_typ == DOSPTYP_386BSD && 570 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 571 sl = BASE_SLICE + i; 572 if (dp[i].dp_flag & 0x80 || 573 dsk.slice == COMPATIBILITY_SLICE) 574 break; 575 } 576 if (dsk.slice == WHOLE_DISK_SLICE) 577 dsk.slice = sl; 578 } 579 if (sl != WHOLE_DISK_SLICE) { 580 if (sl != COMPATIBILITY_SLICE) 581 dp += sl - BASE_SLICE; 582 if (dp->dp_typ != DOSPTYP_386BSD) { 583 printf("Invalid %s\n", "slice"); 584 return -1; 585 } 586 dsk.start = le32toh(dp->dp_start); 587 } 588 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 589 return -1; 590 d = (void *)(sec + LABELOFFSET); 591 if (le32toh(d->d_magic) != DISKMAGIC || 592 le32toh(d->d_magic2) != DISKMAGIC) { 593 if (dsk.part != RAW_PART) { 594 printf("Invalid %s\n", "label"); 595 return -1; 596 } 597 } else { 598 if (!dsk.init) { 599 if (le16toh(d->d_type) == DTYPE_SCSI) 600 dsk.type = TYPE_DA; 601 dsk.init++; 602 } 603 if (dsk.part >= le16toh(d->d_npartitions) || 604 !(le32toh(d->d_partitions[dsk.part].p_size))) { 605 printf("Invalid %s\n", "partition"); 606 return -1; 607 } 608 dsk.start += le32toh(d->d_partitions[dsk.part].p_offset); 609 dsk.start -= le32toh(d->d_partitions[RAW_PART].p_offset); 610 } 611 } 612 return drvread(buf, dsk.start + lba, nblk); 613#else 614 return drvread(buf, lba, nblk); 615#endif 616} 617 618void 619putchar(int c) 620{ 621 if (c == '\n') 622 xputc('\r'); 623 xputc(c); 624} 625 626static int 627xputc(int c) 628{ 629 if (ioctrl & IO_KEYBOARD) 630 putc(c); 631#if 0 632 if (ioctrl & IO_SERIAL) 633 sio_putc(c); 634#endif 635 return c; 636} 637 638static int 639xgetc(int fn) 640{ 641 if (OPT_CHECK(RBX_NOINTR)) 642 return 0; 643 for (;;) { 644 if (ioctrl & IO_KEYBOARD && keyhit(0)) 645 return fn ? 1 : getc(); 646#if 0 647 if (ioctrl & IO_SERIAL && sio_ischar()) 648 return fn ? 1 : sio_getc(); 649#endif 650 if (fn) 651 return 0; 652 } 653} 654