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