Module Name: src Committed By: jakllsch Date: Thu Jan 6 01:08:49 UTC 2011
Modified Files: src/distrib/sets/lists/base: md.amd64 md.i386 src/sbin/gpt: Makefile gpt.c gpt.h src/sys/arch/i386/stand/bootxx: boot1.c bootxx.S pbr.S src/sys/arch/i386/stand/mbr: Makefile src/sys/sys: bootblock.h Added Files: src/sbin/gpt: biosboot.c src/sys/arch/i386/stand/mbr: gpt.S src/sys/arch/i386/stand/mbr/mbr_gpt: Makefile src/sys/arch/i386/stand/mbr/mbr_gpt_com0: Makefile Log Message: Support booting from GPT-partioned disks on PC-BIOS-compatible systems. Much of the work in this commit was done by Mike Volokhov during GSoC 2009. To generate a diff of this commit: cvs rdiff -u -r1.106 -r1.107 src/distrib/sets/lists/base/md.amd64 cvs rdiff -u -r1.137 -r1.138 src/distrib/sets/lists/base/md.i386 cvs rdiff -u -r1.3 -r1.4 src/sbin/gpt/Makefile cvs rdiff -u -r0 -r1.1 src/sbin/gpt/biosboot.c cvs rdiff -u -r1.12 -r1.13 src/sbin/gpt/gpt.c cvs rdiff -u -r1.4 -r1.5 src/sbin/gpt/gpt.h cvs rdiff -u -r1.19 -r1.20 src/sys/arch/i386/stand/bootxx/boot1.c cvs rdiff -u -r1.9 -r1.10 src/sys/arch/i386/stand/bootxx/bootxx.S cvs rdiff -u -r1.18 -r1.19 src/sys/arch/i386/stand/bootxx/pbr.S cvs rdiff -u -r1.2 -r1.3 src/sys/arch/i386/stand/mbr/Makefile cvs rdiff -u -r0 -r1.1 src/sys/arch/i386/stand/mbr/gpt.S cvs rdiff -u -r0 -r1.1 src/sys/arch/i386/stand/mbr/mbr_gpt/Makefile cvs rdiff -u -r0 -r1.1 src/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile cvs rdiff -u -r1.51 -r1.52 src/sys/sys/bootblock.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/base/md.amd64 diff -u src/distrib/sets/lists/base/md.amd64:1.106 src/distrib/sets/lists/base/md.amd64:1.107 --- src/distrib/sets/lists/base/md.amd64:1.106 Thu Dec 16 18:42:49 2010 +++ src/distrib/sets/lists/base/md.amd64 Thu Jan 6 01:08:48 2011 @@ -1,4 +1,4 @@ -# $NetBSD: md.amd64,v 1.106 2010/12/16 18:42:49 christos Exp $ +# $NetBSD: md.amd64,v 1.107 2011/01/06 01:08:48 jakllsch Exp $ ./dev/lms0 base-obsolete obsolete ./dev/mms0 base-obsolete obsolete ./libexec/ld.elf_so-i386 base-sys-shlib compat,pic @@ -298,6 +298,8 @@ ./usr/mdec/mbr_com0 base-sysutil-bin ./usr/mdec/mbr_com0_9600 base-sysutil-bin ./usr/mdec/mbr_ext base-sysutil-bin +./usr/mdec/mbr_gpt base-sysutil-bin +./usr/mdec/mbr_gpt_com0 base-sysutil-bin ./usr/mdec/netboot_3c509.rom base-sysutil-bin ./usr/mdec/netboot_3c590.rom base-sysutil-bin ./usr/mdec/netboot_3c90xb.rom base-sysutil-bin Index: src/distrib/sets/lists/base/md.i386 diff -u src/distrib/sets/lists/base/md.i386:1.137 src/distrib/sets/lists/base/md.i386:1.138 --- src/distrib/sets/lists/base/md.i386:1.137 Sat Sep 11 13:06:36 2010 +++ src/distrib/sets/lists/base/md.i386 Thu Jan 6 01:08:48 2011 @@ -1,4 +1,4 @@ -# $NetBSD: md.i386,v 1.137 2010/09/11 13:06:36 tsutsui Exp $ +# $NetBSD: md.i386,v 1.138 2011/01/06 01:08:48 jakllsch Exp $ ./dev/lms0 base-obsolete obsolete ./dev/mms0 base-obsolete obsolete ./dev/pms0 base-obsolete obsolete @@ -79,6 +79,8 @@ ./usr/mdec/mbr_com0 base-sysutil-bin ./usr/mdec/mbr_com0_9600 base-sysutil-bin ./usr/mdec/mbr_ext base-sysutil-bin +./usr/mdec/mbr_gpt base-sysutil-bin +./usr/mdec/mbr_gpt_com0 base-sysutil-bin ./usr/mdec/netboot_3c509.rom base-sysutil-bin ./usr/mdec/netboot_3c590.rom base-sysutil-bin ./usr/mdec/netboot_3c90xb.rom base-sysutil-bin Index: src/sbin/gpt/Makefile diff -u src/sbin/gpt/Makefile:1.3 src/sbin/gpt/Makefile:1.4 --- src/sbin/gpt/Makefile:1.3 Sat Apr 11 07:58:12 2009 +++ src/sbin/gpt/Makefile Thu Jan 6 01:08:48 2011 @@ -1,9 +1,9 @@ -# $NetBSD: Makefile,v 1.3 2009/04/11 07:58:12 lukem Exp $ +# $NetBSD: Makefile,v 1.4 2011/01/06 01:08:48 jakllsch Exp $ # $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: src/sbin/gpt/gpt.c diff -u src/sbin/gpt/gpt.c:1.12 src/sbin/gpt/gpt.c:1.13 --- src/sbin/gpt/gpt.c:1.12 Fri Apr 2 19:33:09 2010 +++ src/sbin/gpt/gpt.c Thu Jan 6 01:08:48 2011 @@ -31,7 +31,7 @@ __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $"); #endif #ifdef __RCSID -__RCSID("$NetBSD: gpt.c,v 1.12 2010/04/02 19:33:09 christos Exp $"); +__RCSID("$NetBSD: gpt.c,v 1.13 2011/01/06 01:08:48 jakllsch Exp $"); #endif #include <sys/param.h> @@ -756,6 +756,7 @@ const char *name; } cmdsw[] = { { cmd_add, "add" }, + { cmd_biosboot, "biosboot" }, { cmd_create, "create" }, { cmd_destroy, "destroy" }, { NULL, "help" }, @@ -772,7 +773,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[]; @@ -783,6 +784,7 @@ " %s %s\n" " %s %s\n" " %s %s\n" + " %s %s\n" " %*s %s\n" " %s %s\n" " %s %s\n" @@ -790,6 +792,7 @@ " %s %s\n" " %s %s\n", getprogname(), addmsg, + getprogname(), biosbootmsg, getprogname(), createmsg, getprogname(), destroymsg, getprogname(), labelmsg1, Index: src/sbin/gpt/gpt.h diff -u src/sbin/gpt/gpt.h:1.4 src/sbin/gpt/gpt.h:1.5 --- src/sbin/gpt/gpt.h:1.4 Sat Feb 7 18:12:22 2009 +++ src/sbin/gpt/gpt.h Thu Jan 6 01:08:48 2011 @@ -67,7 +67,7 @@ }; struct mbr { - uint16_t mbr_code[223]; + uint8_t mbr_code[446]; struct mbr_part mbr_part[4]; uint16_t mbr_sig; #define MBR_SIG 0xAA55 @@ -90,6 +90,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: src/sys/arch/i386/stand/bootxx/boot1.c diff -u src/sys/arch/i386/stand/bootxx/boot1.c:1.19 src/sys/arch/i386/stand/bootxx/boot1.c:1.20 --- src/sys/arch/i386/stand/bootxx/boot1.c:1.19 Fri Jan 1 03:18:27 2010 +++ src/sys/arch/i386/stand/bootxx/boot1.c Thu Jan 6 01:08:48 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: boot1.c,v 1.19 2010/01/01 03:18:27 christos Exp $ */ +/* $NetBSD: boot1.c,v 1.20 2011/01/06 01:08:48 jakllsch Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: boot1.c,v 1.19 2010/01/01 03:18:27 christos Exp $"); +__RCSID("$NetBSD: boot1.c,v 1.20 2011/01/06 01:08:48 jakllsch Exp $"); #include <lib/libsa/stand.h> #include <lib/libkern/libkern.h> @@ -44,11 +44,11 @@ #define XSTR(x) #x #define STR(x) XSTR(x) -static uint32_t bios_sector; +static daddr_t bios_sector; static struct biosdisk_ll d; -const char *boot1(uint32_t, uint32_t *); +const char *boot1(uint32_t, uint64_t *); extern void putstr(const char *); extern struct disklabel ptn_disklabel; @@ -60,7 +60,7 @@ } const char * -boot1(uint32_t biosdev, uint32_t *sector) +boot1(uint32_t biosdev, uint64_t *sector) { struct stat sb; int fd; Index: src/sys/arch/i386/stand/bootxx/bootxx.S diff -u src/sys/arch/i386/stand/bootxx/bootxx.S:1.9 src/sys/arch/i386/stand/bootxx/bootxx.S:1.10 --- src/sys/arch/i386/stand/bootxx/bootxx.S:1.9 Mon Apr 28 20:23:25 2008 +++ src/sys/arch/i386/stand/bootxx/bootxx.S Thu Jan 6 01:08:48 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: bootxx.S,v 1.9 2008/04/28 20:23:25 martin Exp $ */ +/* $NetBSD: bootxx.S,v 1.10 2011/01/06 01:08:48 jakllsch Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -39,7 +39,7 @@ * * On entry: * %dl BIOS drive number - * %esi Sector number of netbsd partition + * %edi:%esi Sector number of NetBSD partition * %cs, %ds, %es, %ss All zero * %sp near 0xfffc */ @@ -60,6 +60,7 @@ calll real_to_prot .code32 + push %edi movl $_end, %ecx /* zero bss */ movl $__bss_start, %edi subl %edi, %ecx @@ -67,9 +68,11 @@ xor %eax, %eax rep stosl + pop %edi - and $0xff, %edx - push %esi /* save args for secondary bootstrap */ + movzbl %dl, %edx + push %edi /* save args for secondary bootstrap */ + push %esi movl %esp, %esi /* address of sector number */ push %edx push %esi /* args for boot1 */ @@ -84,7 +87,9 @@ pop %edx /* bios disk number */ pop %ebx /* expected partition start sector */ + pop %ecx movl $boot_params, %esi + orb $X86_BP_FLAGS_LBA64VALID, 4(%esi) lcall $SECONDARY_LOAD_ADDRESS/16, $0 boot_fail: Index: src/sys/arch/i386/stand/bootxx/pbr.S diff -u src/sys/arch/i386/stand/bootxx/pbr.S:1.18 src/sys/arch/i386/stand/bootxx/pbr.S:1.19 --- src/sys/arch/i386/stand/bootxx/pbr.S:1.18 Sun Jan 2 02:01:58 2011 +++ src/sys/arch/i386/stand/bootxx/pbr.S Thu Jan 6 01:08:48 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: pbr.S,v 1.18 2011/01/02 02:01:58 jakllsch Exp $ */ +/* $NetBSD: pbr.S,v 1.19 2011/01/06 01:08:48 jakllsch Exp $ */ /*- * Copyright (c) 2003,2004 The NetBSD Foundation, Inc. @@ -97,6 +97,8 @@ * sector we were loaded from (if we were loaded by NetBSD mbr code). * In any case we have to re-read sector zero of the disk and hunt * through the BIOS partition table for the NetBSD partition. + * However, if there's a magic number in %eax, then %ecx:%ebx + * contains the sector we were loaded from. */ .text @@ -119,12 +121,20 @@ . = start + MBR_AFTERBPB /* skip BPB */ start0: +#ifndef BOOT_FROM_FAT + movl %eax, %edi /* move %eax magic out of the way */ +#endif xor %ax, %ax /* don't trust values of ds, es or ss */ mov %ax, %ds mov %ax, %es mov %ax, %ss mov $0xfffc, %sp +#ifndef BOOT_FROM_FAT + cmpl $X86_MBR_GPT_MAGIC, %edi /* did mbr_gpt leave us a LBA? */ + je boot_gpt +#endif + /* A 'reset disk system' request is traditional here... */ push %dx /* some BIOS zap %dl here :-( */ int $0x13 /* ah == 0 from code above */ @@ -332,6 +342,7 @@ jnz error movl %ebp, %esi /* %esi ptn base, %dl disk id */ + movl lba_sector + 4, %edi /* %edi ptn base high */ jmp $0, $bootxx /* our %cs may not be zero */ /* Read disk using int13-extension parameter block */ @@ -355,17 +366,26 @@ movw $0x200 + BOOTXX_SECTORS, %ax /* command 2, xx sectors */ jmp do_read +#ifndef BOOT_FROM_FAT +boot_gpt: + /* 64-bit LBA in %ecx:%ebx */ + movl %ebx, lba_sector + movl %ecx, lba_sector + 4 + movl %ebx, %ebp + jmp boot_lba +#endif + _errtxt: .ascii "Error " /* runs into newline... */ _errcod: .byte 0 /* ... if errcod set */ _newline: .asciz "\r\n" #ifndef TERSE_ERROR -ERR_READ: .asciz "Disk read" -ERR_NO_BOOTXX: .asciz "Not a bootxx image" -ERR_PTN: .asciz "No NetBSD partition" +ERR_READ: .asciz "read" +ERR_NO_BOOTXX: .asciz "no magic" +ERR_PTN: .asciz "no slice" #ifndef NO_LBA_CHECK -ERR_NO_LBA: .asciz "Invalid CHS read" +ERR_NO_LBA: .asciz "need LBA" #endif #endif @@ -387,8 +407,7 @@ .word BOOTADDR /* offset in segment */ .word 0 /* segment */ _lba_sector: - .long 0x0000 /* sector # goes here... */ - .long 0x0000 + .quad 0 /* sector # goes here... */ /* Drive Serial Number */ . = _C_LABEL(start) + MBR_DSN_OFFSET Index: src/sys/arch/i386/stand/mbr/Makefile diff -u src/sys/arch/i386/stand/mbr/Makefile:1.2 src/sys/arch/i386/stand/mbr/Makefile:1.3 --- src/sys/arch/i386/stand/mbr/Makefile:1.2 Sat Jan 19 21:01:34 2008 +++ src/sys/arch/i386/stand/mbr/Makefile Thu Jan 6 01:08:49 2011 @@ -1,5 +1,6 @@ -# $NetBSD: Makefile,v 1.2 2008/01/19 21:01:34 dsl Exp $ +# $NetBSD: Makefile,v 1.3 2011/01/06 01:08:49 jakllsch Exp $ SUBDIR= mbr mbr_bootsel mbr_ext mbr_com0 mbr_com0_9600 +SUBDIR+= mbr_gpt mbr_gpt_com0 .include <bsd.subdir.mk> Index: src/sys/sys/bootblock.h diff -u src/sys/sys/bootblock.h:1.51 src/sys/sys/bootblock.h:1.52 --- src/sys/sys/bootblock.h:1.51 Wed Jan 5 23:13:01 2011 +++ src/sys/sys/bootblock.h Thu Jan 6 01:08:48 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: bootblock.h,v 1.51 2011/01/05 23:13:01 jakllsch Exp $ */ +/* $NetBSD: bootblock.h,v 1.52 2011/01/06 01:08:48 jakllsch Exp $ */ /*- * Copyright (c) 2002-2004 The NetBSD Foundation, Inc. @@ -168,6 +168,8 @@ * * 400 - 439 MP NetBSD: mbr_bootsel * + * 424 - 439 M NetBSD: bootptn_guid (in GPT PMBR only) + * * 440 - 443 M WinNT/2K/XP Drive Serial Number (NT DSN) * http://www.geocities.com/thestarman3/asm/mbr/Win2kmbr.htm * @@ -194,6 +196,9 @@ #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_GPT_GUID_OFFSET 424 /* location of partition GUID to boot */ +#define MBR_GPT_GUID_DEFAULT /* default uninitialized GUID */ \ + {0xeee69d04,0x02f4,0x11e0,0x8f,0x5d,{0x00,0xe0,0x81,0x52,0x9a,0x6b}} #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]) */ @@ -1064,6 +1069,7 @@ #define X86_BOOT_MAGIC_2 X86_BOOT_MAGIC(2) /* bootxx.S */ #define X86_BOOT_MAGIC_PXE X86_BOOT_MAGIC(3) /* start_pxe.S */ #define X86_BOOT_MAGIC_FAT X86_BOOT_MAGIC(4) /* fatboot.S */ +#define X86_MBR_GPT_MAGIC 0xedb88320 /* gpt.S */ /* values for bp_flags */ #define X86_BP_FLAGS_RESET_VIDEO 1 Added files: Index: src/sbin/gpt/biosboot.c diff -u /dev/null src/sbin/gpt/biosboot.c:1.1 --- /dev/null Thu Jan 6 01:08:49 2011 +++ src/sbin/gpt/biosboot.c Thu Jan 6 01:08:48 2011 @@ -0,0 +1,326 @@ +/* $NetBSD: biosboot.c,v 1.1 2011/01/06 01:08:48 jakllsch Exp $ */ + +/* + * 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 <sys/cdefs.h> +#ifdef __RCSID +__RCSID("$NetBSD: biosboot.c,v 1.1 2011/01/06 01:08:48 jakllsch Exp $"); +#endif + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/disk.h> +#include <sys/param.h> +#include <sys/bootblock.h> + +#include <err.h> +#include <fcntl.h> +#include <inttypes.h> +#include <paths.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <util.h> + +#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_mbr_guid_default = MBR_GPT_GUID_DEFAULT; + +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; + uuid_t uuid_patch_magic; + + /* 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 (le32toh(buf->mbr_sig) != MBR_SIG) { + warnx("%s: invalid MBR magic", bootpath); + goto fail; + } + + uuid_dec_le(&buf->mbr_code[MBR_GPT_GUID_OFFSET], &uuid_patch_magic); + + /* + * 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(&uuid_patch_magic, &uuid_mbr_guid_default, 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; + + /* + * 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 == (off_t)size) + break; + } + + if (m == NULL) { + warnx("error: no bootable partition"); + return; + } else + uuid_dec_le(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); + + free(p); + } +#endif + + uuid_enc_le(&mbr->mbr_code[MBR_GPT_GUID_OFFSET], &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); +} Index: src/sys/arch/i386/stand/mbr/gpt.S diff -u /dev/null src/sys/arch/i386/stand/mbr/gpt.S:1.1 --- /dev/null Thu Jan 6 01:08:49 2011 +++ src/sys/arch/i386/stand/mbr/gpt.S Thu Jan 6 01:08:49 2011 @@ -0,0 +1,552 @@ +/* $NetBSD: gpt.S,v 1.1 2011/01/06 01:08:49 jakllsch Exp $ */ + +/* + * 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. + */ + +/* + * x86 PC BIOS 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 <machine/asm.h> +#include <sys/bootblock.h> + +#define BOOTADDR 0x7c00 +#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, UTF-16, 72 b */ + +/* + * Default values of generic disk partitioning + */ +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 512 /* 8192 bytes max */ +#endif +#define GPTHDR_BLKNO 1 +#define GPTHDR_SIZE 92 /* size of GPT header */ +#define GPTHDR_LBASZ 1 /* default LBAs for header */ +#define GPTHDR_PTNSZ 128 /* size of a partition entry */ +#define GPTHDR_PTNN_MIN 128 /* minimum number of ptns */ +#define GPTPTN_SIZE (GPTHDR_PTNSZ * GPTHDR_PTNN_MIN) +#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_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) + * 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 $BOOTADDR + (mbr - start), %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: + call do_lba_read /* 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 $sizeof_efihdr_sign, %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, %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: + * %bx 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 */ + mov $GPTHDR_PTNN_MIN, %bx /* 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 */ + call do_lba_read /* 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: + pop %dx /* ... %dx - drive # */ + movw $lba_sector, %sp /* ... %ecx:%ebx - boot partition LBA */ + pop %ebx + pop %ecx + movl crc32_poly, %eax /* X86_MBR_GPT_MAGIC */ + jmp BOOTADDR + /* THE END */ + +try_nextptn: + addw $GPTHDR_PTNSZ, %bp /* move to next partition */ + dec %bx /* 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. + */ + +#if defined(COM_PORT) && defined(COM_BAUD) +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 <message.S> +#endif + +#if 0 +#include <dump_eax.S> +#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 +crc32_poly = . + 3 /* gross, but saves a few bytes */ + xorl $0xedb88320, %ebx /* EFI CRC32 Polynomial */ +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 + +do_lba_read: + movw $lba_dap, %si + movb $0x42, %ah + int $0x13 /* read */ + ret + +/* + * 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\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: + .quad GPTHDR_BLKNO /* sector # goes here... */ + +efihdr_sign: + .ascii "EFI PART" /* GPT header signature */ + .long 0x00010000 /* GPT header revision */ +sizeof_efihdr_sign = . - efihdr_sign + +/* + * 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 GUID used by installer for safety checks. + */ + . = start + MBR_GPT_GUID_OFFSET +bootptn_guid: + /* MBR_GPT_GUID_DEFAULT */ + .long 0xeee69d04 + .word 0x02f4 + .word 0x11e0 + .byte 0x8f,0x5d + .byte 0x00,0xe0,0x81,0x52,0x9a,0x6b + +/* space for mbr_dsn */ + . = start + MBR_DSN_OFFSET + .long 0 + +/* mbr_bootsel_magic */ + . = start + MBR_BS_MAGIC_OFFSET + .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) Index: src/sys/arch/i386/stand/mbr/mbr_gpt/Makefile diff -u /dev/null src/sys/arch/i386/stand/mbr/mbr_gpt/Makefile:1.1 --- /dev/null Thu Jan 6 01:08:49 2011 +++ src/sys/arch/i386/stand/mbr/mbr_gpt/Makefile Thu Jan 6 01:08:49 2011 @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 2011/01/06 01:08:49 jakllsch Exp $ + +PROG= mbr_gpt +SRCS= gpt.S + +.include <../Makefile.mbr> Index: src/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile diff -u /dev/null src/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile:1.1 --- /dev/null Thu Jan 6 01:08:49 2011 +++ src/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile Thu Jan 6 01:08:49 2011 @@ -0,0 +1,7 @@ +# $NetBSD: Makefile,v 1.1 2011/01/06 01:08:49 jakllsch Exp $ + +PROG= mbr_gpt_com0 +SRCS= gpt.S +AFLAGS+= -DCOM_PORT=0 + +.include <../Makefile.mbr>