2 * Copyright (c) 2008 John Hay
3 * Copyright (c) 2006 M Warner Losh <imp@freebsd.org>
4 * Copyright (c) 1998 Robert Nordier
7 * Redistribution and use in source and binary forms are freely
8 * permitted provided that the above copyright notice and this
9 * paragraph and the following disclaimer are duplicated in all
12 * This software is provided "AS IS" and without any express or
13 * implied warranties, including, without limitation, the implied
14 * warranties of merchantability and fitness for a particular
18 #include <sys/cdefs.h>
19 __FBSDID("$FreeBSD$");
21 #include <sys/param.h>
22 #include <sys/disklabel.h>
23 #include <sys/diskmbr.h>
24 #include <sys/dirent.h>
25 #include <sys/reboot.h>
27 #include <machine/elf.h>
37 #define PATH_KERNEL "/boot/kernel/kernel.gz.tramp"
43 static const char optstr[NOPT] = "agnrsv";
44 static const unsigned char flags[NOPT] = {
53 unsigned board_id; /* board type to pass to kernel, if set by board_* code */
56 static char kname[1024];
58 static uint8_t dsk_meta;
60 static void load(void);
61 static int parse(void);
62 static int dskread(void *, unsigned, unsigned);
64 static void fixup_boot_drv(caddr_t, int, int, int);
67 #define UFS_SMALL_CGBASE
71 #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
73 #define DPRINTF(fmt, ...)
77 xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
79 if ((size_t)fsread(inode, buf, nbyte) != nbyte)
108 if (s - cmd < sizeof(cmd) - 1)
122 dmadat = (void *)(0x20000000 + (16 << 20));
127 /* Process configuration file */
128 if ((ino = lookup(PATH_CONFIG)) ||
129 (ino = lookup(PATH_DOTCONFIG)))
130 fsread(ino, cmd, sizeof(cmd));
135 printf("%s: %s\n", PATH_CONFIG, cmd);
136 /* Do not process this command twice */
141 strcpy(kname, PATH_KERNEL);
143 /* Present the user with the boot2 prompt. */
145 printf("\nDefault: %s\nboot: ", kname);
147 (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0))
163 static Elf32_Phdr ep[2];
168 #ifdef FIXUP_BOOT_DRV
172 staddr = (caddr_t)0xffffffff;
175 if (!(ino = lookup(kname))) {
177 printf("No %s\n", kname);
180 if (xfsread(ino, &eh, sizeof(eh)))
183 printf("Invalid %s\n", "format");
187 for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
188 if (xfsread(ino, ep + j, sizeof(ep[0])))
190 if (ep[j].p_type == PT_LOAD)
193 for (i = 0; i < 2; i++) {
194 p = (caddr_t)ep[i].p_paddr;
195 fs_off = ep[i].p_offset;
196 #ifdef FIXUP_BOOT_DRV
197 if (staddr == (caddr_t)0xffffffff)
199 klen += ep[i].p_filesz;
201 if (xfsread(ino, p, ep[i].p_filesz))
205 #ifdef FIXUP_BOOT_DRV
206 fixup_boot_drv(staddr, klen, bootslice, bootpart);
208 ((void(*)(int, int, int, int))addr)(opts & RBX_MASK, board_id, 0, 0);
218 while ((c = *arg++)) {
219 if (c == ' ' || c == '\t' || c == '\n')
221 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
226 while ((c = *arg++)) {
227 for (i = 0; c != optstr[i]; i++)
230 opts ^= OPT_SET(flags[i]);
234 if ((i = ep - arg)) {
235 if ((size_t)i >= sizeof(kname))
237 memcpy(kname, arg, i + 1);
246 dskread(void *buf, unsigned lba, unsigned nblk)
248 struct dos_partition *dp;
254 sec = dmadat->secbuf;
256 if (drvread(sec, DOSBBSECTOR, 1))
258 dp = (void *)(sec + DOSPARTOFF);
259 for (i = 0; i < NDOSPART; i++) {
260 if (dp[i].dp_typ == DOSPTYP_386BSD)
266 * Although dp_start is aligned within the disk
267 * partition structure, DOSPARTOFF is 446, which is
268 * only word (2) aligned, not longword (4) aligned.
269 * Cope by using memcpy to fetch the start of this
272 memcpy(&dsk_start, &dp[1].dp_start, 4);
273 if (drvread(sec, dsk_start + LABELSECTOR, 1))
275 d = (void *)(sec + LABELOFFSET);
276 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
277 printf("Invalid %s\n", "label");
280 if (!d->d_partitions[0].p_size) {
281 printf("Invalid %s\n", "partition");
284 dsk_start += d->d_partitions[0].p_offset;
285 dsk_start -= d->d_partitions[RAW_PART].p_offset;
288 return drvread(buf, dsk_start + lba, nblk);
291 #ifdef FIXUP_BOOT_DRV
293 * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel
294 * and change it to what was specified on the comandline or /boot.conf
295 * file or to what was encountered on the disk. It will try to handle 3
296 * different disk layouts, raw (dangerously dedicated), slice only and
297 * slice + partition. It will look for the following strings in the
298 * kernel, but if it is one of the first three, the string in the kernel
299 * must use the correct form to match the actual disk layout:
304 * In the case of the first three strings, only the "a" at the end and
305 * the "1" after the "s" will be modified, if they exist. The string
306 * length will not be changed. In the case of the last string, the
307 * whole string will be built up and nul, '\0' terminated.
310 fixup_boot_drv(caddr_t addr, int klen, int bs, int bp)
312 const u_int8_t op[] = "ufs:ROOTDEVNAME";
313 const u_int8_t op2[] = "ufs:ad0";
316 DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n",
317 (int)addr, klen, bs, bp);
322 ps = memmem(addr, klen, op, sizeof(op));
324 p = ps + 4; /* past ufs: */
325 DPRINTF("Found it at 0x%x\n", (int)ps);
326 p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */
333 if (disk_layout != DL_SLICE) {
334 /* append partition */
339 ps = memmem(addr, klen, op2, sizeof(op2) - 1);
341 p = ps + sizeof(op2) - 1;
342 DPRINTF("Found it at 0x%x\n", (int)ps);
353 printf("Could not locate \"%s\" to fix kernel boot device, "
354 "check ROOTDEVNAME is set\n", op);
357 DPRINTF("Changed boot device to %s\n", ps);