1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/crc32.h> 28 #include <sys/cred.h> 29 #include <sys/ddi.h> 30 #include <sys/dkio.h> 31 #include <sys/file.h> 32 #include <sys/kmem.h> 33 #include <sys/sunddi.h> 34 #include <sys/sunldi.h> 35 #include <sys/types.h> 36 #include <sys/varargs.h> 37 #include <sys/vtoc.h> 38 39 #include <sys/vdsk_common.h> 40 41 /* 42 * Hooks for EFI support 43 */ 44 45 /* 46 * This code provides generic functions to the vds and vdc drivers to read 47 * EFI labels from the disk backend and to get the EFI GPT and GPE. This is 48 * inspired from the libefi userland library and the cmlb driver. We will 49 * certainly be able to remove that code if RFE 6213117 is ever implemented. 50 */ 51 52 #ifdef DEBUG 53 54 #define VD_EFI_DEBUG if (vd_efi_debug) vd_efi_print 55 56 static int vd_efi_debug = 0; 57 58 #else 59 60 #define VD_EFI_DEBUG(...) 61 62 #endif 63 64 #define VD_EFI_GPE_LEN(vdisk, nparts) \ 65 ((((sizeof (efi_gpe_t) * (nparts) - 1) / (vdisk)->block_size) + 1) * \ 66 (vdisk)->block_size) 67 68 static void 69 vd_efi_print(const char *format, ...) 70 { 71 va_list args; 72 73 va_start(args, format); 74 vcmn_err(CE_CONT, format, args); 75 va_end(args); 76 } 77 78 /* 79 * Return a 32-bit CRC of the contents of the buffer. 80 * 81 * The seed is 0xffffffff and the result is XORed with 0xffffffff 82 * because this is what the Itanium firmware expects. 83 */ 84 unsigned int 85 vd_efi_crc32(const unsigned char *s, unsigned int len) 86 { 87 unsigned int crc32val; 88 89 CRC32(crc32val, s, len, -1U, crc32_table); 90 91 return (crc32val ^ -1U); 92 } 93 94 static int 95 vd_efi_ioctl(vd_efi_dev_t *dev, int cmd, void *arg) 96 { 97 int status; 98 99 ASSERT(dev->vdisk_ioctl != NULL); 100 ASSERT(dev->vdisk != NULL); 101 status = (*dev->vdisk_ioctl)(dev->vdisk, cmd, (uintptr_t)arg); 102 103 return (status); 104 } 105 106 /* 107 * Swap GPT data to match with the system endianness. 108 */ 109 static void 110 vd_efi_swap_gpt(efi_gpt_t *gpt) 111 { 112 gpt->efi_gpt_Signature = LE_64(gpt->efi_gpt_Signature); 113 gpt->efi_gpt_Revision = LE_32(gpt->efi_gpt_Revision); 114 gpt->efi_gpt_HeaderSize = LE_32(gpt->efi_gpt_HeaderSize); 115 gpt->efi_gpt_HeaderCRC32 = LE_32(gpt->efi_gpt_HeaderCRC32); 116 gpt->efi_gpt_MyLBA = LE_64(gpt->efi_gpt_MyLBA); 117 gpt->efi_gpt_AlternateLBA = LE_64(gpt->efi_gpt_AlternateLBA); 118 gpt->efi_gpt_FirstUsableLBA = LE_64(gpt->efi_gpt_FirstUsableLBA); 119 gpt->efi_gpt_LastUsableLBA = LE_64(gpt->efi_gpt_LastUsableLBA); 120 UUID_LE_CONVERT(gpt->efi_gpt_DiskGUID, gpt->efi_gpt_DiskGUID); 121 gpt->efi_gpt_PartitionEntryLBA = LE_64(gpt->efi_gpt_PartitionEntryLBA); 122 gpt->efi_gpt_NumberOfPartitionEntries = 123 LE_32(gpt->efi_gpt_NumberOfPartitionEntries); 124 gpt->efi_gpt_SizeOfPartitionEntry = 125 LE_32(gpt->efi_gpt_SizeOfPartitionEntry); 126 gpt->efi_gpt_PartitionEntryArrayCRC32 = 127 LE_32(gpt->efi_gpt_PartitionEntryArrayCRC32); 128 } 129 130 /* 131 * Swap GPE data to match with the system endianness. 132 */ 133 static void 134 vd_efi_swap_gpe(efi_gpe_t *gpe, int nparts) 135 { 136 int i, j; 137 138 for (i = 0; i < nparts; i++) { 139 UUID_LE_CONVERT(gpe[i].efi_gpe_PartitionTypeGUID, 140 gpe[i].efi_gpe_PartitionTypeGUID); 141 UUID_LE_CONVERT(gpe[i].efi_gpe_UniquePartitionGUID, 142 gpe[i].efi_gpe_UniquePartitionGUID); 143 gpe[i].efi_gpe_StartingLBA = LE_64(gpe[i].efi_gpe_StartingLBA); 144 gpe[i].efi_gpe_EndingLBA = LE_64(gpe[i].efi_gpe_EndingLBA); 145 gpe[i].efi_gpe_Attributes.PartitionAttrs = 146 LE_16(gpe[i].efi_gpe_Attributes.PartitionAttrs); 147 for (j = 0; j < EFI_PART_NAME_LEN; j++) { 148 gpe[i].efi_gpe_PartitionName[j] = 149 LE_16(gpe[i].efi_gpe_PartitionName[j]); 150 } 151 } 152 } 153 154 /* 155 * Check that an EFI GPT is valid. This function should be called with a raw 156 * EFI GPT i.e. GPT data should be in little endian format as indicated in the 157 * EFI specification and they should not have been swapped to match with the 158 * system endianness. 159 */ 160 static int 161 vd_efi_check_gpt(vd_efi_dev_t *dev, efi_gpt_t *gpt) 162 { 163 uint_t crc_stored, crc_computed; 164 165 if (gpt->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) { 166 VD_EFI_DEBUG("Bad EFI signature: 0x%llx != 0x%llx\n", 167 (long long)gpt->efi_gpt_Signature, 168 (long long)LE_64(EFI_SIGNATURE)); 169 return (EINVAL); 170 } 171 172 /* 173 * check CRC of the header; the size of the header should 174 * never be larger than one block 175 */ 176 if (LE_32(gpt->efi_gpt_HeaderSize) > dev->block_size) { 177 VD_EFI_DEBUG("Header size (%u bytes) larger than one block" 178 "(%u bytes)\n", LE_32(gpt->efi_gpt_HeaderSize), 179 dev->block_size); 180 return (EINVAL); 181 } 182 183 crc_stored = LE_32(gpt->efi_gpt_HeaderCRC32); 184 gpt->efi_gpt_HeaderCRC32 = LE_32(0); 185 crc_computed = vd_efi_crc32((unsigned char *)gpt, 186 LE_32(gpt->efi_gpt_HeaderSize)); 187 gpt->efi_gpt_HeaderCRC32 = LE_32(crc_stored); 188 189 if (crc_stored != crc_computed) { 190 VD_EFI_DEBUG("Bad EFI CRC: 0x%x != 0x%x\n", 191 crc_stored, crc_computed); 192 return (EINVAL); 193 } 194 195 return (0); 196 } 197 198 /* 199 * Allocate and read the EFI GPT and GPE from the disk backend. Note that the 200 * on-disk GPT and GPE are stored in little endian format but this function 201 * returns them using the endianness of the system so that any field in the 202 * GPT/GPE structures can be directly accessible without any further conversion. 203 * The caller is responsible for freeing the allocated structures by calling 204 * vd_efi_free(). 205 */ 206 int 207 vd_efi_alloc_and_read(vd_efi_dev_t *dev, efi_gpt_t **efi_gpt, 208 efi_gpe_t **efi_gpe) 209 { 210 dk_efi_t dk_efi; 211 efi_gpt_t *gpt = NULL; 212 efi_gpe_t *gpe = NULL; 213 size_t gpt_len, gpe_len; 214 int nparts, status; 215 216 ASSERT(dev->block_size >= sizeof (efi_gpt_t)); 217 gpt_len = dev->block_size; 218 gpt = kmem_zalloc(gpt_len, KM_SLEEP); 219 220 /* 221 * Read the EFI GPT. 222 */ 223 dk_efi.dki_lba = 1; 224 dk_efi.dki_data = gpt; 225 dk_efi.dki_length = gpt_len; 226 227 if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 228 VD_EFI_DEBUG("DKIOCGETEFI (GPT, LBA=1) error %d\n", status); 229 goto errdone; 230 } 231 232 if ((status = vd_efi_check_gpt(dev, gpt)) != 0) { 233 /* 234 * No valid label here; try the alternate. The alternate GPT is 235 * located in the last block of the disk. 236 */ 237 dk_efi.dki_lba = dev->disk_size - 1; 238 dk_efi.dki_data = gpt; 239 dk_efi.dki_length = gpt_len; 240 241 if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 242 VD_EFI_DEBUG("DKIOCGETEFI (LBA=%lu) error %d\n", 243 dev->disk_size - 1, status); 244 goto errdone; 245 } 246 247 if ((status = vd_efi_check_gpt(dev, gpt)) != 0) 248 goto errdone; 249 250 VD_EFI_DEBUG("efi_read: primary label corrupt; using backup\n"); 251 } 252 253 /* swap GPT data after checking the GPT is valid */ 254 vd_efi_swap_gpt(gpt); 255 256 /* 257 * Read the EFI GPE. 258 */ 259 nparts = gpt->efi_gpt_NumberOfPartitionEntries; 260 261 if (nparts > NDKMAP + 1) { 262 VD_EFI_DEBUG("Too many EFI partitions (%u)", nparts); 263 status = EINVAL; 264 goto errdone; 265 } 266 267 if (nparts == 0) { 268 VD_EFI_DEBUG("No partition defined"); 269 status = EINVAL; 270 goto errdone; 271 } 272 273 gpe_len = VD_EFI_GPE_LEN(dev, nparts); 274 gpe = kmem_zalloc(gpe_len, KM_SLEEP); 275 276 dk_efi.dki_lba = gpt->efi_gpt_PartitionEntryLBA; 277 dk_efi.dki_data = (efi_gpt_t *)gpe; 278 dk_efi.dki_length = gpe_len; 279 280 if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 281 VD_EFI_DEBUG("DKIOCGETEFI (GPE, LBA=%lu) error %d\n", 282 gpt->efi_gpt_PartitionEntryLBA, status); 283 goto errdone; 284 } 285 286 vd_efi_swap_gpe(gpe, nparts); 287 288 *efi_gpt = gpt; 289 *efi_gpe = gpe; 290 291 return (0); 292 293 errdone: 294 295 if (gpe != NULL) 296 kmem_free(gpe, gpe_len); 297 if (gpt != NULL) 298 kmem_free(gpt, gpt_len); 299 300 return (status); 301 } 302 303 /* 304 * Free the EFI GPE and GPT structures returned by vd_efi_alloc_and_read(). 305 */ 306 void 307 vd_efi_free(vd_efi_dev_t *dev, efi_gpt_t *gpt, efi_gpe_t *gpe) 308 { 309 kmem_free(gpe, VD_EFI_GPE_LEN(dev, 310 gpt->efi_gpt_NumberOfPartitionEntries)); 311 kmem_free(gpt, dev->block_size); 312 } 313