14bac2208Snarayan /* 24bac2208Snarayan * CDDL HEADER START 34bac2208Snarayan * 44bac2208Snarayan * The contents of this file are subject to the terms of the 54bac2208Snarayan * Common Development and Distribution License (the "License"). 64bac2208Snarayan * You may not use this file except in compliance with the License. 74bac2208Snarayan * 84bac2208Snarayan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94bac2208Snarayan * or http://www.opensolaris.org/os/licensing. 104bac2208Snarayan * See the License for the specific language governing permissions 114bac2208Snarayan * and limitations under the License. 124bac2208Snarayan * 134bac2208Snarayan * When distributing Covered Code, include this CDDL HEADER in each 144bac2208Snarayan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154bac2208Snarayan * If applicable, add the following below this CDDL HEADER, with the 164bac2208Snarayan * fields enclosed by brackets "[]" replaced with your own identifying 174bac2208Snarayan * information: Portions Copyright [yyyy] [name of copyright owner] 184bac2208Snarayan * 194bac2208Snarayan * CDDL HEADER END 204bac2208Snarayan */ 214bac2208Snarayan 224bac2208Snarayan /* 23*d84f0041SAlexandre Chartre * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 244bac2208Snarayan * Use is subject to license terms. 254bac2208Snarayan */ 264bac2208Snarayan 274bac2208Snarayan #include <sys/crc32.h> 284bac2208Snarayan #include <sys/cred.h> 294bac2208Snarayan #include <sys/ddi.h> 304bac2208Snarayan #include <sys/dkio.h> 314bac2208Snarayan #include <sys/file.h> 324bac2208Snarayan #include <sys/kmem.h> 334bac2208Snarayan #include <sys/sunddi.h> 344bac2208Snarayan #include <sys/sunldi.h> 354bac2208Snarayan #include <sys/types.h> 364bac2208Snarayan #include <sys/varargs.h> 374bac2208Snarayan #include <sys/vtoc.h> 384bac2208Snarayan 394bac2208Snarayan #include <sys/vdsk_common.h> 404bac2208Snarayan 414bac2208Snarayan /* 424bac2208Snarayan * Hooks for EFI support 434bac2208Snarayan */ 444bac2208Snarayan 454bac2208Snarayan /* 46edcc0754Sachartre * This code provides generic functions to the vds and vdc drivers to read 47edcc0754Sachartre * EFI labels from the disk backend and to get the EFI GPT and GPE. This is 48edcc0754Sachartre * inspired from the libefi userland library and the cmlb driver. We will 49edcc0754Sachartre * certainly be able to remove that code if RFE 6213117 is ever implemented. 504bac2208Snarayan */ 514bac2208Snarayan 5211f54b6eSAlexandre Chartre #ifdef DEBUG 5311f54b6eSAlexandre Chartre 544bac2208Snarayan #define VD_EFI_DEBUG if (vd_efi_debug) vd_efi_print 554bac2208Snarayan 56edcc0754Sachartre static int vd_efi_debug = 0; 5711f54b6eSAlexandre Chartre 5811f54b6eSAlexandre Chartre #else 5911f54b6eSAlexandre Chartre 6011f54b6eSAlexandre Chartre #define VD_EFI_DEBUG(...) 6111f54b6eSAlexandre Chartre 62edcc0754Sachartre #endif 634bac2208Snarayan 64edcc0754Sachartre #define VD_EFI_GPE_LEN(vdisk, nparts) \ 65edcc0754Sachartre ((((sizeof (efi_gpe_t) * (nparts) - 1) / (vdisk)->block_size) + 1) * \ 66edcc0754Sachartre (vdisk)->block_size) 674bac2208Snarayan 684bac2208Snarayan static void 694bac2208Snarayan vd_efi_print(const char *format, ...) 704bac2208Snarayan { 714bac2208Snarayan va_list args; 724bac2208Snarayan 734bac2208Snarayan va_start(args, format); 744bac2208Snarayan vcmn_err(CE_CONT, format, args); 754bac2208Snarayan va_end(args); 764bac2208Snarayan } 774bac2208Snarayan 784bac2208Snarayan /* 794bac2208Snarayan * Return a 32-bit CRC of the contents of the buffer. 804bac2208Snarayan * 814bac2208Snarayan * The seed is 0xffffffff and the result is XORed with 0xffffffff 824bac2208Snarayan * because this is what the Itanium firmware expects. 834bac2208Snarayan */ 844bac2208Snarayan unsigned int 854bac2208Snarayan vd_efi_crc32(const unsigned char *s, unsigned int len) 864bac2208Snarayan { 874bac2208Snarayan unsigned int crc32val; 884bac2208Snarayan 894bac2208Snarayan CRC32(crc32val, s, len, -1U, crc32_table); 904bac2208Snarayan 914bac2208Snarayan return (crc32val ^ -1U); 924bac2208Snarayan } 934bac2208Snarayan 944bac2208Snarayan static int 95edcc0754Sachartre vd_efi_ioctl(vd_efi_dev_t *dev, int cmd, void *arg) 964bac2208Snarayan { 974bac2208Snarayan int status; 984bac2208Snarayan 99edcc0754Sachartre ASSERT(dev->vdisk_ioctl != NULL); 100edcc0754Sachartre ASSERT(dev->vdisk != NULL); 101edcc0754Sachartre status = (*dev->vdisk_ioctl)(dev->vdisk, cmd, (uintptr_t)arg); 1024bac2208Snarayan 103edcc0754Sachartre return (status); 104edcc0754Sachartre } 105edcc0754Sachartre 106edcc0754Sachartre /* 107edcc0754Sachartre * Swap GPT data to match with the system endianness. 108edcc0754Sachartre */ 109edcc0754Sachartre static void 110edcc0754Sachartre vd_efi_swap_gpt(efi_gpt_t *gpt) 111edcc0754Sachartre { 112edcc0754Sachartre gpt->efi_gpt_Signature = LE_64(gpt->efi_gpt_Signature); 113edcc0754Sachartre gpt->efi_gpt_Revision = LE_32(gpt->efi_gpt_Revision); 114edcc0754Sachartre gpt->efi_gpt_HeaderSize = LE_32(gpt->efi_gpt_HeaderSize); 115edcc0754Sachartre gpt->efi_gpt_HeaderCRC32 = LE_32(gpt->efi_gpt_HeaderCRC32); 116edcc0754Sachartre gpt->efi_gpt_MyLBA = LE_64(gpt->efi_gpt_MyLBA); 117edcc0754Sachartre gpt->efi_gpt_AlternateLBA = LE_64(gpt->efi_gpt_AlternateLBA); 118edcc0754Sachartre gpt->efi_gpt_FirstUsableLBA = LE_64(gpt->efi_gpt_FirstUsableLBA); 119edcc0754Sachartre gpt->efi_gpt_LastUsableLBA = LE_64(gpt->efi_gpt_LastUsableLBA); 120edcc0754Sachartre UUID_LE_CONVERT(gpt->efi_gpt_DiskGUID, gpt->efi_gpt_DiskGUID); 121edcc0754Sachartre gpt->efi_gpt_PartitionEntryLBA = LE_64(gpt->efi_gpt_PartitionEntryLBA); 122edcc0754Sachartre gpt->efi_gpt_NumberOfPartitionEntries = 123edcc0754Sachartre LE_32(gpt->efi_gpt_NumberOfPartitionEntries); 124edcc0754Sachartre gpt->efi_gpt_SizeOfPartitionEntry = 125edcc0754Sachartre LE_32(gpt->efi_gpt_SizeOfPartitionEntry); 126edcc0754Sachartre gpt->efi_gpt_PartitionEntryArrayCRC32 = 127edcc0754Sachartre LE_32(gpt->efi_gpt_PartitionEntryArrayCRC32); 128edcc0754Sachartre } 129edcc0754Sachartre 130edcc0754Sachartre /* 131edcc0754Sachartre * Swap GPE data to match with the system endianness. 132edcc0754Sachartre */ 133edcc0754Sachartre static void 134edcc0754Sachartre vd_efi_swap_gpe(efi_gpe_t *gpe, int nparts) 135edcc0754Sachartre { 136edcc0754Sachartre int i, j; 137edcc0754Sachartre 138edcc0754Sachartre for (i = 0; i < nparts; i++) { 139edcc0754Sachartre UUID_LE_CONVERT(gpe[i].efi_gpe_PartitionTypeGUID, 140edcc0754Sachartre gpe[i].efi_gpe_PartitionTypeGUID); 141edcc0754Sachartre UUID_LE_CONVERT(gpe[i].efi_gpe_UniquePartitionGUID, 142edcc0754Sachartre gpe[i].efi_gpe_UniquePartitionGUID); 143edcc0754Sachartre gpe[i].efi_gpe_StartingLBA = LE_64(gpe[i].efi_gpe_StartingLBA); 144edcc0754Sachartre gpe[i].efi_gpe_EndingLBA = LE_64(gpe[i].efi_gpe_EndingLBA); 145edcc0754Sachartre gpe[i].efi_gpe_Attributes.PartitionAttrs = 146edcc0754Sachartre LE_16(gpe[i].efi_gpe_Attributes.PartitionAttrs); 147edcc0754Sachartre for (j = 0; j < EFI_PART_NAME_LEN; j++) { 148edcc0754Sachartre gpe[i].efi_gpe_PartitionName[j] = 149edcc0754Sachartre LE_16(gpe[i].efi_gpe_PartitionName[j]); 150edcc0754Sachartre } 151edcc0754Sachartre } 152edcc0754Sachartre } 153edcc0754Sachartre 154edcc0754Sachartre /* 155edcc0754Sachartre * Check that an EFI GPT is valid. This function should be called with a raw 156edcc0754Sachartre * EFI GPT i.e. GPT data should be in little endian format as indicated in the 157edcc0754Sachartre * EFI specification and they should not have been swapped to match with the 158edcc0754Sachartre * system endianness. 159edcc0754Sachartre */ 160edcc0754Sachartre static int 161edcc0754Sachartre vd_efi_check_gpt(vd_efi_dev_t *dev, efi_gpt_t *gpt) 162edcc0754Sachartre { 163edcc0754Sachartre uint_t crc_stored, crc_computed; 164edcc0754Sachartre 165edcc0754Sachartre if (gpt->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) { 1664bac2208Snarayan VD_EFI_DEBUG("Bad EFI signature: 0x%llx != 0x%llx\n", 167edcc0754Sachartre (long long)gpt->efi_gpt_Signature, 1684bac2208Snarayan (long long)LE_64(EFI_SIGNATURE)); 1694bac2208Snarayan return (EINVAL); 1704bac2208Snarayan } 1714bac2208Snarayan 1724bac2208Snarayan /* 1734bac2208Snarayan * check CRC of the header; the size of the header should 1744bac2208Snarayan * never be larger than one block 1754bac2208Snarayan */ 176edcc0754Sachartre if (LE_32(gpt->efi_gpt_HeaderSize) > dev->block_size) { 177edcc0754Sachartre VD_EFI_DEBUG("Header size (%u bytes) larger than one block" 178edcc0754Sachartre "(%u bytes)\n", LE_32(gpt->efi_gpt_HeaderSize), 179edcc0754Sachartre dev->block_size); 180edcc0754Sachartre return (EINVAL); 181edcc0754Sachartre } 1824bac2208Snarayan 183edcc0754Sachartre crc_stored = LE_32(gpt->efi_gpt_HeaderCRC32); 184edcc0754Sachartre gpt->efi_gpt_HeaderCRC32 = LE_32(0); 185edcc0754Sachartre crc_computed = vd_efi_crc32((unsigned char *)gpt, 186edcc0754Sachartre LE_32(gpt->efi_gpt_HeaderSize)); 187edcc0754Sachartre gpt->efi_gpt_HeaderCRC32 = LE_32(crc_stored); 188edcc0754Sachartre 189edcc0754Sachartre if (crc_stored != crc_computed) { 1904bac2208Snarayan VD_EFI_DEBUG("Bad EFI CRC: 0x%x != 0x%x\n", 191edcc0754Sachartre crc_stored, crc_computed); 1924bac2208Snarayan return (EINVAL); 1934bac2208Snarayan } 1944bac2208Snarayan 1954bac2208Snarayan return (0); 1964bac2208Snarayan } 1974bac2208Snarayan 198edcc0754Sachartre /* 199edcc0754Sachartre * Allocate and read the EFI GPT and GPE from the disk backend. Note that the 200edcc0754Sachartre * on-disk GPT and GPE are stored in little endian format but this function 201edcc0754Sachartre * returns them using the endianness of the system so that any field in the 202edcc0754Sachartre * GPT/GPE structures can be directly accessible without any further conversion. 203edcc0754Sachartre * The caller is responsible for freeing the allocated structures by calling 204edcc0754Sachartre * vd_efi_free(). 205edcc0754Sachartre */ 206edcc0754Sachartre int 207edcc0754Sachartre vd_efi_alloc_and_read(vd_efi_dev_t *dev, efi_gpt_t **efi_gpt, 208edcc0754Sachartre efi_gpe_t **efi_gpe) 2094bac2208Snarayan { 210edcc0754Sachartre dk_efi_t dk_efi; 211edcc0754Sachartre efi_gpt_t *gpt = NULL; 212edcc0754Sachartre efi_gpe_t *gpe = NULL; 213*d84f0041SAlexandre Chartre efi_gpt_t *data = NULL; 214*d84f0041SAlexandre Chartre size_t gpt_len, gpe_len, data_len; 215edcc0754Sachartre int nparts, status; 216edcc0754Sachartre 217edcc0754Sachartre ASSERT(dev->block_size >= sizeof (efi_gpt_t)); 218edcc0754Sachartre gpt_len = dev->block_size; 219edcc0754Sachartre gpt = kmem_zalloc(gpt_len, KM_SLEEP); 2204bac2208Snarayan 2214bac2208Snarayan /* 222edcc0754Sachartre * Read the EFI GPT. 2234bac2208Snarayan */ 224edcc0754Sachartre dk_efi.dki_lba = 1; 225edcc0754Sachartre dk_efi.dki_data = gpt; 226edcc0754Sachartre dk_efi.dki_length = gpt_len; 227edcc0754Sachartre 228*d84f0041SAlexandre Chartre status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi); 229*d84f0041SAlexandre Chartre 230*d84f0041SAlexandre Chartre if (status == EINVAL) { 231*d84f0041SAlexandre Chartre /* 232*d84f0041SAlexandre Chartre * Because the DKIOCGETEFI ioctl was initially incorrectly 233*d84f0041SAlexandre Chartre * implemented for a ZFS volume, the ioctl can fail with 234*d84f0041SAlexandre Chartre * EINVAL if it is done on a ZFS volume managed by an old 235*d84f0041SAlexandre Chartre * version of Solaris. This can happen if a ZFS volume is 236*d84f0041SAlexandre Chartre * exported as a single-slice disk by a service domain 237*d84f0041SAlexandre Chartre * running Solaris older than Solaris 10 Update 6. 238*d84f0041SAlexandre Chartre * 239*d84f0041SAlexandre Chartre * So we retry the ioctl to read both the GPT and the GPE at 240*d84f0041SAlexandre Chartre * the same time accordingly to the old implementation. 241*d84f0041SAlexandre Chartre */ 242*d84f0041SAlexandre Chartre data_len = sizeof (efi_gpt_t) + sizeof (efi_gpe_t); 243*d84f0041SAlexandre Chartre data = kmem_zalloc(data_len, KM_SLEEP); 244*d84f0041SAlexandre Chartre 245*d84f0041SAlexandre Chartre dk_efi.dki_lba = 1; 246*d84f0041SAlexandre Chartre dk_efi.dki_data = data; 247*d84f0041SAlexandre Chartre dk_efi.dki_length = data_len; 248*d84f0041SAlexandre Chartre status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi); 249*d84f0041SAlexandre Chartre 250*d84f0041SAlexandre Chartre if (status == 0) 251*d84f0041SAlexandre Chartre bcopy(data, gpt, sizeof (efi_gpt_t)); 252*d84f0041SAlexandre Chartre } 253*d84f0041SAlexandre Chartre 254*d84f0041SAlexandre Chartre if (status != 0) { 255edcc0754Sachartre VD_EFI_DEBUG("DKIOCGETEFI (GPT, LBA=1) error %d\n", status); 256edcc0754Sachartre goto errdone; 2574bac2208Snarayan } 2584bac2208Snarayan 259edcc0754Sachartre if ((status = vd_efi_check_gpt(dev, gpt)) != 0) { 2604bac2208Snarayan /* 261edcc0754Sachartre * No valid label here; try the alternate. The alternate GPT is 262edcc0754Sachartre * located in the last block of the disk. 2634bac2208Snarayan */ 264edcc0754Sachartre dk_efi.dki_lba = dev->disk_size - 1; 265edcc0754Sachartre dk_efi.dki_data = gpt; 266edcc0754Sachartre dk_efi.dki_length = gpt_len; 267edcc0754Sachartre 268edcc0754Sachartre if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 269edcc0754Sachartre VD_EFI_DEBUG("DKIOCGETEFI (LBA=%lu) error %d\n", 270edcc0754Sachartre dev->disk_size - 1, status); 271edcc0754Sachartre goto errdone; 272edcc0754Sachartre } 273edcc0754Sachartre 274edcc0754Sachartre if ((status = vd_efi_check_gpt(dev, gpt)) != 0) 275edcc0754Sachartre goto errdone; 276edcc0754Sachartre 277edcc0754Sachartre VD_EFI_DEBUG("efi_read: primary label corrupt; using backup\n"); 278edcc0754Sachartre } 279edcc0754Sachartre 280edcc0754Sachartre /* swap GPT data after checking the GPT is valid */ 281edcc0754Sachartre vd_efi_swap_gpt(gpt); 282edcc0754Sachartre 283edcc0754Sachartre /* 284edcc0754Sachartre * Read the EFI GPE. 285edcc0754Sachartre */ 286edcc0754Sachartre nparts = gpt->efi_gpt_NumberOfPartitionEntries; 287edcc0754Sachartre 288edcc0754Sachartre if (nparts > NDKMAP + 1) { 289edcc0754Sachartre VD_EFI_DEBUG("Too many EFI partitions (%u)", nparts); 2904bac2208Snarayan status = EINVAL; 291edcc0754Sachartre goto errdone; 2924bac2208Snarayan } 293edcc0754Sachartre 294edcc0754Sachartre if (nparts == 0) { 295edcc0754Sachartre VD_EFI_DEBUG("No partition defined"); 296edcc0754Sachartre status = EINVAL; 297edcc0754Sachartre goto errdone; 2984bac2208Snarayan } 299edcc0754Sachartre 300edcc0754Sachartre gpe_len = VD_EFI_GPE_LEN(dev, nparts); 301edcc0754Sachartre gpe = kmem_zalloc(gpe_len, KM_SLEEP); 302edcc0754Sachartre 303*d84f0041SAlexandre Chartre if (data != NULL) { 304*d84f0041SAlexandre Chartre /* 305*d84f0041SAlexandre Chartre * The data variable is not NULL if we have used the old ioctl 306*d84f0041SAlexandre Chartre * implementation for a ZFS volume. In that case, we only expect 307*d84f0041SAlexandre Chartre * one partition and GPE data are already available in the data 308*d84f0041SAlexandre Chartre * buffer, right after GPT data. 309*d84f0041SAlexandre Chartre */ 310*d84f0041SAlexandre Chartre if (nparts != 1) { 311*d84f0041SAlexandre Chartre VD_EFI_DEBUG("Unexpected number of partitions (%u)", 312*d84f0041SAlexandre Chartre nparts); 313*d84f0041SAlexandre Chartre status = EINVAL; 314*d84f0041SAlexandre Chartre goto errdone; 315*d84f0041SAlexandre Chartre } 316*d84f0041SAlexandre Chartre 317*d84f0041SAlexandre Chartre bcopy(data + 1, gpe, sizeof (efi_gpe_t)); 318*d84f0041SAlexandre Chartre 319*d84f0041SAlexandre Chartre } else { 320edcc0754Sachartre dk_efi.dki_lba = gpt->efi_gpt_PartitionEntryLBA; 321edcc0754Sachartre dk_efi.dki_data = (efi_gpt_t *)gpe; 322edcc0754Sachartre dk_efi.dki_length = gpe_len; 323edcc0754Sachartre 324edcc0754Sachartre if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 325edcc0754Sachartre VD_EFI_DEBUG("DKIOCGETEFI (GPE, LBA=%lu) error %d\n", 326edcc0754Sachartre gpt->efi_gpt_PartitionEntryLBA, status); 327edcc0754Sachartre goto errdone; 3284bac2208Snarayan } 329*d84f0041SAlexandre Chartre } 330edcc0754Sachartre 331edcc0754Sachartre vd_efi_swap_gpe(gpe, nparts); 332edcc0754Sachartre 333edcc0754Sachartre *efi_gpt = gpt; 334edcc0754Sachartre *efi_gpe = gpe; 335edcc0754Sachartre 336edcc0754Sachartre errdone: 337edcc0754Sachartre 338*d84f0041SAlexandre Chartre if (data != NULL) 339*d84f0041SAlexandre Chartre kmem_free(data, data_len); 340*d84f0041SAlexandre Chartre 341*d84f0041SAlexandre Chartre if (status != 0) { 342edcc0754Sachartre if (gpe != NULL) 343edcc0754Sachartre kmem_free(gpe, gpe_len); 344edcc0754Sachartre if (gpt != NULL) 345edcc0754Sachartre kmem_free(gpt, gpt_len); 346*d84f0041SAlexandre Chartre } 347edcc0754Sachartre 3484bac2208Snarayan return (status); 3494bac2208Snarayan } 3504bac2208Snarayan 3514bac2208Snarayan /* 352edcc0754Sachartre * Free the EFI GPE and GPT structures returned by vd_efi_alloc_and_read(). 3534bac2208Snarayan */ 3544bac2208Snarayan void 355edcc0754Sachartre vd_efi_free(vd_efi_dev_t *dev, efi_gpt_t *gpt, efi_gpe_t *gpe) 3564bac2208Snarayan { 357edcc0754Sachartre kmem_free(gpe, VD_EFI_GPE_LEN(dev, 358edcc0754Sachartre gpt->efi_gpt_NumberOfPartitionEntries)); 359edcc0754Sachartre kmem_free(gpt, dev->block_size); 3604bac2208Snarayan } 361