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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  * Copyright 2014 Toomas Soome <tsoome@me.com>
  26  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  27  * Copyright (c) 2018, Joyent, Inc.
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <errno.h>
  33 #include <strings.h>
  34 #include <unistd.h>
  35 #include <smbios.h>
  36 #include <uuid/uuid.h>
  37 #include <libintl.h>
  38 #include <sys/types.h>
  39 #include <sys/dkio.h>
  40 #include <sys/vtoc.h>
  41 #include <sys/mhd.h>
  42 #include <sys/param.h>
  43 #include <sys/dktp/fdisk.h>
  44 #include <sys/efi_partition.h>
  45 #include <sys/byteorder.h>
  46 #include <sys/ddi.h>
  47 
  48 /*
  49  * The original conversion array used simple array index, but since
  50  * we do need to take account of VTOC tag numbers from other systems,
  51  * we need to provide tag values too, or the array will grow too large.
  52  *
  53  * Still we will fabricate the missing p_tag values.
  54  */
  55 static struct uuid_to_ptag {
  56         struct uuid     uuid;
  57         ushort_t        p_tag;
  58 } conversion_array[] = {
  59         { EFI_UNUSED, V_UNASSIGNED },
  60         { EFI_BOOT, V_BOOT },
  61         { EFI_ROOT, V_ROOT },
  62         { EFI_SWAP, V_SWAP },
  63         { EFI_USR, V_USR },
  64         { EFI_BACKUP, V_BACKUP },
  65         { EFI_VAR, V_VAR },
  66         { EFI_HOME, V_HOME },
  67         { EFI_ALTSCTR, V_ALTSCTR },
  68         { EFI_RESERVED, V_RESERVED },
  69         { EFI_SYSTEM, V_SYSTEM },               /* V_SYSTEM is 0xc */
  70         { EFI_LEGACY_MBR, 0x10 },
  71         { EFI_SYMC_PUB, 0x11 },
  72         { EFI_SYMC_CDS, 0x12 },
  73         { EFI_MSFT_RESV, 0x13 },
  74         { EFI_DELL_BASIC, 0x14 },
  75         { EFI_DELL_RAID, 0x15 },
  76         { EFI_DELL_SWAP, 0x16 },
  77         { EFI_DELL_LVM, 0x17 },
  78         { EFI_DELL_RESV, 0x19 },
  79         { EFI_AAPL_HFS, 0x1a },
  80         { EFI_AAPL_UFS, 0x1b },
  81         { EFI_AAPL_ZFS, 0x1c },
  82         { EFI_AAPL_APFS, 0x1d },
  83         { EFI_BIOS_BOOT, V_BIOS_BOOT },         /* V_BIOS_BOOT is 0x18 */
  84         { EFI_FREEBSD_BOOT,  V_FREEBSD_BOOT },
  85         { EFI_FREEBSD_SWAP, V_FREEBSD_SWAP },
  86         { EFI_FREEBSD_UFS, V_FREEBSD_UFS },
  87         { EFI_FREEBSD_VINUM, V_FREEBSD_VINUM },
  88         { EFI_FREEBSD_ZFS, V_FREEBSD_ZFS },
  89         { EFI_FREEBSD_NANDFS, V_FREEBSD_NANDFS }
  90 };
  91 
  92 /*
  93  * Default vtoc information for non-SVr4 partitions
  94  */
  95 struct dk_map2  default_vtoc_map[NDKMAP] = {
  96         {       V_ROOT,         0       },              /* a - 0 */
  97         {       V_SWAP,         V_UNMNT },              /* b - 1 */
  98         {       V_BACKUP,       V_UNMNT },              /* c - 2 */
  99         {       V_UNASSIGNED,   0       },              /* d - 3 */
 100         {       V_UNASSIGNED,   0       },              /* e - 4 */
 101         {       V_UNASSIGNED,   0       },              /* f - 5 */
 102         {       V_USR,          0       },              /* g - 6 */
 103         {       V_UNASSIGNED,   0       },              /* h - 7 */
 104 
 105 #if defined(_SUNOS_VTOC_16)
 106 
 107 #if defined(i386) || defined(__amd64)
 108         {       V_BOOT,         V_UNMNT },              /* i - 8 */
 109         {       V_ALTSCTR,      0       },              /* j - 9 */
 110 
 111 #else
 112 #error No VTOC format defined.
 113 #endif                  /* defined(i386) */
 114 
 115         {       V_UNASSIGNED,   0       },              /* k - 10 */
 116         {       V_UNASSIGNED,   0       },              /* l - 11 */
 117         {       V_UNASSIGNED,   0       },              /* m - 12 */
 118         {       V_UNASSIGNED,   0       },              /* n - 13 */
 119         {       V_UNASSIGNED,   0       },              /* o - 14 */
 120         {       V_UNASSIGNED,   0       },              /* p - 15 */
 121 #endif                  /* defined(_SUNOS_VTOC_16) */
 122 };
 123 
 124 #ifdef DEBUG
 125 int efi_debug = 1;
 126 #else
 127 int efi_debug = 0;
 128 #endif
 129 
 130 #define EFI_FIXES_DB "/usr/share/hwdata/efi.fixes"
 131 
 132 extern unsigned int     efi_crc32(const unsigned char *, unsigned int);
 133 static int              efi_read(int, struct dk_gpt *);
 134 
 135 static int
 136 read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
 137 {
 138         struct dk_minfo         disk_info;
 139 
 140         if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
 141                 return (errno);
 142         *capacity = disk_info.dki_capacity;
 143         *lbsize = disk_info.dki_lbsize;
 144         return (0);
 145 }
 146 
 147 /*
 148  * the number of blocks the EFI label takes up (round up to nearest
 149  * block)
 150  */
 151 #define NBLOCKS(p, l)   (1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
 152                                 ((l) - 1)) / (l)))
 153 /* number of partitions -- limited by what we can malloc */
 154 #define MAX_PARTS       ((4294967295UL - sizeof (struct dk_gpt)) / \
 155                             sizeof (struct dk_part))
 156 
 157 int
 158 efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
 159 {
 160         diskaddr_t      capacity;
 161         uint_t          lbsize;
 162         uint_t          nblocks;
 163         size_t          length;
 164         struct dk_gpt   *vptr;
 165         struct uuid     uuid;
 166 
 167         if (read_disk_info(fd, &capacity, &lbsize) != 0) {
 168                 if (efi_debug)
 169                         (void) fprintf(stderr,
 170                             "couldn't read disk information\n");
 171                 return (-1);
 172         }
 173 
 174         nblocks = NBLOCKS(nparts, lbsize);
 175         if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
 176                 /* 16K plus one block for the GPT */
 177                 nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
 178         }
 179 
 180         if (nparts > MAX_PARTS) {
 181                 if (efi_debug) {
 182                         (void) fprintf(stderr,
 183                         "the maximum number of partitions supported is %lu\n",
 184                             MAX_PARTS);
 185                 }
 186                 return (-1);
 187         }
 188 
 189         length = sizeof (struct dk_gpt) +
 190             sizeof (struct dk_part) * (nparts - 1);
 191 
 192         if ((*vtoc = calloc(1, length)) == NULL)
 193                 return (-1);
 194 
 195         vptr = *vtoc;
 196 
 197         vptr->efi_version = EFI_VERSION_CURRENT;
 198         vptr->efi_lbasize = lbsize;
 199         vptr->efi_nparts = nparts;
 200         /*
 201          * add one block here for the PMBR; on disks with a 512 byte
 202          * block size and 128 or fewer partitions, efi_first_u_lba
 203          * should work out to "34"
 204          */
 205         vptr->efi_first_u_lba = nblocks + 1;
 206         vptr->efi_last_lba = capacity - 1;
 207         vptr->efi_altern_lba = capacity -1;
 208         vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
 209 
 210         (void) uuid_generate((uchar_t *)&uuid);
 211         UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
 212         return (0);
 213 }
 214 
 215 /*
 216  * Read EFI - return partition number upon success.
 217  */
 218 int
 219 efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
 220 {
 221         int                     rval;
 222         uint32_t                nparts;
 223         int                     length;
 224         struct mboot            *mbr;
 225         struct ipart            *ipart;
 226         diskaddr_t              capacity;
 227         uint_t                  lbsize;
 228         int                     i;
 229 
 230         if (read_disk_info(fd, &capacity, &lbsize) != 0)
 231                 return (VT_ERROR);
 232 
 233         if ((mbr = calloc(1, lbsize)) == NULL)
 234                 return (VT_ERROR);
 235 
 236         if ((ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) {
 237                 free(mbr);
 238                 return (VT_ERROR);
 239         }
 240 
 241         if (mbr->signature != MBB_MAGIC) {
 242                 free(mbr);
 243                 return (VT_EINVAL);
 244         }
 245         ipart = (struct ipart *)(uintptr_t)mbr->parts;
 246 
 247         /* Check if we have partition with ID EFI_PMBR */
 248         for (i = 0; i < FD_NUMPART; i++) {
 249                 if (ipart[i].systid == EFI_PMBR)
 250                         break;
 251         }
 252         free(mbr);
 253         if (i == FD_NUMPART)
 254                 return (VT_EINVAL);
 255 
 256         /* figure out the number of entries that would fit into 16K */
 257         nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
 258         length = (int) sizeof (struct dk_gpt) +
 259             (int) sizeof (struct dk_part) * (nparts - 1);
 260         if ((*vtoc = calloc(1, length)) == NULL)
 261                 return (VT_ERROR);
 262 
 263         (*vtoc)->efi_nparts = nparts;
 264         rval = efi_read(fd, *vtoc);
 265 
 266         if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
 267                 void *tmp;
 268                 length = (int) sizeof (struct dk_gpt) +
 269                     (int) sizeof (struct dk_part) *
 270                     ((*vtoc)->efi_nparts - 1);
 271                 nparts = (*vtoc)->efi_nparts;
 272                 if ((tmp = realloc(*vtoc, length)) == NULL) {
 273                         free (*vtoc);
 274                         *vtoc = NULL;
 275                         return (VT_ERROR);
 276                 } else {
 277                         *vtoc = tmp;
 278                         rval = efi_read(fd, *vtoc);
 279                 }
 280         }
 281 
 282         if (rval < 0) {
 283                 if (efi_debug) {
 284                         (void) fprintf(stderr,
 285                             "read of EFI table failed, rval=%d\n", rval);
 286                 }
 287                 free (*vtoc);
 288                 *vtoc = NULL;
 289         }
 290 
 291         return (rval);
 292 }
 293 
 294 static int
 295 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
 296 {
 297         void *data = dk_ioc->dki_data;
 298         int error;
 299 
 300         dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
 301         error = ioctl(fd, cmd, (void *)dk_ioc);
 302         dk_ioc->dki_data = data;
 303 
 304         return (error);
 305 }
 306 
 307 static int
 308 check_label(int fd, dk_efi_t *dk_ioc)
 309 {
 310         efi_gpt_t               *efi;
 311         uint_t                  crc;
 312 
 313         if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
 314                 switch (errno) {
 315                 case EIO:
 316                         return (VT_EIO);
 317                 default:
 318                         return (VT_ERROR);
 319                 }
 320         }
 321         efi = dk_ioc->dki_data;
 322         if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
 323                 if (efi_debug)
 324                         (void) fprintf(stderr,
 325                             "Bad EFI signature: 0x%llx != 0x%llx\n",
 326                             (long long)efi->efi_gpt_Signature,
 327                             (long long)LE_64(EFI_SIGNATURE));
 328                 return (VT_EINVAL);
 329         }
 330 
 331         /*
 332          * check CRC of the header; the size of the header should
 333          * never be larger than one block
 334          */
 335         crc = efi->efi_gpt_HeaderCRC32;
 336         efi->efi_gpt_HeaderCRC32 = 0;
 337 
 338         if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
 339             crc != LE_32(efi_crc32((unsigned char *)efi,
 340             LE_32(efi->efi_gpt_HeaderSize)))) {
 341                 if (efi_debug)
 342                         (void) fprintf(stderr,
 343                             "Bad EFI CRC: 0x%x != 0x%x\n",
 344                             crc,
 345                             LE_32(efi_crc32((unsigned char *)efi,
 346                             sizeof (struct efi_gpt))));
 347                 return (VT_EINVAL);
 348         }
 349 
 350         return (0);
 351 }
 352 
 353 static int
 354 efi_read(int fd, struct dk_gpt *vtoc)
 355 {
 356         int                     i, j;
 357         int                     label_len;
 358         int                     rval = 0;
 359         int                     vdc_flag = 0;
 360         struct dk_minfo         disk_info;
 361         dk_efi_t                dk_ioc;
 362         efi_gpt_t               *efi;
 363         efi_gpe_t               *efi_parts;
 364         struct dk_cinfo         dki_info;
 365         uint32_t                user_length;
 366         boolean_t               legacy_label = B_FALSE;
 367 
 368         /*
 369          * get the partition number for this file descriptor.
 370          */
 371         if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
 372                 if (efi_debug) {
 373                         (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
 374                 }
 375                 switch (errno) {
 376                 case EIO:
 377                         return (VT_EIO);
 378                 case EINVAL:
 379                         return (VT_EINVAL);
 380                 default:
 381                         return (VT_ERROR);
 382                 }
 383         }
 384 
 385         if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
 386             (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
 387                 /*
 388                  * The controller and drive name "vdc" (virtual disk client)
 389                  * indicates a LDoms virtual disk.
 390                  */
 391                 vdc_flag++;
 392         }
 393 
 394         /* get the LBA size */
 395         if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
 396                 if (efi_debug) {
 397                         (void) fprintf(stderr,
 398                             "assuming LBA 512 bytes %d\n",
 399                             errno);
 400                 }
 401                 disk_info.dki_lbsize = DEV_BSIZE;
 402         }
 403         if (disk_info.dki_lbsize == 0) {
 404                 if (efi_debug) {
 405                         (void) fprintf(stderr,
 406                             "efi_read: assuming LBA 512 bytes\n");
 407                 }
 408                 disk_info.dki_lbsize = DEV_BSIZE;
 409         }
 410         /*
 411          * Read the EFI GPT to figure out how many partitions we need
 412          * to deal with.
 413          */
 414         dk_ioc.dki_lba = 1;
 415         if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
 416                 label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
 417         } else {
 418                 label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
 419                     disk_info.dki_lbsize;
 420                 if (label_len % disk_info.dki_lbsize) {
 421                         /* pad to physical sector size */
 422                         label_len += disk_info.dki_lbsize;
 423                         label_len &= ~(disk_info.dki_lbsize - 1);
 424                 }
 425         }
 426 
 427         if ((dk_ioc.dki_data = calloc(1, label_len)) == NULL)
 428                 return (VT_ERROR);
 429 
 430         dk_ioc.dki_length = disk_info.dki_lbsize;
 431         user_length = vtoc->efi_nparts;
 432         efi = dk_ioc.dki_data;
 433         if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
 434                 /*
 435                  * No valid label here; try the alternate. Note that here
 436                  * we just read GPT header and save it into dk_ioc.data,
 437                  * Later, we will read GUID partition entry array if we
 438                  * can get valid GPT header.
 439                  */
 440 
 441                 /*
 442                  * This is a workaround for legacy systems. In the past, the
 443                  * last sector of SCSI disk was invisible on x86 platform. At
 444                  * that time, backup label was saved on the next to the last
 445                  * sector. It is possible for users to move a disk from previous
 446                  * solaris system to present system. Here, we attempt to search
 447                  * legacy backup EFI label first.
 448                  */
 449                 dk_ioc.dki_lba = disk_info.dki_capacity - 2;
 450                 dk_ioc.dki_length = disk_info.dki_lbsize;
 451                 rval = check_label(fd, &dk_ioc);
 452                 if (rval == VT_EINVAL) {
 453                         /*
 454                          * we didn't find legacy backup EFI label, try to
 455                          * search backup EFI label in the last block.
 456                          */
 457                         dk_ioc.dki_lba = disk_info.dki_capacity - 1;
 458                         dk_ioc.dki_length = disk_info.dki_lbsize;
 459                         rval = check_label(fd, &dk_ioc);
 460                         if (rval == 0) {
 461                                 legacy_label = B_TRUE;
 462                                 if (efi_debug)
 463                                         (void) fprintf(stderr,
 464                                             "efi_read: primary label corrupt; "
 465                                             "using EFI backup label located on"
 466                                             " the last block\n");
 467                         }
 468                 } else {
 469                         if ((efi_debug) && (rval == 0))
 470                                 (void) fprintf(stderr, "efi_read: primary label"
 471                                     " corrupt; using legacy EFI backup label "
 472                                     " located on the next to last block\n");
 473                 }
 474 
 475                 if (rval == 0) {
 476                         dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
 477                         vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
 478                         vtoc->efi_nparts =
 479                             LE_32(efi->efi_gpt_NumberOfPartitionEntries);
 480                         /*
 481                          * Partition tables are between backup GPT header
 482                          * table and ParitionEntryLBA (the starting LBA of
 483                          * the GUID partition entries array). Now that we
 484                          * already got valid GPT header and saved it in
 485                          * dk_ioc.dki_data, we try to get GUID partition
 486                          * entry array here.
 487                          */
 488                         /* LINTED */
 489                         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
 490                             + disk_info.dki_lbsize);
 491                         if (legacy_label)
 492                                 dk_ioc.dki_length = disk_info.dki_capacity - 1 -
 493                                     dk_ioc.dki_lba;
 494                         else
 495                                 dk_ioc.dki_length = disk_info.dki_capacity - 2 -
 496                                     dk_ioc.dki_lba;
 497                         dk_ioc.dki_length *= disk_info.dki_lbsize;
 498                         if (dk_ioc.dki_length >
 499                             ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
 500                                 rval = VT_EINVAL;
 501                         } else {
 502                                 /*
 503                                  * read GUID partition entry array
 504                                  */
 505                                 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
 506                         }
 507                 }
 508 
 509         } else if (rval == 0) {
 510 
 511                 dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
 512                 /* LINTED */
 513                 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
 514                     + disk_info.dki_lbsize);
 515                 dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
 516                 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
 517 
 518         } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
 519                 /*
 520                  * When the device is a LDoms virtual disk, the DKIOCGETEFI
 521                  * ioctl can fail with EINVAL if the virtual disk backend
 522                  * is a ZFS volume serviced by a domain running an old version
 523                  * of Solaris. This is because the DKIOCGETEFI ioctl was
 524                  * initially incorrectly implemented for a ZFS volume and it
 525                  * expected the GPT and GPE to be retrieved with a single ioctl.
 526                  * So we try to read the GPT and the GPE using that old style
 527                  * ioctl.
 528                  */
 529                 dk_ioc.dki_lba = 1;
 530                 dk_ioc.dki_length = label_len;
 531                 rval = check_label(fd, &dk_ioc);
 532         }
 533 
 534         if (rval < 0) {
 535                 free(efi);
 536                 return (rval);
 537         }
 538 
 539         /* LINTED -- always longlong aligned */
 540         efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
 541 
 542         /*
 543          * Assemble this into a "dk_gpt" struct for easier
 544          * digestibility by applications.
 545          */
 546         vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
 547         vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
 548         vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
 549         vtoc->efi_lbasize = disk_info.dki_lbsize;
 550         vtoc->efi_last_lba = disk_info.dki_capacity - 1;
 551         vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
 552         vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
 553         vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
 554         UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
 555 
 556         /*
 557          * If the array the user passed in is too small, set the length
 558          * to what it needs to be and return
 559          */
 560         if (user_length < vtoc->efi_nparts) {
 561                 return (VT_EINVAL);
 562         }
 563 
 564         for (i = 0; i < vtoc->efi_nparts; i++) {
 565 
 566                 UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
 567                     efi_parts[i].efi_gpe_PartitionTypeGUID);
 568 
 569                 for (j = 0;
 570                     j < sizeof (conversion_array)
 571                     / sizeof (struct uuid_to_ptag); j++) {
 572 
 573                         if (bcmp(&vtoc->efi_parts[i].p_guid,
 574                             &conversion_array[j].uuid,
 575                             sizeof (struct uuid)) == 0) {
 576                                 vtoc->efi_parts[i].p_tag =
 577                                     conversion_array[j].p_tag;
 578                                 break;
 579                         }
 580                 }
 581                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
 582                         continue;
 583                 vtoc->efi_parts[i].p_flag =
 584                     LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
 585                 vtoc->efi_parts[i].p_start =
 586                     LE_64(efi_parts[i].efi_gpe_StartingLBA);
 587                 vtoc->efi_parts[i].p_size =
 588                     LE_64(efi_parts[i].efi_gpe_EndingLBA) -
 589                     vtoc->efi_parts[i].p_start + 1;
 590                 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
 591                         vtoc->efi_parts[i].p_name[j] =
 592                             (uchar_t)LE_16(
 593                             efi_parts[i].efi_gpe_PartitionName[j]);
 594                 }
 595 
 596                 UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
 597                     efi_parts[i].efi_gpe_UniquePartitionGUID);
 598         }
 599         free(efi);
 600 
 601         return (dki_info.dki_partition);
 602 }
 603 
 604 static void
 605 hardware_workarounds(int *slot, int *active)
 606 {
 607         smbios_struct_t s_sys, s_mb;
 608         smbios_info_t sys, mb;
 609         smbios_hdl_t *shp;
 610         char buf[0x400];
 611         FILE *fp;
 612         int err;
 613 
 614         if ((fp = fopen(EFI_FIXES_DB, "rF")) == NULL)
 615                 return;
 616 
 617         if ((shp = smbios_open(NULL, SMB_VERSION, 0, &err)) == NULL) {
 618                 if (efi_debug)
 619                         (void) fprintf(stderr,
 620                             "libefi failed to load SMBIOS: %s\n",
 621                             smbios_errmsg(err));
 622                 (void) fclose(fp);
 623                 return;
 624         }
 625 
 626         if (smbios_lookup_type(shp, SMB_TYPE_SYSTEM, &s_sys) == SMB_ERR ||
 627             smbios_info_common(shp, s_sys.smbstr_id, &sys) == SMB_ERR)
 628                 (void) memset(&sys, '\0', sizeof (sys));
 629         if (smbios_lookup_type(shp, SMB_TYPE_BASEBOARD, &s_mb) == SMB_ERR ||
 630             smbios_info_common(shp, s_mb.smbstr_id, &mb) == SMB_ERR)
 631                 (void) memset(&mb, '\0', sizeof (mb));
 632 
 633         while (fgets(buf, sizeof (buf), fp) != NULL) {
 634                 char *tok, *val, *end;
 635 
 636                 tok = buf + strspn(buf, " \t");
 637                 if (*tok == '#')
 638                         continue;
 639                 while (*tok != '\0') {
 640                         tok += strspn(tok, " \t");
 641                         if ((val = strchr(tok, '=')) == NULL)
 642                                 break;
 643                         *val++ = '\0';
 644                         if (*val == '"')
 645                                 end = strchr(++val, '"');
 646                         else
 647                                 end = strpbrk(val, " \t\n");
 648                         if (end == NULL)
 649                                 break;
 650                         *end++ = '\0';
 651 
 652                         if (strcmp(tok, "sys.manufacturer") == 0 &&
 653                             (sys.smbi_manufacturer == NULL ||
 654                             strcasecmp(val, sys.smbi_manufacturer)))
 655                                 break;
 656                         if (strcmp(tok, "sys.product") == 0 &&
 657                             (sys.smbi_product == NULL ||
 658                             strcasecmp(val, sys.smbi_product)))
 659                                 break;
 660                         if (strcmp(tok, "sys.version") == 0 &&
 661                             (sys.smbi_version == NULL ||
 662                             strcasecmp(val, sys.smbi_version)))
 663                                 break;
 664                         if (strcmp(tok, "mb.manufacturer") == 0 &&
 665                             (mb.smbi_manufacturer == NULL ||
 666                             strcasecmp(val, mb.smbi_manufacturer)))
 667                                 break;
 668                         if (strcmp(tok, "mb.product") == 0 &&
 669                             (mb.smbi_product == NULL ||
 670                             strcasecmp(val, mb.smbi_product)))
 671                                 break;
 672                         if (strcmp(tok, "mb.version") == 0 &&
 673                             (mb.smbi_version == NULL ||
 674                             strcasecmp(val, mb.smbi_version)))
 675                                 break;
 676 
 677                         if (strcmp(tok, "pmbr_slot") == 0) {
 678                                 *slot = atoi(val);
 679                                 if (*slot < 0 || *slot > 3)
 680                                         *slot = 0;
 681                                 if (efi_debug)
 682                                         (void) fprintf(stderr,
 683                                             "Using slot %d\n", *slot);
 684                         }
 685 
 686                         if (strcmp(tok, "pmbr_active") == 0) {
 687                                 *active = atoi(val);
 688                                 if (*active < 0 || *active > 1)
 689                                         *active = 0;
 690                                 if (efi_debug)
 691                                         (void) fprintf(stderr,
 692                                             "Using active %d\n", *active);
 693                         }
 694 
 695                         tok = end;
 696                 }
 697         }
 698         (void) fclose(fp);
 699         smbios_close(shp);
 700 }
 701 
 702 /* writes a "protective" MBR */
 703 static int
 704 write_pmbr(int fd, struct dk_gpt *vtoc)
 705 {
 706         dk_efi_t        dk_ioc;
 707         struct mboot    mb;
 708         uchar_t         *cp;
 709         diskaddr_t      size_in_lba;
 710         uchar_t         *buf;
 711         int             len, slot, active;
 712 
 713         slot = active = 0;
 714 
 715         hardware_workarounds(&slot, &active);
 716 
 717         len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
 718         buf = calloc(len, 1);
 719 
 720         /*
 721          * Preserve any boot code and disk signature if the first block is
 722          * already an MBR.
 723          */
 724         dk_ioc.dki_lba = 0;
 725         dk_ioc.dki_length = len;
 726         /* LINTED -- always longlong aligned */
 727         dk_ioc.dki_data = (efi_gpt_t *)buf;
 728         if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
 729                 (void) memcpy(&mb, buf, sizeof (mb));
 730                 bzero(&mb, sizeof (mb));
 731                 mb.signature = LE_16(MBB_MAGIC);
 732         } else {
 733                 (void) memcpy(&mb, buf, sizeof (mb));
 734                 if (mb.signature != LE_16(MBB_MAGIC)) {
 735                         bzero(&mb, sizeof (mb));
 736                         mb.signature = LE_16(MBB_MAGIC);
 737                 }
 738         }
 739 
 740         bzero(&mb.parts, sizeof (mb.parts));
 741         cp = (uchar_t *)&mb.parts[slot * sizeof (struct ipart)];
 742         /* bootable or not */
 743         *cp++ = active ? ACTIVE : NOTACTIVE;
 744         /* beginning CHS; 0xffffff if not representable */
 745         *cp++ = 0xff;
 746         *cp++ = 0xff;
 747         *cp++ = 0xff;
 748         /* OS type */
 749         *cp++ = EFI_PMBR;
 750         /* ending CHS; 0xffffff if not representable */
 751         *cp++ = 0xff;
 752         *cp++ = 0xff;
 753         *cp++ = 0xff;
 754         /* starting LBA: 1 (little endian format) by EFI definition */
 755         *cp++ = 0x01;
 756         *cp++ = 0x00;
 757         *cp++ = 0x00;
 758         *cp++ = 0x00;
 759         /* ending LBA: last block on the disk (little endian format) */
 760         size_in_lba = vtoc->efi_last_lba;
 761         if (size_in_lba < 0xffffffff) {
 762                 *cp++ = (size_in_lba & 0x000000ff);
 763                 *cp++ = (size_in_lba & 0x0000ff00) >> 8;
 764                 *cp++ = (size_in_lba & 0x00ff0000) >> 16;
 765                 *cp++ = (size_in_lba & 0xff000000) >> 24;
 766         } else {
 767                 *cp++ = 0xff;
 768                 *cp++ = 0xff;
 769                 *cp++ = 0xff;
 770                 *cp++ = 0xff;
 771         }
 772 
 773         (void) memcpy(buf, &mb, sizeof (mb));
 774         /* LINTED -- always longlong aligned */
 775         dk_ioc.dki_data = (efi_gpt_t *)buf;
 776         dk_ioc.dki_lba = 0;
 777         dk_ioc.dki_length = len;
 778         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
 779                 free(buf);
 780                 switch (errno) {
 781                 case EIO:
 782                         return (VT_EIO);
 783                 case EINVAL:
 784                         return (VT_EINVAL);
 785                 default:
 786                         return (VT_ERROR);
 787                 }
 788         }
 789         free(buf);
 790         return (0);
 791 }
 792 
 793 /* make sure the user specified something reasonable */
 794 static int
 795 check_input(struct dk_gpt *vtoc)
 796 {
 797         int                     resv_part = -1;
 798         int                     i, j;
 799         diskaddr_t              istart, jstart, isize, jsize, endsect;
 800 
 801         /*
 802          * Sanity-check the input (make sure no partitions overlap)
 803          */
 804         for (i = 0; i < vtoc->efi_nparts; i++) {
 805                 /* It can't be unassigned and have an actual size */
 806                 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
 807                     (vtoc->efi_parts[i].p_size != 0)) {
 808                         if (efi_debug) {
 809                                 (void) fprintf(stderr,
 810 "partition %d is \"unassigned\" but has a size of %llu",
 811                                     i,
 812                                     vtoc->efi_parts[i].p_size);
 813                         }
 814                         return (VT_EINVAL);
 815                 }
 816                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
 817                         if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
 818                                 continue;
 819                         /* we have encountered an unknown uuid */
 820                         vtoc->efi_parts[i].p_tag = 0xff;
 821                 }
 822                 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
 823                         if (resv_part != -1) {
 824                                 if (efi_debug) {
 825                                         (void) fprintf(stderr,
 826 "found duplicate reserved partition at %d\n",
 827                                             i);
 828                                 }
 829                                 return (VT_EINVAL);
 830                         }
 831                         resv_part = i;
 832                 }
 833                 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
 834                     (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
 835                         if (efi_debug) {
 836                                 (void) fprintf(stderr,
 837                                     "Partition %d starts at %llu.  ",
 838                                     i,
 839                                     vtoc->efi_parts[i].p_start);
 840                                 (void) fprintf(stderr,
 841                                     "It must be between %llu and %llu.\n",
 842                                     vtoc->efi_first_u_lba,
 843                                     vtoc->efi_last_u_lba);
 844                         }
 845                         return (VT_EINVAL);
 846                 }
 847                 if ((vtoc->efi_parts[i].p_start +
 848                     vtoc->efi_parts[i].p_size <
 849                     vtoc->efi_first_u_lba) ||
 850                     (vtoc->efi_parts[i].p_start +
 851                     vtoc->efi_parts[i].p_size >
 852                     vtoc->efi_last_u_lba + 1)) {
 853                         if (efi_debug) {
 854                                 (void) fprintf(stderr,
 855                                     "Partition %d ends at %llu.  ",
 856                                     i,
 857                                     vtoc->efi_parts[i].p_start +
 858                                     vtoc->efi_parts[i].p_size);
 859                                 (void) fprintf(stderr,
 860                                     "It must be between %llu and %llu.\n",
 861                                     vtoc->efi_first_u_lba,
 862                                     vtoc->efi_last_u_lba);
 863                         }
 864                         return (VT_EINVAL);
 865                 }
 866 
 867                 for (j = 0; j < vtoc->efi_nparts; j++) {
 868                         isize = vtoc->efi_parts[i].p_size;
 869                         jsize = vtoc->efi_parts[j].p_size;
 870                         istart = vtoc->efi_parts[i].p_start;
 871                         jstart = vtoc->efi_parts[j].p_start;
 872                         if ((i != j) && (isize != 0) && (jsize != 0)) {
 873                                 endsect = jstart + jsize -1;
 874                                 if ((jstart <= istart) &&
 875                                     (istart <= endsect)) {
 876                                         if (efi_debug) {
 877                                                 (void) fprintf(stderr,
 878 "Partition %d overlaps partition %d.",
 879                                                     i, j);
 880                                         }
 881                                         return (VT_EINVAL);
 882                                 }
 883                         }
 884                 }
 885         }
 886         /* just a warning for now */
 887         if ((resv_part == -1) && efi_debug) {
 888                 (void) fprintf(stderr,
 889                     "no reserved partition found\n");
 890         }
 891         return (0);
 892 }
 893 
 894 /*
 895  * add all the unallocated space to the current label
 896  */
 897 int
 898 efi_use_whole_disk(int fd)
 899 {
 900         struct dk_gpt           *efi_label;
 901         int                     rval;
 902         int                     i;
 903         uint_t                  phy_last_slice = 0;
 904         diskaddr_t              pl_start = 0;
 905         diskaddr_t              pl_size;
 906 
 907         rval = efi_alloc_and_read(fd, &efi_label);
 908         if (rval < 0) {
 909                 return (rval);
 910         }
 911 
 912         /* find the last physically non-zero partition */
 913         for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
 914                 if (pl_start < efi_label->efi_parts[i].p_start) {
 915                         pl_start = efi_label->efi_parts[i].p_start;
 916                         phy_last_slice = i;
 917                 }
 918         }
 919         pl_size = efi_label->efi_parts[phy_last_slice].p_size;
 920 
 921         /*
 922          * If alter_lba is 1, we are using the backup label.
 923          * Since we can locate the backup label by disk capacity,
 924          * there must be no unallocated space.
 925          */
 926         if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba
 927             >= efi_label->efi_last_lba)) {
 928                 if (efi_debug) {
 929                         (void) fprintf(stderr,
 930                             "efi_use_whole_disk: requested space not found\n");
 931                 }
 932                 efi_free(efi_label);
 933                 return (VT_ENOSPC);
 934         }
 935 
 936         /*
 937          * If there is space between the last physically non-zero partition
 938          * and the reserved partition, just add the unallocated space to this
 939          * area. Otherwise, the unallocated space is added to the last
 940          * physically non-zero partition.
 941          */
 942         if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
 943             EFI_MIN_RESV_SIZE) {
 944                 efi_label->efi_parts[phy_last_slice].p_size +=
 945                     efi_label->efi_last_lba - efi_label->efi_altern_lba;
 946         }
 947 
 948         /*
 949          * Move the reserved partition. There is currently no data in
 950          * here except fabricated devids (which get generated via
 951          * efi_write()). So there is no need to copy data.
 952          */
 953         efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
 954             efi_label->efi_last_lba - efi_label->efi_altern_lba;
 955         efi_label->efi_last_u_lba += efi_label->efi_last_lba
 956             - efi_label->efi_altern_lba;
 957 
 958         rval = efi_write(fd, efi_label);
 959         if (rval < 0) {
 960                 if (efi_debug) {
 961                         (void) fprintf(stderr,
 962                             "efi_use_whole_disk:fail to write label, rval=%d\n",
 963                             rval);
 964                 }
 965                 efi_free(efi_label);
 966                 return (rval);
 967         }
 968 
 969         efi_free(efi_label);
 970         return (0);
 971 }
 972 
 973 
 974 /*
 975  * write EFI label and backup label
 976  */
 977 int
 978 efi_write(int fd, struct dk_gpt *vtoc)
 979 {
 980         dk_efi_t                dk_ioc;
 981         efi_gpt_t               *efi;
 982         efi_gpe_t               *efi_parts;
 983         int                     i, j;
 984         struct dk_cinfo         dki_info;
 985         int                     nblocks;
 986         diskaddr_t              lba_backup_gpt_hdr;
 987 
 988         if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
 989                 if (efi_debug)
 990                         (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
 991                 switch (errno) {
 992                 case EIO:
 993                         return (VT_EIO);
 994                 case EINVAL:
 995                         return (VT_EINVAL);
 996                 default:
 997                         return (VT_ERROR);
 998                 }
 999         }
1000 
1001         if (check_input(vtoc))
1002                 return (VT_EINVAL);
1003 
1004         dk_ioc.dki_lba = 1;
1005         if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
1006                 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
1007         } else {
1008                 dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
1009                     vtoc->efi_lbasize) *
1010                     vtoc->efi_lbasize;
1011         }
1012 
1013         /*
1014          * the number of blocks occupied by GUID partition entry array
1015          */
1016         nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
1017 
1018         /*
1019          * Backup GPT header is located on the block after GUID
1020          * partition entry array. Here, we calculate the address
1021          * for backup GPT header.
1022          */
1023         lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
1024         if ((dk_ioc.dki_data = calloc(1, dk_ioc.dki_length)) == NULL)
1025                 return (VT_ERROR);
1026 
1027         efi = dk_ioc.dki_data;
1028 
1029         /* stuff user's input into EFI struct */
1030         efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
1031         efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
1032         efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
1033         efi->efi_gpt_Reserved1 = 0;
1034         efi->efi_gpt_MyLBA = LE_64(1ULL);
1035         efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
1036         efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
1037         efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
1038         efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
1039         efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
1040         efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
1041         UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
1042 
1043         /* LINTED -- always longlong aligned */
1044         efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
1045 
1046         for (i = 0; i < vtoc->efi_nparts; i++) {
1047                 for (j = 0;
1048                     j < sizeof (conversion_array) /
1049                     sizeof (struct uuid_to_ptag); j++) {
1050 
1051                         if (vtoc->efi_parts[i].p_tag ==
1052                             conversion_array[j].p_tag) {
1053                                 UUID_LE_CONVERT(
1054                                     efi_parts[i].efi_gpe_PartitionTypeGUID,
1055                                     conversion_array[j].uuid);
1056                                 break;
1057                         }
1058                 }
1059 
1060                 if (j == sizeof (conversion_array) /
1061                     sizeof (struct uuid_to_ptag)) {
1062                         /*
1063                          * If we didn't have a matching uuid match, bail here.
1064                          * Don't write a label with unknown uuid.
1065                          */
1066                         if (efi_debug) {
1067                                 (void) fprintf(stderr,
1068                                     "Unknown uuid for p_tag %d\n",
1069                                     vtoc->efi_parts[i].p_tag);
1070                         }
1071                         return (VT_EINVAL);
1072                 }
1073 
1074                 efi_parts[i].efi_gpe_StartingLBA =
1075                     LE_64(vtoc->efi_parts[i].p_start);
1076                 efi_parts[i].efi_gpe_EndingLBA =
1077                     LE_64(vtoc->efi_parts[i].p_start +
1078                     vtoc->efi_parts[i].p_size - 1);
1079                 efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
1080                     LE_16(vtoc->efi_parts[i].p_flag);
1081                 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
1082                         efi_parts[i].efi_gpe_PartitionName[j] =
1083                             LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
1084                 }
1085                 if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
1086                     uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
1087                         (void) uuid_generate((uchar_t *)
1088                             &vtoc->efi_parts[i].p_uguid);
1089                 }
1090                 bcopy(&vtoc->efi_parts[i].p_uguid,
1091                     &efi_parts[i].efi_gpe_UniquePartitionGUID,
1092                     sizeof (uuid_t));
1093         }
1094         efi->efi_gpt_PartitionEntryArrayCRC32 =
1095             LE_32(efi_crc32((unsigned char *)efi_parts,
1096             vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
1097         efi->efi_gpt_HeaderCRC32 =
1098             LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
1099 
1100         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1101                 free(dk_ioc.dki_data);
1102                 switch (errno) {
1103                 case EIO:
1104                         return (VT_EIO);
1105                 case EINVAL:
1106                         return (VT_EINVAL);
1107                 default:
1108                         return (VT_ERROR);
1109                 }
1110         }
1111 
1112         /* write backup partition array */
1113         dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
1114         dk_ioc.dki_length -= vtoc->efi_lbasize;
1115         /* LINTED */
1116         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
1117             vtoc->efi_lbasize);
1118 
1119         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1120                 /*
1121                  * we wrote the primary label okay, so don't fail
1122                  */
1123                 if (efi_debug) {
1124                         (void) fprintf(stderr,
1125                             "write of backup partitions to block %llu "
1126                             "failed, errno %d\n",
1127                             vtoc->efi_last_u_lba + 1,
1128                             errno);
1129                 }
1130         }
1131         /*
1132          * now swap MyLBA and AlternateLBA fields and write backup
1133          * partition table header
1134          */
1135         dk_ioc.dki_lba = lba_backup_gpt_hdr;
1136         dk_ioc.dki_length = vtoc->efi_lbasize;
1137         /* LINTED */
1138         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
1139             vtoc->efi_lbasize);
1140         efi->efi_gpt_AlternateLBA = LE_64(1ULL);
1141         efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
1142         efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
1143         efi->efi_gpt_HeaderCRC32 = 0;
1144         efi->efi_gpt_HeaderCRC32 =
1145             LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
1146             sizeof (struct efi_gpt)));
1147 
1148         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1149                 if (efi_debug) {
1150                         (void) fprintf(stderr,
1151                             "write of backup header to block %llu failed, "
1152                             "errno %d\n",
1153                             lba_backup_gpt_hdr,
1154                             errno);
1155                 }
1156         }
1157         /* write the PMBR */
1158         (void) write_pmbr(fd, vtoc);
1159         free(dk_ioc.dki_data);
1160         return (0);
1161 }
1162 
1163 void
1164 efi_free(struct dk_gpt *ptr)
1165 {
1166         free(ptr);
1167 }
1168 
1169 /*
1170  * Input: File descriptor
1171  * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
1172  * Otherwise 0.
1173  */
1174 int
1175 efi_type(int fd)
1176 {
1177         struct vtoc vtoc;
1178         struct extvtoc extvtoc;
1179 
1180         if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) {
1181                 if (errno == ENOTSUP)
1182                         return (1);
1183                 else if (errno == ENOTTY) {
1184                         if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1)
1185                                 if (errno == ENOTSUP)
1186                                         return (1);
1187                 }
1188         }
1189         return (0);
1190 }
1191 
1192 void
1193 efi_err_check(struct dk_gpt *vtoc)
1194 {
1195         int                     resv_part = -1;
1196         int                     i, j;
1197         diskaddr_t              istart, jstart, isize, jsize, endsect;
1198         int                     overlap = 0;
1199 
1200         /*
1201          * make sure no partitions overlap
1202          */
1203         for (i = 0; i < vtoc->efi_nparts; i++) {
1204                 /* It can't be unassigned and have an actual size */
1205                 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
1206                     (vtoc->efi_parts[i].p_size != 0)) {
1207                         (void) fprintf(stderr,
1208                             "partition %d is \"unassigned\" but has a size "
1209                             "of %llu\n", i, vtoc->efi_parts[i].p_size);
1210                 }
1211                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
1212                         continue;
1213                 }
1214                 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
1215                         if (resv_part != -1) {
1216                                 (void) fprintf(stderr,
1217                                     "found duplicate reserved partition at "
1218                                     "%d\n", i);
1219                         }
1220                         resv_part = i;
1221                         if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
1222                                 (void) fprintf(stderr,
1223                                     "Warning: reserved partition size must "
1224                                     "be %d sectors\n", EFI_MIN_RESV_SIZE);
1225                 }
1226                 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
1227                     (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
1228                         (void) fprintf(stderr,
1229                             "Partition %d starts at %llu\n",
1230                             i,
1231                             vtoc->efi_parts[i].p_start);
1232                         (void) fprintf(stderr,
1233                             "It must be between %llu and %llu.\n",
1234                             vtoc->efi_first_u_lba,
1235                             vtoc->efi_last_u_lba);
1236                 }
1237                 if ((vtoc->efi_parts[i].p_start +
1238                     vtoc->efi_parts[i].p_size <
1239                     vtoc->efi_first_u_lba) ||
1240                     (vtoc->efi_parts[i].p_start +
1241                     vtoc->efi_parts[i].p_size >
1242                     vtoc->efi_last_u_lba + 1)) {
1243                         (void) fprintf(stderr,
1244                             "Partition %d ends at %llu\n",
1245                             i,
1246                             vtoc->efi_parts[i].p_start +
1247                             vtoc->efi_parts[i].p_size);
1248                         (void) fprintf(stderr,
1249                             "It must be between %llu and %llu.\n",
1250                             vtoc->efi_first_u_lba,
1251                             vtoc->efi_last_u_lba);
1252                 }
1253 
1254                 for (j = 0; j < vtoc->efi_nparts; j++) {
1255                         isize = vtoc->efi_parts[i].p_size;
1256                         jsize = vtoc->efi_parts[j].p_size;
1257                         istart = vtoc->efi_parts[i].p_start;
1258                         jstart = vtoc->efi_parts[j].p_start;
1259                         if ((i != j) && (isize != 0) && (jsize != 0)) {
1260                                 endsect = jstart + jsize -1;
1261                                 if ((jstart <= istart) &&
1262                                     (istart <= endsect)) {
1263                                         if (!overlap) {
1264                                         (void) fprintf(stderr,
1265                                             "label error: EFI Labels do not "
1266                                             "support overlapping partitions\n");
1267                                         }
1268                                         (void) fprintf(stderr,
1269                                             "Partition %d overlaps partition "
1270                                             "%d.\n", i, j);
1271                                         overlap = 1;
1272                                 }
1273                         }
1274                 }
1275         }
1276         /* make sure there is a reserved partition */
1277         if (resv_part == -1) {
1278                 (void) fprintf(stderr,
1279                     "no reserved partition found\n");
1280         }
1281 }
1282 
1283 /*
1284  * We need to get information necessary to construct a *new* efi
1285  * label type
1286  */
1287 int
1288 efi_auto_sense(int fd, struct dk_gpt **vtoc)
1289 {
1290 
1291         int     i;
1292 
1293         /*
1294          * Now build the default partition table
1295          */
1296         if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
1297                 if (efi_debug) {
1298                         (void) fprintf(stderr, "efi_alloc_and_init failed.\n");
1299                 }
1300                 return (-1);
1301         }
1302 
1303         for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
1304                 (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
1305                 (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
1306                 (*vtoc)->efi_parts[i].p_start = 0;
1307                 (*vtoc)->efi_parts[i].p_size = 0;
1308         }
1309         /*
1310          * Make constants first
1311          * and variable partitions later
1312          */
1313 
1314         /* root partition - s0 128 MB */
1315         (*vtoc)->efi_parts[0].p_start = 34;
1316         (*vtoc)->efi_parts[0].p_size = 262144;
1317 
1318         /* partition - s1  128 MB */
1319         (*vtoc)->efi_parts[1].p_start = 262178;
1320         (*vtoc)->efi_parts[1].p_size = 262144;
1321 
1322         /* partition -s2 is NOT the Backup disk */
1323         (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
1324 
1325         /* partition -s6 /usr partition - HOG */
1326         (*vtoc)->efi_parts[6].p_start = 524322;
1327         (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
1328             - (1024 * 16);
1329 
1330         /* efi reserved partition - s9 16K */
1331         (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
1332         (*vtoc)->efi_parts[8].p_size = (1024 * 16);
1333         (*vtoc)->efi_parts[8].p_tag = V_RESERVED;
1334         return (0);
1335 }