# $Id: gptboot.patch,v 1.2 2009/08/16 12:21:08 bubuchka Exp $ # gptboot-200908160843Z.patch Index: usr.sbin/installboot/arch/i386.c =================================================================== RCS file: /cvsroot/src/usr.sbin/installboot/arch/i386.c,v retrieving revision 1.33 diff -u -r1.33 i386.c --- usr.sbin/installboot/arch/i386.c 7 May 2009 07:03:39 -0000 1.33 +++ usr.sbin/installboot/arch/i386.c 16 Aug 2009 08:29:07 -0000 @@ -41,6 +41,8 @@ #include #ifndef HAVE_NBTOOL_CONFIG_H #include +#include +#include #include #endif @@ -286,6 +288,66 @@ } static int +update_i386_fatboot_params(ib_params *params, struct x86_fatboot_params *bpp) +{ + struct x86_fatboot_params bp; + struct dkwedge_info dkw; + struct disklabel dl; + uint32_t bplen; + int p; + + bplen = le32toh(bpp->bp_length); + if (bplen > sizeof bp) + /* Ignore pad space in bootxx */ + bplen = sizeof bp; + + /* Take (and update) local copy so we handle size mismatches */ + memset(&bp, 0, sizeof bp); + memcpy(&bp, bpp, bplen); + + if (bplen == sizeof(bpp->bp_length)) + /* no parametres - old fatboot */ + return 0; + + if (ioctl(params->fsfd, DIOCGWEDGEINFO, &dkw) != -1) { + if (memcmp(dkw.dkw_ptype, DKW_PTYPE_FAT, + sizeof(DKW_PTYPE_FAT))) + warnx("%s: partition type is not 'msdos', " + "installing anyway", + params->filesystem); + bp.bp_poffset = dkw.dkw_offset; + } else if (ioctl(params->fsfd, DIOCGDINFO, &dl) != -1) { + p = params->filesystem[strlen(params->filesystem) - 1] - 'a'; + if (p < 0 || p >= dl.d_npartitions) { + warnx("%s: bad partition", params->filesystem); + return EINVAL; + } + if (dl.d_partitions[p].p_fstype != FS_MSDOS) + warnx("%s: partition type is not 'msdos', " + "installing anyway", + params->filesystem); + bp.bp_poffset = dl.d_partitions[p].p_offset; + } else { + warnx("%s: unable to get disk partitioning\n", + params->filesystem); + bp.bp_poffset = 0; + } + + /* too few parametres - print them from here */ + printf("Boot options: "); + printf("poffset %"PRIu64"\n", bp.bp_poffset); + + /* Check we aren't trying to set anything we can't save */ + if (!is_zero((char *)&bp + bplen, sizeof bp - bplen)) { + warnx("Patch area in stage1 bootstrap is too small"); + return 1; + } + + memcpy(bpp, &bp, bplen); + return 0; +} + +static int i386_setboot(ib_params *params) { unsigned int u; @@ -356,8 +418,11 @@ */ if (params->s1stat.st_size == 512) { /* Magic number is at end of pbr code */ - magic = (void *)(bootstrap.b + 512 - 16 + 4); + magic = (void *)(bootstrap.b + 512 - 24 + 4); expected_magic = htole32(X86_BOOT_MAGIC_FAT); + if (*magic != expected_magic) + /* try old location */ + magic = (void *)(bootstrap.b + 512 - 16 + 4); } else { /* Magic number is at start of sector following label */ magic = (void *)(bootstrap.b + 512 * 2 + 4); @@ -448,8 +513,13 @@ * that follows the magic number. * See sys/arch/i386/stand/bootxx/bootxx.S for more information. */ - if (update_i386_boot_params(params, (void *)(magic + 1))) - return 0; + if (*magic == htole32(X86_BOOT_MAGIC_FAT)) { + if (update_i386_fatboot_params(params, (void *)(magic + 1))) + return 0; + } else { + if (update_i386_boot_params(params, (void *)(magic + 1))) + return 0; + } if (params->flags & IB_NOWRITE) { return 1; Index: sbin/gpt/Makefile =================================================================== RCS file: /cvsroot/src/sbin/gpt/Makefile,v retrieving revision 1.3 diff -u -r1.3 Makefile --- sbin/gpt/Makefile 11 Apr 2009 07:58:12 -0000 1.3 +++ sbin/gpt/Makefile 16 Aug 2009 08:30:12 -0000 @@ -2,8 +2,8 @@ # $FreeBSD: src/sbin/gpt/Makefile,v 1.7 2005/09/01 02:49:20 marcel Exp $ PROG= gpt -SRCS= add.c create.c destroy.c gpt.c label.c map.c migrate.c recover.c \ - remove.c show.c +SRCS= add.c biosboot.c create.c destroy.c gpt.c label.c map.c migrate.c \ + recover.c remove.c show.c MAN= gpt.8 LDADD+= -lprop -lutil Index: sbin/gpt/gpt.c =================================================================== RCS file: /cvsroot/src/sbin/gpt/gpt.c,v retrieving revision 1.9 diff -u -r1.9 gpt.c --- sbin/gpt/gpt.c 7 Feb 2009 18:12:22 -0000 1.9 +++ sbin/gpt/gpt.c 16 Aug 2009 08:31:39 -0000 @@ -748,6 +748,7 @@ const char *name; } cmdsw[] = { { cmd_add, "add" }, + { cmd_biosboot, "biosboot" }, { cmd_create, "create" }, { cmd_destroy, "destroy" }, { NULL, "help" }, @@ -764,7 +765,7 @@ static void usage(void) { - extern const char addmsg[], createmsg[], destroymsg[]; + extern const char addmsg[], biosbootmsg[], createmsg[], destroymsg[]; extern const char labelmsg1[], labelmsg2[], labelmsg3[]; extern const char migratemsg[], recovermsg[], removemsg1[]; extern const char removemsg2[], showmsg[]; @@ -775,6 +776,7 @@ " %s %s\n" " %s %s\n" " %s %s\n" + " %s %s\n" " %*s %s\n" " %s %s\n" " %s %s\n" @@ -782,6 +784,7 @@ " %s %s\n" " %s %s\n", getprogname(), addmsg, + getprogname(), biosbootmsg, getprogname(), createmsg, getprogname(), destroymsg, getprogname(), labelmsg1, Index: sbin/gpt/gpt.h =================================================================== RCS file: /cvsroot/src/sbin/gpt/gpt.h,v retrieving revision 1.4 diff -u -r1.4 gpt.h --- sbin/gpt/gpt.h 7 Feb 2009 18:12:22 -0000 1.4 +++ sbin/gpt/gpt.h 16 Aug 2009 08:31:39 -0000 @@ -67,7 +67,10 @@ }; struct mbr { - uint16_t mbr_code[223]; + uint8_t mbr_code[424]; + uuid_t mbr_uuid; + uint16_t mbr_dsn[2]; + uint16_t mbr_bs_magic; struct mbr_part mbr_part[4]; uint16_t mbr_sig; #define MBR_SIG 0xAA55 @@ -90,6 +93,7 @@ void utf8_to_utf16(const uint8_t *, uint16_t *, size_t); int cmd_add(int, char *[]); +int cmd_biosboot(int, char *[]); int cmd_create(int, char *[]); int cmd_destroy(int, char *[]); int cmd_label(int, char *[]); Index: sys/sys/bootblock.h =================================================================== RCS file: /cvsroot/src/sys/sys/bootblock.h,v retrieving revision 1.46 diff -u -r1.46 bootblock.h --- sys/sys/bootblock.h 1 Apr 2009 10:17:04 -0000 1.46 +++ sys/sys/bootblock.h 16 Aug 2009 08:32:41 -0000 @@ -168,6 +168,8 @@ * * 400 - 439 MP NetBSD: mbr_bootsel * + * 424 - 439 M NetBSD: bootptn_guid (GPT LBA0) + * * 440 - 443 M WinNT/2K/XP Drive Serial Number (NT DSN) * http://www.geocities.com/thestarman3/asm/mbr/Win2kmbr.htm * @@ -194,11 +196,13 @@ #define MBR_BOOTCODE_OFFSET 90 /* offsetof(mbr_sector, mbr_bootcode) */ #define MBR_BS_OFFSET 400 /* offsetof(mbr_sector, mbr_bootsel) */ #define MBR_BS_OLD_OFFSET 404 /* where mbr_bootsel used to be */ +#define MBR_GUID_OFFSET 424 /* location of alterable GUID to boot */ #define MBR_DSN_OFFSET 440 /* offsetof(mbr_sector, mbr_dsn) */ #define MBR_BS_MAGIC_OFFSET 444 /* offsetof(mbr_sector, mbr_bootsel_magic) */ #define MBR_PART_OFFSET 446 /* offsetof(mbr_sector, mbr_part[0]) */ #define MBR_MAGIC_OFFSET 510 /* offsetof(mbr_sector, mbr_magic) */ #define MBR_MAGIC 0xaa55 /* MBR magic number */ +#define MBR_PARAMS_MAGIC 0x0805 /* MBR parametres passed sign */ #define MBR_BS_MAGIC 0xb5e1 /* mbr_bootsel magic number */ #define MBR_PART_COUNT 4 /* Number of partitions in MBR */ #define MBR_BS_PARTNAMESIZE 8 /* Size of name mbr_bootsel nametab */ @@ -1057,6 +1061,11 @@ uint32_t bp_consaddr; /* ioaddr for console */ }; +struct x86_fatboot_params { + uint32_t bp_length; /* length of patchable data */ + uint64_t bp_poffset; /* partition offset */ +}; + #endif /* !defined(__ASSEMBLER__) */ /* } */ #define X86_BOOT_MAGIC(n) ('x' << 24 | 0x86b << 12 | 'm' << 4 | (n)) @@ -1065,6 +1074,9 @@ #define X86_BOOT_MAGIC_PXE X86_BOOT_MAGIC(3) /* start_pxe.S */ #define X86_BOOT_MAGIC_FAT X86_BOOT_MAGIC(4) /* fatboot.S */ + /* LBA passed from parent loader is 64-bit wide */ +#define X86_BOOT_MAGIC_64_FLAG (1 << 32) + /* values for bp_flags */ #define X86_BP_FLAGS_RESET_VIDEO 1 #define X86_BP_FLAGS_PASSWORD 2 Index: sys/arch/i386/stand/boot/version =================================================================== RCS file: /cvsroot/src/sys/arch/i386/stand/boot/version,v retrieving revision 1.9 diff -u -r1.9 version --- sys/arch/i386/stand/boot/version 19 Nov 2008 12:36:41 -0000 1.9 +++ sys/arch/i386/stand/boot/version 16 Aug 2009 08:58:27 -0000 @@ -40,3 +40,4 @@ 5.1: Change boot messages to replace build date with kernel version. 5.2: Support for multiboot. 5.3: Autoload kernel module for root file system. +5.4: GUID Partition Table support. Index: sys/arch/i386/stand/fatboot/fatboot.S =================================================================== RCS file: /cvsroot/src/sys/arch/i386/stand/fatboot/fatboot.S,v retrieving revision 1.3 diff -u -r1.3 fatboot.S --- sys/arch/i386/stand/fatboot/fatboot.S 29 Apr 2008 06:53:02 -0000 1.3 +++ sys/arch/i386/stand/fatboot/fatboot.S 16 Aug 2009 08:58:27 -0000 @@ -104,13 +104,18 @@ . = start + PBR_AFTERBPB /* skip BPB */ start0: - xor %eax, %eax /* don't trust values of ds, es or ss */ + cmp $MBR_PARAMS_MAGIC, %ax /* check is we have input params */ + je 1f /* ptn offset is expected in ecx:ebx */ + movl lba_self, %ebx /* otherwise use installboot values */ + movl lba_self + 4, %ecx +1: xor %eax, %eax /* don't trust values of ds, es or ss */ mov %ax, %ds mov %ax, %es mov %ax, %ss mov $start, %sp mov %sp, %bp /* to access the pbp */ push %dx /* save drive at -2(%bp) */ + push %ebx /* save lower part of LBA for exit */ set_err(ERR_NOT_FAT16) cmpl $'A'|'T'<<8|'1'<<16|'6'<<24, bs_file_sys_type+1(%bp) @@ -119,6 +124,7 @@ /* Add 'reserved' (inside ptn) to 'hidden' (ptn offset) */ mov bpb_res_sectors(%bp), %ax addl bpb_hidden_secs(%bp), %eax + addl %ebx, %eax /* partition offset */ mov %eax, fat_sector(%bp) /* To get first sector of FAT */ /* Determine base of root directory */ @@ -127,11 +133,10 @@ shl $16,%edx xchg %ax,%dx /* FAT size now in %edx */ addl fat_sector(%bp), %edx /* Directory is after FATs */ - push %cs /* %cs is zero */ - push %cs /* 64-bit for LBA read */ - pushl %edx /* Sector number of root dir */ + pushl %ecx /* LBA of root dir */ + pushl %edx - push $0x1000 /* Read to 0x10000:0 */ + push $0x1000 /* Read to 0x1000:0 */ pop %es /* Which we need in %es later */ push %es push %cs /* Offset zero */ @@ -206,7 +211,7 @@ pushl %edx /* Sector to read */ sub %eax, %edx /* Recover base segment */ push %di /* Target address segment! */ - push $0 + push %cs /* 0x0000 */ push sec_p_cl_w(%bp) call read_lba /* Read a cluster */ @@ -252,15 +257,6 @@ set_err(ERR_NO_BOOT_MAGIC_2) err1: jmp error -/* Set parameters expected by /boot */ -magic_ok: - mov bpb_hidden_secs(%bp), %ebx /* ptn base sector */ - movb -2(%bp), %dl /* disk number (could pop %dx) */ - mov $boot_params + 4, %si - push %es - push $0 - lret - /* Read disk using on-stack int13-extension parameter block */ read_lba: pop %ax /* Save rtn addr */ @@ -277,6 +273,21 @@ jc err1 ret $12 /* Discard all except high LBA zeros */ +/* Set parameters expected by /boot and jump into it */ +magic_ok: + andb $0x80, %es:(4+3) /* set X86_BOOT_MAGIC_64_FLAG */ + pop %ecx /* partition LBA at %ecx:%ebx */ + pop %ebx +#if 0 /* XXX do we really need to pass this? */ + add bpb_hidden_secs(%bp), %ebx /* ptn base sector */ +#endif + pop %dx /* disk number */ + mov $boot_params + 4, %si + + push %es + push %cs /* 0x0000 */ + lret + /* * I hate #including source files, but pbr_magic below has to be at * the correct absolute address. @@ -312,12 +323,15 @@ * use any of our valuable bytes. */ - . = _C_LABEL(start) + 0x1fe - 2 - 4 - 4 + . = _C_LABEL(start) + MBR_MAGIC_OFFSET - 2 - 8 - 4 - 4 boot_params: .long X86_BOOT_MAGIC_FAT .long 1f - . +lba_self: + .long 0 + .long 0 1: -fat_cache: .word 0xffff /* Sector number in buffer */ - . = _C_LABEL(start) + 0x1fe - .word 0xaa55 +fat_cache: .word 0xffff /* Sector number in buffer */ + . = _C_LABEL(start) + MBR_MAGIC_OFFSET + .word MBR_MAGIC fat_buffer: /* 2 sectors worth of FAT table */ Index: sys/arch/i386/stand/lib/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/i386/stand/lib/Makefile,v retrieving revision 1.28 diff -u -r1.28 Makefile --- sys/arch/i386/stand/lib/Makefile 30 Mar 2009 09:22:52 -0000 1.28 +++ sys/arch/i386/stand/lib/Makefile 16 Aug 2009 08:58:27 -0000 @@ -14,6 +14,7 @@ CPPFLAGS= -I$S/lib/libsa ${I386CPPFLAGS} ${I386MISCCPPFLAGS} #CPPFLAGS+= -DDISK_DEBUG #CPPFLAGS+= -DNO_DISKLABEL +#CPPFLAGS+= -DNO_GPT #CPPFLAGS+= -DSAVE_MEMORY SRCS= pcio.c conio.S comio.S comio_direct.c biosvideomode.S Index: sys/arch/i386/stand/lib/biosdisk.c =================================================================== RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosdisk.c,v retrieving revision 1.28 diff -u -r1.28 biosdisk.c --- sys/arch/i386/stand/lib/biosdisk.c 5 Jan 2008 15:28:43 -0000 1.28 +++ sys/arch/i386/stand/lib/biosdisk.c 16 Aug 2009 08:58:27 -0000 @@ -65,8 +65,10 @@ #include #include +#include #include #include +#include #include @@ -81,7 +83,24 @@ #include "bootinfo.h" #endif +#ifndef NO_GPT +#define MAX_GPT_HDR_ENTRIES 128 /* XXX 128 ptns is VERY common case */ +struct gpt { + struct gpt_hdr hdr; + struct gpt_ent pea[MAX_GPT_HDR_ENTRIES]; +#define SIZEOF_GPT_PEA(gp) ((gp)->hdr.hdr_entries * (gp)->hdr.hdr_entsz) +}; + +#define BUFSIZE (sizeof(struct gpt)) /* must be large enough for GPT */ + +uuid_t gpt_ent_type_unused = GPT_ENT_TYPE_UNUSED; +uuid_t gpt_ent_type_netbsd_raidframe = GPT_ENT_TYPE_NETBSD_RAIDFRAME; + +/* XXX where to find the crc32 header file? */ +extern uint32_t crc32(uint32_t, const uint8_t *, size_t); +#else #define BUFSIZE 2048 /* must be large enough for a CD sector */ +#endif /* NO_GPT */ struct biosdisk { struct biosdisk_ll ll; @@ -157,6 +176,106 @@ return d; } +#ifndef NO_GPT +static int +read_gpt(struct biosdisk *d) +{ + int secsize, i; + uint32_t crc; + daddr_t gptsector[2]; + struct biosdisk_extinfo ed; + struct gpt *gp = (struct gpt *)d->buf; + + /* + * XXX + * the struct biosdisk_ll can be extended and filed using the logic + * below, yet the set_geometry() seem requires similar approach for + * detecting the sector size + */ + gptsector[0] = GPT_HDR_BLKNO; + if (set_geometry(&d->ll, &ed) == 0 && d->ll.flags & BIOSDISK_INT13EXT) { + gptsector[1] = ed.totsec - 1; + secsize = ed.sbytes; + } else { +#ifdef DISK_DEBUG + printf("Unable to determine extended disk geometry - " + "using CHS\n"); +#endif + /* at least try some other reasonable values then */ + gptsector[1] = d->ll.chs_sectors - 1; + secsize = d->ll.secsize; + } + + /* + * Use any valid GPT available, do not require both GPTs to be valid + */ + for (i = 0; i < 2; i++) { + (void)memset(gp, 0, sizeof(*gp)); + /* + * Read and verify GPT header + */ + if (readsects(&d->ll, gptsector[i], 1, (char *)&gp->hdr, 0)) { +#ifdef DISK_DEBUG + printf("Error reading %s GPT header\n", + (i == 0) ? "primary" : "secondary"); +#endif + continue; + } + + if (memcmp(GPT_HDR_SIG, gp->hdr.hdr_sig, + sizeof(gp->hdr.hdr_sig))) + continue; + + if (gp->hdr.hdr_lba_self != gptsector[i]) + continue; + + crc = gp->hdr.hdr_crc_self; + gp->hdr.hdr_crc_self = 0; + if (crc32(0, (const uint8_t *)&gp->hdr, GPT_HDR_SIZE) != crc) + continue; + + /* XXX boot can't support too many partitions - fix header */ + if (gp->hdr.hdr_entries > MAX_GPT_HDR_ENTRIES) { + printf("Can't support so many partitions - " + "limiting to first %d\n", MAX_GPT_HDR_ENTRIES); + gp->hdr.hdr_entries = MAX_GPT_HDR_ENTRIES; + crc = crc32(0, (const uint8_t *)&gp->hdr, GPT_HDR_SIZE); + } + + gp->hdr.hdr_crc_self = crc; + + /* + * Read and verify GPT Partitions Array + */ + if (readsects(&d->ll, gp->hdr.hdr_lba_table, + (SIZEOF_GPT_PEA(gp) + secsize - 1) / secsize, + (char *)&gp->pea, 0)) { +#ifdef DISK_DEBUG + printf("Error reading GPT%d entries array\n", i + 1); +#endif + continue; + } + + if (crc32(0, (const uint8_t *)gp->pea, SIZEOF_GPT_PEA(gp)) + != gp->hdr.hdr_crc_table) + continue; + + /* + * All checks passed - valid GPT found + */ + break; + } + + if (i >= 2) + return -1; + +#ifdef DISK_DEBUG + printf("using %s GPT\n", (i == 0) ? "primary" : "secondary"); +#endif + return 0; +} +#endif /* !NO_GPT */ + #ifndef NO_DISKLABEL static int check_label(struct biosdisk *d, int sector) @@ -299,12 +418,14 @@ int biosdisk_findpartition(int biosdev, u_int sector) { -#ifdef NO_DISKLABEL - return 0; -#else struct biosdisk *d; int partition = 0; +#ifndef NO_GPT + struct gpt_ent *ep; +#endif +#ifndef NO_DISKLABEL struct disklabel *lp; +#endif #ifdef DISK_DEBUG printf("looking for partition device %x, sector %u\n", biosdev, sector); #endif @@ -314,6 +435,22 @@ if (d == NULL) return 0; +#ifndef NO_GPT + if (read_gpt(d) == 0) { + ep = ((struct gpt *)d->buf)->pea; + for (partition = MAX_GPT_HDR_ENTRIES; --partition;) { + if (!memcmp(&ep[partition].ent_type, + &gpt_ent_type_unused, sizeof(uuid_t))) + continue; + if (ep[partition].ent_lba_start == sector) + break; + } + /* don't check disklabel if GPT found */ + goto out; + } +#endif + +#ifndef NO_DISKLABEL if (read_label(d) == 0) { lp = (struct disklabel *)(d->buf + LABELOFFSET); for (partition = lp->d_npartitions; --partition;){ @@ -323,10 +460,13 @@ break; } } +#endif +#ifndef NO_GPT +out: +#endif dealloc(d, sizeof(*d)); return partition; -#endif /* NO_DISKLABEL */ } int @@ -337,6 +477,9 @@ struct biosdisk *d; int biosdev; int partition; +#ifndef NO_GPT + struct gpt *gp; +#endif #ifndef NO_DISKLABEL struct disklabel *lp; #endif @@ -360,6 +503,54 @@ bi_wedge.matchblk = -1; #endif +#ifndef NO_GPT + error = read_gpt(d); + if (error == -1) { + error = 0; + goto nogpt; + } + if (error) + goto out; + + gp = (struct gpt *)d->buf; + if (partition >= gp->hdr.hdr_entries || + !memcmp(&gp->pea[partition].ent_type, &gpt_ent_type_unused, + sizeof(uuid_t))) { +#if DISK_DEBUG + printf("illegal GUID partition\n"); +#endif + error = EPART; + goto out; + } + +#ifdef _STANDALONE + bi_wedge.startblk = gp->pea[partition].ent_lba_start; + bi_wedge.nblks = gp->pea[partition].ent_lba_end - + gp->pea[partition].ent_lba_start + 1; + bi_wedge.matchblk = gp->hdr.hdr_lba_self; + bi_wedge.matchnblks = 1; + { + MD5_CTX ctx; + uint8_t buf[d->ll.secsize]; + + (void)memset(buf, 0, sizeof(buf)); + (void)memcpy(buf, &gp->hdr, sizeof(gp->hdr)); + + MD5Init(&ctx); + MD5Update(&ctx, (void *) buf, sizeof(buf)); + MD5Final(bi_wedge.matchhash, &ctx); + } +#endif + d->boff = gp->pea[partition].ent_lba_start; + if (!memcmp(&gp->pea[partition].ent_type, + &gpt_ent_type_netbsd_raidframe, sizeof(uuid_t))) + d->boff += RF_PROTECTED_SECTORS; + + /* GPT found - do not parse disklabel */ + goto nolabel; +nogpt: +#endif /* !NO_GPT */ + #ifndef NO_DISKLABEL if (partition == RAW_PART) goto nolabel; @@ -401,9 +592,12 @@ d->boff = lp->d_partitions[partition].p_offset; if (lp->d_partitions[partition].p_fstype == FS_RAID) d->boff += RF_PROTECTED_SECTORS; -nolabel: #endif /* NO_DISKLABEL */ +#if !defined(NO_GPT) || !defined(NO_DISKLABEL) +nolabel: +#endif + #ifdef DISK_DEBUG printf("partition @%d\n", d->boff); #endif @@ -417,7 +611,7 @@ out: va_end(ap); if (error) - dealloc(d, sizeof(struct biosdisk)); + dealloc(d, sizeof(*d)); return error; } @@ -431,7 +625,7 @@ if (d->ll.type == BIOSDISK_TYPE_FD) delay(3000000); /* 2s is enough on all PCs I found */ - dealloc(d, sizeof(struct biosdisk)); + dealloc(d, sizeof(*d)); f->f_devdata = NULL; return 0; } Index: sys/arch/i386/stand/mbr/Makefile =================================================================== RCS file: /cvsroot/src/sys/arch/i386/stand/mbr/Makefile,v retrieving revision 1.2 diff -u -r1.2 Makefile --- sys/arch/i386/stand/mbr/Makefile 19 Jan 2008 21:01:34 -0000 1.2 +++ sys/arch/i386/stand/mbr/Makefile 16 Aug 2009 09:02:03 -0000 @@ -1,5 +1,6 @@ # $NetBSD: Makefile,v 1.2 2008/01/19 21:01:34 dsl Exp $ SUBDIR= mbr mbr_bootsel mbr_ext mbr_com0 mbr_com0_9600 +SUBDIR+= mbr_gpt mbr_gpt_com0 .include New: sbin/gpt/biosboot.c =================================================================== --- /dev/null 2009-08-16 10:37:22.000000000 +0300 +++ sbin/gpt/biosboot.c 2009-08-16 10:47:46.000000000 +0300 @@ -0,0 +1,331 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to the NetBSD Foundation + * by Mike M. Volokhov. Development of this software was supported by the + * Google Summer of Code program. + * The GSoC project was mentored by Allen Briggs and Joerg Sonnenberger. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifdef __RCSID +__RCSID("$NetBSD$"); +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "map.h" +#include "gpt.h" + +#define DEFAULT_BOOTDIR "/usr/mdec" +#define DEFAULT_BOOTCODE "mbr_gpt" + +static daddr_t start; +static uint64_t size; + +static char *bootpath; +static unsigned int entry; + +const uuid_t uuid_type_efi = GPT_ENT_TYPE_EFI; +const uuid_t uuid_type_unused = GPT_ENT_TYPE_UNUSED; + +const char biosbootmsg[] = "biosboot [-c bootcode] [-i index] device ..."; + +static void +usage_biosboot(void) +{ + fprintf(stderr, "usage: %s %s\n", getprogname(), biosbootmsg); + exit(1); +} + +static struct mbr* +read_boot(void) +{ + int bfd, ret = 0; + struct mbr *buf; + struct stat st; + + /* XXX how to do the following better? */ + if (bootpath == NULL) { + bootpath = strdup(DEFAULT_BOOTDIR "/" DEFAULT_BOOTCODE); + } else { + if (strchr(bootpath, '/') == 0) { + char *p; + if ((p = strdup(bootpath)) == NULL) + err(1, "Malloc failed"); + free(bootpath); + (void)asprintf(&bootpath, "%s/%s", DEFAULT_BOOTDIR, p); + free(p); + } + } + if (bootpath == NULL) + err(1, "Malloc failed"); + + if ((buf = malloc((size_t)secsz)) == NULL) + err(1, "Malloc failed"); + + if ((bfd = open(bootpath, O_RDONLY)) < 0 || fstat(bfd, &st) == -1) { + warn("%s", bootpath); + goto fail; + } + + if (st.st_size != secsz) { + warnx("%s: the bootcode does not match '%s' sector size", + bootpath, device_name); + goto fail; + } + + if (read(bfd, buf, secsz) != st.st_size) { + warn("%s", bootpath); + goto fail; + } + + if (((struct mbr *)buf)->mbr_sig != htole16(MBR_SIG)) { + warnx("%s: invalid MBR magic", bootpath); + goto fail; + } + + /* + * The loader have to contain some magic in patchable area, + * such we can be sure that we won't trash something important + */ + if (!uuid_equal(&((struct mbr *)buf)->mbr_uuid, + &uuid_type_efi, NULL)) { + warnx("%s: the bootcode does not support required options", + bootpath); + goto fail; + } + + ret++; + + fail: + if (bfd >= 0) + close(bfd); + if (ret == 0) { + free(buf); + buf = NULL; + } + return buf; +} + +static void +biosboot(int fd) +{ + map_t *gpt, *tpg; + map_t *tbl, *lbt; + map_t *mbrmap, *m; + struct mbr *mbr, *bootcode; + struct gpt_ent *pp; + uuid_t buuid, buuid_default = uuid_type_unused; + + /* + * Parse and validate partition maps + */ + gpt = map_find(MAP_TYPE_PRI_GPT_HDR); + if (gpt == NULL) { + warnx("%s: error: no primary GPT header; run create or recover", + device_name); + return; + } + + tpg = map_find(MAP_TYPE_SEC_GPT_HDR); + if (tpg == NULL) { + warnx("%s: error: no secondary GPT header; run recover", + device_name); + return; + } + + tbl = map_find(MAP_TYPE_PRI_GPT_TBL); + lbt = map_find(MAP_TYPE_SEC_GPT_TBL); + if (tbl == NULL || lbt == NULL) { + warnx("%s: error: run recover -- trust me", device_name); + return; + } + + mbrmap = map_find(MAP_TYPE_PMBR); + if (mbrmap == NULL || mbrmap->map_start != 0) { + warnx("%s: error: no valid Protective MBR found", device_name); + return; + } + + mbr = mbrmap->map_data; + + /* + * Update the boot code + */ + if ((bootcode = read_boot()) == NULL) { + warnx("error reading bootcode"); + return; + } + (void)memcpy(&mbr->mbr_code, &bootcode->mbr_code, + sizeof(mbr->mbr_code)); + free(bootcode); + + /* + * Walk through the GPT and see where we can boot from + */ + for (m = map_first(); m != NULL; m = m->map_next) { + if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) + continue; + + pp = m->map_data; + + /* first, prefer user selection */ + if (entry > 0 && m->map_index == entry) + break; + + /* next, partition as could be specified by wedge */ + if (entry < 1 && + size > 0 && m->map_start == start && m->map_size == size) + break; + + /* at least, try to use EFI system partition */ + le_uuid_dec(pp->ent_type, &buuid); + if (uuid_equal(&buuid, &uuid_type_efi, NULL)) + le_uuid_dec(pp->ent_guid, &buuid_default); + } + + if (m == NULL) { + /* no match found */ + if (uuid_is_nil(&buuid_default, NULL)) { + warnx("error: no bootable partition"); + return; + } + buuid = buuid_default; + } else + le_uuid_dec(pp->ent_guid, &buuid); + +#if 1 + { + char *p; + + uuid_to_string(&buuid, &p, NULL); + printf("Boot device: %s\n", device_name); + printf("Partition GUID: %s\n", p); + printf("Boot code: %s\n", bootpath); + } +#endif + + mbr->mbr_uuid = buuid; + if (gpt_write(fd, mbrmap) == -1) { + warnx("error: cannot update Protective MBR"); + return; + } +} + +int +cmd_biosboot(int argc, char *argv[]) +{ + struct dkwedge_info dkw; + struct stat sb; + char devpath[MAXPATHLEN]; + char *dev, *p; + int ch, fd; + + while ((ch = getopt(argc, argv, "c:i:")) != -1) { + switch(ch) { + case 'c': + if (bootpath != NULL) + usage_biosboot(); + if ((bootpath = strdup(optarg)) == NULL) + err(1, "Malloc failed"); + break; + case 'i': + if (entry > 0) + usage_biosboot(); + entry = strtoul(optarg, &p, 10); + if (*p != 0 || entry < 1) + usage_biosboot(); + break; + default: + usage_biosboot(); + } + } + + if (argc == optind) + usage_biosboot(); + + while (optind < argc) { + dev = argv[optind++]; + start = 0; + size = 0; + +#ifdef __NetBSD__ + /* + * If a dk wedge was specified, loader should be + * installed onto parent device + */ + if ((fd = opendisk(dev, O_RDONLY, devpath, sizeof(devpath), 0)) + == -1) + goto next; + if (fstat(fd, &sb) == -1) + goto close; + +#ifdef DIOCGWEDGEINFO + if ((sb.st_mode & S_IFMT) != S_IFREG && + ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) { + if (entry > 0) + /* wedges and indexes are mutually exclusive */ + usage_biosboot(); + dev = dkw.dkw_parent; + start = dkw.dkw_offset; + size = dkw.dkw_size; + } +#endif + close: + close(fd); +#endif /* __NetBSD__*/ + + fd = gpt_open(dev); + next: + if (fd == -1) { + warn("unable to open device '%s'", device_name); + continue; + } + + biosboot(fd); + + gpt_close(fd); + } + + return (0); +} New: sys/arch/i386/stand/mbr/gpt.S =================================================================== --- /dev/null 2009-08-16 10:37:22.000000000 +0300 +++ sys/arch/i386/stand/mbr/gpt.S 2009-08-16 10:49:53.000000000 +0300 @@ -0,0 +1,550 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to the NetBSD Foundation + * by Mike M. Volokhov, based on the mbr.S code by Wolfgang Solfrank, + * Frank van der Linden, and David Laight. + * Development of this software was supported by the + * Google Summer of Code program. + * The GSoC project was mentored by Allen Briggs and Joerg Sonnenberger. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * i386 master boot code - GUID partition table format + */ + +/* Compile options: + * COM_PORT - do serial io to specified port number + * 0..3 => bios port, otherwise actual io_addr + * COM_BAUD - initialise serial port baud rate + * + * NO_LBA_CHECK - no check if bios supports LBA reads + * NO_CRC_CHECK - disable crc checks for GPT + * NO_BANNER - do not output title line 'banner' + */ + +#ifdef COM_PORT +#if COM_PORT < 4 +/* The first 4 items in the 40:xx segment are the serial port base addresses */ +#define COM_PORT_VAL (0x400 + (COM_PORT * 2)) +#else +#define COM_PORT_VAL $COM_PORT +#endif + +#if !defined(COM_FREQ) +#define COM_FREQ 1843200 +#endif +#endif + +#include +#include + +#define BOOTADDR 0x7c00 +#define LOADADDR 0x0600 /* address we are linked to */ +#define GPTBUFADDR 0xa000 /* GPT buffer (both header & array) */ + +/* + * GPT header structure, offsets + */ +#define GPTHDR_SIG_O 0 /* header signature, 8 b */ +#define GPTHDR_REV_O 8 /* GPT revision, 4 b */ +#define GPTHDR_SIZE_O 12 /* header size, 4 b */ +#define GPTHDR_CRC_O 16 /* header CRC32, 4 b */ +#define GPTHDR_RSVD_O 20 /* reserved, 4 b */ +#define GPTHDR_MYLBA_O 24 /* this header LBA, 8 b */ +#define GPTHDR_ALTLBA_O 32 /* alternate header LBA, 8 b */ +#define GPTHDR_SLBA_O 40 /* first usable LBA, 8 b */ +#define GPTHDR_ELBA_O 48 /* last usable LBA, 8 b */ +#define GPTHDR_GUID_O 56 /* disk GUID, 16 b */ +#define GPTHDR_PTNLBA_O 72 /* ptn. entry LBA, 8 b */ +#define GPTHDR_PTNN_O 80 /* number of ptns, 4 b */ +#define GPTHDR_PTNSZ_O 84 /* partition size, 4 b */ +#define GPTHDR_PTNCRC_O 88 /* ptn. array CRC32, 4 b */ + +/* + * GPT partition entry structure, offsets + */ +#define GPTPTN_TYPE_O 0 /* ptn. type GUID, 16 b */ +#define GPTPTN_GUID_O 16 /* ptn. unique GUID, 16 b */ +#define GPTPTN_SLBA_O 32 /* ptn. starting LBA, 8 b */ +#define GPTPTN_ELBA_O 40 /* ptn. ending LBA, 8 b */ +#define GPTPTN_ATTR_O 48 /* ptn. attributes, 8 b */ +#define GPTPTN_NAME_O 56 /* ptn. name, unicode, 72 b */ + +/* + * Default values of generic disk partitioning + */ +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 512 /* 8192 bytes max */ +#endif +#define GPTHDR_SIZE_DFLT 92 /* default size of GPT header */ +#define GPTHDR_LBASZ 1 /* default LBAs for header */ +#define GPTHDR_PTNSZ_DFLT 128 /* default size of a ptn */ +#define GPTHDR_PTNN_DFLT 128 /* default number of ptns */ +#define GPTPTN_SIZE (GPTHDR_PTNSZ_DFLT * GPTHDR_PTNN_DFLT) +#if GPTPTN_SIZE % SECTOR_SIZE == 0 +#define GPTPTN_LBASZ (GPTPTN_SIZE / SECTOR_SIZE) +#else +#define GPTPTN_LBASZ (GPTPTN_SIZE / SECTOR_SIZE + 1) +#endif +#define GPT_SIZE (GPTHDR_SIZE_DFLT + GPTPTN_SIZE) +#define GPT_LBASZ (GPTHDR_LBASZ + GPTPTN_LBASZ) + +/* + * Minimum and maximum drive number that is considered to be valid. + */ +#define MINDRV 0x80 +#define MAXDRV 0x8f + +/* + * Error codes. Done this way to save space. + */ +#define ERR_INVPART 'P' /* Invalid partition table */ +#define ERR_READ 'R' /* Read error */ +#define ERR_NOOS 'S' /* Magic no. check failed for part. */ +#define ERR_NO_LBA 'L' /* Sector above chs limit */ + +#define set_err(err) movb $err, %al + + .text + .code16 +/* + * Move ourselves out of the way first. + * (to the address we are linked at - 0x600) + * and zero our bss + */ +ENTRY(start) + xor %ax, %ax + mov %ax, %ss + movw $BOOTADDR, %sp + mov %ax, %es + mov %ax, %ds + movw $mbr, %di + mov $mbr - LOADADDR + BOOTADDR, %si + push %ax /* zero for %cs of lret */ + push %di + movw $(bss_start - mbr), %cx + rep + movsb /* relocate code (zero %cx on exit) */ + mov $(bss_end - bss_start + 511)/512, %ch + rep + stosw /* zero bss */ + lret /* Ensures %cs == 0 */ + +/* + * Sanity check the drive number passed by the BIOS. Some BIOSs may not + * do this and pass garbage. + */ +mbr: + cmpb $MAXDRV, %dl /* relies on MINDRV being 0x80 */ + jle 1f + movb $MINDRV, %dl /* garbage in, boot disk 0 */ +1: + push %dx /* save drive number */ + push %dx /* twice - for err_msg loop */ + +#if defined(COM_PORT) && defined(COM_BAUD) + mov $com_args, %si + mov $num_com_args, %cl /* %ch is zero from above */ + mov COM_PORT_VAL, %dx +1: lodsw + add %ah, %dl + outb %dx + loop 1b +#endif + +#ifndef NO_BANNER + mov $banner, %si + call message +#endif + +/* + * Read and validate GUID partition tables + * + * Register use: + * %ax temp + * %bx temp + * %cx counters (%ch was preset to zero via %cx before) + * %dx disk pointer (inherited from BIOS or the check above) + * %bp GPT header pointer + */ +#ifndef NO_LBA_CHECK +/* + * Determine whether we have int13-extensions, by calling int 13, function 41. + * Check for the magic number returned, and the disk packet capability. + * On entry %dx should contain BIOS disk number. + */ +lba_check: + movw $0x55aa, %bx + movb $0x41, %ah + int $0x13 + set_err(ERR_NO_LBA) + jc 1f /* no int13 extensions */ + cmpw $0xaa55, %bx + jnz 1f + testb $1, %cl + jnz gpt +1: jmp err_msg +#endif + +gpt: + /* + * Read GPT header + */ + movw $GPTBUFADDR, %bp /* start from primary GPT layout */ +read_gpt: + movw $lba_dap, %si + movb $0x42, %ah + int $0x13 /* read GPT header */ + jc try_gpt2 + + /* + * Verify GPT header + */ + movw $efihdr_sign, %si /* verify GPT signature... */ + movw %bp, %di /* ptn signature is at offset 0 */ + movb $8, %cl /* signature length */ + repe + cmpsb /* compare */ + jne try_gpt2 /* if not equal - try GPT2 */ + +#ifndef NO_CRC_CHECK + mov %bp, %si /* verify CRC32 of the header... */ + mov $GPTHDR_SIZE_DFLT, %di /* header boundary */ + add %bp, %di + xor %eax, %eax + xchgl %eax, GPTHDR_CRC_O(%bp) /* save and reset header CRC */ + call crc32 + cmp %eax, %ebx /* is CRC correct? */ + jne try_gpt2 +#endif + +#if 0 /* XXX: weak check - safely disabled due to space constraints */ + movw $lba_sector, %si /* verify GPT location... */ + mov $GPTHDR_MYLBA_O, %di + add %bp, %di + movb $8, %cl /* LBA size */ + repe + cmpsb /* compare */ + jne try_gpt2 /* if not equal - try GPT2 */ +#endif + + /* + * All header checks passed - now verify GPT partitions array + */ +#ifndef NO_CRC_CHECK + movl GPTHDR_PTNCRC_O(%bp), %eax /* original array checksum */ + push %bp /* save header pointer for try_gpt2 */ +#endif + + /* + * point %bp to GPT partitions array location + */ + cmp $GPTBUFADDR, %bp + je 1f + mov $GPTBUFADDR, %bp + jmp 2f +1: mov $GPTBUFADDR + GPTPTN_LBASZ * SECTOR_SIZE, %bp +2: + +#ifndef NO_CRC_CHECK + mov %bp, %si /* array location for CRC32 check */ + mov $GPTPTN_SIZE, %di /* array boundary */ + add %bp, %di + call crc32 + cmp %eax, %ebx /* is CRC correct? */ + jne 1f /* if no - try GPT2 */ + pop %ax /* restore stack consistency */ +#endif + jmp gpt_parse + +#ifndef NO_CRC_CHECK +1: pop %bp /* restore after unsucc. array check */ +#endif +try_gpt2: + cmp $GPTBUFADDR, %bp /* is this GPT1? */ + set_err(ERR_INVPART) + jne err_msg /* if no - we just tried GPT2. Stop. */ + + mov %bp, %si /* use [%bp] as tmp buffer */ + movb $0x1a, (%si) /* init buffer size (per v.1.0) */ + movb $0x48, %ah /* request extended LBA status */ + int $0x13 /* ... to get GPT2 location */ + set_err(ERR_NO_LBA) + jc err_msg /* on error - stop */ +#define LBA_DKINFO_OFFSET 16 /* interested offset in out buffer */ + addw $LBA_DKINFO_OFFSET, %si /* ... contains number of disk LBAs */ +#undef LBA_DKINFO_OFFSET + movw $lba_sector, %di + movb $8, %cl /* LBA size */ + rep + movsb /* do get */ + subl $GPT_LBASZ, lba_sector /* calculate location of GPT2 */ + sbbl $0, lba_sector + 4 /* 64-bit LBA correction */ + + movw $GPTBUFADDR + GPTPTN_LBASZ * SECTOR_SIZE, %bp + /* the GPT2 header location */ + jmp read_gpt /* try once again */ + +/* + * GPT header validation done. + * Now parse GPT partitions and try to boot from appropriate. + * Register use: + * %bl partition counter + * %bp partition entry pointer (already initialized on entry) + * %di partition entry moving pointer + * %si variables pointer + * %cx counter + */ + +gpt_parse: + movw $BOOTADDR, lba_rbuff /* from now we will read boot code */ + movb $1, lba_count /* read PBR only */ + movb $GPTHDR_PTNN_DFLT, %bl /* number of GUID partitions to parse */ +do_gpt_parse: + movw $bootptn_guid, %si /* lookup the boot partition GUID */ + movb $0x10, %cl /* sizeof GUID */ + movw %bp, %di /* set pointer to partition entry */ + add %cx, %di /* partition GUID at offset 16 */ + repe + cmpsb /* do compare */ + jne try_nextptn /* doesn't seem appropriate ptn */ + + /* + * Read partition boot record + */ + mov $GPTPTN_SLBA_O, %si /* point %si to partition LBA */ + add %bp, %si + movw $lba_sector, %di + movb $8, %cl /* LBA size */ + rep + movsb /* set read pointer to LBA of PBR */ + movw $lba_dap, %si + movb $0x42, %ah + int $0x13 /* read PBR */ + jz try_nextptn + + /* + * Check signature for valid bootcode and try to boot + */ + movb BOOTADDR, %al /* first byte non-zero */ + testb %al, %al + jz 1f + movw BOOTADDR + MBR_MAGIC_OFFSET, %ax +1: cmp $MBR_MAGIC, %ax + jne try_nextptn +do_boot: + aam /* on exit: %ax - MBR_PARAMS_MAGIC */ + pop %dx /* ... %dx - drive # */ + movw $lba_sector, %sp /* ... %ecx%ebx - boot partition LBA */ + pop %ebx + pop %ecx + jmp start - LOADADDR + BOOTADDR + /* THE END */ + +try_nextptn: + addw $GPTHDR_PTNSZ_DFLT, %bp /* move to next partition */ + decb %bl /* ptncounter-- */ + jnz do_gpt_parse + set_err(ERR_NOOS) /* no bootable partitions were found */ + /* jmp err_msg */ /* stop */ + +/* Something went wrong... + * Output error code, + * reset disk subsystem - needed after read failure, + * and wait for user key + */ +err_msg: + movb %al, errcod + movw $errtxt, %si + call message + pop %dx /* drive we errored on */ + xor %ax,%ax /* only need %ah = 0 */ + int $0x13 /* reset disk subsystem */ + int $0x18 /* BIOS might ask for a key */ + /* press and retry boot seq. */ +1: sti + hlt + jmp 1b + +/* + * I hate #including source files, but the stuff below has to be at + * the correct absolute address. + * Clearly this could be done with a linker script. + */ + +#ifdef COM_PORT +message: + pusha +message_1: + lodsb + test %al, %al + jz 3f + mov COM_PORT_VAL, %dx + outb %al, %dx + add $5, %dl +2: inb %dx + test $0x40, %al + jz 2b + jmp message_1 +3: popa + ret +#else +#include +#endif + +#if 0 +#include +#endif + +#ifndef NO_CRC_CHECK +/* + * The CRC32 calculation + * + * %si address of block to hash + * %di stop address + * %ax scratch (but restored after exit) + * %dx scratch (but restored after exit) + * %cx counter + * %ebx crc (returned) + */ +crc32: + push %dx /* preserve drive number */ + push %ax /* preserve original CRC */ + + xorl %ebx, %ebx + decl %ebx /* init value */ +1: + lodsb /* load next message byte to %al */ + movb $8, %cl /* set bit counter */ +2: + movb %al, %dl + xorb %bl, %dl /* xoring with previous result */ + shrl $1, %ebx + shrb $1, %al + testb $1, %dl + jz 3f + xorl $0xedb88320, %ebx /* CRC32 modulus */ +3: + loop 2b /* loop over bits */ + cmp %di, %si /* do we reached end of message? */ + jne 1b + notl %ebx /* result correction */ + + pop %ax + pop %dx + ret +#endif + +/* + * Data definition block + */ + +errtxt: .ascii "Error " /* runs into crlf if errcod set */ +errcod: .byte 0 +crlf: .asciz "\r\n" + +#ifndef NO_BANNER +banner: .asciz "NetBSD GPT boot\r\n" +#endif + +#if defined(COM_PORT) && defined(COM_BAUD) +#define COM_DIVISOR (((COM_FREQ / COM_BAUD) + 8) / 16) +com_args: + .byte 0x80 /* divisor latch enable */ + .byte +3 /* io_port + 3 */ + .byte COM_DIVISOR & 0xff + .byte -3 /* io_port */ + .byte COM_DIVISOR >> 8 /* high baud */ + .byte +1 /* io_port + 1 */ + .byte 0x03 /* 8 bit no parity */ + .byte +2 /* io_port + 3 */ +num_com_args = (. - com_args)/2 +#endif + +/* + * Control block for int-13 LBA read - Disk Address Packet + */ +lba_dap: + .byte 0x10 /* control block length */ + .byte 0 /* reserved */ +lba_count: + .word GPT_LBASZ /* sector count */ +lba_rbuff: + .word GPTBUFADDR /* offset in segment */ + .word 0 /* segment */ +lba_sector: + .long 0x0001 /* sector # goes here... */ + .long 0x0000 + +efihdr_sign: + .ascii "EFI PART" /* GPT header signature */ + +/* + * Stuff from here on is overwritten by gpt/fdisk - the offset must not change + * + * Get amount of space to makefile can report it. + * (Unfortunately I can't seem to get the value reported when it is -ve) + */ +mbr_space = bootptn_guid - . + +/* + * GUID of the bootable partition. Patchable area. + * Default data represents the EFI System Partition GUID and used + * by installer for safety checks. + */ + . = start + MBR_GUID_OFFSET +bootptn_guid: + .long 0xc12a7328 + .long 0x11d2f81f + .long 0xa0004bba + .long 0x3bc93ec9 + +/* space for mbr_dsn */ + . = start + MBR_DSN_OFFSET +mbr_dsn: + .long 0 + +/* mbr_bootsel_magic */ + . = start + MBR_BS_MAGIC_OFFSET +mbr_bootsel_magic: + .word 0 + +/* mbr partition table */ + . = start + MBR_PART_OFFSET +parttab: + .fill 0x40, 0x01, 0x00 + + . = start + MBR_MAGIC_OFFSET + .word MBR_MAGIC + +/* zeroed data space */ +bss_off = 0 +bss_start = . +#define BSS(name, size) name = bss_start + bss_off; bss_off = bss_off + size + BSS(dump_eax_buff, 16) + BSS(bss_end, 0) New: sys/arch/i386/stand/mbr/mbr_gpt/Makefile =================================================================== WARNING: ensure existence of directory sys/arch/i386/stand/mbr/mbr_gpt --- /dev/null 2009-08-16 10:37:22.000000000 +0300 +++ sys/arch/i386/stand/mbr/mbr_gpt/Makefile 2009-08-16 10:49:53.000000000 +0300 @@ -0,0 +1,6 @@ +# $NetBSD$ + +PROG= mbr_gpt +SRCS= gpt.S + +.include <../Makefile.mbr> New: sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile =================================================================== WARNING: ensure existence of directory sys/arch/i386/stand/mbr/mbr_gpt_com0 --- /dev/null 2009-08-16 10:37:22.000000000 +0300 +++ sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile 2009-08-16 10:49:53.000000000 +0300 @@ -0,0 +1,7 @@ +# $NetBSD$ + +PROG= mbr_gpt_com0 +SRCS= gpt.S +AFLAGS+= -DCOM_PORT=0 + +.include <../Makefile.mbr>