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: releng/11.0/sys/boot/mips/beri/boot2/boot2.c 298309 2016-04-19 23:44:33Z pfg $"); 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 dmadat __dmadat; 122 123static struct dsk { 124 unsigned type; /* BOOTINFO_DEV_TYPE_x object type. */ 125 uintptr_t unitptr; /* Unit number or pointer to object. */ 126 uint8_t slice; 127 uint8_t part; 128#if 0 129 unsigned start; 130 int init; 131#endif 132} dsk; 133static char cmd[512], cmddup[512], knamebuf[1024]; 134static const char *kname; 135uint32_t opts; 136#if 0 137static int comspeed = SIOSPD; 138#endif 139struct bootinfo bootinfo; 140static uint8_t ioctrl = IO_KEYBOARD; 141 142void exit(int); 143void putchar(int); 144static void boot_fromdram(void); 145static void boot_fromfs(void); 146static void load(void); 147static int parse(void); 148static int dskread(void *, unsigned, unsigned); 149static int xputc(int); 150static int xgetc(int); 151 152 153#define UFS_SMALL_CGBASE 154#include "ufsread.c" 155 156static inline int 157xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 158{ 159 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 160 printf("Invalid %s\n", "format"); 161 return -1; 162 } 163 return 0; 164} 165 166static inline void 167getstr(void) 168{ 169 char *s; 170 int c; 171 172 s = cmd; 173 for (;;) { 174 switch (c = xgetc(0)) { 175 case 0: 176 break; 177 case '\177': 178 case '\b': 179 if (s > cmd) { 180 s--; 181 printf("\b \b"); 182 } 183 break; 184 case '\n': 185 case '\r': 186 putchar('\n'); 187 *s = 0; 188 return; 189 default: 190 if (s - cmd < sizeof(cmd) - 1) 191 *s++ = c; 192 putchar(c); 193 } 194 } 195} 196 197int 198main(u_int argc, const char *argv[], const char *envv[], uint64_t memsize) 199{ 200 uint8_t autoboot; 201 ufs_ino_t ino; 202 size_t nbyte; 203 204 /* Arguments from Miniboot. */ 205 beri_argc = argc; 206 beri_argv = argv; 207 beri_envv = envv; 208 beri_memsize = memsize; 209 210 dmadat = &__dmadat; 211#if 0 212 /* XXXRW: more here. */ 213 v86.ctl = V86_FLAGS; 214 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 215 dsk.drive = *(uint8_t *)PTOV(ARGS); 216#endif 217 dsk.type = TYPE_DEFAULT; 218#if 0 219 dsk.unit = dsk.drive & DRV_MASK; 220 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 221#endif 222 bootinfo.bi_version = BOOTINFO_VERSION; 223 bootinfo.bi_size = sizeof(bootinfo); 224 225 /* Process configuration file */ 226 227 autoboot = 1; 228 229 if ((ino = lookup(PATH_CONFIG)) || 230 (ino = lookup(PATH_DOTCONFIG))) { 231 nbyte = fsread(ino, cmd, sizeof(cmd) - 1); 232 cmd[nbyte] = '\0'; 233 } 234 235 if (*cmd) { 236 memcpy(cmddup, cmd, sizeof(cmd)); 237 if (parse()) 238 autoboot = 0; 239 if (!OPT_CHECK(RBX_QUIET)) 240 printf("%s: %s", PATH_CONFIG, cmddup); 241 /* Do not process this command twice */ 242 *cmd = 0; 243 } 244 245 /* 246 * Try to exec stage 3 boot loader. If interrupted by a keypress, 247 * or in case of failure, try to load a kernel directly instead. 248 */ 249 250 if (!kname) { 251 kname = PATH_LOADER; 252 if (autoboot && !keyhit(3*SECOND)) { 253 boot_fromfs(); 254 kname = PATH_KERNEL; 255 } 256 } 257 258 /* Present the user with the boot2 prompt. */ 259 260 for (;;) { 261 if (!autoboot || !OPT_CHECK(RBX_QUIET)) 262 printf("\nFreeBSD/mips boot\n" 263 "Default: %s%ju:%s\n" 264 "boot: ", 265 dev_nm[dsk.type], dsk.unitptr, kname); 266#if 0 267 if (ioctrl & IO_SERIAL) 268 sio_flush(); 269#endif 270 if (!autoboot || keyhit(3*SECOND)) 271 getstr(); 272 else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 273 putchar('\n'); 274 autoboot = 0; 275 if (parse()) 276 putchar('\a'); 277 else 278 load(); 279 } 280} 281 282/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 283void 284exit(int x) 285{ 286} 287 288static void 289boot(void *entryp, int argc, const char *argv[], const char *envv[]) 290{ 291 292 bootinfo.bi_kernelname = (bi_ptr_t)kname; 293 bootinfo.bi_boot2opts = opts & RBX_MASK; 294 bootinfo.bi_boot_dev_type = dsk.type; 295 bootinfo.bi_boot_dev_unitptr = dsk.unitptr; 296 bootinfo.bi_memsize = beri_memsize; 297#if 0 298 /* 299 * XXXRW: A possible future way to distinguish Miniboot passing a memory 300 * size vs DTB..? 301 */ 302 if (beri_memsize <= BERI_MEMVSDTB) 303 bootinfo.bi_memsize = beri_memsize; 304 else 305 bootinfo.bi_dtb = beri_memsize; 306#endif 307 ((void(*)(int, const char **, const char **, void *))entryp)(argc, argv, 308 envv, &bootinfo); 309} 310 311/* 312 * Boot a kernel that has mysteriously (i.e., by JTAG) appeared in DRAM; 313 * assume that it is already properly relocated, etc, and invoke its entry 314 * address without question or concern. 315 */ 316static void 317boot_fromdram(void) 318{ 319 void *kaddr = DRAM_KERNEL_ADDR; /* XXXRW: Something better here. */ 320 Elf64_Ehdr *ehp = kaddr; 321 322 if (!IS_ELF(*ehp)) { 323 printf("Invalid %s\n", "format"); 324 return; 325 } 326 boot((void *)ehp->e_entry, beri_argc, beri_argv, beri_envv); 327} 328 329static void 330boot_fromfs(void) 331{ 332 union { 333 Elf64_Ehdr eh; 334 } hdr; 335 static Elf64_Phdr ep[2]; 336#if 0 337 static Elf64_Shdr es[2]; 338#endif 339 caddr_t p; 340 ufs_ino_t ino; 341 uint64_t addr; 342 int i, j; 343 344 if (!(ino = lookup(kname))) { 345 if (!ls) 346 printf("No %s\n", kname); 347 return; 348 } 349 if (xfsread(ino, &hdr, sizeof(hdr))) 350 return; 351 352 if (IS_ELF(hdr.eh)) { 353 fs_off = hdr.eh.e_phoff; 354 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 355 if (xfsread(ino, ep + j, sizeof(ep[0]))) 356 return; 357 if (ep[j].p_type == PT_LOAD) 358 j++; 359 } 360 for (i = 0; i < 2; i++) { 361 p = (caddr_t)ep[i].p_paddr; 362 fs_off = ep[i].p_offset; 363 if (xfsread(ino, p, ep[i].p_filesz)) 364 return; 365 } 366 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 367#if 0 368 bootinfo.bi_symtab = VTOP(p); 369 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 370 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 371 (hdr.eh.e_shstrndx + 1); 372 if (xfsread(ino, &es, sizeof(es))) 373 return; 374 for (i = 0; i < 2; i++) { 375 *(Elf32_Word *)p = es[i].sh_size; 376 p += sizeof(es[i].sh_size); 377 fs_off = es[i].sh_offset; 378 if (xfsread(ino, p, es[i].sh_size)) 379 return; 380 p += es[i].sh_size; 381 } 382 } 383#endif 384 addr = hdr.eh.e_entry; 385#if 0 386 bootinfo.bi_esymtab = VTOP(p); 387#endif 388 } else { 389 printf("Invalid %s\n", "format"); 390 return; 391 } 392 boot((void *)addr, beri_argc, beri_argv, beri_envv); 393} 394 395static void 396load(void) 397{ 398 399 switch (dsk.type) { 400 case BOOTINFO_DEV_TYPE_DRAM: 401 boot_fromdram(); 402 break; 403 404 default: 405 boot_fromfs(); 406 break; 407 } 408} 409 410static int 411parse() 412{ 413 char *arg = cmd; 414 char *ep, *p, *q; 415 char unit; 416 size_t len; 417 const char *cp; 418#if 0 419 int c, i, j; 420#else 421 int c, i; 422#endif 423 424 while ((c = *arg++)) { 425 if (c == ' ' || c == '\t' || c == '\n') 426 continue; 427 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 428 ep = p; 429 if (*p) 430 *p++ = 0; 431 if (c == '-') { 432 while ((c = *arg++)) { 433 if (c == 'P') { 434 cp = "yes"; 435#if 0 436 } else { 437 opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 438 cp = "no"; 439 } 440#endif 441 printf("Keyboard: %s\n", cp); 442 continue; 443#if 0 444 } else if (c == 'S') { 445 j = 0; 446 while ((unsigned int)(i = *arg++ - '0') <= 9) 447 j = j * 10 + i; 448 if (j > 0 && i == -'0') { 449 comspeed = j; 450 break; 451 } 452 /* Fall through to error below ('S' not in optstr[]). */ 453#endif 454 } 455 for (i = 0; c != optstr[i]; i++) 456 if (i == NOPT - 1) 457 return -1; 458 opts ^= OPT_SET(flags[i]); 459 } 460 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 461 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 462#if 0 463 if (ioctrl & IO_SERIAL) { 464 if (sio_init(115200 / comspeed) != 0) 465 ioctrl &= ~IO_SERIAL; 466 } 467#endif 468 } else { 469 /*- 470 * Parse a device/kernel name. Format(s): 471 * 472 * path 473 * deviceX:path 474 * 475 * NB: Utterly incomprehensible but space-efficient ARM/i386 476 * parsing removed in favour of larger but easier-to-read C. This 477 * is still not great, however -- e.g., relating to unit handling. 478 * 479 * TODO: it would be nice if a DRAM pointer could be specified 480 * here. 481 * 482 * XXXRW: Pick up pieces here. 483 */ 484 485 /* 486 * Search for a parens; if none, then it's just a path. 487 * Otherwise, it's a devicename. 488 */ 489 arg--; 490 q = strsep(&arg, ":"); 491 if (arg != NULL) { 492 len = strlen(q); 493 if (len < 2) { 494 printf("Invalid device: name too short\n"); 495 return (-1); 496 } 497 498 /* 499 * First, handle one-digit unit. 500 */ 501 unit = q[len-1]; 502 if (unit < '0' || unit > '9') { 503 printf("Invalid device: invalid unit\n", q, 504 unit); 505 return (-1); 506 } 507 unit -= '0'; 508 q[len-1] = '\0'; 509 510 /* 511 * Next, find matching device. 512 */ 513 for (i = 0; i < dev_nm_count; i++) { 514 if (strcmp(q, dev_nm[i]) == 0) 515 break; 516 } 517 if (i == dev_nm_count) { 518 printf("Invalid device: no driver match\n"); 519 return (-1); 520 } 521 dsk.type = i; 522 dsk.unitptr = unit; /* Someday: also a DRAM pointer? */ 523 } else 524 arg = q; 525 if ((i = ep - arg)) { 526 if ((size_t)i >= sizeof(knamebuf)) 527 return -1; 528 memcpy(knamebuf, arg, i + 1); 529 kname = knamebuf; 530 } 531 } 532 arg = p; 533 } 534 return 0; 535} 536 537static int 538drvread(void *buf, unsigned lba, unsigned nblk) 539{ 540 541 /* XXXRW: eventually, we may want to pass 'drive' and 'unit' here. */ 542 switch (dsk.type) { 543 case BOOTINFO_DEV_TYPE_CFI: 544 return (cfi_read(buf, lba, nblk)); 545 546 case BOOTINFO_DEV_TYPE_SDCARD: 547 return (altera_sdcard_read(buf, lba, nblk)); 548 549 default: 550 return (-1); 551 } 552} 553 554static int 555dskread(void *buf, unsigned lba, unsigned nblk) 556{ 557#if 0 558 /* 559 * XXXRW: For now, assume no partition table around the file system; it's 560 * just in raw flash. 561 */ 562 struct dos_partition *dp; 563 struct disklabel *d; 564 char *sec; 565 unsigned i; 566 uint8_t sl; 567 568 if (!dsk_meta) { 569 sec = dmadat->secbuf; 570 dsk.start = 0; 571 if (drvread(sec, DOSBBSECTOR, 1)) 572 return -1; 573 dp = (void *)(sec + DOSPARTOFF); 574 sl = dsk.slice; 575 if (sl < BASE_SLICE) { 576 for (i = 0; i < NDOSPART; i++) 577 if (dp[i].dp_typ == DOSPTYP_386BSD && 578 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 579 sl = BASE_SLICE + i; 580 if (dp[i].dp_flag & 0x80 || 581 dsk.slice == COMPATIBILITY_SLICE) 582 break; 583 } 584 if (dsk.slice == WHOLE_DISK_SLICE) 585 dsk.slice = sl; 586 } 587 if (sl != WHOLE_DISK_SLICE) { 588 if (sl != COMPATIBILITY_SLICE) 589 dp += sl - BASE_SLICE; 590 if (dp->dp_typ != DOSPTYP_386BSD) { 591 printf("Invalid %s\n", "slice"); 592 return -1; 593 } 594 dsk.start = le32toh(dp->dp_start); 595 } 596 if (drvread(sec, dsk.start + LABELSECTOR, 1)) 597 return -1; 598 d = (void *)(sec + LABELOFFSET); 599 if (le32toh(d->d_magic) != DISKMAGIC || 600 le32toh(d->d_magic2) != DISKMAGIC) { 601 if (dsk.part != RAW_PART) { 602 printf("Invalid %s\n", "label"); 603 return -1; 604 } 605 } else { 606 if (!dsk.init) { 607 if (le16toh(d->d_type) == DTYPE_SCSI) 608 dsk.type = TYPE_DA; 609 dsk.init++; 610 } 611 if (dsk.part >= le16toh(d->d_npartitions) || 612 !(le32toh(d->d_partitions[dsk.part].p_size))) { 613 printf("Invalid %s\n", "partition"); 614 return -1; 615 } 616 dsk.start += le32toh(d->d_partitions[dsk.part].p_offset); 617 dsk.start -= le32toh(d->d_partitions[RAW_PART].p_offset); 618 } 619 } 620 return drvread(buf, dsk.start + lba, nblk); 621#else 622 return drvread(buf, lba, nblk); 623#endif 624} 625 626void 627putchar(int c) 628{ 629 if (c == '\n') 630 xputc('\r'); 631 xputc(c); 632} 633 634static int 635xputc(int c) 636{ 637 if (ioctrl & IO_KEYBOARD) 638 putc(c); 639#if 0 640 if (ioctrl & IO_SERIAL) 641 sio_putc(c); 642#endif 643 return c; 644} 645 646static int 647xgetc(int fn) 648{ 649 if (OPT_CHECK(RBX_NOINTR)) 650 return 0; 651 for (;;) { 652 if (ioctrl & IO_KEYBOARD && keyhit(0)) 653 return fn ? 1 : getc(); 654#if 0 655 if (ioctrl & IO_SERIAL && sio_ischar()) 656 return fn ? 1 : sio_getc(); 657#endif 658 if (fn) 659 return 0; 660 } 661} 662