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