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 33 #include <stdarg.h> 34 #include <stdbool.h> 35 36 #include <sys/param.h> 37 #include <sys/disk/bsd.h> 38 #include <efi.h> 39 40 #include "boot_module.h" 41 42 #define BSD_LABEL_BUFFER 8192 43 #define BSD_LABEL_OFFSET DEV_BSIZE 44 45 static dev_info_t *devinfo; 46 static dev_info_t *devices; 47 48 static int 49 dskread(void *buf, uint64_t lba, int nblk) 50 { 51 int size; 52 EFI_STATUS status; 53 54 lba += devinfo->partoff; 55 lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE); 56 size = nblk * DEV_BSIZE; 57 58 status = devinfo->dev->ReadBlocks(devinfo->dev, 59 devinfo->dev->Media->MediaId, lba, size, buf); 60 61 if (status != EFI_SUCCESS) { 62 DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, " 63 "status: %lu\n", devinfo->dev, 64 devinfo->dev->Media->MediaId, (uintmax_t)lba, size, 65 EFI_ERROR_CODE(status)); 66 return (-1); 67 } 68 69 return (0); 70 } 71 72 #include "ufsread.c" 73 74 static struct dmadat __dmadat __aligned(512); 75 static char ufs_buffer[BSD_LABEL_BUFFER] __aligned(512); 76 77 static int 78 init_dev(dev_info_t* dev) 79 { 80 struct disklabel *dl; 81 uint64_t bs; 82 int ok; 83 84 devinfo = dev; 85 dmadat = &__dmadat; 86 87 /* 88 * First try offset 0. This is the typical GPT case where we have no 89 * further partitioning (as well as the degenerate MBR case where 90 * the bsdlabel has a 0 offset). 91 */ 92 devinfo->partoff = 0; 93 ok = fsread(0, NULL, 0); 94 if (ok >= 0) 95 return (ok); 96 97 /* 98 * Next, we look for a bsdlabel. This is technically located in sector 99 * 1. For 4k sectors, this offset is 4096, for 512b sectors it's 100 * 512. However, we have to fall back to 512 here because we create 101 * images that assume 512 byte blocks, but these can be put on devices 102 * who have 4k (or other) block sizes. If there's a crazy block size, we 103 * skip the 'at one sector' and go stright to checking at 512 bytes. 104 * There are other offsets that are historic, but we don't probe those 105 * since they were never used for MBR disks on FreeBSD on systems that 106 * could boot UEFI. UEFI is little endian only, as are BSD labels. We 107 * will retry fsread(0) only if there's a label found with a non-zero 108 * offset. 109 */ 110 if (dskread(ufs_buffer, 0, BSD_LABEL_BUFFER / DEV_BSIZE) != 0) 111 return (-1); 112 dl = NULL; 113 bs = devinfo->dev->Media->BlockSize; 114 if (bs != 0 && bs <= BSD_LABEL_BUFFER / 2) 115 dl = (struct disklabel *)&ufs_buffer[bs]; 116 if (dl == NULL || dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC) 117 dl = (struct disklabel *)&ufs_buffer[BSD_LABEL_OFFSET]; 118 if (dl->d_magic != BSD_MAGIC || dl->d_magic2 != BSD_MAGIC || 119 dl->d_partitions[0].p_offset == 0) 120 return (-1); 121 devinfo->partoff = dl->d_partitions[0].p_offset; 122 return (fsread(0, NULL, 0)); 123 } 124 125 static EFI_STATUS 126 probe(dev_info_t* dev) 127 { 128 129 if (init_dev(dev) < 0) 130 return (EFI_UNSUPPORTED); 131 132 add_device(&devices, dev); 133 134 return (EFI_SUCCESS); 135 } 136 137 static EFI_STATUS 138 load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize) 139 { 140 ufs_ino_t ino; 141 size_t size; 142 ssize_t read; 143 void *buf; 144 145 #ifdef EFI_DEBUG 146 { 147 CHAR16 *text = efi_devpath_name(dev->devpath); 148 DPRINTF("UFS Loading '%s' from %S\n", filepath, text); 149 efi_free_devpath_name(text); 150 } 151 #endif 152 if (init_dev(dev) < 0) { 153 DPRINTF("Failed to init device\n"); 154 return (EFI_UNSUPPORTED); 155 } 156 157 if ((ino = lookup(filepath)) == 0) { 158 DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath); 159 return (EFI_NOT_FOUND); 160 } 161 162 if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { 163 printf("Failed to read size of '%s' ino: %d\n", filepath, ino); 164 return (EFI_INVALID_PARAMETER); 165 } 166 167 buf = malloc(size); 168 if (buf == NULL) { 169 printf("Failed to allocate read buffer %zu for '%s'\n", 170 size, filepath); 171 return (EFI_OUT_OF_RESOURCES); 172 } 173 174 read = fsread(ino, buf, size); 175 if ((size_t)read != size) { 176 printf("Failed to read '%s' (%zd != %zu)\n", filepath, read, 177 size); 178 free(buf); 179 return (EFI_INVALID_PARAMETER); 180 } 181 182 DPRINTF("Load complete\n"); 183 184 *bufp = buf; 185 *bufsize = size; 186 187 return (EFI_SUCCESS); 188 } 189 190 static void 191 status(void) 192 { 193 int i; 194 dev_info_t *dev; 195 196 for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++) 197 ; 198 199 printf("%s found ", ufs_module.name); 200 switch (i) { 201 case 0: 202 printf("no partitions\n"); 203 break; 204 case 1: 205 printf("%d partition\n", i); 206 break; 207 default: 208 printf("%d partitions\n", i); 209 } 210 } 211 212 static dev_info_t * 213 _devices(void) 214 { 215 216 return (devices); 217 } 218 219 const boot_module_t ufs_module = 220 { 221 .name = "UFS", 222 .probe = probe, 223 .load = load, 224 .status = status, 225 .devices = _devices 226 }; 227