boot2.c revision 183636
118334Speter/*-
290075Sobrien * Copyright (c) 2008 John Hay
3169689Skan * Copyright (c) 2006 Warner Losh
418334Speter * Copyright (c) 1998 Robert Nordier
590075Sobrien * All rights reserved.
618334Speter *
790075Sobrien * Redistribution and use in source and binary forms are freely
890075Sobrien * permitted provided that the above copyright notice and this
990075Sobrien * paragraph and the following disclaimer are duplicated in all
1090075Sobrien * such forms.
1118334Speter *
1290075Sobrien * This software is provided "AS IS" and without any express or
1390075Sobrien * implied warranties, including, without limitation, the implied
1490075Sobrien * warranties of merchantability and fitness for a particular
1590075Sobrien * purpose.
1618334Speter */
1718334Speter
1890075Sobrien#include <sys/cdefs.h>
19169689Skan__FBSDID("$FreeBSD: head/sys/boot/arm/at91/boot2/boot2.c 183636 2008-10-05 23:59:52Z imp $");
20169689Skan
2118334Speter#include <sys/param.h>
22132718Skan#include <sys/disklabel.h>
23132718Skan#include <sys/diskmbr.h>
24132718Skan#include <sys/dirent.h>
25169689Skan#include <sys/reboot.h>
26169689Skan
27169689Skan#include <machine/elf.h>
28117395Skan
2918334Speter#include <stdarg.h>
3018334Speter
3118334Speter#include "lib.h"
3218334Speter#include "board.h"
3318334Speter
3418334Speter#define RBX_ASKNAME	0x0	/* -a */
3518334Speter#define RBX_SINGLE	0x1	/* -s */
3618334Speter/* 0x2 is reserved for log2(RB_NOSYNC). */
3718334Speter/* 0x3 is reserved for log2(RB_HALT). */
3818334Speter/* 0x4 is reserved for log2(RB_INITNAME). */
3918334Speter#define RBX_DFLTROOT	0x5	/* -r */
4018334Speter/* #define RBX_KDB 	0x6	   -d */
41117395Skan/* 0x7 is reserved for log2(RB_RDONLY). */
4218334Speter/* 0x8 is reserved for log2(RB_DUMP). */
4318334Speter/* 0x9 is reserved for log2(RB_MINIROOT). */
44117395Skan#define RBX_CONFIG	0xa	/* -c */
45117395Skan#define RBX_VERBOSE	0xb	/* -v */
4618334Speter/* #define RBX_SERIAL	0xc	   -h */
4718334Speter/* #define RBX_CDROM	0xd	   -C */
4818334Speter/* 0xe is reserved for log2(RB_POWEROFF). */
4918334Speter#define RBX_GDB 	0xf	/* -g */
5018334Speter/* #define RBX_MUTE	0x10	   -m */
5118334Speter/* 0x11 is reserved for log2(RB_SELFTEST). */
5218334Speter/* 0x12 is reserved for boot programs. */
5318334Speter/* 0x13 is reserved for boot programs. */
5418334Speter/* #define RBX_PAUSE	0x14	   -p */
5518334Speter/* #define RBX_QUIET	0x15	   -q */
5618334Speter#define RBX_NOINTR	0x1c	/* -n */
5718334Speter/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
5818334Speter/* #define RBX_DUAL	0x1d	   -D */
59117395Skan/* 0x1f is reserved for log2(RB_BOOTINFO). */
6090075Sobrien
6190075Sobrien/* pass: -a, -s, -r, -v, -g */
6290075Sobrien#define RBX_MASK	(OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
6390075Sobrien			OPT_SET(RBX_DFLTROOT) | \
6490075Sobrien			OPT_SET(RBX_VERBOSE) | \
6590075Sobrien			OPT_SET(RBX_GDB))
6690075Sobrien
6790075Sobrien#define PATH_CONFIG	"/boot.config"
6890075Sobrien//#define PATH_KERNEL	"/boot/kernel/kernel"
6990075Sobrien#define PATH_KERNEL	"/boot/kernel/kernel.gz.tramp"
70132718Skan
71169689Skanextern uint32_t _end;
72169689Skan
7390075Sobrien#define NOPT		6
7490075Sobrien
7590075Sobrien#define OPT_SET(opt)	(1 << (opt))
7690075Sobrien#define OPT_CHECK(opt)	((opts) & OPT_SET(opt))
7790075Sobrien
7890075Sobrienstatic const char optstr[NOPT] = "agnrsv";
7990075Sobrienstatic const unsigned char flags[NOPT] = {
8090075Sobrien	RBX_ASKNAME,
8190075Sobrien	RBX_GDB,
8290075Sobrien	RBX_NOINTR,
8390075Sobrien	RBX_DFLTROOT,
8490075Sobrien	RBX_SINGLE,
8590075Sobrien	RBX_VERBOSE
86132718Skan};
8790075Sobrien
88132718Skanunsigned dsk_start;
8990075Sobrienstatic char cmd[512];
9090075Sobrienstatic char kname[1024];
9190075Sobrienstatic uint32_t opts;
9290075Sobrienstatic int dsk_meta;
9390075Sobrien
9490075Sobrienstatic void load(void);
9590075Sobrienstatic int parse(void);
9690075Sobrienstatic int xfsread(ino_t, void *, size_t);
9790075Sobrienstatic int dskread(void *, unsigned, unsigned);
9890075Sobrien
99132718Skan#define	UFS_SMALL_CGBASE
100117395Skan#include "ufsread.c"
10190075Sobrien
10290075Sobrien#ifdef DEBUG
103169689Skan#define	DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
104132718Skan#else
10590075Sobrien#define	DPRINTF(fmt, ...)
10690075Sobrien#endif
10790075Sobrien
10890075Sobrienstatic inline int
10990075Sobrienxfsread(ino_t inode, void *buf, size_t nbyte)
11090075Sobrien{
11190075Sobrien	if ((size_t)fsread(inode, buf, nbyte) != nbyte)
11290075Sobrien		return -1;
11390075Sobrien	return 0;
114117395Skan}
11590075Sobrien
11690075Sobrienstatic inline void
11790075Sobriengetstr(int c)
11890075Sobrien{
11990075Sobrien	char *s;
12090075Sobrien
12190075Sobrien	s = cmd;
12290075Sobrien	if (c == 0)
12390075Sobrien		c = getc(10000);
12490075Sobrien	for (;;) {
12590075Sobrien		switch (c) {
12690075Sobrien		case 0:
12790075Sobrien			break;
12890075Sobrien		case '\177':
12990075Sobrien		case '\b':
13090075Sobrien			if (s > cmd) {
131117395Skan				s--;
13290075Sobrien				printf("\b \b");
13390075Sobrien			}
13490075Sobrien			break;
13590075Sobrien		case '\n':
13690075Sobrien		case '\r':
13790075Sobrien			*s = 0;
138117395Skan			return;
13990075Sobrien		default:
14090075Sobrien			if (s - cmd < sizeof(cmd) - 1)
14190075Sobrien				*s++ = c;
14290075Sobrien			xputchar(c);
14390075Sobrien		}
14490075Sobrien		c = getc(10000);
14590075Sobrien	}
14690075Sobrien}
14790075Sobrien
14890075Sobrienint
14990075Sobrienmain(void)
15090075Sobrien{
15190075Sobrien	int autoboot, c = 0;
15290075Sobrien	ino_t ino;
15390075Sobrien
15490075Sobrien	dmadat = (void *)(0x20000000 + (16 << 20));
15590075Sobrien	board_init();
15690075Sobrien
15790075Sobrien	autoboot = 1;
15890075Sobrien
15990075Sobrien	/* Process configuration file */
16090075Sobrien	if ((ino = lookup(PATH_CONFIG)))
16190075Sobrien		fsread(ino, cmd, sizeof(cmd));
162169689Skan
163169689Skan	if (*cmd) {
164169689Skan		if (parse())
165169689Skan			autoboot = 0;
166169689Skan		printf("%s: %s\n", PATH_CONFIG, cmd);
167169689Skan		/* Do not process this command twice */
168169689Skan		*cmd = 0;
169169689Skan	}
170169689Skan
171169689Skan	if (*kname == '\0')
172169689Skan		strcpy(kname, PATH_KERNEL);
173169689Skan
174169689Skan	/* Present the user with the boot2 prompt. */
175169689Skan	for (;;) {
176169689Skan		printf("\nDefault: %s\nboot: ", kname);
177169689Skan		if (!autoboot ||
178169689Skan		    (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0))
17918334Speter			getstr(c);
18018334Speter		xputchar('\n');
18118334Speter		autoboot = 0;
182117395Skan		c = 0;
18318334Speter		if (parse())
18490075Sobrien			xputchar('\a');
18590075Sobrien		else
18690075Sobrien			load();
18790075Sobrien	}
18818334Speter}
189169689Skan
190169689Skanstatic void
191169689Skanload(void)
19218334Speter{
19390075Sobrien	Elf32_Ehdr eh;
19490075Sobrien	static Elf32_Phdr ep[2];
19518334Speter	caddr_t p;
19690075Sobrien	ino_t ino;
19790075Sobrien	uint32_t addr;
19890075Sobrien	int i, j;
19990075Sobrien
20090075Sobrien	if (!(ino = lookup(kname))) {
20190075Sobrien		if (!ls)
20290075Sobrien			printf("No %s\n", kname);
20318334Speter		return;
20490075Sobrien	}
20590075Sobrien	if (xfsread(ino, &eh, sizeof(eh)))
20690075Sobrien		return;
20790075Sobrien	if (!IS_ELF(eh)) {
20818334Speter		printf("Invalid %s\n", "format");
20990075Sobrien		return;
21090075Sobrien	}
21190075Sobrien	fs_off = eh.e_phoff;
21290075Sobrien	for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
21318334Speter		if (xfsread(ino, ep + j, sizeof(ep[0])))
21490075Sobrien			return;
21590075Sobrien		if (ep[j].p_type == PT_LOAD)
21690075Sobrien			j++;
21790075Sobrien	}
21890075Sobrien	for (i = 0; i < 2; i++) {
21990075Sobrien		p = (caddr_t)ep[i].p_paddr;
22090075Sobrien		fs_off = ep[i].p_offset;
22118334Speter		if (xfsread(ino, p, ep[i].p_filesz))
22290075Sobrien			return;
22390075Sobrien	}
22490075Sobrien	addr = eh.e_entry;
22590075Sobrien	((void(*)(int))addr)(opts & RBX_MASK);
22690075Sobrien}
227117395Skan
22890075Sobrienstatic int
22990075Sobrienparse()
23090075Sobrien{
23118334Speter	char *arg = cmd;
23290075Sobrien	char *ep, *p;
23390075Sobrien	int c, i;
23418334Speter
23518334Speter	while ((c = *arg++)) {
23690075Sobrien		if (c == ' ' || c == '\t' || c == '\n')
23790075Sobrien			continue;
23890075Sobrien		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
23950397Sobrien		ep = p;
24090075Sobrien		if (*p)
24190075Sobrien			*p++ = 0;
24290075Sobrien		if (c == '-') {
24318334Speter			while ((c = *arg++)) {
24490075Sobrien				for (i = 0; c != optstr[i]; i++)
24590075Sobrien					if (i == NOPT - 1)
24690075Sobrien						return -1;
24790075Sobrien				opts ^= OPT_SET(flags[i]);
24890075Sobrien			}
249132718Skan		} else {
250132718Skan			arg--;
251132718Skan			if ((i = ep - arg)) {
252132718Skan				if ((size_t)i >= sizeof(kname))
253132718Skan					return -1;
25490075Sobrien				memcpy(kname, arg, i + 1);
25590075Sobrien			}
25690075Sobrien		}
25790075Sobrien		arg = p;
25890075Sobrien	}
259169689Skan	return 0;
26090075Sobrien}
26190075Sobrien
26290075Sobrienstatic int
26390075Sobriendskread(void *buf, unsigned lba, unsigned nblk)
26490075Sobrien{
26590075Sobrien	struct dos_partition *dp;
26690075Sobrien	struct disklabel *d;
267261188Spfg	char *sec;
268261188Spfg	int i;
269261188Spfg
270261188Spfg	if (!dsk_meta) {
271261188Spfg		sec = dmadat->secbuf;
272261188Spfg		dsk_start = 0;
27390075Sobrien		if (drvread(sec, DOSBBSECTOR, 1))
27490075Sobrien			return -1;
27590075Sobrien		dp = (void *)(sec + DOSPARTOFF);
27690075Sobrien		for (i = 0; i < NDOSPART; i++) {
27790075Sobrien			if (dp[i].dp_typ == DOSPTYP_386BSD)
278169689Skan				break;
279169689Skan		}
280169689Skan		if (i == NDOSPART)
28190075Sobrien			return -1;
282169689Skan		/*
283169689Skan		 * Although dp_start is aligned within the disk
284169689Skan		 * partition structure, DOSPARTOFF is 446, which is
285169689Skan		 * only word (2) aligned, not longword (4) aligned.
28690075Sobrien		 * Cope by using memcpy to fetch the start of this
28790075Sobrien		 * partition.
28890075Sobrien		 */
28990075Sobrien		memcpy(&dsk_start, &dp[1].dp_start, 4);
290169689Skan		if (drvread(sec, dsk_start + LABELSECTOR, 1))
291169689Skan			return -1;
29290075Sobrien		d = (void *)(sec + LABELOFFSET);
293169689Skan		if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
294169689Skan			printf("Invalid %s\n", "label");
29590075Sobrien			return -1;
296169689Skan		}
297169689Skan		if (!d->d_partitions[0].p_size) {
298169689Skan			printf("Invalid %s\n", "partition");
29990075Sobrien			return -1;
30090075Sobrien		}
30190075Sobrien		dsk_start += d->d_partitions[0].p_offset;
30290075Sobrien		dsk_start -= d->d_partitions[RAW_PART].p_offset;
30390075Sobrien		dsk_meta++;
30490075Sobrien	}
30518334Speter	return drvread(buf, dsk_start + lba, nblk);
306117395Skan}
307117395Skan