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