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