boot2.c revision 346482
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 346482 2019-04-21 04:26:02Z 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	beri_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 : beri_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
655int
656getchar(void)
657{
658
659	return xgetc(0);
660}
661
662void
663exit(int code)
664{
665
666        printf("error: loader exit\n");
667        while (1);
668        __unreachable();
669}
670