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 /* 23edcc0754Sachartre * Copyright 2008 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 52*11f54b6eSAlexandre Chartre #ifdef DEBUG 53*11f54b6eSAlexandre Chartre 544bac2208Snarayan #define VD_EFI_DEBUG if (vd_efi_debug) vd_efi_print 554bac2208Snarayan 56edcc0754Sachartre static int vd_efi_debug = 0; 57*11f54b6eSAlexandre Chartre 58*11f54b6eSAlexandre Chartre #else 59*11f54b6eSAlexandre Chartre 60*11f54b6eSAlexandre Chartre #define VD_EFI_DEBUG(...) 61*11f54b6eSAlexandre 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; 213edcc0754Sachartre size_t gpt_len, gpe_len; 214edcc0754Sachartre int nparts, status; 215edcc0754Sachartre 216edcc0754Sachartre ASSERT(dev->block_size >= sizeof (efi_gpt_t)); 217edcc0754Sachartre gpt_len = dev->block_size; 218edcc0754Sachartre gpt = kmem_zalloc(gpt_len, KM_SLEEP); 2194bac2208Snarayan 2204bac2208Snarayan /* 221edcc0754Sachartre * Read the EFI GPT. 2224bac2208Snarayan */ 223edcc0754Sachartre dk_efi.dki_lba = 1; 224edcc0754Sachartre dk_efi.dki_data = gpt; 225edcc0754Sachartre dk_efi.dki_length = gpt_len; 226edcc0754Sachartre 227edcc0754Sachartre if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 228edcc0754Sachartre VD_EFI_DEBUG("DKIOCGETEFI (GPT, LBA=1) error %d\n", status); 229edcc0754Sachartre goto errdone; 2304bac2208Snarayan } 2314bac2208Snarayan 232edcc0754Sachartre if ((status = vd_efi_check_gpt(dev, gpt)) != 0) { 2334bac2208Snarayan /* 234edcc0754Sachartre * No valid label here; try the alternate. The alternate GPT is 235edcc0754Sachartre * located in the last block of the disk. 2364bac2208Snarayan */ 237edcc0754Sachartre dk_efi.dki_lba = dev->disk_size - 1; 238edcc0754Sachartre dk_efi.dki_data = gpt; 239edcc0754Sachartre dk_efi.dki_length = gpt_len; 240edcc0754Sachartre 241edcc0754Sachartre if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 242edcc0754Sachartre VD_EFI_DEBUG("DKIOCGETEFI (LBA=%lu) error %d\n", 243edcc0754Sachartre dev->disk_size - 1, status); 244edcc0754Sachartre goto errdone; 245edcc0754Sachartre } 246edcc0754Sachartre 247edcc0754Sachartre if ((status = vd_efi_check_gpt(dev, gpt)) != 0) 248edcc0754Sachartre goto errdone; 249edcc0754Sachartre 250edcc0754Sachartre VD_EFI_DEBUG("efi_read: primary label corrupt; using backup\n"); 251edcc0754Sachartre } 252edcc0754Sachartre 253edcc0754Sachartre /* swap GPT data after checking the GPT is valid */ 254edcc0754Sachartre vd_efi_swap_gpt(gpt); 255edcc0754Sachartre 256edcc0754Sachartre /* 257edcc0754Sachartre * Read the EFI GPE. 258edcc0754Sachartre */ 259edcc0754Sachartre nparts = gpt->efi_gpt_NumberOfPartitionEntries; 260edcc0754Sachartre 261edcc0754Sachartre if (nparts > NDKMAP + 1) { 262edcc0754Sachartre VD_EFI_DEBUG("Too many EFI partitions (%u)", nparts); 2634bac2208Snarayan status = EINVAL; 264edcc0754Sachartre goto errdone; 2654bac2208Snarayan } 266edcc0754Sachartre 267edcc0754Sachartre if (nparts == 0) { 268edcc0754Sachartre VD_EFI_DEBUG("No partition defined"); 269edcc0754Sachartre status = EINVAL; 270edcc0754Sachartre goto errdone; 2714bac2208Snarayan } 272edcc0754Sachartre 273edcc0754Sachartre gpe_len = VD_EFI_GPE_LEN(dev, nparts); 274edcc0754Sachartre gpe = kmem_zalloc(gpe_len, KM_SLEEP); 275edcc0754Sachartre 276edcc0754Sachartre dk_efi.dki_lba = gpt->efi_gpt_PartitionEntryLBA; 277edcc0754Sachartre dk_efi.dki_data = (efi_gpt_t *)gpe; 278edcc0754Sachartre dk_efi.dki_length = gpe_len; 279edcc0754Sachartre 280edcc0754Sachartre if ((status = vd_efi_ioctl(dev, DKIOCGETEFI, &dk_efi)) != 0) { 281edcc0754Sachartre VD_EFI_DEBUG("DKIOCGETEFI (GPE, LBA=%lu) error %d\n", 282edcc0754Sachartre gpt->efi_gpt_PartitionEntryLBA, status); 283edcc0754Sachartre goto errdone; 2844bac2208Snarayan } 285edcc0754Sachartre 286edcc0754Sachartre vd_efi_swap_gpe(gpe, nparts); 287edcc0754Sachartre 288edcc0754Sachartre *efi_gpt = gpt; 289edcc0754Sachartre *efi_gpe = gpe; 290edcc0754Sachartre 291edcc0754Sachartre return (0); 292edcc0754Sachartre 293edcc0754Sachartre errdone: 294edcc0754Sachartre 295edcc0754Sachartre if (gpe != NULL) 296edcc0754Sachartre kmem_free(gpe, gpe_len); 297edcc0754Sachartre if (gpt != NULL) 298edcc0754Sachartre kmem_free(gpt, gpt_len); 299edcc0754Sachartre 3004bac2208Snarayan return (status); 3014bac2208Snarayan } 3024bac2208Snarayan 3034bac2208Snarayan /* 304edcc0754Sachartre * Free the EFI GPE and GPT structures returned by vd_efi_alloc_and_read(). 3054bac2208Snarayan */ 3064bac2208Snarayan void 307edcc0754Sachartre vd_efi_free(vd_efi_dev_t *dev, efi_gpt_t *gpt, efi_gpe_t *gpe) 3084bac2208Snarayan { 309edcc0754Sachartre kmem_free(gpe, VD_EFI_GPE_LEN(dev, 310edcc0754Sachartre gpt->efi_gpt_NumberOfPartitionEntries)); 311edcc0754Sachartre kmem_free(gpt, dev->block_size); 3124bac2208Snarayan } 313