1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 1998 Robert Nordier 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * Copyright (c) 2001 Robert Drehmel 5ca987d46SWarner Losh * All rights reserved. 6ca987d46SWarner Losh * Copyright (c) 2014 Nathan Whitehorn 7ca987d46SWarner Losh * All rights reserved. 8ca987d46SWarner Losh * Copyright (c) 2015 Eric McCorkle 9ca987d46SWarner Losh * All rights reverved. 10ca987d46SWarner Losh * 11ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 12ca987d46SWarner Losh * modification, are permitted provided that the following conditions 13ca987d46SWarner Losh * are met: 14ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 15ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 16ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 17ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 18ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 19ca987d46SWarner Losh * 20ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30ca987d46SWarner Losh * SUCH DAMAGE. 31ca987d46SWarner Losh * 32ca987d46SWarner Losh * $FreeBSD$ 33ca987d46SWarner Losh */ 34ca987d46SWarner Losh 35ca987d46SWarner Losh #include <stdarg.h> 36ca987d46SWarner Losh #include <stdbool.h> 37ca987d46SWarner Losh #include <sys/cdefs.h> 38ca987d46SWarner Losh #include <sys/param.h> 3999589326SWarner Losh #include <sys/disk/bsd.h> 40ca987d46SWarner Losh #include <efi.h> 41ca987d46SWarner Losh 42ca987d46SWarner Losh #include "boot_module.h" 43ca987d46SWarner Losh 4499589326SWarner Losh #define BSD_LABEL_BUFFER 8192 4599589326SWarner Losh #define BSD_LABEL_OFFSET DEV_BSIZE 4699589326SWarner Losh 47ca987d46SWarner Losh static dev_info_t *devinfo; 48ca987d46SWarner Losh static dev_info_t *devices; 49ca987d46SWarner Losh 50ca987d46SWarner Losh static int 5156e53cb8SWarner Losh dskread(void *buf, uint64_t lba, int nblk) 52ca987d46SWarner Losh { 53ca987d46SWarner Losh int size; 54ca987d46SWarner Losh EFI_STATUS status; 55ca987d46SWarner Losh 5699589326SWarner Losh lba += devinfo->partoff; 57ca987d46SWarner Losh lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE); 58ca987d46SWarner Losh size = nblk * DEV_BSIZE; 59ca987d46SWarner Losh 60ca987d46SWarner Losh status = devinfo->dev->ReadBlocks(devinfo->dev, 61ca987d46SWarner Losh devinfo->dev->Media->MediaId, lba, size, buf); 62ca987d46SWarner Losh 63ca987d46SWarner Losh if (status != EFI_SUCCESS) { 64ca987d46SWarner Losh DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, " 65ca987d46SWarner Losh "status: %lu\n", devinfo->dev, 66ca987d46SWarner Losh devinfo->dev->Media->MediaId, (uintmax_t)lba, size, 67ca987d46SWarner Losh EFI_ERROR_CODE(status)); 68ca987d46SWarner Losh return (-1); 69ca987d46SWarner Losh } 70ca987d46SWarner Losh 71ca987d46SWarner Losh return (0); 72ca987d46SWarner Losh } 73ca987d46SWarner Losh 74ca987d46SWarner Losh #include "ufsread.c" 75ca987d46SWarner Losh 76ca987d46SWarner Losh static struct dmadat __dmadat; 77ca987d46SWarner Losh 78ca987d46SWarner Losh static int 79ca987d46SWarner Losh init_dev(dev_info_t* dev) 80ca987d46SWarner Losh { 8199589326SWarner Losh char buffer[BSD_LABEL_BUFFER]; 8299589326SWarner Losh struct disklabel *dl; 8399589326SWarner Losh uint64_t bs; 8499589326SWarner Losh int ok; 85ca987d46SWarner Losh 86ca987d46SWarner Losh devinfo = dev; 87ca987d46SWarner Losh dmadat = &__dmadat; 88ca987d46SWarner Losh 8999589326SWarner Losh /* 9099589326SWarner Losh * First try offset 0. This is the typical GPT case where we have no 9199589326SWarner Losh * further partitioning (as well as the degenerate MBR case where 9299589326SWarner Losh * the bsdlabel has a 0 offset). 9399589326SWarner Losh */ 9499589326SWarner Losh devinfo->partoff = 0; 9599589326SWarner Losh ok = fsread(0, NULL, 0); 9699589326SWarner Losh if (ok >= 0) 9799589326SWarner Losh return (ok); 9899589326SWarner Losh 9999589326SWarner Losh /* 10099589326SWarner Losh * Next, we look for a bsdlabel. This is technically located in sector 10199589326SWarner Losh * 1. For 4k sectors, this offset is 4096, for 512b sectors it's 10299589326SWarner Losh * 512. However, we have to fall back to 512 here because we create 10399589326SWarner Losh * images that assume 512 byte blocks, but these can be put on devices 10499589326SWarner Losh * who have 4k (or other) block sizes. If there's a crazy block size, we 10599589326SWarner Losh * skip the 'at one sector' and go stright to checking at 512 bytes. 10699589326SWarner Losh * There are other offsets that are historic, but we don't probe those 10799589326SWarner Losh * since they were never used for MBR disks on FreeBSD on systems that 10899589326SWarner Losh * could boot UEFI. UEFI is little endian only, as are BSD labels. We 10999589326SWarner Losh * will retry fsread(0) only if there's a label found with a non-zero 11099589326SWarner Losh * offset. 11199589326SWarner Losh */ 11299589326SWarner Losh if (dskread(buffer, 0, BSD_LABEL_BUFFER / DEV_BSIZE) != 0) 11399589326SWarner Losh return (-1); 11499589326SWarner Losh dl = NULL; 11599589326SWarner Losh bs = devinfo->dev->Media->BlockSize; 11699589326SWarner Losh if (bs != 0 && bs <= BSD_LABEL_BUFFER / 2) 11799589326SWarner Losh dl = (struct disklabel *)&buffer[bs]; 11899589326SWarner Losh if (dl == NULL || dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC) 11999589326SWarner Losh dl = (struct disklabel *)&buffer[BSD_LABEL_OFFSET]; 12099589326SWarner Losh if (dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC || 12199589326SWarner Losh dl->d_partitions[0].p_offset == 0) 12299589326SWarner Losh return (-1); 12399589326SWarner Losh devinfo->partoff = dl->d_partitions[0].p_offset; 12499589326SWarner Losh return (fsread(0, NULL, 0)); 125ca987d46SWarner Losh } 126ca987d46SWarner Losh 127ca987d46SWarner Losh static EFI_STATUS 128ca987d46SWarner Losh probe(dev_info_t* dev) 129ca987d46SWarner Losh { 130ca987d46SWarner Losh 131ca987d46SWarner Losh if (init_dev(dev) < 0) 132ca987d46SWarner Losh return (EFI_UNSUPPORTED); 133ca987d46SWarner Losh 134ca987d46SWarner Losh add_device(&devices, dev); 135ca987d46SWarner Losh 136ca987d46SWarner Losh return (EFI_SUCCESS); 137ca987d46SWarner Losh } 138ca987d46SWarner Losh 139ca987d46SWarner Losh static EFI_STATUS 140ca987d46SWarner Losh load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize) 141ca987d46SWarner Losh { 142ca987d46SWarner Losh ufs_ino_t ino; 143ca987d46SWarner Losh EFI_STATUS status; 144ca987d46SWarner Losh size_t size; 145ca987d46SWarner Losh ssize_t read; 146ca987d46SWarner Losh void *buf; 147ca987d46SWarner Losh 148ca987d46SWarner Losh #ifdef EFI_DEBUG 149ca987d46SWarner Losh { 150ca987d46SWarner Losh CHAR16 *text = efi_devpath_name(dev->devpath); 151*375cd3bbSWarner Losh DPRINTF("UFS Loading '%s' from %S\n", filepath, text); 152ca987d46SWarner Losh efi_free_devpath_name(text); 153ca987d46SWarner Losh } 154ca987d46SWarner Losh #endif 155ca987d46SWarner Losh if (init_dev(dev) < 0) { 156ca987d46SWarner Losh DPRINTF("Failed to init device\n"); 157ca987d46SWarner Losh return (EFI_UNSUPPORTED); 158ca987d46SWarner Losh } 159ca987d46SWarner Losh 160ca987d46SWarner Losh if ((ino = lookup(filepath)) == 0) { 161ca987d46SWarner Losh DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath); 162ca987d46SWarner Losh return (EFI_NOT_FOUND); 163ca987d46SWarner Losh } 164ca987d46SWarner Losh 165ca987d46SWarner Losh if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { 166ca987d46SWarner Losh printf("Failed to read size of '%s' ino: %d\n", filepath, ino); 167ca987d46SWarner Losh return (EFI_INVALID_PARAMETER); 168ca987d46SWarner Losh } 169ca987d46SWarner Losh 170ca987d46SWarner Losh if ((status = BS->AllocatePool(EfiLoaderData, size, &buf)) != 171ca987d46SWarner Losh EFI_SUCCESS) { 172ca987d46SWarner Losh printf("Failed to allocate read buffer %zu for '%s' (%lu)\n", 173ca987d46SWarner Losh size, filepath, EFI_ERROR_CODE(status)); 174ca987d46SWarner Losh return (status); 175ca987d46SWarner Losh } 176ca987d46SWarner Losh 177ca987d46SWarner Losh read = fsread(ino, buf, size); 178ca987d46SWarner Losh if ((size_t)read != size) { 179ca987d46SWarner Losh printf("Failed to read '%s' (%zd != %zu)\n", filepath, read, 180ca987d46SWarner Losh size); 181ca987d46SWarner Losh (void)BS->FreePool(buf); 182ca987d46SWarner Losh return (EFI_INVALID_PARAMETER); 183ca987d46SWarner Losh } 184ca987d46SWarner Losh 185ca987d46SWarner Losh DPRINTF("Load complete\n"); 186ca987d46SWarner Losh 187ca987d46SWarner Losh *bufp = buf; 188ca987d46SWarner Losh *bufsize = size; 189ca987d46SWarner Losh 190ca987d46SWarner Losh return (EFI_SUCCESS); 191ca987d46SWarner Losh } 192ca987d46SWarner Losh 193ca987d46SWarner Losh static void 194ca987d46SWarner Losh status(void) 195ca987d46SWarner Losh { 196ca987d46SWarner Losh int i; 197ca987d46SWarner Losh dev_info_t *dev; 198ca987d46SWarner Losh 199ca987d46SWarner Losh for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++) 200ca987d46SWarner Losh ; 201ca987d46SWarner Losh 202ca987d46SWarner Losh printf("%s found ", ufs_module.name); 203ca987d46SWarner Losh switch (i) { 204ca987d46SWarner Losh case 0: 205ca987d46SWarner Losh printf("no partitions\n"); 206ca987d46SWarner Losh break; 207ca987d46SWarner Losh case 1: 208ca987d46SWarner Losh printf("%d partition\n", i); 209ca987d46SWarner Losh break; 210ca987d46SWarner Losh default: 211ca987d46SWarner Losh printf("%d partitions\n", i); 212ca987d46SWarner Losh } 213ca987d46SWarner Losh } 214ca987d46SWarner Losh 215ca987d46SWarner Losh static dev_info_t * 216ca987d46SWarner Losh _devices(void) 217ca987d46SWarner Losh { 218ca987d46SWarner Losh 219ca987d46SWarner Losh return (devices); 220ca987d46SWarner Losh } 221ca987d46SWarner Losh 222ca987d46SWarner Losh const boot_module_t ufs_module = 223ca987d46SWarner Losh { 224ca987d46SWarner Losh .name = "UFS", 225ca987d46SWarner Losh .probe = probe, 226ca987d46SWarner Losh .load = load, 227ca987d46SWarner Losh .status = status, 228ca987d46SWarner Losh .devices = _devices 229ca987d46SWarner Losh }; 230