diff options
author | Warner Losh <imp@FreeBSD.org> | 2018-05-29 03:58:29 +0000 |
---|---|---|
committer | Warner Losh <imp@FreeBSD.org> | 2018-05-29 03:58:29 +0000 |
commit | 9958932695e95d4f42bbe98a4acd2f84efb4ccb0 (patch) | |
tree | 40f82a49c2d88cd6cd97129f6790a454b8a303fd /stand/efi/boot1 | |
parent | 23d2383783ad04ff89f3c63354e0b28bd457a05b (diff) | |
download | src-9958932695e95d4f42bbe98a4acd2f84efb4ccb0.tar.gz src-9958932695e95d4f42bbe98a4acd2f84efb4ccb0.zip |
Teach ufs_module.c about bsd labels and probe 'a' partition.
If the check for a UFS partition at offset 0 on the disk fails, check
to see if there's a BSD disklabel at block 1 (standard) or at offset
512 (install images assume 512 sector size). If found, probe for UFS
on the 'a' partition.
This fixes UEFI booting images from a BSD labeled MBR slice when the
'a' partiton isn't at offset 0. This is a stop-gap fix since we plan
on removing boot1.efi in FreeBSD 12. We can't easily do that for 11.2,
however, hence the short MFC window.
Tested by: emaste@
MFC After: 3 days
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D15598
Notes
Notes:
svn path=/head/; revision=334310
Diffstat (limited to 'stand/efi/boot1')
-rw-r--r-- | stand/efi/boot1/boot_module.h | 1 | ||||
-rw-r--r-- | stand/efi/boot1/ufs_module.c | 46 |
2 files changed, 46 insertions, 1 deletions
diff --git a/stand/efi/boot1/boot_module.h b/stand/efi/boot1/boot_module.h index bfade34fe9cb..891694ee101d 100644 --- a/stand/efi/boot1/boot_module.h +++ b/stand/efi/boot1/boot_module.h @@ -50,6 +50,7 @@ typedef struct dev_info EFI_DEVICE_PATH *devpath; EFI_HANDLE *devhandle; void *devdata; + uint64_t partoff; BOOLEAN preferred; struct dev_info *next; } dev_info_t; diff --git a/stand/efi/boot1/ufs_module.c b/stand/efi/boot1/ufs_module.c index 76c15e41b8d5..af50d9217452 100644 --- a/stand/efi/boot1/ufs_module.c +++ b/stand/efi/boot1/ufs_module.c @@ -36,10 +36,14 @@ #include <stdbool.h> #include <sys/cdefs.h> #include <sys/param.h> +#include <sys/disk/bsd.h> #include <efi.h> #include "boot_module.h" +#define BSD_LABEL_BUFFER 8192 +#define BSD_LABEL_OFFSET DEV_BSIZE + static dev_info_t *devinfo; static dev_info_t *devices; @@ -49,6 +53,7 @@ dskread(void *buf, uint64_t lba, int nblk) int size; EFI_STATUS status; + lba += devinfo->partoff; lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE); size = nblk * DEV_BSIZE; @@ -73,11 +78,50 @@ static struct dmadat __dmadat; static int init_dev(dev_info_t* dev) { + char buffer[BSD_LABEL_BUFFER]; + struct disklabel *dl; + uint64_t bs; + int ok; devinfo = dev; dmadat = &__dmadat; - return fsread(0, NULL, 0); + /* + * First try offset 0. This is the typical GPT case where we have no + * further partitioning (as well as the degenerate MBR case where + * the bsdlabel has a 0 offset). + */ + devinfo->partoff = 0; + ok = fsread(0, NULL, 0); + if (ok >= 0) + return (ok); + + /* + * Next, we look for a bsdlabel. This is technically located in sector + * 1. For 4k sectors, this offset is 4096, for 512b sectors it's + * 512. However, we have to fall back to 512 here because we create + * images that assume 512 byte blocks, but these can be put on devices + * who have 4k (or other) block sizes. If there's a crazy block size, we + * skip the 'at one sector' and go stright to checking at 512 bytes. + * There are other offsets that are historic, but we don't probe those + * since they were never used for MBR disks on FreeBSD on systems that + * could boot UEFI. UEFI is little endian only, as are BSD labels. We + * will retry fsread(0) only if there's a label found with a non-zero + * offset. + */ + if (dskread(buffer, 0, BSD_LABEL_BUFFER / DEV_BSIZE) != 0) + return (-1); + dl = NULL; + bs = devinfo->dev->Media->BlockSize; + if (bs != 0 && bs <= BSD_LABEL_BUFFER / 2) + dl = (struct disklabel *)&buffer[bs]; + if (dl == NULL || dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC) + dl = (struct disklabel *)&buffer[BSD_LABEL_OFFSET]; + if (dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC || + dl->d_partitions[0].p_offset == 0) + return (-1); + devinfo->partoff = dl->d_partitions[0].p_offset; + return (fsread(0, NULL, 0)); } static EFI_STATUS |