19 20#include <sys/param.h> 21#include <sys/disklabel.h> 22#include <sys/diskmbr.h> 23#include <sys/dirent.h> 24#include <sys/reboot.h> 25 26#include <machine/elf.h> 27 28#include <stdarg.h> 29 30#include "lib.h" 31 32#define RBX_ASKNAME 0x0 /* -a */ 33#define RBX_SINGLE 0x1 /* -s */ 34/* 0x2 is reserved for log2(RB_NOSYNC). */ 35/* 0x3 is reserved for log2(RB_HALT). */ 36/* 0x4 is reserved for log2(RB_INITNAME). */ 37#define RBX_DFLTROOT 0x5 /* -r */ 38/* #define RBX_KDB 0x6 -d */ 39/* 0x7 is reserved for log2(RB_RDONLY). */ 40/* 0x8 is reserved for log2(RB_DUMP). */ 41/* 0x9 is reserved for log2(RB_MINIROOT). */ 42#define RBX_CONFIG 0xa /* -c */ 43#define RBX_VERBOSE 0xb /* -v */ 44/* #define RBX_SERIAL 0xc -h */ 45/* #define RBX_CDROM 0xd -C */ 46/* 0xe is reserved for log2(RB_POWEROFF). */ 47#define RBX_GDB 0xf /* -g */ 48/* #define RBX_MUTE 0x10 -m */ 49/* 0x11 is reserved for log2(RB_SELFTEST). */ 50/* 0x12 is reserved for boot programs. */ 51/* 0x13 is reserved for boot programs. */ 52/* #define RBX_PAUSE 0x14 -p */ 53/* #define RBX_QUIET 0x15 -q */ 54#define RBX_NOINTR 0x1c /* -n */ 55/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 56/* #define RBX_DUAL 0x1d -D */ 57/* 0x1f is reserved for log2(RB_BOOTINFO). */ 58 59/* pass: -a, -s, -r, -v, -g */ 60#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ 61 OPT_SET(RBX_DFLTROOT) | \ 62 OPT_SET(RBX_VERBOSE) | \ 63 OPT_SET(RBX_GDB)) 64 65#define PATH_CONFIG "/boot.config" 66#define PATH_KERNEL "/boot/kernel/kernel" 67 68extern uint32_t _end; 69 70#define NOPT 6 71 72#define OPT_SET(opt) (1 << (opt)) 73#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 74 75static const char optstr[NOPT] = "agnrsv"; 76static const unsigned char flags[NOPT] = { 77 RBX_ASKNAME, 78 RBX_GDB, 79 RBX_NOINTR, 80 RBX_DFLTROOT, 81 RBX_SINGLE, 82 RBX_VERBOSE 83}; 84 85static unsigned dsk_start; 86static char cmd[512]; 87static char kname[1024]; 88static uint32_t opts; 89static int dsk_meta; 90static int bootslice; 91static int bootpart; 92static int disk_layout; 93#define DL_UNKNOWN 0 94#define DL_RAW 1 /* Dangerously dedicated */ 95#define DL_SLICE 2 /* Use only slices (DOS partitions) */ 96#define DL_SLICEPART 3 /* Use slices and partitions */ 97 98static void load(void); 99static int parse(void); 100static int xfsread(ino_t, void *, size_t); 101static int dskread(void *, unsigned, unsigned); 102static int drvread(void *, unsigned, unsigned); 103#ifdef FIXUP_BOOT_DRV 104static void fixup_boot_drv(caddr_t, int, int, int); 105#endif 106 107#include "ufsread.c" 108 109#ifdef DEBUG 110#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__) 111#else 112#define DPRINTF(fmt, ...) 113#endif 114 115static inline int 116xfsread(ino_t inode, void *buf, size_t nbyte) 117{ 118 if ((size_t)fsread(inode, buf, nbyte) != nbyte) 119 return -1; 120 return 0; 121} 122 123static inline void 124getstr(int c) 125{ 126 char *s; 127 128 s = cmd; 129 if (c == 0) 130 c = getc(10000); 131 for (;;) { 132 switch (c) { 133 case 0: 134 break; 135 case '\177': 136 case '\b': 137 if (s > cmd) { 138 s--; 139 printf("\b \b"); 140 } 141 break; 142 case '\n': 143 case '\r': 144 *s = 0; 145 return; 146 default: 147 if (s - cmd < sizeof(cmd) - 1) 148 *s++ = c; 149 xputchar(c); 150 } 151 c = getc(10000); 152 } 153} 154 155int 156main(void) 157{ 158 const char *bt; 159 int autoboot, c = 0; 160 ino_t ino; 161 162 dmadat = (void *)(0x1c0000); 163 p_memset((char *)dmadat, 0, 32 * 1024); 164 bt = board_init(); 165
| 19 20#include <sys/param.h> 21#include <sys/disklabel.h> 22#include <sys/diskmbr.h> 23#include <sys/dirent.h> 24#include <sys/reboot.h> 25 26#include <machine/elf.h> 27 28#include <stdarg.h> 29 30#include "lib.h" 31 32#define RBX_ASKNAME 0x0 /* -a */ 33#define RBX_SINGLE 0x1 /* -s */ 34/* 0x2 is reserved for log2(RB_NOSYNC). */ 35/* 0x3 is reserved for log2(RB_HALT). */ 36/* 0x4 is reserved for log2(RB_INITNAME). */ 37#define RBX_DFLTROOT 0x5 /* -r */ 38/* #define RBX_KDB 0x6 -d */ 39/* 0x7 is reserved for log2(RB_RDONLY). */ 40/* 0x8 is reserved for log2(RB_DUMP). */ 41/* 0x9 is reserved for log2(RB_MINIROOT). */ 42#define RBX_CONFIG 0xa /* -c */ 43#define RBX_VERBOSE 0xb /* -v */ 44/* #define RBX_SERIAL 0xc -h */ 45/* #define RBX_CDROM 0xd -C */ 46/* 0xe is reserved for log2(RB_POWEROFF). */ 47#define RBX_GDB 0xf /* -g */ 48/* #define RBX_MUTE 0x10 -m */ 49/* 0x11 is reserved for log2(RB_SELFTEST). */ 50/* 0x12 is reserved for boot programs. */ 51/* 0x13 is reserved for boot programs. */ 52/* #define RBX_PAUSE 0x14 -p */ 53/* #define RBX_QUIET 0x15 -q */ 54#define RBX_NOINTR 0x1c /* -n */ 55/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 56/* #define RBX_DUAL 0x1d -D */ 57/* 0x1f is reserved for log2(RB_BOOTINFO). */ 58 59/* pass: -a, -s, -r, -v, -g */ 60#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ 61 OPT_SET(RBX_DFLTROOT) | \ 62 OPT_SET(RBX_VERBOSE) | \ 63 OPT_SET(RBX_GDB)) 64 65#define PATH_CONFIG "/boot.config" 66#define PATH_KERNEL "/boot/kernel/kernel" 67 68extern uint32_t _end; 69 70#define NOPT 6 71 72#define OPT_SET(opt) (1 << (opt)) 73#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 74 75static const char optstr[NOPT] = "agnrsv"; 76static const unsigned char flags[NOPT] = { 77 RBX_ASKNAME, 78 RBX_GDB, 79 RBX_NOINTR, 80 RBX_DFLTROOT, 81 RBX_SINGLE, 82 RBX_VERBOSE 83}; 84 85static unsigned dsk_start; 86static char cmd[512]; 87static char kname[1024]; 88static uint32_t opts; 89static int dsk_meta; 90static int bootslice; 91static int bootpart; 92static int disk_layout; 93#define DL_UNKNOWN 0 94#define DL_RAW 1 /* Dangerously dedicated */ 95#define DL_SLICE 2 /* Use only slices (DOS partitions) */ 96#define DL_SLICEPART 3 /* Use slices and partitions */ 97 98static void load(void); 99static int parse(void); 100static int xfsread(ino_t, void *, size_t); 101static int dskread(void *, unsigned, unsigned); 102static int drvread(void *, unsigned, unsigned); 103#ifdef FIXUP_BOOT_DRV 104static void fixup_boot_drv(caddr_t, int, int, int); 105#endif 106 107#include "ufsread.c" 108 109#ifdef DEBUG 110#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__) 111#else 112#define DPRINTF(fmt, ...) 113#endif 114 115static inline int 116xfsread(ino_t inode, void *buf, size_t nbyte) 117{ 118 if ((size_t)fsread(inode, buf, nbyte) != nbyte) 119 return -1; 120 return 0; 121} 122 123static inline void 124getstr(int c) 125{ 126 char *s; 127 128 s = cmd; 129 if (c == 0) 130 c = getc(10000); 131 for (;;) { 132 switch (c) { 133 case 0: 134 break; 135 case '\177': 136 case '\b': 137 if (s > cmd) { 138 s--; 139 printf("\b \b"); 140 } 141 break; 142 case '\n': 143 case '\r': 144 *s = 0; 145 return; 146 default: 147 if (s - cmd < sizeof(cmd) - 1) 148 *s++ = c; 149 xputchar(c); 150 } 151 c = getc(10000); 152 } 153} 154 155int 156main(void) 157{ 158 const char *bt; 159 int autoboot, c = 0; 160 ino_t ino; 161 162 dmadat = (void *)(0x1c0000); 163 p_memset((char *)dmadat, 0, 32 * 1024); 164 bt = board_init(); 165
|
167 168 autoboot = 1; 169 170 /* Process configuration file */ 171 if ((ino = lookup(PATH_CONFIG))) 172 fsread(ino, cmd, sizeof(cmd)); 173 174 if (*cmd) { 175 if (parse()) 176 autoboot = 0; 177 printf("%s: %s\n", PATH_CONFIG, cmd); 178 /* Do not process this command twice */ 179 *cmd = 0; 180 } 181 182 if (*kname == '\0') 183 strcpy(kname, PATH_KERNEL); 184 185 /* Present the user with the boot2 prompt. */ 186 for (;;) { 187 printf("\nDefault: %s\nboot: ", kname); 188 if (!autoboot || 189 (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0)) 190 getstr(c); 191 xputchar('\n'); 192 autoboot = 0; 193 c = 0; 194 DPRINTF("cmd is '%s'\n", cmd); 195 if (parse()) 196 xputchar('\a'); 197 else 198 load(); 199 } 200} 201 202static void 203load(void) 204{ 205 Elf32_Ehdr eh; 206 static Elf32_Phdr ep[2]; 207 caddr_t p; 208 ino_t ino; 209 uint32_t addr; 210 int i, j; 211#ifdef FIXUP_BOOT_DRV 212 caddr_t staddr; 213 int klen; 214 215 staddr = (caddr_t)0xffffffff; 216 klen = 0; 217#endif 218 if (!(ino = lookup(kname))) { 219 if (!ls) 220 printf("No %s\n", kname); 221 return; 222 } 223 DPRINTF("Found %s\n", kname); 224 if (xfsread(ino, &eh, sizeof(eh))) 225 return; 226 if (!IS_ELF(eh)) { 227 printf("Invalid %s\n", "format"); 228 return; 229 } 230 fs_off = eh.e_phoff; 231 for (j = i = 0; i < eh.e_phnum && j < 2; i++) { 232 if (xfsread(ino, ep + j, sizeof(ep[0]))) 233 return; 234 if (ep[j].p_type == PT_LOAD) 235 j++; 236 } 237 for (i = 0; i < 2; i++) { 238 p = (caddr_t)(ep[i].p_paddr & 0x0fffffff); 239 fs_off = ep[i].p_offset; 240#ifdef FIXUP_BOOT_DRV 241 if (staddr == (caddr_t)0xffffffff) 242 staddr = p; 243 klen += ep[i].p_filesz; 244#endif 245 if (xfsread(ino, p, ep[i].p_filesz)) 246 return; 247 } 248 addr = eh.e_entry & 0x0fffffff; 249 DPRINTF("Entry point %x for %s\n", addr, kname); 250 clr_board(); 251#ifdef FIXUP_BOOT_DRV 252 fixup_boot_drv(staddr, klen, bootslice, bootpart); 253#endif 254 ((void(*)(int))addr)(RB_BOOTINFO /* XXX | (opts & RBX_MASK) */); 255} 256 257static int 258parse() 259{ 260 char *arg = cmd; 261 char *ep, *p; 262 int c, i; 263 264 while ((c = *arg++)) { 265 if (c == ' ' || c == '\t' || c == '\n') 266 continue; 267 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 268 ep = p; 269 if (*p) 270 *p++ = 0; 271 if (c == '-') { 272 while ((c = *arg++)) { 273 for (i = 0; c != optstr[i]; i++) 274 if (i == NOPT - 1) 275 return -1; 276 opts ^= OPT_SET(flags[i]); 277 } 278 } else { 279 arg--; 280 /* look for ad0s1a:... | ad0s1:... */ 281 if (strlen(arg) > 6 && arg[0] == 'a' && 282 arg[1] == 'd' && arg[3] == 's' && 283 (arg[5] == ':' || arg[6] == ':')) { 284 /* XXX Should also handle disk. */ 285 bootslice = arg[4] - '0'; 286 if (bootslice < 1 || bootslice > 4) 287 return (-1); 288 bootpart = 0; 289 if (arg[5] != ':') 290 bootpart = arg[5] - 'a'; 291 if (bootpart < 0 || bootpart > 7) 292 return (-1); 293 dsk_meta = 0; 294 if (arg[5] == ':') 295 arg += 6; 296 else 297 arg += 7; 298 /* look for ad0a:... */ 299 } else if (strlen(arg) > 4 && arg[0] == 'a' && 300 arg[1] == 'd' && arg[2] == '0' && arg[4] == ':') { 301 bootslice = 0; 302 bootpart = arg[3] - 'a'; 303 if (bootpart < 0 || bootpart > 7) 304 return (-1); 305 dsk_meta = 0; 306 arg += 5; 307 } 308 if ((i = ep - arg)) { 309 if ((size_t)i >= sizeof(kname)) 310 return -1; 311 memcpy(kname, arg, i + 1); 312 } 313 } 314 arg = p; 315 } 316 return 0; 317} 318 319/* 320 * dskread() will try to handle the disk layouts that are typically 321 * encountered. 322 * - raw or "Dangerously Dedicated" mode. No real slice table, just the 323 * default one that is included with bsdlabel -B. Typically this is 324 * used with ROOTDEVNAME=\"ufs:ad0a\". 325 * - slice only. Only a slice table is installed with no bsd label or 326 * bsd partition table. This is typically used with 327 * ROOTDEVNAME=\"ufs:ad0s1\". 328 * - slice + bsd label + partition table. This is typically done with 329 * with fdisk + bsdlabel and is used with ROOTDEVNAME=\"ufs:ad0s1a\". 330 */ 331static int 332dskread(void *buf, unsigned lba, unsigned nblk) 333{ 334 struct dos_partition *dp; 335 struct disklabel *d; 336 char *sec; 337 int i; 338 339 if (!dsk_meta) { 340 sec = dmadat->secbuf; 341 dsk_start = 0; 342 if (drvread(sec, DOSBBSECTOR, 1)) 343 return -1; 344 dp = (void *)(sec + DOSPARTOFF); 345 if (bootslice != 0) { 346 i = bootslice - 1; 347 if (dp[i].dp_typ != DOSPTYP_386BSD) 348 return -1; 349 } else { 350 for (i = 0; i < NDOSPART; i++) { 351 if ((dp[i].dp_typ == DOSPTYP_386BSD) && 352 (dp[i].dp_flag == 0x80)) 353 break; 354 } 355 } 356 if (i != NDOSPART) { 357 bootslice = i + 1; 358 DPRINTF("Found an active fbsd slice. (%d)\n", i + 1); 359 /* 360 * Although dp_start is aligned within the disk 361 * partition structure, DOSPARTOFF is 446, which 362 * is only word (2) aligned, not longword (4) 363 * aligned. Cope by using memcpy to fetch the 364 * start of this partition. 365 */ 366 memcpy(&dsk_start, &dp[i].dp_start, 4); 367 dsk_start = swap32(dsk_start); 368 DPRINTF("dsk_start %x\n", dsk_start); 369 if ((bootslice == 4) && (dsk_start == 0)) { 370 disk_layout = DL_RAW; 371 bootslice = 0; 372 } 373 } 374 if (drvread(sec, dsk_start + LABELSECTOR, 1)) 375 return -1; 376 d = (void *)(sec + LABELOFFSET); 377 if ((d->d_magic == DISKMAGIC && d->d_magic2 == DISKMAGIC) || 378 (swap32(d->d_magic) == DISKMAGIC && 379 swap32(d->d_magic2) == DISKMAGIC)) { 380 DPRINTF("p_size = %x\n", 381 !d->d_partitions[bootpart].p_size); 382 if (!d->d_partitions[bootpart].p_size) { 383 printf("Invalid partition\n"); 384 return -1; 385 } 386 DPRINTF("p_offset %x, RAW %x\n", 387 swap32(d->d_partitions[bootpart].p_offset), 388 swap32(d->d_partitions[RAW_PART].p_offset)); 389 dsk_start += swap32(d->d_partitions[bootpart].p_offset); 390 dsk_start -= swap32(d->d_partitions[RAW_PART].p_offset); 391 if ((disk_layout == DL_UNKNOWN) && (bootslice == 0)) 392 disk_layout = DL_RAW; 393 else if (disk_layout == DL_UNKNOWN) 394 disk_layout = DL_SLICEPART; 395 } else { 396 disk_layout = DL_SLICE; 397 DPRINTF("Invalid %s\n", "label"); 398 } 399 DPRINTF("bootslice %d, bootpart %d, dsk_start %u\n", bootslice, 400 bootpart, dsk_start); 401 dsk_meta++; 402 } 403 return drvread(buf, dsk_start + lba, nblk); 404} 405 406static int 407drvread(void *buf, unsigned lba, unsigned nblk) 408{ 409 static unsigned c = 0x2d5c7c2f; 410 411 printf("%c\b", c = c << 8 | c >> 24); 412 return (avila_read((char *)buf, lba, nblk)); 413} 414 415#ifdef FIXUP_BOOT_DRV 416/* 417 * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel 418 * and change it to what was specified on the comandline or /boot.conf 419 * file or to what was encountered on the disk. It will try to handle 3 420 * different disk layouts, raw (dangerously dedicated), slice only and 421 * slice + partition. It will look for the following strings in the 422 * kernel, but if it is one of the first three, the string in the kernel 423 * must use the correct form to match the actual disk layout: 424 * - ufs:ad0a 425 * - ufs:ad0s1 426 * - ufs:ad0s1a 427 * - ufs:ROOTDEVNAME 428 * In the case of the first three strings, only the "a" at the end and 429 * the "1" after the "s" will be modified, if they exist. The string 430 * length will not be changed. In the case of the last string, the 431 * whole string will be built up and nul, '\0' terminated. 432 */ 433static void 434fixup_boot_drv(caddr_t addr, int klen, int bs, int bp) 435{ 436 const u_int8_t op[] = "ufs:ROOTDEVNAME"; 437 const u_int8_t op2[] = "ufs:ad0"; 438 u_int8_t *p, *ps; 439 440 DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n", 441 (int)addr, klen, bs, bp); 442 if (bs > 4) 443 return; 444 if (bp > 7) 445 return; 446 ps = memmem(addr, klen, op, sizeof(op)); 447 if (ps != NULL) { 448 p = ps + 4; /* past ufs: */ 449 DPRINTF("Found it at 0x%x\n", (int)ps); 450 p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */ 451 p += 3; 452 if (bs > 0) { 453 /* append slice */ 454 *p++ = 's'; 455 *p++ = bs + '0'; 456 } 457 if (disk_layout != DL_SLICE) { 458 /* append partition */ 459 *p++ = bp + 'a'; 460 } 461 *p = '\0'; 462 } else { 463 ps = memmem(addr, klen, op2, sizeof(op2) - 1); 464 if (ps != NULL) { 465 p = ps + sizeof(op2) - 1; 466 DPRINTF("Found it at 0x%x\n", (int)ps); 467 if (*p == 's') { 468 /* fix slice */ 469 p++; 470 *p++ = bs + '0'; 471 } 472 if (*p == 'a') 473 *p = bp + 'a'; 474 } 475 } 476 if (ps == NULL) { 477 printf("Could not locate \"%s\" to fix kernel boot device, " 478 "check ROOTDEVNAME is set\n", op); 479 return; 480 } 481 DPRINTF("Changed boot device to %s\n", ps); 482} 483#endif
| 167 168 autoboot = 1; 169 170 /* Process configuration file */ 171 if ((ino = lookup(PATH_CONFIG))) 172 fsread(ino, cmd, sizeof(cmd)); 173 174 if (*cmd) { 175 if (parse()) 176 autoboot = 0; 177 printf("%s: %s\n", PATH_CONFIG, cmd); 178 /* Do not process this command twice */ 179 *cmd = 0; 180 } 181 182 if (*kname == '\0') 183 strcpy(kname, PATH_KERNEL); 184 185 /* Present the user with the boot2 prompt. */ 186 for (;;) { 187 printf("\nDefault: %s\nboot: ", kname); 188 if (!autoboot || 189 (OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0)) 190 getstr(c); 191 xputchar('\n'); 192 autoboot = 0; 193 c = 0; 194 DPRINTF("cmd is '%s'\n", cmd); 195 if (parse()) 196 xputchar('\a'); 197 else 198 load(); 199 } 200} 201 202static void 203load(void) 204{ 205 Elf32_Ehdr eh; 206 static Elf32_Phdr ep[2]; 207 caddr_t p; 208 ino_t ino; 209 uint32_t addr; 210 int i, j; 211#ifdef FIXUP_BOOT_DRV 212 caddr_t staddr; 213 int klen; 214 215 staddr = (caddr_t)0xffffffff; 216 klen = 0; 217#endif 218 if (!(ino = lookup(kname))) { 219 if (!ls) 220 printf("No %s\n", kname); 221 return; 222 } 223 DPRINTF("Found %s\n", kname); 224 if (xfsread(ino, &eh, sizeof(eh))) 225 return; 226 if (!IS_ELF(eh)) { 227 printf("Invalid %s\n", "format"); 228 return; 229 } 230 fs_off = eh.e_phoff; 231 for (j = i = 0; i < eh.e_phnum && j < 2; i++) { 232 if (xfsread(ino, ep + j, sizeof(ep[0]))) 233 return; 234 if (ep[j].p_type == PT_LOAD) 235 j++; 236 } 237 for (i = 0; i < 2; i++) { 238 p = (caddr_t)(ep[i].p_paddr & 0x0fffffff); 239 fs_off = ep[i].p_offset; 240#ifdef FIXUP_BOOT_DRV 241 if (staddr == (caddr_t)0xffffffff) 242 staddr = p; 243 klen += ep[i].p_filesz; 244#endif 245 if (xfsread(ino, p, ep[i].p_filesz)) 246 return; 247 } 248 addr = eh.e_entry & 0x0fffffff; 249 DPRINTF("Entry point %x for %s\n", addr, kname); 250 clr_board(); 251#ifdef FIXUP_BOOT_DRV 252 fixup_boot_drv(staddr, klen, bootslice, bootpart); 253#endif 254 ((void(*)(int))addr)(RB_BOOTINFO /* XXX | (opts & RBX_MASK) */); 255} 256 257static int 258parse() 259{ 260 char *arg = cmd; 261 char *ep, *p; 262 int c, i; 263 264 while ((c = *arg++)) { 265 if (c == ' ' || c == '\t' || c == '\n') 266 continue; 267 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 268 ep = p; 269 if (*p) 270 *p++ = 0; 271 if (c == '-') { 272 while ((c = *arg++)) { 273 for (i = 0; c != optstr[i]; i++) 274 if (i == NOPT - 1) 275 return -1; 276 opts ^= OPT_SET(flags[i]); 277 } 278 } else { 279 arg--; 280 /* look for ad0s1a:... | ad0s1:... */ 281 if (strlen(arg) > 6 && arg[0] == 'a' && 282 arg[1] == 'd' && arg[3] == 's' && 283 (arg[5] == ':' || arg[6] == ':')) { 284 /* XXX Should also handle disk. */ 285 bootslice = arg[4] - '0'; 286 if (bootslice < 1 || bootslice > 4) 287 return (-1); 288 bootpart = 0; 289 if (arg[5] != ':') 290 bootpart = arg[5] - 'a'; 291 if (bootpart < 0 || bootpart > 7) 292 return (-1); 293 dsk_meta = 0; 294 if (arg[5] == ':') 295 arg += 6; 296 else 297 arg += 7; 298 /* look for ad0a:... */ 299 } else if (strlen(arg) > 4 && arg[0] == 'a' && 300 arg[1] == 'd' && arg[2] == '0' && arg[4] == ':') { 301 bootslice = 0; 302 bootpart = arg[3] - 'a'; 303 if (bootpart < 0 || bootpart > 7) 304 return (-1); 305 dsk_meta = 0; 306 arg += 5; 307 } 308 if ((i = ep - arg)) { 309 if ((size_t)i >= sizeof(kname)) 310 return -1; 311 memcpy(kname, arg, i + 1); 312 } 313 } 314 arg = p; 315 } 316 return 0; 317} 318 319/* 320 * dskread() will try to handle the disk layouts that are typically 321 * encountered. 322 * - raw or "Dangerously Dedicated" mode. No real slice table, just the 323 * default one that is included with bsdlabel -B. Typically this is 324 * used with ROOTDEVNAME=\"ufs:ad0a\". 325 * - slice only. Only a slice table is installed with no bsd label or 326 * bsd partition table. This is typically used with 327 * ROOTDEVNAME=\"ufs:ad0s1\". 328 * - slice + bsd label + partition table. This is typically done with 329 * with fdisk + bsdlabel and is used with ROOTDEVNAME=\"ufs:ad0s1a\". 330 */ 331static int 332dskread(void *buf, unsigned lba, unsigned nblk) 333{ 334 struct dos_partition *dp; 335 struct disklabel *d; 336 char *sec; 337 int i; 338 339 if (!dsk_meta) { 340 sec = dmadat->secbuf; 341 dsk_start = 0; 342 if (drvread(sec, DOSBBSECTOR, 1)) 343 return -1; 344 dp = (void *)(sec + DOSPARTOFF); 345 if (bootslice != 0) { 346 i = bootslice - 1; 347 if (dp[i].dp_typ != DOSPTYP_386BSD) 348 return -1; 349 } else { 350 for (i = 0; i < NDOSPART; i++) { 351 if ((dp[i].dp_typ == DOSPTYP_386BSD) && 352 (dp[i].dp_flag == 0x80)) 353 break; 354 } 355 } 356 if (i != NDOSPART) { 357 bootslice = i + 1; 358 DPRINTF("Found an active fbsd slice. (%d)\n", i + 1); 359 /* 360 * Although dp_start is aligned within the disk 361 * partition structure, DOSPARTOFF is 446, which 362 * is only word (2) aligned, not longword (4) 363 * aligned. Cope by using memcpy to fetch the 364 * start of this partition. 365 */ 366 memcpy(&dsk_start, &dp[i].dp_start, 4); 367 dsk_start = swap32(dsk_start); 368 DPRINTF("dsk_start %x\n", dsk_start); 369 if ((bootslice == 4) && (dsk_start == 0)) { 370 disk_layout = DL_RAW; 371 bootslice = 0; 372 } 373 } 374 if (drvread(sec, dsk_start + LABELSECTOR, 1)) 375 return -1; 376 d = (void *)(sec + LABELOFFSET); 377 if ((d->d_magic == DISKMAGIC && d->d_magic2 == DISKMAGIC) || 378 (swap32(d->d_magic) == DISKMAGIC && 379 swap32(d->d_magic2) == DISKMAGIC)) { 380 DPRINTF("p_size = %x\n", 381 !d->d_partitions[bootpart].p_size); 382 if (!d->d_partitions[bootpart].p_size) { 383 printf("Invalid partition\n"); 384 return -1; 385 } 386 DPRINTF("p_offset %x, RAW %x\n", 387 swap32(d->d_partitions[bootpart].p_offset), 388 swap32(d->d_partitions[RAW_PART].p_offset)); 389 dsk_start += swap32(d->d_partitions[bootpart].p_offset); 390 dsk_start -= swap32(d->d_partitions[RAW_PART].p_offset); 391 if ((disk_layout == DL_UNKNOWN) && (bootslice == 0)) 392 disk_layout = DL_RAW; 393 else if (disk_layout == DL_UNKNOWN) 394 disk_layout = DL_SLICEPART; 395 } else { 396 disk_layout = DL_SLICE; 397 DPRINTF("Invalid %s\n", "label"); 398 } 399 DPRINTF("bootslice %d, bootpart %d, dsk_start %u\n", bootslice, 400 bootpart, dsk_start); 401 dsk_meta++; 402 } 403 return drvread(buf, dsk_start + lba, nblk); 404} 405 406static int 407drvread(void *buf, unsigned lba, unsigned nblk) 408{ 409 static unsigned c = 0x2d5c7c2f; 410 411 printf("%c\b", c = c << 8 | c >> 24); 412 return (avila_read((char *)buf, lba, nblk)); 413} 414 415#ifdef FIXUP_BOOT_DRV 416/* 417 * fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel 418 * and change it to what was specified on the comandline or /boot.conf 419 * file or to what was encountered on the disk. It will try to handle 3 420 * different disk layouts, raw (dangerously dedicated), slice only and 421 * slice + partition. It will look for the following strings in the 422 * kernel, but if it is one of the first three, the string in the kernel 423 * must use the correct form to match the actual disk layout: 424 * - ufs:ad0a 425 * - ufs:ad0s1 426 * - ufs:ad0s1a 427 * - ufs:ROOTDEVNAME 428 * In the case of the first three strings, only the "a" at the end and 429 * the "1" after the "s" will be modified, if they exist. The string 430 * length will not be changed. In the case of the last string, the 431 * whole string will be built up and nul, '\0' terminated. 432 */ 433static void 434fixup_boot_drv(caddr_t addr, int klen, int bs, int bp) 435{ 436 const u_int8_t op[] = "ufs:ROOTDEVNAME"; 437 const u_int8_t op2[] = "ufs:ad0"; 438 u_int8_t *p, *ps; 439 440 DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n", 441 (int)addr, klen, bs, bp); 442 if (bs > 4) 443 return; 444 if (bp > 7) 445 return; 446 ps = memmem(addr, klen, op, sizeof(op)); 447 if (ps != NULL) { 448 p = ps + 4; /* past ufs: */ 449 DPRINTF("Found it at 0x%x\n", (int)ps); 450 p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */ 451 p += 3; 452 if (bs > 0) { 453 /* append slice */ 454 *p++ = 's'; 455 *p++ = bs + '0'; 456 } 457 if (disk_layout != DL_SLICE) { 458 /* append partition */ 459 *p++ = bp + 'a'; 460 } 461 *p = '\0'; 462 } else { 463 ps = memmem(addr, klen, op2, sizeof(op2) - 1); 464 if (ps != NULL) { 465 p = ps + sizeof(op2) - 1; 466 DPRINTF("Found it at 0x%x\n", (int)ps); 467 if (*p == 's') { 468 /* fix slice */ 469 p++; 470 *p++ = bs + '0'; 471 } 472 if (*p == 'a') 473 *p = bp + 'a'; 474 } 475 } 476 if (ps == NULL) { 477 printf("Could not locate \"%s\" to fix kernel boot device, " 478 "check ROOTDEVNAME is set\n", op); 479 return; 480 } 481 DPRINTF("Changed boot device to %s\n", ps); 482} 483#endif
|