2 * Copyright (c) 2013-2014 Robert N. M. Watson
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.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * Copyright (c) 1998 Robert Nordier
31 * All rights reserved.
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
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
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
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>
54 #include <machine/bootinfo.h>
55 #include <machine/elf.h>
70 static const char **beri_argv, **beri_envv;
71 static uint64_t beri_memsize;
76 #define SECOND 1 /* Circa that many ticks in a second. */
78 #define RBX_ASKNAME 0x0 /* -a */
79 #define RBX_SINGLE 0x1 /* -s */
80 /* 0x2 is reserved for log2(RB_NOSYNC). */
81 /* 0x3 is reserved for log2(RB_HALT). */
82 /* 0x4 is reserved for log2(RB_INITNAME). */
83 #define RBX_DFLTROOT 0x5 /* -r */
84 #define RBX_KDB 0x6 /* -d */
85 /* 0x7 is reserved for log2(RB_RDONLY). */
86 /* 0x8 is reserved for log2(RB_DUMP). */
87 /* 0x9 is reserved for log2(RB_MINIROOT). */
88 #define RBX_CONFIG 0xa /* -c */
89 #define RBX_VERBOSE 0xb /* -v */
90 #define RBX_SERIAL 0xc /* -h */
91 #define RBX_CDROM 0xd /* -C */
92 /* 0xe is reserved for log2(RB_POWEROFF). */
93 #define RBX_GDB 0xf /* -g */
94 #define RBX_MUTE 0x10 /* -m */
95 /* 0x11 is reserved for log2(RB_SELFTEST). */
96 /* 0x12 is reserved for boot programs. */
97 /* 0x13 is reserved for boot programs. */
98 #define RBX_PAUSE 0x14 /* -p */
99 #define RBX_QUIET 0x15 /* -q */
100 #define RBX_NOINTR 0x1c /* -n */
101 /* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
102 #define RBX_DUAL 0x1d /* -D */
103 /* 0x1f is reserved for log2(RB_BOOTINFO). */
105 /* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */
106 #define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
107 OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \
108 OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \
109 OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \
110 OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \
111 OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL))
115 #define MEM_BASE 0x12
119 * XXXRW: I think this has to do with whether boot2 expects a partition
122 #define DRV_HARD 0x80
123 #define DRV_MASK 0x7f
125 /* Default to using CFI flash. */
126 #define TYPE_DEFAULT BOOTINFO_DEV_TYPE_SDCARD
128 /* Hard-coded assumption about location of JTAG-loaded kernel. */
129 #define DRAM_KERNEL_ADDR ((void *)mips_phys_to_cached(0x20000))
131 #define OPT_SET(opt) (1 << (opt))
132 #define OPT_CHECK(opt) ((opts) & OPT_SET(opt))
134 extern uint32_t _end;
136 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
137 static const unsigned char flags[NOPT] = {
154 /* These must match BOOTINFO_DEV_TYPE constants. */
155 static const char *const dev_nm[] = {"dram", "cfi", "sdcard"};
156 static const u_int dev_nm_count = sizeof(dev_nm) / sizeof(dev_nm[0]);
158 static struct dmadat __dmadat;
161 unsigned type; /* BOOTINFO_DEV_TYPE_x object type. */
162 uintptr_t unitptr; /* Unit number or pointer to object. */
170 static char cmd[512], cmddup[512], knamebuf[1024];
171 static const char *kname;
172 static uint32_t opts;
174 static int comspeed = SIOSPD;
176 struct bootinfo bootinfo;
177 static uint8_t ioctrl = IO_KEYBOARD;
181 static void boot_fromdram(void);
182 static void boot_fromfs(void);
183 static void load(void);
184 static int parse(void);
185 static int dskread(void *, unsigned, unsigned);
186 static int xputc(int);
187 static int xgetc(int);
190 #define UFS_SMALL_CGBASE
194 xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
196 if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
197 printf("Invalid %s\n", "format");
211 switch (c = xgetc(0)) {
227 if (s - cmd < sizeof(cmd) - 1)
235 main(u_int argc, const char *argv[], const char *envv[], uint64_t memsize)
241 /* Arguments from Miniboot. */
245 beri_memsize = memsize;
249 /* XXXRW: more here. */
251 v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
252 dsk.drive = *(uint8_t *)PTOV(ARGS);
254 dsk.type = TYPE_DEFAULT;
256 dsk.unit = dsk.drive & DRV_MASK;
257 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
259 bootinfo.bi_version = BOOTINFO_VERSION;
260 bootinfo.bi_size = sizeof(bootinfo);
262 /* Process configuration file */
266 if ((ino = lookup(PATH_CONFIG)) ||
267 (ino = lookup(PATH_DOTCONFIG))) {
268 nbyte = fsread(ino, cmd, sizeof(cmd) - 1);
273 memcpy(cmddup, cmd, sizeof(cmd));
276 if (!OPT_CHECK(RBX_QUIET))
277 printf("%s: %s", PATH_CONFIG, cmddup);
278 /* Do not process this command twice */
283 * Try to exec stage 3 boot loader. If interrupted by a keypress,
284 * or in case of failure, try to load a kernel directly instead.
289 if (autoboot && !keyhit(3*SECOND)) {
295 /* Present the user with the boot2 prompt. */
298 if (!autoboot || !OPT_CHECK(RBX_QUIET))
299 printf("\nFreeBSD/mips boot\n"
300 "Default: %s%ju:%s\n"
302 dev_nm[dsk.type], dsk.unitptr, kname);
304 if (ioctrl & IO_SERIAL)
307 if (!autoboot || keyhit(3*SECOND))
309 else if (!autoboot || !OPT_CHECK(RBX_QUIET))
319 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
326 boot(void *entryp, int argc, const char *argv[], const char *envv[])
329 bootinfo.bi_kernelname = (bi_ptr_t)kname;
330 bootinfo.bi_boot2opts = opts & RBX_MASK;
331 bootinfo.bi_boot_dev_type = dsk.type;
332 bootinfo.bi_boot_dev_unitptr = dsk.unitptr;
333 bootinfo.bi_memsize = beri_memsize;
336 * XXXRW: A possible future way to distinguish Miniboot passing a memory
339 if (beri_memsize <= BERI_MEMVSDTB)
340 bootinfo.bi_memsize = beri_memsize;
342 bootinfo.bi_dtb = beri_memsize;
344 ((void(*)(int, const char **, const char **, void *))entryp)(argc, argv,
349 * Boot a kernel that has mysteriously (i.e., by JTAG) appeared in DRAM;
350 * assume that it is already properly relocated, etc, and invoke its entry
351 * address without question or concern.
356 void *kaddr = DRAM_KERNEL_ADDR; /* XXXRW: Something better here. */
357 Elf64_Ehdr *ehp = kaddr;
360 printf("Invalid %s\n", "format");
363 boot((void *)ehp->e_entry, beri_argc, beri_argv, beri_envv);
372 static Elf64_Phdr ep[2];
374 static Elf64_Shdr es[2];
381 if (!(ino = lookup(kname))) {
383 printf("No %s\n", kname);
386 if (xfsread(ino, &hdr, sizeof(hdr)))
389 if (IS_ELF(hdr.eh)) {
390 fs_off = hdr.eh.e_phoff;
391 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
392 if (xfsread(ino, ep + j, sizeof(ep[0])))
394 if (ep[j].p_type == PT_LOAD)
397 for (i = 0; i < 2; i++) {
398 p = (caddr_t)ep[i].p_paddr;
399 fs_off = ep[i].p_offset;
400 if (xfsread(ino, p, ep[i].p_filesz))
403 p += roundup2(ep[1].p_memsz, PAGE_SIZE);
405 bootinfo.bi_symtab = VTOP(p);
406 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
407 fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
408 (hdr.eh.e_shstrndx + 1);
409 if (xfsread(ino, &es, sizeof(es)))
411 for (i = 0; i < 2; i++) {
412 *(Elf32_Word *)p = es[i].sh_size;
413 p += sizeof(es[i].sh_size);
414 fs_off = es[i].sh_offset;
415 if (xfsread(ino, p, es[i].sh_size))
421 addr = hdr.eh.e_entry;
423 bootinfo.bi_esymtab = VTOP(p);
426 printf("Invalid %s\n", "format");
429 boot((void *)addr, beri_argc, beri_argv, beri_envv);
437 case BOOTINFO_DEV_TYPE_DRAM:
461 while ((c = *arg++)) {
462 if (c == ' ' || c == '\t' || c == '\n')
464 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
469 while ((c = *arg++)) {
474 opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL);
478 printf("Keyboard: %s\n", cp);
481 } else if (c == 'S') {
483 while ((unsigned int)(i = *arg++ - '0') <= 9)
485 if (j > 0 && i == -'0') {
489 /* Fall through to error below ('S' not in optstr[]). */
492 for (i = 0; c != optstr[i]; i++)
495 opts ^= OPT_SET(flags[i]);
497 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
498 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
500 if (ioctrl & IO_SERIAL) {
501 if (sio_init(115200 / comspeed) != 0)
502 ioctrl &= ~IO_SERIAL;
507 * Parse a device/kernel name. Format(s):
512 * NB: Utterly incomprehensible but space-efficient ARM/i386
513 * parsing removed in favour of larger but easier-to-read C. This
514 * is still not great, however -- e.g., relating to unit handling.
516 * TODO: it would be nice if a DRAM pointer could be specified
519 * XXXRW: Pick up pieces here.
523 * Search for a parens; if none, then it's just a path.
524 * Otherwise, it's a devicename.
527 q = strsep(&arg, ":");
531 printf("Invalid device: name too short\n");
536 * First, handle one-digit unit.
539 if (unit < '0' || unit > '9') {
540 printf("Invalid device: invalid unit\n", q,
548 * Next, find matching device.
550 for (i = 0; i < dev_nm_count; i++) {
551 if (strcmp(q, dev_nm[i]) == 0)
554 if (i == dev_nm_count) {
555 printf("Invalid device: no driver match\n");
559 dsk.unitptr = unit; /* Someday: also a DRAM pointer? */
562 if ((i = ep - arg)) {
563 if ((size_t)i >= sizeof(knamebuf))
565 memcpy(knamebuf, arg, i + 1);
575 drvread(void *buf, unsigned lba, unsigned nblk)
578 /* XXXRW: eventually, we may want to pass 'drive' and 'unit' here. */
580 case BOOTINFO_DEV_TYPE_CFI:
581 return (cfi_read(buf, lba, nblk));
583 case BOOTINFO_DEV_TYPE_SDCARD:
584 return (altera_sdcard_read(buf, lba, nblk));
592 dskread(void *buf, unsigned lba, unsigned nblk)
596 * XXXRW: For now, assume no partition table around the file system; it's
599 struct dos_partition *dp;
606 sec = dmadat->secbuf;
608 if (drvread(sec, DOSBBSECTOR, 1))
610 dp = (void *)(sec + DOSPARTOFF);
612 if (sl < BASE_SLICE) {
613 for (i = 0; i < NDOSPART; i++)
614 if (dp[i].dp_typ == DOSPTYP_386BSD &&
615 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
617 if (dp[i].dp_flag & 0x80 ||
618 dsk.slice == COMPATIBILITY_SLICE)
621 if (dsk.slice == WHOLE_DISK_SLICE)
624 if (sl != WHOLE_DISK_SLICE) {
625 if (sl != COMPATIBILITY_SLICE)
626 dp += sl - BASE_SLICE;
627 if (dp->dp_typ != DOSPTYP_386BSD) {
628 printf("Invalid %s\n", "slice");
631 dsk.start = le32toh(dp->dp_start);
633 if (drvread(sec, dsk.start + LABELSECTOR, 1))
635 d = (void *)(sec + LABELOFFSET);
636 if (le32toh(d->d_magic) != DISKMAGIC ||
637 le32toh(d->d_magic2) != DISKMAGIC) {
638 if (dsk.part != RAW_PART) {
639 printf("Invalid %s\n", "label");
644 if (le16toh(d->d_type) == DTYPE_SCSI)
648 if (dsk.part >= le16toh(d->d_npartitions) ||
649 !(le32toh(d->d_partitions[dsk.part].p_size))) {
650 printf("Invalid %s\n", "partition");
653 dsk.start += le32toh(d->d_partitions[dsk.part].p_offset);
654 dsk.start -= le32toh(d->d_partitions[RAW_PART].p_offset);
657 return drvread(buf, dsk.start + lba, nblk);
659 return drvread(buf, lba, nblk);
674 if (ioctrl & IO_KEYBOARD)
677 if (ioctrl & IO_SERIAL)
686 if (OPT_CHECK(RBX_NOINTR))
689 if (ioctrl & IO_KEYBOARD && keyhit(0))
690 return fn ? 1 : getc();
692 if (ioctrl & IO_SERIAL && sio_ischar())
693 return fn ? 1 : sio_getc();