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
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;
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;
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) {
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
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);
|
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 2019 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
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, LE_32(efi_crc32((unsigned char *)efi,
345 LE_32(efi->efi_gpt_HeaderSize))));
346 return (VT_EINVAL);
347 }
348
349 return (0);
350 }
351
352 static int
353 efi_read(int fd, struct dk_gpt *vtoc)
354 {
355 int i, j;
356 int label_len;
357 int rval = 0;
358 int vdc_flag = 0;
359 struct dk_minfo disk_info;
360 dk_efi_t dk_ioc;
361 efi_gpt_t *efi;
362 efi_gpe_t *efi_parts;
363 struct dk_cinfo dki_info;
364 uint32_t user_length;
365 boolean_t legacy_label = B_FALSE;
697 (void) fclose(fp);
698 smbios_close(shp);
699 }
700
701 /* writes a "protective" MBR */
702 static int
703 write_pmbr(int fd, struct dk_gpt *vtoc)
704 {
705 dk_efi_t dk_ioc;
706 struct mboot mb;
707 uchar_t *cp;
708 diskaddr_t size_in_lba;
709 uchar_t *buf;
710 int len, slot, active;
711
712 slot = active = 0;
713
714 hardware_workarounds(&slot, &active);
715
716 len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
717 buf = calloc(1, len);
718
719 /*
720 * Preserve any boot code and disk signature if the first block is
721 * already an MBR.
722 */
723 dk_ioc.dki_lba = 0;
724 dk_ioc.dki_length = len;
725 /* LINTED -- always longlong aligned */
726 dk_ioc.dki_data = (efi_gpt_t *)buf;
727 if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
728 (void) memcpy(&mb, buf, sizeof (mb));
729 bzero(&mb, sizeof (mb));
730 mb.signature = LE_16(MBB_MAGIC);
731 } else {
732 (void) memcpy(&mb, buf, sizeof (mb));
733 if (mb.signature != LE_16(MBB_MAGIC)) {
734 bzero(&mb, sizeof (mb));
735 mb.signature = LE_16(MBB_MAGIC);
736 }
737 }
738
739 bzero(&mb.parts, sizeof (mb.parts));
740 cp = (uchar_t *)&mb.parts[slot * sizeof (struct ipart)];
741 /* bootable or not */
742 *cp++ = active ? ACTIVE : NOTACTIVE;
743 /* beginning CHS; same as starting LBA (but one-based) */
744 *cp++ = 0x0;
745 *cp++ = 0x2;
746 *cp++ = 0x0;
747 /* OS type */
748 *cp++ = EFI_PMBR;
749 /* ending CHS; 0xffffff if not representable */
750 *cp++ = 0xff;
751 *cp++ = 0xff;
752 *cp++ = 0xff;
753 /* starting LBA: 1 (little endian format) by EFI definition */
754 *cp++ = 0x01;
755 *cp++ = 0x00;
756 *cp++ = 0x00;
757 *cp++ = 0x00;
758 /* ending LBA: last block on the disk (little endian format) */
759 size_in_lba = vtoc->efi_last_lba;
760 if (size_in_lba < 0xffffffff) {
761 *cp++ = (size_in_lba & 0x000000ff);
762 *cp++ = (size_in_lba & 0x0000ff00) >> 8;
763 *cp++ = (size_in_lba & 0x00ff0000) >> 16;
764 *cp++ = (size_in_lba & 0xff000000) >> 24;
765 } else {
766 *cp++ = 0xff;
1011
1012 /*
1013 * the number of blocks occupied by GUID partition entry array
1014 */
1015 nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
1016
1017 /*
1018 * Backup GPT header is located on the block after GUID
1019 * partition entry array. Here, we calculate the address
1020 * for backup GPT header.
1021 */
1022 lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
1023 if ((dk_ioc.dki_data = calloc(1, dk_ioc.dki_length)) == NULL)
1024 return (VT_ERROR);
1025
1026 efi = dk_ioc.dki_data;
1027
1028 /* stuff user's input into EFI struct */
1029 efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
1030 efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
1031 efi->efi_gpt_HeaderSize = LE_32(EFI_HEADER_SIZE);
1032 efi->efi_gpt_Reserved1 = 0;
1033 efi->efi_gpt_MyLBA = LE_64(1ULL);
1034 efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
1035 efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
1036 efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
1037 efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
1038 efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
1039 efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
1040 UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
1041
1042 /* LINTED -- always longlong aligned */
1043 efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
1044
1045 for (i = 0; i < vtoc->efi_nparts; i++) {
1046 for (j = 0;
1047 j < sizeof (conversion_array) /
1048 sizeof (struct uuid_to_ptag); j++) {
1049
1050 if (vtoc->efi_parts[i].p_tag ==
1051 conversion_array[j].p_tag) {
1076 LE_64(vtoc->efi_parts[i].p_start +
1077 vtoc->efi_parts[i].p_size - 1);
1078 efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
1079 LE_16(vtoc->efi_parts[i].p_flag);
1080 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
1081 efi_parts[i].efi_gpe_PartitionName[j] =
1082 LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
1083 }
1084 if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
1085 uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
1086 (void) uuid_generate((uchar_t *)
1087 &vtoc->efi_parts[i].p_uguid);
1088 }
1089 bcopy(&vtoc->efi_parts[i].p_uguid,
1090 &efi_parts[i].efi_gpe_UniquePartitionGUID,
1091 sizeof (uuid_t));
1092 }
1093 efi->efi_gpt_PartitionEntryArrayCRC32 =
1094 LE_32(efi_crc32((unsigned char *)efi_parts,
1095 vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
1096 efi->efi_gpt_HeaderCRC32 = LE_32(efi_crc32((unsigned char *)efi,
1097 EFI_HEADER_SIZE));
1098
1099 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1100 free(dk_ioc.dki_data);
1101 switch (errno) {
1102 case EIO:
1103 return (VT_EIO);
1104 case EINVAL:
1105 return (VT_EINVAL);
1106 default:
1107 return (VT_ERROR);
1108 }
1109 }
1110
1111 /* write backup partition array */
1112 dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
1113 dk_ioc.dki_length -= vtoc->efi_lbasize;
1114 /* LINTED */
1115 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
1116 vtoc->efi_lbasize);
1117
1124 "write of backup partitions to block %llu "
1125 "failed, errno %d\n",
1126 vtoc->efi_last_u_lba + 1,
1127 errno);
1128 }
1129 }
1130 /*
1131 * now swap MyLBA and AlternateLBA fields and write backup
1132 * partition table header
1133 */
1134 dk_ioc.dki_lba = lba_backup_gpt_hdr;
1135 dk_ioc.dki_length = vtoc->efi_lbasize;
1136 /* LINTED */
1137 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
1138 vtoc->efi_lbasize);
1139 efi->efi_gpt_AlternateLBA = LE_64(1ULL);
1140 efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
1141 efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
1142 efi->efi_gpt_HeaderCRC32 = 0;
1143 efi->efi_gpt_HeaderCRC32 =
1144 LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data, EFI_HEADER_SIZE));
1145
1146 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1147 if (efi_debug) {
1148 (void) fprintf(stderr,
1149 "write of backup header to block %llu failed, "
1150 "errno %d\n",
1151 lba_backup_gpt_hdr,
1152 errno);
1153 }
1154 }
1155 /* write the PMBR */
1156 (void) write_pmbr(fd, vtoc);
1157 free(dk_ioc.dki_data);
1158 return (0);
1159 }
1160
1161 void
1162 efi_free(struct dk_gpt *ptr)
1163 {
1164 free(ptr);
|