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