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 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <smbios.h>
35 #include <uuid/uuid.h>
36 #include <libintl.h>
37 #include <sys/types.h>
38 #include <sys/dkio.h>
39 #include <sys/vtoc.h>
40 #include <sys/mhd.h>
41 #include <sys/param.h>
42 #include <sys/dktp/fdisk.h>
43 #include <sys/efi_partition.h>
44 #include <sys/byteorder.h>
45 #include <sys/ddi.h>
46
171 }
172
173 nblocks = NBLOCKS(nparts, lbsize);
174 if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
175 /* 16K plus one block for the GPT */
176 nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
177 }
178
179 if (nparts > MAX_PARTS) {
180 if (efi_debug) {
181 (void) fprintf(stderr,
182 "the maximum number of partitions supported is %lu\n",
183 MAX_PARTS);
184 }
185 return (-1);
186 }
187
188 length = sizeof (struct dk_gpt) +
189 sizeof (struct dk_part) * (nparts - 1);
190
191 if ((*vtoc = calloc(length, 1)) == NULL)
192 return (-1);
193
194 vptr = *vtoc;
195
196 vptr->efi_version = EFI_VERSION_CURRENT;
197 vptr->efi_lbasize = lbsize;
198 vptr->efi_nparts = nparts;
199 /*
200 * add one block here for the PMBR; on disks with a 512 byte
201 * block size and 128 or fewer partitions, efi_first_u_lba
202 * should work out to "34"
203 */
204 vptr->efi_first_u_lba = nblocks + 1;
205 vptr->efi_last_lba = capacity - 1;
206 vptr->efi_altern_lba = capacity -1;
207 vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
208
209 (void) uuid_generate((uchar_t *)&uuid);
210 UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
211 return (0);
212 }
213
214 /*
215 * Read EFI - return partition number upon success.
216 */
217 int
218 efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
219 {
220 int rval;
221 uint32_t nparts;
222 int length;
223 struct mboot *mbr;
224 struct ipart *ipart;
225 diskaddr_t capacity;
226 uint_t lbsize;
227 int i;
228
229 if (read_disk_info(fd, &capacity, &lbsize) != 0)
230 return (VT_ERROR);
231
232 if ((mbr = calloc(lbsize, 1)) == NULL)
233 return (VT_ERROR);
234
235 if ((ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) {
236 free(mbr);
237 return (VT_ERROR);
238 }
239
240 if (mbr->signature != MBB_MAGIC) {
241 free(mbr);
242 return (VT_EINVAL);
243 }
244 ipart = (struct ipart *)(uintptr_t)mbr->parts;
245
246 /* Check if we have partition with ID EFI_PMBR */
247 for (i = 0; i < FD_NUMPART; i++) {
248 if (ipart[i].systid == EFI_PMBR)
249 break;
250 }
251 free(mbr);
252 if (i == FD_NUMPART)
253 return (VT_EINVAL);
254
255 /* figure out the number of entries that would fit into 16K */
256 nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
257 length = (int) sizeof (struct dk_gpt) +
258 (int) sizeof (struct dk_part) * (nparts - 1);
259 if ((*vtoc = calloc(length, 1)) == NULL)
260 return (VT_ERROR);
261
262 (*vtoc)->efi_nparts = nparts;
263 rval = efi_read(fd, *vtoc);
264
265 if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
266 void *tmp;
267 length = (int) sizeof (struct dk_gpt) +
268 (int) sizeof (struct dk_part) *
269 ((*vtoc)->efi_nparts - 1);
270 nparts = (*vtoc)->efi_nparts;
271 if ((tmp = realloc(*vtoc, length)) == NULL) {
272 free (*vtoc);
273 *vtoc = NULL;
274 return (VT_ERROR);
275 } else {
276 *vtoc = tmp;
277 rval = efi_read(fd, *vtoc);
278 }
279 }
406 }
407 disk_info.dki_lbsize = DEV_BSIZE;
408 }
409 /*
410 * Read the EFI GPT to figure out how many partitions we need
411 * to deal with.
412 */
413 dk_ioc.dki_lba = 1;
414 if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
415 label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
416 } else {
417 label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
418 disk_info.dki_lbsize;
419 if (label_len % disk_info.dki_lbsize) {
420 /* pad to physical sector size */
421 label_len += disk_info.dki_lbsize;
422 label_len &= ~(disk_info.dki_lbsize - 1);
423 }
424 }
425
426 if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
427 return (VT_ERROR);
428
429 dk_ioc.dki_length = disk_info.dki_lbsize;
430 user_length = vtoc->efi_nparts;
431 efi = dk_ioc.dki_data;
432 if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
433 /*
434 * No valid label here; try the alternate. Note that here
435 * we just read GPT header and save it into dk_ioc.data,
436 * Later, we will read GUID partition entry array if we
437 * can get valid GPT header.
438 */
439
440 /*
441 * This is a workaround for legacy systems. In the past, the
442 * last sector of SCSI disk was invisible on x86 platform. At
443 * that time, backup label was saved on the next to the last
444 * sector. It is possible for users to move a disk from previous
445 * solaris system to present system. Here, we attempt to search
446 * legacy backup EFI label first.
1003 dk_ioc.dki_lba = 1;
1004 if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
1005 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
1006 } else {
1007 dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
1008 vtoc->efi_lbasize) *
1009 vtoc->efi_lbasize;
1010 }
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(dk_ioc.dki_length, 1)) == 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(sizeof (struct efi_gpt));
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);
|
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
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 }
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.
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);
|