From owner-freebsd-current@FreeBSD.ORG Sun Jun 10 14:35:37 2012 Return-Path: Delivered-To: current@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 19DE9106564A; Sun, 10 Jun 2012 14:35:37 +0000 (UTC) (envelope-from hrs@FreeBSD.org) Received: from mail.allbsd.org (gatekeeper.allbsd.org [IPv6:2001:2f0:104:e001::32]) by mx1.freebsd.org (Postfix) with ESMTP id B8B438FC0A; Sun, 10 Jun 2012 14:35:35 +0000 (UTC) Received: from alph.allbsd.org (p4242-ipbf1504funabasi.chiba.ocn.ne.jp [118.7.211.242]) (authenticated bits=128) by mail.allbsd.org (8.14.5/8.14.5) with ESMTP id q5AEZInm047291; Sun, 10 Jun 2012 23:35:28 +0900 (JST) (envelope-from hrs@FreeBSD.org) Received: from localhost (localhost [IPv6:::1]) (authenticated bits=0) by alph.allbsd.org (8.14.4/8.14.4) with ESMTP id q5AEZFFe090966; Sun, 10 Jun 2012 23:35:16 +0900 (JST) (envelope-from hrs@FreeBSD.org) Date: Sun, 10 Jun 2012 22:48:13 +0900 (JST) Message-Id: <20120610.224813.710171778841273502.hrs@allbsd.org> To: current@FreeBSD.org From: Hiroki Sato In-Reply-To: <4FD05573.70801@FreeBSD.org> References: <4FCF3021.5070802@FreeBSD.org> <20120606.200735.1551208261335301113.hrs@allbsd.org> <4FD05573.70801@FreeBSD.org> X-PGPkey-fingerprint: BDB3 443F A5DD B3D0 A530 FFD7 4F2C D3D8 2793 CF2D X-Mailer: Mew version 6.4.50 on Emacs 23.4 / Mule 6.0 (HANACHIRUSATO) Mime-Version: 1.0 Content-Type: Multipart/Signed; protocol="application/pgp-signature"; micalg=pgp-sha1; boundary="--Security_Multipart0(Sun_Jun_10_22_48_13_2012_513)--" Content-Transfer-Encoding: 7bit X-Virus-Scanned: clamav-milter 0.97.4 at gatekeeper.allbsd.org X-Virus-Status: Clean X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.7 (mail.allbsd.org [133.31.130.32]); Sun, 10 Jun 2012 23:35:28 +0900 (JST) X-Spam-Status: No, score=-98.6 required=13.0 tests=CONTENT_TYPE_PRESENT, QENCPTR2,RCVD_IN_RP_RNBL,USER_IN_WHITELIST autolearn=no version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on gatekeeper.allbsd.org Cc: wblock@wonkity.com, ae@FreeBSD.org, jhb@FreeBSD.org Subject: CFR: backup GPT header support in pmbr and loader(8) (Re: Handbook mirroring section) X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Jun 2012 14:35:37 -0000 ----Security_Multipart0(Sun_Jun_10_22_48_13_2012_513)-- Content-Type: Multipart/Mixed; boundary="--Next_Part(Sun_Jun_10_22_48_13_2012_239)--" Content-Transfer-Encoding: 7bit ----Next_Part(Sun_Jun_10_22_48_13_2012_239)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit [move from -doc@ to -current@] "Andrey V. Elsukov" wrote in <4FD05573.70801@FreeBSD.org>: ae> On 06.06.2012 15:07, Hiroki Sato wrote: ae> > ae> 1. When geom_mirror module is not loaded GEOM_PART will complain that the ae> > ae> backup GPT header is not in the last LBA and partition table will be marked ae> > ae> as CORRUPT. The recover operation will destroy the GEOM_MIRROR's metadata. ae> > ae> ae> > ae> 2. If primary GPT header or table become damaged, then gptboot will not ae> > ae> detect GPT because the backup GPT header is not in the last LBA. So, the ae> > ae> system will not boot. ae> > ae> > Thanks, I see. Do you think the attached patch is too aggressive for ae> > the problem 2? The value of altlba should be matched with one in the ae> > original secondary header when the primary header is corrupted and ae> > the secondary header is looked up in this way. ae> ae> Yes, i also have thought about this and this should work for most GEOM classes, ae> but i revised again PMBR code and it seems that it will not work anyway :) ae> Our PMBR doesn't use backup GPT header and table, and it doesn't verify ae> correctness of primary GPT. ae> ae> From the other side, there are three situations when we use GPT: ae> 1. FreeBSD is only one system on the disk and we use PMBR and gptboot to boot it. ae> ae> In case if we will fix PMBR your patch will help. I created the attached patchset for the loader and pmbr to support backup GPT header when the primary one is corrupted. Can anyone test and/or review it? The pmbr program now checks the GPT signature, and if failed it tries to search the backup header from the last LBA. When GEOM metadata is found at the last LBA, the second last will be checked. The loader(8) program also supports the same algorithm to search the backup header. ae> 2. FreeBSD is no one on the disk, but we still use legacy boot method (PMBR+gptboot). ae> ae> I don't know what behavior have other systems when they detect invalid GPT (i.e. ae> when backup header is not in the last LBA). ae> ae> 3. We use UEFI (it is not work yet). ae> ae> Also i don't know what UEFI firmware will do with invalid GPT. I am investigating how Windows and other UEFI-based software recognize the backup header now. Hopefully they use the alternative LBA field and do not unconditionally overwrite the last LBA for recovering. Probably it is difficult to make UEFI recognize the backup header that is not located at the last LBA when the primary header is corrupted. -- Hiroki ----Next_Part(Sun_Jun_10_22_48_13_2012_239)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="boot-gpt.20120610-1.diff" Index: common/gpt.c =================================================================== --- common/gpt.c (revision 236848) +++ common/gpt.c (working copy) @@ -40,6 +40,7 @@ #include "gpt.h" #define MAXTBLENTS 128 +#define GEOM_MAGIC "GEOM::" static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr; static uint64_t hdr_primary_lba, hdr_backup_lba; @@ -345,8 +346,18 @@ altlba = hdr_primary.hdr_lba_alt; } else { altlba = drvsize(dskp); - if (altlba > 0) - altlba--; + if (altlba > 0) { + do { + altlba--; + /* + * Check GEOM metadata and decrement + * the altlba if found. + */ + if (drvread(dskp, secbuf, altlba, 1) != 0) + break; + } while (memcmp(secbuf, GEOM_MAGIC, + sizeof(GEOM_MAGIC) - 1) == 0); + } } if (altlba == 0) printf("%s: unable to locate backup GPT header\n", BOOTPROG); Index: i386/pmbr/pmbr.s =================================================================== --- i386/pmbr/pmbr.s (revision 236848) +++ i386/pmbr/pmbr.s (working copy) @@ -42,8 +42,9 @@ .set STACK,EXEC+SECSIZE*4 # Stack address .set GPT_ADDR,STACK # GPT header address .set GPT_SIG,0 - .set GPT_SIG_0,0x20494645 - .set GPT_SIG_1,0x54524150 + .set GPT_SIG_0,0x20494645 # "EFI " + .set GPT_SIG_1,0x54524150 # "PART" + .set GEOM_MAGIC,0x4d4f4547 # "GEOM" .set GPT_MYLBA,24 .set GPT_PART_LBA,72 .set GPT_NPART,80 @@ -52,6 +53,8 @@ .set PART_TYPE,0 .set PART_START_LBA,32 .set PART_END_LBA,40 + .set DPBUF,PART_ADDR+SECSIZE + .set DPBUF_SEC,0x10 # Number of sectors .set NHRDRV,0x475 # Number of hard drives @@ -91,16 +94,40 @@ jb main.2 # Yes main.1: movb $0x80,%dl # Assume drive 0x80 # -# Load the primary GPT header from LBA 1 and verify signature. +# Load the GPT header and verify signature. Try LBA 1 for the primary one and +# the last LBA for the backup if it is broken. Skip the LBAs if GEOM +# metadata found at the backup location. # -main.2: movw $GPT_ADDR,%bx +main.2: call getdrvparams # Read drive parameters + movb $1,%dh # %dh := 1 (reading primary) +main.2a: movw $GPT_ADDR,%bx movw $lba,%si - call read + call read # Read header and check GPT sig cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG - jnz err_pt + jnz main.2b cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4 - jnz err_pt + jnz main.2b + jmp load_part +main.2b: cmpb $1,%dh # Reading primary? + je main.3 # Try backup if yes + cmpl $GEOM_MAGIC,GPT_ADDR # GEOM sig at backup location? + jz main.3 # Skip GEOM metadata + jmp err_pt # Invalid table found # +# Try alternative LBAs from the last sector for the GPT header. +# +main.3: movb $0,%dh # %dh := 0 (reading backup) + movw $DPBUF+DPBUF_SEC,%si # %si = last sector + 1 + movw $lba,%di # %di = $lba + cmpl $0,(%si) # + jnz main.3a # + decl 0x4(%si) # 0x4(%si) = last sec (32-64) +main.3a: decl (%si) # 0x0(%si) = last sec (0-31) + movw $2,%cx + rep + movsw # $lastsec--, copy it to $lba + jmp main.2a # Read the next sector +# # Load a partition table sector from disk and look for a FreeBSD boot # partition. # @@ -172,6 +199,16 @@ jc err_rd # If error ret # +# Check the number of LBAs on the drive index %dx. Trashes %ax and %si. +# +getdrvparams: + movw $DPBUF,%si # Set the address of result buf + movw $0x001e,(%si) # len + movw $0x4800,%ax # BIOS: Read Drive Parameters + int $0x13 # Call the BIOS + jc err_rd # "I/O error" if error + ret +# # Various error message entry points. # err_big: movw $msg_big,%si # "Boot loader too ----Next_Part(Sun_Jun_10_22_48_13_2012_239)---- ----Security_Multipart0(Sun_Jun_10_22_48_13_2012_513)-- Content-Type: application/pgp-signature Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (FreeBSD) iEUEABECAAYFAk/UpZ0ACgkQTyzT2CeTzy2EuQCYvKwHIbw1KxbtwJysEYyC9uyL 4ACdHIhJkm8atN0qobTepmZNI1GiNpM= =bJDW -----END PGP SIGNATURE----- ----Security_Multipart0(Sun_Jun_10_22_48_13_2012_513)----