gptboot.c (172921) | gptboot.c (172940) |
---|---|
1/*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are freely 6 * permitted provided that the above copyright notice and this 7 * paragraph and the following disclaimer are duplicated in all 8 * such forms. 9 * 10 * This software is provided "AS IS" and without any express or 11 * implied warranties, including, without limitation, the implied 12 * warranties of merchantability and fitness for a particular 13 * purpose. 14 */ 15 16#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are freely 6 * permitted provided that the above copyright notice and this 7 * paragraph and the following disclaimer are duplicated in all 8 * such forms. 9 * 10 * This software is provided "AS IS" and without any express or 11 * implied warranties, including, without limitation, the implied 12 * warranties of merchantability and fitness for a particular 13 * purpose. 14 */ 15 16#include <sys/cdefs.h> |
17__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 172921 2007-10-24 04:03:25Z jhb $"); | 17__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 172940 2007-10-24 21:33:00Z jhb $"); |
18 19#include <sys/param.h> | 18 19#include <sys/param.h> |
20#include <sys/disklabel.h> 21#include <sys/diskmbr.h> | 20#include <sys/gpt.h> |
22#include <sys/dirent.h> 23#include <sys/reboot.h> 24 25#include <machine/bootinfo.h> 26#include <machine/elf.h> 27 28#include <stdarg.h> 29 30#include <a.out.h> 31 32#include <btxv86.h> 33 | 21#include <sys/dirent.h> 22#include <sys/reboot.h> 23 24#include <machine/bootinfo.h> 25#include <machine/elf.h> 26 27#include <stdarg.h> 28 29#include <a.out.h> 30 31#include <btxv86.h> 32 |
34#include "boot2.h" | |
35#include "lib.h" 36 37#define IO_KEYBOARD 1 38#define IO_SERIAL 2 39 40#define SECOND 18 /* Circa that many ticks in a second. */ 41 42#define RBX_ASKNAME 0x0 /* -a */ --- 51 unchanged lines hidden (view full) --- 94#define TYPE_MAXHARD TYPE_DA 95#define TYPE_FD 2 96 97#define OPT_SET(opt) (1 << (opt)) 98#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 99 100extern uint32_t _end; 101 | 33#include "lib.h" 34 35#define IO_KEYBOARD 1 36#define IO_SERIAL 2 37 38#define SECOND 18 /* Circa that many ticks in a second. */ 39 40#define RBX_ASKNAME 0x0 /* -a */ --- 51 unchanged lines hidden (view full) --- 92#define TYPE_MAXHARD TYPE_DA 93#define TYPE_FD 2 94 95#define OPT_SET(opt) (1 << (opt)) 96#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 97 98extern uint32_t _end; 99 |
100static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; |
|
102static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 103static const unsigned char flags[NOPT] = { 104 RBX_DUAL, 105 RBX_SERIAL, 106 RBX_ASKNAME, 107 RBX_CDROM, 108 RBX_CONFIG, 109 RBX_KDB, --- 9 unchanged lines hidden (view full) --- 119 120static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 121static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 122 123static struct dsk { 124 unsigned drive; 125 unsigned type; 126 unsigned unit; | 101static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 102static const unsigned char flags[NOPT] = { 103 RBX_DUAL, 104 RBX_SERIAL, 105 RBX_ASKNAME, 106 RBX_CDROM, 107 RBX_CONFIG, 108 RBX_KDB, --- 9 unchanged lines hidden (view full) --- 118 119static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 120static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 121 122static struct dsk { 123 unsigned drive; 124 unsigned type; 125 unsigned unit; |
127 unsigned slice; 128 unsigned part; 129 unsigned start; | 126 int part; 127 daddr_t start; |
130 int init; 131} dsk; 132static char cmd[512]; 133static char kname[1024]; 134static uint32_t opts; 135static int comspeed = SIOSPD; 136static struct bootinfo bootinfo; 137static uint8_t ioctrl = IO_KEYBOARD; 138 139void exit(int); | 128 int init; 129} dsk; 130static char cmd[512]; 131static char kname[1024]; 132static uint32_t opts; 133static int comspeed = SIOSPD; 134static struct bootinfo bootinfo; 135static uint8_t ioctrl = IO_KEYBOARD; 136 137void exit(int); |
138static int bcmp(const void *, const void *, size_t); |
|
140static void load(void); 141static int parse(void); 142static int xfsread(ino_t, void *, size_t); | 139static void load(void); 140static int parse(void); 141static int xfsread(ino_t, void *, size_t); |
143static int dskread(void *, unsigned, unsigned); | 142static int dskread(void *, daddr_t, unsigned); |
144static void printf(const char *,...); 145static void putchar(int); | 143static void printf(const char *,...); 144static void putchar(int); |
145static void memcpy(void *, const void *, int); |
|
146static uint32_t memsize(void); | 146static uint32_t memsize(void); |
147static int drvread(void *, unsigned, unsigned); | 147static int drvread(void *, daddr_t, unsigned); |
148static int keyhit(unsigned); 149static int xputc(int); 150static int xgetc(int); 151static int getc(int); 152 | 148static int keyhit(unsigned); 149static int xputc(int); 150static int xgetc(int); 151static int getc(int); 152 |
153static void memcpy(void *, const void *, int); | |
154static void 155memcpy(void *dst, const void *src, int len) 156{ 157 const char *s = src; 158 char *d = dst; 159 160 while (len--) 161 *d++ = *s++; 162} 163 164static inline int 165strcmp(const char *s1, const char *s2) 166{ 167 for (; *s1 == *s2 && *s1; s1++, s2++); 168 return (unsigned char)*s1 - (unsigned char)*s2; 169} 170 | 153static void 154memcpy(void *dst, const void *src, int len) 155{ 156 const char *s = src; 157 char *d = dst; 158 159 while (len--) 160 *d++ = *s++; 161} 162 163static inline int 164strcmp(const char *s1, const char *s2) 165{ 166 for (; *s1 == *s2 && *s1; s1++, s2++); 167 return (unsigned char)*s1 - (unsigned char)*s2; 168} 169 |
170#define GPTBOOT |
|
171#include "ufsread.c" 172 173static inline int 174xfsread(ino_t inode, void *buf, size_t nbyte) 175{ 176 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 177 printf("Invalid %s\n", "format"); 178 return -1; --- 55 unchanged lines hidden (view full) --- 234 int autoboot; 235 ino_t ino; 236 237 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 238 v86.ctl = V86_FLAGS; 239 dsk.drive = *(uint8_t *)PTOV(ARGS); 240 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 241 dsk.unit = dsk.drive & DRV_MASK; | 171#include "ufsread.c" 172 173static inline int 174xfsread(ino_t inode, void *buf, size_t nbyte) 175{ 176 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 177 printf("Invalid %s\n", "format"); 178 return -1; --- 55 unchanged lines hidden (view full) --- 234 int autoboot; 235 ino_t ino; 236 237 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 238 v86.ctl = V86_FLAGS; 239 dsk.drive = *(uint8_t *)PTOV(ARGS); 240 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 241 dsk.unit = dsk.drive & DRV_MASK; |
242 dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; | 242 dsk.part = -1; |
243 bootinfo.bi_version = BOOTINFO_VERSION; 244 bootinfo.bi_size = sizeof(bootinfo); 245 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 246 bootinfo.bi_extmem = memsize(); 247 bootinfo.bi_memsizes_valid++; 248 249 /* Process configuration file */ 250 --- 24 unchanged lines hidden (view full) --- 275 } 276 } 277 278 /* Present the user with the boot2 prompt. */ 279 280 for (;;) { 281 if (!autoboot || !OPT_CHECK(RBX_QUIET)) 282 printf("\nFreeBSD/i386 boot\n" | 243 bootinfo.bi_version = BOOTINFO_VERSION; 244 bootinfo.bi_size = sizeof(bootinfo); 245 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 246 bootinfo.bi_extmem = memsize(); 247 bootinfo.bi_memsizes_valid++; 248 249 /* Process configuration file */ 250 --- 24 unchanged lines hidden (view full) --- 275 } 276 } 277 278 /* Present the user with the boot2 prompt. */ 279 280 for (;;) { 281 if (!autoboot || !OPT_CHECK(RBX_QUIET)) 282 printf("\nFreeBSD/i386 boot\n" |
283 "Default: %u:%s(%u,%c)%s\n" | 283 "Default: %u:%s(%up%u)%s\n" |
284 "boot: ", 285 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, | 284 "boot: ", 285 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, |
286 'a' + dsk.part, kname); | 286 dsk.part, kname); |
287 if (ioctrl & IO_SERIAL) 288 sio_flush(); 289 if (!autoboot || keyhit(5*SECOND)) 290 getstr(); 291 else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 292 putchar('\n'); 293 autoboot = 0; 294 if (parse()) --- 95 unchanged lines hidden (view full) --- 390 } 391 } 392 addr = hdr.eh.e_entry & 0xffffff; 393 } 394 bootinfo.bi_esymtab = VTOP(p); 395 bootinfo.bi_kernelname = VTOP(kname); 396 bootinfo.bi_bios_dev = dsk.drive; 397 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), | 287 if (ioctrl & IO_SERIAL) 288 sio_flush(); 289 if (!autoboot || keyhit(5*SECOND)) 290 getstr(); 291 else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 292 putchar('\n'); 293 autoboot = 0; 294 if (parse()) --- 95 unchanged lines hidden (view full) --- 390 } 391 } 392 addr = hdr.eh.e_entry & 0xffffff; 393 } 394 bootinfo.bi_esymtab = VTOP(p); 395 bootinfo.bi_kernelname = VTOP(kname); 396 bootinfo.bi_bios_dev = dsk.drive; 397 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), |
398 MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), | 398 MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), |
399 0, 0, 0, VTOP(&bootinfo)); 400} 401 402static int | 399 0, 0, 0, VTOP(&bootinfo)); 400} 401 402static int |
403parse() | 403parse(void) |
404{ 405 char *arg = cmd; 406 char *ep, *p, *q; 407 const char *cp; 408 unsigned int drv; 409 int c, i, j; 410 411 while ((c = *arg++)) { --- 50 unchanged lines hidden (view full) --- 462 if (i == NDEV - 1) 463 return -1; 464 dsk.type = i; 465 arg += 3; 466 dsk.unit = *arg - '0'; 467 if (arg[1] != ',' || dsk.unit > 9) 468 return -1; 469 arg += 2; | 404{ 405 char *arg = cmd; 406 char *ep, *p, *q; 407 const char *cp; 408 unsigned int drv; 409 int c, i, j; 410 411 while ((c = *arg++)) { --- 50 unchanged lines hidden (view full) --- 462 if (i == NDEV - 1) 463 return -1; 464 dsk.type = i; 465 arg += 3; 466 dsk.unit = *arg - '0'; 467 if (arg[1] != ',' || dsk.unit > 9) 468 return -1; 469 arg += 2; |
470 dsk.slice = WHOLE_DISK_SLICE; | 470 dsk.part = -1; |
471 if (arg[1] == ',') { | 471 if (arg[1] == ',') { |
472 dsk.slice = *arg - '0' + 1; 473 if (dsk.slice > NDOSPART) | 472 dsk.part = *arg - '0'; 473 if (dsk.part < 1 || dsk.part > 9) |
474 return -1; 475 arg += 2; 476 } | 474 return -1; 475 arg += 2; 476 } |
477 if (arg[1] != ')') | 477 if (arg[0] != ')') |
478 return -1; | 478 return -1; |
479 dsk.part = *arg - 'a'; 480 if (dsk.part > 7) 481 return (-1); 482 arg += 2; | 479 arg++; |
483 if (drv == -1) 484 drv = dsk.unit; 485 dsk.drive = (dsk.type <= TYPE_MAXHARD 486 ? DRV_HARD : 0) + drv; 487 dsk_meta = 0; 488 } 489 if ((i = ep - arg)) { 490 if ((size_t)i >= sizeof(kname)) 491 return -1; 492 memcpy(kname, arg, i + 1); 493 } 494 } 495 arg = p; 496 } 497 return 0; 498} 499 500static int | 480 if (drv == -1) 481 drv = dsk.unit; 482 dsk.drive = (dsk.type <= TYPE_MAXHARD 483 ? DRV_HARD : 0) + drv; 484 dsk_meta = 0; 485 } 486 if ((i = ep - arg)) { 487 if ((size_t)i >= sizeof(kname)) 488 return -1; 489 memcpy(kname, arg, i + 1); 490 } 491 } 492 arg = p; 493 } 494 return 0; 495} 496 497static int |
501dskread(void *buf, unsigned lba, unsigned nblk) | 498dskread(void *buf, daddr_t lba, unsigned nblk) |
502{ | 499{ |
503 struct dos_partition *dp; 504 struct disklabel *d; | 500 struct gpt_hdr hdr; 501 struct gpt_ent *ent; |
505 char *sec; | 502 char *sec; |
506 unsigned sl, i; | 503 daddr_t slba, elba; 504 int part, entries_per_sec; |
507 508 if (!dsk_meta) { | 505 506 if (!dsk_meta) { |
507 /* Read and verify GPT. */ |
|
509 sec = dmadat->secbuf; 510 dsk.start = 0; | 508 sec = dmadat->secbuf; 509 dsk.start = 0; |
511 if (drvread(sec, DOSBBSECTOR, 1)) | 510 if (drvread(sec, 1, 1)) |
512 return -1; | 511 return -1; |
513 dp = (void *)(sec + DOSPARTOFF); 514 sl = dsk.slice; 515 if (sl < BASE_SLICE) { 516 for (i = 0; i < NDOSPART; i++) 517 if (dp[i].dp_typ == DOSPTYP_386BSD && 518 (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 519 sl = BASE_SLICE + i; 520 if (dp[i].dp_flag & 0x80 || 521 dsk.slice == COMPATIBILITY_SLICE) | 512 memcpy(&hdr, sec, sizeof(hdr)); 513 if (bcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || 514 hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || 515 hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { 516 printf("Invalid GPT header\n"); 517 return -1; 518 } 519 520 /* XXX: CRC check? */ 521 522 /* 523 * If the partition isn't specified, then search for the first UFS 524 * partition and hope it is /. Perhaps we should be using an OS 525 * flag in the GPT entry to mark / partitions. 526 * 527 * If the partition is specified, then figure out the LBA for the 528 * sector containing that partition index and load it. 529 */ 530 entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; 531 if (dsk.part == -1) { 532 slba = hdr.hdr_lba_table; 533 elba = slba + hdr.hdr_entries / entries_per_sec; 534 while (slba < elba && dsk.part == -1) { 535 if (drvread(sec, slba, 1)) 536 return -1; 537 for (part = 0; part < entries_per_sec; part++) { 538 ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); 539 if (bcmp(&ent->ent_type, &freebsd_ufs_uuid, 540 sizeof(uuid_t)) == 0) { 541 dsk.part = (slba - hdr.hdr_lba_table) * 542 entries_per_sec + part + 1; 543 dsk.start = ent->ent_lba_start; |
522 break; | 544 break; |
545 } |
|
523 } | 546 } |
524 if (dsk.slice == WHOLE_DISK_SLICE) 525 dsk.slice = sl; 526 } 527 if (sl != WHOLE_DISK_SLICE) { 528 if (sl != COMPATIBILITY_SLICE) 529 dp += sl - BASE_SLICE; 530 if (dp->dp_typ != DOSPTYP_386BSD) { 531 printf("Invalid %s\n", "slice"); 532 return -1; | 547 slba++; |
533 } | 548 } |
534 dsk.start = dp->dp_start; 535 } 536 if (drvread(sec, dsk.start + LABELSECTOR, 1)) | 549 if (dsk.part == -1) { 550 printf("No UFS partition was found\n"); |
537 return -1; | 551 return -1; |
538 d = (void *)(sec + LABELOFFSET); 539 if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 540 if (dsk.part != RAW_PART) { 541 printf("Invalid %s\n", "label"); 542 return -1; | |
543 } 544 } else { | 552 } 553 } else { |
545 if (!dsk.init) { 546 if (d->d_type == DTYPE_SCSI) 547 dsk.type = TYPE_DA; 548 dsk.init++; | 554 if (dsk.part > hdr.hdr_entries) { 555 printf("Invalid partition index\n"); 556 return -1; |
549 } | 557 } |
550 if (dsk.part >= d->d_npartitions || 551 !d->d_partitions[dsk.part].p_size) { 552 printf("Invalid %s\n", "partition"); | 558 slba = hdr.hdr_lba_table + (dsk.part - 1) / entries_per_sec; 559 if (drvread(sec, slba, 1)) |
553 return -1; | 560 return -1; |
561 part = (dsk.part - 1) % entries_per_sec; 562 ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); 563 if (bcmp(&ent->ent_type, &freebsd_ufs_uuid, sizeof(uuid_t)) != 0) { 564 printf("Specified partition is not UFS\n"); 565 return -1; |
|
554 } | 566 } |
555 dsk.start += d->d_partitions[dsk.part].p_offset; 556 dsk.start -= d->d_partitions[RAW_PART].p_offset; | 567 dsk.start = ent->ent_lba_start; |
557 } | 568 } |
569 /* 570 * XXX: No way to detect SCSI vs. ATA currently. 571 */ 572#if 0 573 if (!dsk.init) { 574 if (d->d_type == DTYPE_SCSI) 575 dsk.type = TYPE_DA; 576 dsk.init++; 577 } 578#endif |
|
558 } 559 return drvread(buf, dsk.start + lba, nblk); 560} 561 562static void 563printf(const char *fmt,...) 564{ 565 va_list ap; --- 35 unchanged lines hidden (view full) --- 601putchar(int c) 602{ 603 if (c == '\n') 604 xputc('\r'); 605 xputc(c); 606} 607 608static int | 579 } 580 return drvread(buf, dsk.start + lba, nblk); 581} 582 583static void 584printf(const char *fmt,...) 585{ 586 va_list ap; --- 35 unchanged lines hidden (view full) --- 622putchar(int c) 623{ 624 if (c == '\n') 625 xputc('\r'); 626 xputc(c); 627} 628 629static int |
609drvread(void *buf, unsigned lba, unsigned nblk) | 630bcmp(const void *b1, const void *b2, size_t length) |
610{ | 631{ |
632 const char *p1 = b1, *p2 = b2; 633 634 if (length == 0) 635 return (0); 636 do { 637 if (*p1++ != *p2++) 638 break; 639 } while (--length); 640 return (length); 641} 642 643static struct { 644 uint16_t len; 645 uint16_t count; 646 uint16_t seg; 647 uint16_t off; 648 uint64_t lba; 649} packet; 650 651static int 652drvread(void *buf, daddr_t lba, unsigned nblk) 653{ |
|
611 static unsigned c = 0x2d5c7c2f; 612 613 if (!OPT_CHECK(RBX_QUIET)) 614 printf("%c\b", c = c << 8 | c >> 24); | 654 static unsigned c = 0x2d5c7c2f; 655 656 if (!OPT_CHECK(RBX_QUIET)) 657 printf("%c\b", c = c << 8 | c >> 24); |
615 v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 616 v86.addr = XREADORG; /* call to xread in boot1 */ 617 v86.es = VTOPSEG(buf); 618 v86.eax = lba; 619 v86.ebx = VTOPOFF(buf); 620 v86.ecx = lba >> 16; 621 v86.edx = nblk << 8 | dsk.drive; 622 v86int(); | 658 packet.len = 0x10; 659 packet.count = nblk; 660 packet.seg = VTOPOFF(buf); 661 packet.off = VTOPSEG(buf); 662 packet.lba = lba; |
623 v86.ctl = V86_FLAGS; | 663 v86.ctl = V86_FLAGS; |
664 v86.addr = 0x13; 665 v86.eax = 0x4200; 666 v86.edx = dsk.drive; 667 v86.ds = VTOPSEG(&packet); 668 v86.esi = VTOPOFF(&packet); 669 v86int(); |
|
624 if (V86_CY(v86.efl)) { 625 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 626 return -1; 627 } 628 return 0; 629} 630 631static int --- 51 unchanged lines hidden --- | 670 if (V86_CY(v86.efl)) { 671 printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 672 return -1; 673 } 674 return 0; 675} 676 677static int --- 51 unchanged lines hidden --- |