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 76*3d5e12ebSAndrew Turner static struct dmadat __dmadat __aligned(512); 77*3d5e12ebSAndrew Turner static char ufs_buffer[BSD_LABEL_BUFFER] __aligned(512); 78ca987d46SWarner Losh 79ca987d46SWarner Losh static int 80ca987d46SWarner Losh init_dev(dev_info_t* dev) 81ca987d46SWarner Losh { 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 */ 112*3d5e12ebSAndrew Turner if (dskread(ufs_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) 117*3d5e12ebSAndrew Turner dl = (struct disklabel *)&ufs_buffer[bs]; 11899589326SWarner Losh if (dl == NULL || dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC) 119*3d5e12ebSAndrew Turner dl = (struct disklabel *)&ufs_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 size_t size; 144ca987d46SWarner Losh ssize_t read; 145ca987d46SWarner Losh void *buf; 146ca987d46SWarner Losh 147ca987d46SWarner Losh #ifdef EFI_DEBUG 148ca987d46SWarner Losh { 149ca987d46SWarner Losh CHAR16 *text = efi_devpath_name(dev->devpath); 150375cd3bbSWarner Losh DPRINTF("UFS Loading '%s' from %S\n", filepath, text); 151ca987d46SWarner Losh efi_free_devpath_name(text); 152ca987d46SWarner Losh } 153ca987d46SWarner Losh #endif 154ca987d46SWarner Losh if (init_dev(dev) < 0) { 155ca987d46SWarner Losh DPRINTF("Failed to init device\n"); 156ca987d46SWarner Losh return (EFI_UNSUPPORTED); 157ca987d46SWarner Losh } 158ca987d46SWarner Losh 159ca987d46SWarner Losh if ((ino = lookup(filepath)) == 0) { 160ca987d46SWarner Losh DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath); 161ca987d46SWarner Losh return (EFI_NOT_FOUND); 162ca987d46SWarner Losh } 163ca987d46SWarner Losh 164ca987d46SWarner Losh if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { 165ca987d46SWarner Losh printf("Failed to read size of '%s' ino: %d\n", filepath, ino); 166ca987d46SWarner Losh return (EFI_INVALID_PARAMETER); 167ca987d46SWarner Losh } 168ca987d46SWarner Losh 169fef7bfefSWarner Losh buf = malloc(size); 170fef7bfefSWarner Losh if (buf == NULL) { 171fef7bfefSWarner Losh printf("Failed to allocate read buffer %zu for '%s'\n", 172fef7bfefSWarner Losh size, filepath); 173fef7bfefSWarner Losh return (EFI_OUT_OF_RESOURCES); 174ca987d46SWarner Losh } 175ca987d46SWarner Losh 176ca987d46SWarner Losh read = fsread(ino, buf, size); 177ca987d46SWarner Losh if ((size_t)read != size) { 178ca987d46SWarner Losh printf("Failed to read '%s' (%zd != %zu)\n", filepath, read, 179ca987d46SWarner Losh size); 180fef7bfefSWarner Losh free(buf); 181ca987d46SWarner Losh return (EFI_INVALID_PARAMETER); 182ca987d46SWarner Losh } 183ca987d46SWarner Losh 184ca987d46SWarner Losh DPRINTF("Load complete\n"); 185ca987d46SWarner Losh 186ca987d46SWarner Losh *bufp = buf; 187ca987d46SWarner Losh *bufsize = size; 188ca987d46SWarner Losh 189ca987d46SWarner Losh return (EFI_SUCCESS); 190ca987d46SWarner Losh } 191ca987d46SWarner Losh 192ca987d46SWarner Losh static void 193ca987d46SWarner Losh status(void) 194ca987d46SWarner Losh { 195ca987d46SWarner Losh int i; 196ca987d46SWarner Losh dev_info_t *dev; 197ca987d46SWarner Losh 198ca987d46SWarner Losh for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++) 199ca987d46SWarner Losh ; 200ca987d46SWarner Losh 201ca987d46SWarner Losh printf("%s found ", ufs_module.name); 202ca987d46SWarner Losh switch (i) { 203ca987d46SWarner Losh case 0: 204ca987d46SWarner Losh printf("no partitions\n"); 205ca987d46SWarner Losh break; 206ca987d46SWarner Losh case 1: 207ca987d46SWarner Losh printf("%d partition\n", i); 208ca987d46SWarner Losh break; 209ca987d46SWarner Losh default: 210ca987d46SWarner Losh printf("%d partitions\n", i); 211ca987d46SWarner Losh } 212ca987d46SWarner Losh } 213ca987d46SWarner Losh 214ca987d46SWarner Losh static dev_info_t * 215ca987d46SWarner Losh _devices(void) 216ca987d46SWarner Losh { 217ca987d46SWarner Losh 218ca987d46SWarner Losh return (devices); 219ca987d46SWarner Losh } 220ca987d46SWarner Losh 221ca987d46SWarner Losh const boot_module_t ufs_module = 222ca987d46SWarner Losh { 223ca987d46SWarner Losh .name = "UFS", 224ca987d46SWarner Losh .probe = probe, 225ca987d46SWarner Losh .load = load, 226ca987d46SWarner Losh .status = status, 227ca987d46SWarner Losh .devices = _devices 228ca987d46SWarner Losh }; 229