xref: /titanic_44/usr/src/lib/libefi/common/rdwr_efi.c (revision 6dfee4834394825da35b977ca71cdc965bc7b6a4)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <uuid/uuid.h>
35 #include <libintl.h>
36 #include <sys/types.h>
37 #include <sys/dkio.h>
38 #include <sys/vtoc.h>
39 #include <sys/mhd.h>
40 #include <sys/param.h>
41 #include <sys/dktp/fdisk.h>
42 #include <sys/efi_partition.h>
43 #include <sys/byteorder.h>
44 #include <sys/ddi.h>
45 
46 static struct uuid_to_ptag {
47 	struct uuid	uuid;
48 } conversion_array[] = {
49 	{ EFI_UNUSED },
50 	{ EFI_BOOT },
51 	{ EFI_ROOT },
52 	{ EFI_SWAP },
53 	{ EFI_USR },
54 	{ EFI_BACKUP },
55 	{ 0 },			/* STAND is never used */
56 	{ EFI_VAR },
57 	{ EFI_HOME },
58 	{ EFI_ALTSCTR },
59 	{ 0 },			/* CACHE (cachefs) is never used */
60 	{ EFI_RESERVED },
61 	{ EFI_SYSTEM },
62 	{ EFI_LEGACY_MBR },
63 	{ EFI_RESV3 },
64 	{ EFI_RESV4 },
65 	{ EFI_MSFT_RESV },
66 	{ EFI_DELL_BASIC },
67 	{ EFI_DELL_RAID },
68 	{ EFI_DELL_SWAP },
69 	{ EFI_DELL_LVM },
70 	{ EFI_DELL_RESV }
71 };
72 
73 /*
74  * Default vtoc information for non-SVr4 partitions
75  */
76 struct dk_map2  default_vtoc_map[NDKMAP] = {
77 	{	V_ROOT,		0	},		/* a - 0 */
78 	{	V_SWAP,		V_UNMNT	},		/* b - 1 */
79 	{	V_BACKUP,	V_UNMNT	},		/* c - 2 */
80 	{	V_UNASSIGNED,	0	},		/* d - 3 */
81 	{	V_UNASSIGNED,	0	},		/* e - 4 */
82 	{	V_UNASSIGNED,	0	},		/* f - 5 */
83 	{	V_USR,		0	},		/* g - 6 */
84 	{	V_UNASSIGNED,	0	},		/* h - 7 */
85 
86 #if defined(_SUNOS_VTOC_16)
87 
88 #if defined(i386) || defined(__amd64)
89 	{	V_BOOT,		V_UNMNT	},		/* i - 8 */
90 	{	V_ALTSCTR,	0	},		/* j - 9 */
91 
92 #else
93 #error No VTOC format defined.
94 #endif			/* defined(i386) */
95 
96 	{	V_UNASSIGNED,	0	},		/* k - 10 */
97 	{	V_UNASSIGNED,	0	},		/* l - 11 */
98 	{	V_UNASSIGNED,	0	},		/* m - 12 */
99 	{	V_UNASSIGNED,	0	},		/* n - 13 */
100 	{	V_UNASSIGNED,	0	},		/* o - 14 */
101 	{	V_UNASSIGNED,	0	},		/* p - 15 */
102 #endif			/* defined(_SUNOS_VTOC_16) */
103 };
104 
105 /*
106  * This is the size of the reserved partition.
107  * Valid in case of EFI labels.
108  */
109 #define	EFI_MIN_RESV_SIZE	(16 * 1024)
110 
111 #ifdef DEBUG
112 int efi_debug = 1;
113 #else
114 int efi_debug = 0;
115 #endif
116 
117 extern unsigned int	efi_crc32(const unsigned char *, unsigned int);
118 static int		efi_read(int, struct dk_gpt *);
119 
120 static int
121 read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
122 {
123 	struct dk_minfo		disk_info;
124 
125 	if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
126 		return (errno);
127 	*capacity = disk_info.dki_capacity;
128 	*lbsize = disk_info.dki_lbsize;
129 	return (0);
130 }
131 
132 /*
133  * the number of blocks the EFI label takes up (round up to nearest
134  * block)
135  */
136 #define	NBLOCKS(p, l)	(1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
137 				((l) - 1)) / (l)))
138 /* number of partitions -- limited by what we can malloc */
139 #define	MAX_PARTS	((4294967295UL - sizeof (struct dk_gpt)) / \
140 			    sizeof (struct dk_part))
141 
142 int
143 efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
144 {
145 	diskaddr_t	capacity;
146 	uint_t		lbsize;
147 	uint_t		nblocks;
148 	size_t		length;
149 	struct dk_gpt	*vptr;
150 	struct uuid	uuid;
151 
152 	if (read_disk_info(fd, &capacity, &lbsize) != 0) {
153 		if (efi_debug)
154 			(void) fprintf(stderr,
155 			    "couldn't read disk information\n");
156 		return (-1);
157 	}
158 
159 	nblocks = NBLOCKS(nparts, lbsize);
160 	if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
161 		/* 16K plus one block for the GPT */
162 		nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
163 	}
164 
165 	if (nparts > MAX_PARTS) {
166 		if (efi_debug) {
167 			(void) fprintf(stderr,
168 			"the maximum number of partitions supported is %lu\n",
169 			    MAX_PARTS);
170 		}
171 		return (-1);
172 	}
173 
174 	length = sizeof (struct dk_gpt) +
175 	    sizeof (struct dk_part) * (nparts - 1);
176 
177 	if ((*vtoc = calloc(length, 1)) == NULL)
178 		return (-1);
179 
180 	vptr = *vtoc;
181 
182 	vptr->efi_version = EFI_VERSION_CURRENT;
183 	vptr->efi_lbasize = lbsize;
184 	vptr->efi_nparts = nparts;
185 	/*
186 	 * add one block here for the PMBR; on disks with a 512 byte
187 	 * block size and 128 or fewer partitions, efi_first_u_lba
188 	 * should work out to "34"
189 	 */
190 	vptr->efi_first_u_lba = nblocks + 1;
191 	vptr->efi_last_lba = capacity - 1;
192 	vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
193 	(void) uuid_generate((uchar_t *)&uuid);
194 	UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
195 	return (0);
196 }
197 
198 /*
199  * Read EFI - return partition number upon success.
200  */
201 int
202 efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
203 {
204 	int			rval;
205 	uint32_t		nparts;
206 	int			length;
207 
208 	/* figure out the number of entries that would fit into 16K */
209 	nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
210 	length = (int) sizeof (struct dk_gpt) +
211 			    (int) sizeof (struct dk_part) * (nparts - 1);
212 	if ((*vtoc = calloc(length, 1)) == NULL)
213 		return (VT_ERROR);
214 
215 	(*vtoc)->efi_nparts = nparts;
216 	rval = efi_read(fd, *vtoc);
217 
218 	if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
219 		void *tmp;
220 		length = (int) sizeof (struct dk_gpt) +
221 				(int) sizeof (struct dk_part) *
222 				((*vtoc)->efi_nparts - 1);
223 		nparts = (*vtoc)->efi_nparts;
224 		if ((tmp = realloc(*vtoc, length)) == NULL) {
225 			free (*vtoc);
226 			*vtoc = NULL;
227 			return (VT_ERROR);
228 		} else {
229 			*vtoc = tmp;
230 			rval = efi_read(fd, *vtoc);
231 		}
232 	}
233 
234 	if (rval < 0) {
235 		if (efi_debug) {
236 			(void) fprintf(stderr,
237 			    "read of EFI table failed, rval=%d\n", rval);
238 		}
239 		free (*vtoc);
240 		*vtoc = NULL;
241 	}
242 
243 	return (rval);
244 }
245 
246 static int
247 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
248 {
249 	void *data = dk_ioc->dki_data;
250 	int error;
251 
252 	dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
253 	error = ioctl(fd, cmd, (void *)dk_ioc);
254 	dk_ioc->dki_data = data;
255 
256 	return (error);
257 }
258 
259 static int
260 check_label(int fd, dk_efi_t *dk_ioc)
261 {
262 	efi_gpt_t		*efi;
263 	uint_t			crc;
264 
265 	if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
266 		switch (errno) {
267 		case EIO:
268 			return (VT_EIO);
269 		default:
270 			return (VT_ERROR);
271 		}
272 	}
273 	efi = dk_ioc->dki_data;
274 	if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
275 		if (efi_debug)
276 			(void) fprintf(stderr,
277 			    "Bad EFI signature: 0x%llx != 0x%llx\n",
278 			    (long long)efi->efi_gpt_Signature,
279 			    (long long)LE_64(EFI_SIGNATURE));
280 		return (VT_EINVAL);
281 	}
282 
283 	/*
284 	 * check CRC of the header; the size of the header should
285 	 * never be larger than one block
286 	 */
287 	crc = efi->efi_gpt_HeaderCRC32;
288 	efi->efi_gpt_HeaderCRC32 = 0;
289 
290 	if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
291 	    crc != LE_32(efi_crc32((unsigned char *)efi,
292 	    LE_32(efi->efi_gpt_HeaderSize)))) {
293 		if (efi_debug)
294 			(void) fprintf(stderr,
295 				"Bad EFI CRC: 0x%x != 0x%x\n",
296 				crc,
297 				LE_32(efi_crc32((unsigned char *)efi,
298 				    sizeof (struct efi_gpt))));
299 		return (VT_EINVAL);
300 	}
301 
302 	return (0);
303 }
304 
305 static int
306 efi_read(int fd, struct dk_gpt *vtoc)
307 {
308 	int			i, j;
309 	int			label_len;
310 	int			rval = 0;
311 	int			md_flag = 0;
312 	struct dk_minfo		disk_info;
313 	dk_efi_t		dk_ioc;
314 	efi_gpt_t		*efi;
315 	efi_gpe_t		*efi_parts;
316 	struct dk_cinfo		dki_info;
317 	uint32_t		user_length;
318 
319 	/*
320 	 * get the partition number for this file descriptor.
321 	 */
322 	if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
323 		if (efi_debug)
324 		    (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
325 		switch (errno) {
326 		case EIO:
327 			return (VT_EIO);
328 		case EINVAL:
329 			return (VT_EINVAL);
330 		default:
331 			return (VT_ERROR);
332 		}
333 	}
334 	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
335 	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
336 		md_flag++;
337 	}
338 	/* get the LBA size */
339 	if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
340 		if (efi_debug) {
341 			(void) fprintf(stderr,
342 			    "assuming LBA 512 bytes %d\n",
343 			    errno);
344 		}
345 		disk_info.dki_lbsize = DEV_BSIZE;
346 	}
347 	if (disk_info.dki_lbsize == 0) {
348 		if (efi_debug) {
349 			(void) fprintf(stderr,
350 			    "efi_read: assuming LBA 512 bytes\n");
351 		}
352 		disk_info.dki_lbsize = DEV_BSIZE;
353 	}
354 	/*
355 	 * Read the EFI GPT to figure out how many partitions we need
356 	 * to deal with.
357 	 */
358 	dk_ioc.dki_lba = 1;
359 	if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
360 		label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
361 	} else {
362 		label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
363 				    disk_info.dki_lbsize;
364 		if (label_len % disk_info.dki_lbsize) {
365 			/* pad to physical sector size */
366 			label_len += disk_info.dki_lbsize;
367 			label_len &= ~(disk_info.dki_lbsize - 1);
368 		}
369 	}
370 
371 	if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
372 		return (VT_ERROR);
373 
374 	dk_ioc.dki_length = label_len;
375 	user_length = vtoc->efi_nparts;
376 	efi = dk_ioc.dki_data;
377 	if (md_flag) {
378 		if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
379 			switch (errno) {
380 			case EIO:
381 				return (VT_EIO);
382 			default:
383 				return (VT_ERROR);
384 			}
385 		}
386 	} else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
387 		/* no valid label here; try the alternate */
388 		dk_ioc.dki_lba = disk_info.dki_capacity - 1;
389 		dk_ioc.dki_length = disk_info.dki_lbsize;
390 		if (check_label(fd, &dk_ioc) == 0) {
391 			if (efi_debug) {
392 				(void) fprintf(stderr,
393 				    "efi_read: primary label corrupt; "
394 				    "using backup\n");
395 			}
396 			dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
397 			vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
398 			vtoc->efi_nparts =
399 			    LE_32(efi->efi_gpt_NumberOfPartitionEntries);
400 			/*
401 			 * partitions are between last usable LBA and
402 			 * backup partition header
403 			 */
404 			dk_ioc.dki_data++;
405 			dk_ioc.dki_length = disk_info.dki_capacity -
406 						    dk_ioc.dki_lba - 1;
407 			dk_ioc.dki_length *= disk_info.dki_lbsize;
408 			if (dk_ioc.dki_length > (len_t)label_len) {
409 				rval = VT_EINVAL;
410 			} else {
411 				rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
412 			}
413 		}
414 	}
415 	if (rval < 0) {
416 		free(efi);
417 		return (rval);
418 	}
419 
420 	/* partitions start in the next block */
421 	/* LINTED -- always longlong aligned */
422 	efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
423 
424 	/*
425 	 * Assemble this into a "dk_gpt" struct for easier
426 	 * digestibility by applications.
427 	 */
428 	vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
429 	vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
430 	vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
431 	vtoc->efi_lbasize = disk_info.dki_lbsize;
432 	vtoc->efi_last_lba = disk_info.dki_capacity - 1;
433 	vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
434 	vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
435 	UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
436 
437 	/*
438 	 * If the array the user passed in is too small, set the length
439 	 * to what it needs to be and return
440 	 */
441 	if (user_length < vtoc->efi_nparts) {
442 		return (VT_EINVAL);
443 	}
444 
445 	for (i = 0; i < vtoc->efi_nparts; i++) {
446 
447 	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
448 		efi_parts[i].efi_gpe_PartitionTypeGUID);
449 
450 	    for (j = 0;
451 		j < sizeof (conversion_array) / sizeof (struct uuid_to_ptag);
452 		j++) {
453 
454 		    if (bcmp(&vtoc->efi_parts[i].p_guid,
455 			&conversion_array[j].uuid,
456 			sizeof (struct uuid)) == 0) {
457 			    vtoc->efi_parts[i].p_tag = j;
458 			    break;
459 		    }
460 	    }
461 	    if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
462 		    continue;
463 	    vtoc->efi_parts[i].p_flag =
464 		LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
465 	    vtoc->efi_parts[i].p_start =
466 		LE_64(efi_parts[i].efi_gpe_StartingLBA);
467 	    vtoc->efi_parts[i].p_size =
468 		LE_64(efi_parts[i].efi_gpe_EndingLBA) -
469 		    vtoc->efi_parts[i].p_start + 1;
470 	    for (j = 0; j < EFI_PART_NAME_LEN; j++) {
471 		vtoc->efi_parts[i].p_name[j] =
472 		    (uchar_t)LE_16(efi_parts[i].efi_gpe_PartitionName[j]);
473 	    }
474 
475 	    UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
476 		efi_parts[i].efi_gpe_UniquePartitionGUID);
477 	}
478 	free(efi);
479 
480 	return (dki_info.dki_partition);
481 }
482 
483 /* writes a "protective" MBR */
484 static int
485 write_pmbr(int fd, struct dk_gpt *vtoc)
486 {
487 	dk_efi_t	dk_ioc;
488 	struct mboot	mb;
489 	uchar_t		*cp;
490 	diskaddr_t	size_in_lba;
491 
492 	mb.signature = LE_16(MBB_MAGIC);
493 	bzero(&mb.parts, sizeof (mb.parts));
494 	cp = (uchar_t *)&mb.parts[0];
495 	/* bootable or not */
496 	*cp++ = 0;
497 	/* beginning CHS; 0xffffff if not representable */
498 	*cp++ = 0xff;
499 	*cp++ = 0xff;
500 	*cp++ = 0xff;
501 	/* OS type */
502 	*cp++ = EFI_PMBR;
503 	/* ending CHS; 0xffffff if not representable */
504 	*cp++ = 0xff;
505 	*cp++ = 0xff;
506 	*cp++ = 0xff;
507 	/* starting LBA: 1 (little endian format) by EFI definition */
508 	*cp++ = 0x01;
509 	*cp++ = 0x00;
510 	*cp++ = 0x00;
511 	*cp++ = 0x00;
512 	/* ending LBA: last block on the disk (little endian format) */
513 	size_in_lba = vtoc->efi_last_lba;
514 	if (size_in_lba < 0xffffffff) {
515 		*cp++ = (size_in_lba & 0x000000ff);
516 		*cp++ = (size_in_lba & 0x0000ff00) >> 8;
517 		*cp++ = (size_in_lba & 0x00ff0000) >> 16;
518 		*cp++ = (size_in_lba & 0xff000000) >> 24;
519 	} else {
520 		*cp++ = 0xff;
521 		*cp++ = 0xff;
522 		*cp++ = 0xff;
523 		*cp++ = 0xff;
524 	}
525 	/* LINTED -- always longlong aligned */
526 	dk_ioc.dki_data = (efi_gpt_t *)&mb;
527 	dk_ioc.dki_lba = 0;
528 	dk_ioc.dki_length = sizeof (mb);
529 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
530 		switch (errno) {
531 		case EIO:
532 			return (VT_EIO);
533 		case EINVAL:
534 			return (VT_EINVAL);
535 		default:
536 			return (VT_ERROR);
537 		}
538 	}
539 	return (0);
540 }
541 
542 /* make sure the user specified something reasonable */
543 static int
544 check_input(struct dk_gpt *vtoc)
545 {
546 	int			resv_part = -1;
547 	int			i, j;
548 	diskaddr_t		istart, jstart, isize, jsize, endsect;
549 
550 	/*
551 	 * Sanity-check the input (make sure no partitions overlap)
552 	 */
553 	for (i = 0; i < vtoc->efi_nparts; i++) {
554 		/* It can't be unassigned and have an actual size */
555 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
556 		    (vtoc->efi_parts[i].p_size != 0)) {
557 			if (efi_debug) {
558 				(void) fprintf(stderr,
559 "partition %d is \"unassigned\" but has a size of %llu",
560 				    i,
561 				    vtoc->efi_parts[i].p_size);
562 			}
563 			return (VT_EINVAL);
564 		}
565 		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
566 			continue;
567 		}
568 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
569 			if (resv_part != -1) {
570 				if (efi_debug) {
571 				    (void) fprintf(stderr,
572 "found duplicate reserved partition at %d\n",
573 					i);
574 				}
575 				return (VT_EINVAL);
576 			}
577 			resv_part = i;
578 		}
579 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
580 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
581 			if (efi_debug) {
582 				(void) fprintf(stderr,
583 				    "Partition %d starts at %llu.  ",
584 				    i,
585 				    vtoc->efi_parts[i].p_start);
586 				(void) fprintf(stderr,
587 				    "It must be between %llu and %llu.\n",
588 				    vtoc->efi_first_u_lba,
589 				    vtoc->efi_last_u_lba);
590 			}
591 			return (VT_EINVAL);
592 		}
593 		if ((vtoc->efi_parts[i].p_start +
594 		    vtoc->efi_parts[i].p_size <
595 		    vtoc->efi_first_u_lba) ||
596 		    (vtoc->efi_parts[i].p_start +
597 		    vtoc->efi_parts[i].p_size >
598 		    vtoc->efi_last_u_lba + 1)) {
599 			if (efi_debug) {
600 				(void) fprintf(stderr,
601 				    "Partition %d ends at %llu.  ",
602 				    i,
603 				    vtoc->efi_parts[i].p_start +
604 				    vtoc->efi_parts[i].p_size);
605 				(void) fprintf(stderr,
606 				    "It must be between %llu and %llu.\n",
607 				    vtoc->efi_first_u_lba,
608 				    vtoc->efi_last_u_lba);
609 			}
610 			return (VT_EINVAL);
611 		}
612 
613 		for (j = 0; j < vtoc->efi_nparts; j++) {
614 			isize = vtoc->efi_parts[i].p_size;
615 			jsize = vtoc->efi_parts[j].p_size;
616 			istart = vtoc->efi_parts[i].p_start;
617 			jstart = vtoc->efi_parts[j].p_start;
618 			if ((i != j) && (isize != 0) && (jsize != 0)) {
619 				endsect = jstart + jsize -1;
620 				if ((jstart <= istart) &&
621 				    (istart <= endsect)) {
622 					if (efi_debug) {
623 						(void) fprintf(stderr,
624 "Partition %d overlaps partition %d.",
625 						    i, j);
626 					    }
627 					    return (VT_EINVAL);
628 				}
629 			}
630 		}
631 	}
632 	/* just a warning for now */
633 	if ((resv_part == -1) && efi_debug) {
634 		(void) fprintf(stderr,
635 				"no reserved partition found\n");
636 	}
637 	return (0);
638 }
639 
640 /*
641  * write EFI label and backup label
642  */
643 int
644 efi_write(int fd, struct dk_gpt *vtoc)
645 {
646 	dk_efi_t		dk_ioc;
647 	efi_gpt_t		*efi;
648 	efi_gpe_t		*efi_parts;
649 	int			i, j;
650 	struct dk_cinfo		dki_info;
651 	int			md_flag = 0;
652 
653 	if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
654 		if (efi_debug)
655 			(void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
656 		switch (errno) {
657 		case EIO:
658 			return (VT_EIO);
659 		case EINVAL:
660 			return (VT_EINVAL);
661 		default:
662 			return (VT_ERROR);
663 		}
664 	}
665 
666 	/* check if we are dealing wih a metadevice */
667 	if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
668 	    (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
669 		md_flag = 1;
670 	}
671 
672 	if (check_input(vtoc)) {
673 		/*
674 		 * not valid; if it's a metadevice just pass it down
675 		 * because SVM will do its own checking
676 		 */
677 		if (md_flag == 0) {
678 			return (VT_EINVAL);
679 		}
680 	}
681 
682 	dk_ioc.dki_lba = 1;
683 	if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
684 		dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
685 	} else {
686 		dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
687 				    vtoc->efi_lbasize) *
688 				    vtoc->efi_lbasize;
689 	}
690 
691 	if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL)
692 		return (VT_ERROR);
693 
694 	efi = dk_ioc.dki_data;
695 
696 	/* stuff user's input into EFI struct */
697 	efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
698 	efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
699 	efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
700 	efi->efi_gpt_Reserved1 = 0;
701 	efi->efi_gpt_MyLBA = LE_64(1ULL);
702 	efi->efi_gpt_AlternateLBA = LE_64(vtoc->efi_last_lba);
703 	efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
704 	efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
705 	efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
706 	efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
707 	efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
708 	UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
709 
710 	/* LINTED -- always longlong aligned */
711 	efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + sizeof (efi_gpt_t));
712 
713 	for (i = 0; i < vtoc->efi_nparts; i++) {
714 	    for (j = 0;
715 		j < sizeof (conversion_array) / sizeof (struct uuid_to_ptag);
716 		j++) {
717 
718 		    if (vtoc->efi_parts[i].p_tag == j) {
719 			    UUID_LE_CONVERT(
720 				efi_parts[i].efi_gpe_PartitionTypeGUID,
721 				conversion_array[j].uuid);
722 		    }
723 	    }
724 	    efi_parts[i].efi_gpe_StartingLBA =
725 		LE_64(vtoc->efi_parts[i].p_start);
726 	    efi_parts[i].efi_gpe_EndingLBA =
727 		LE_64(vtoc->efi_parts[i].p_start +
728 		vtoc->efi_parts[i].p_size - 1);
729 	    efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
730 		    LE_16(vtoc->efi_parts[i].p_flag);
731 	    for (j = 0; j < EFI_PART_NAME_LEN; j++) {
732 		    efi_parts[i].efi_gpe_PartitionName[j] =
733 			LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
734 	    }
735 	    if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
736 		uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
737 		    (void) uuid_generate((uchar_t *)
738 			&vtoc->efi_parts[i].p_uguid);
739 	    }
740 	    bcopy(&vtoc->efi_parts[i].p_uguid,
741 		&efi_parts[i].efi_gpe_UniquePartitionGUID,
742 		sizeof (uuid_t));
743 	}
744 	efi->efi_gpt_PartitionEntryArrayCRC32 =
745 	    LE_32(efi_crc32((unsigned char *)efi_parts,
746 	    vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
747 	efi->efi_gpt_HeaderCRC32 =
748 	    LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
749 
750 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
751 		free(dk_ioc.dki_data);
752 		switch (errno) {
753 		case EIO:
754 			return (VT_EIO);
755 		case EINVAL:
756 			return (VT_EINVAL);
757 		default:
758 			return (VT_ERROR);
759 		}
760 	}
761 	/* if it's a metadevice we're done */
762 	if (md_flag) {
763 		free(dk_ioc.dki_data);
764 		return (0);
765 	}
766 	/* write backup partition array */
767 	dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
768 	dk_ioc.dki_length -= vtoc->efi_lbasize;
769 	dk_ioc.dki_data++;
770 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
771 		/*
772 		 * we wrote the primary label okay, so don't fail
773 		 */
774 		if (efi_debug) {
775 			(void) fprintf(stderr,
776 			    "write of backup partitions to block %llu "
777 			    "failed, errno %d\n",
778 			    vtoc->efi_last_u_lba + 1,
779 			    errno);
780 		}
781 	}
782 	/*
783 	 * now swap MyLBA and AlternateLBA fields and write backup
784 	 * partition table header
785 	 */
786 	dk_ioc.dki_lba = vtoc->efi_last_lba;
787 	dk_ioc.dki_length = vtoc->efi_lbasize;
788 	dk_ioc.dki_data--;
789 	efi->efi_gpt_AlternateLBA = LE_64(1ULL);
790 	efi->efi_gpt_MyLBA = LE_64(vtoc->efi_last_lba);
791 	efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
792 	efi->efi_gpt_HeaderCRC32 = 0;
793 	efi->efi_gpt_HeaderCRC32 =
794 	    LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
795 	    sizeof (struct efi_gpt)));
796 
797 	if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
798 		if (efi_debug) {
799 			(void) fprintf(stderr,
800 			    "write of backup header to block %llu failed, "
801 			    "errno %d\n",
802 			    vtoc->efi_last_lba,
803 			    errno);
804 		}
805 	}
806 	/* write the PMBR */
807 	(void) write_pmbr(fd, vtoc);
808 	if (ioctl(fd, MHIOCREREGISTERDEVID) == -1) {
809 		if (efi_debug) {
810 		    (void) fprintf(stderr,
811 			    "MHIOCREREGISTERDEVID failed %d\n",
812 			    errno);
813 		}
814 	}
815 	free(dk_ioc.dki_data);
816 	return (0);
817 }
818 
819 void
820 efi_free(struct dk_gpt *ptr)
821 {
822 	free(ptr);
823 }
824 
825 /*
826  * Input: File descriptor
827  * Output: 1 if disk is >1TB OR has an EFI label, 0 otherwise.
828  */
829 int
830 efi_type(int fd)
831 {
832 	struct vtoc vtoc;
833 
834 	if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1) {
835 		if (errno == ENOTSUP) {
836 			return (1);
837 		}
838 	}
839 	return (0);
840 }
841 
842 void
843 efi_err_check(struct dk_gpt *vtoc)
844 {
845 	int			resv_part = -1;
846 	int			i, j;
847 	diskaddr_t		istart, jstart, isize, jsize, endsect;
848 	int			overlap = 0;
849 
850 	/*
851 	 * make sure no partitions overlap
852 	 */
853 	for (i = 0; i < vtoc->efi_nparts; i++) {
854 		/* It can't be unassigned and have an actual size */
855 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
856 		    (vtoc->efi_parts[i].p_size != 0)) {
857 			(void) fprintf(stderr,
858 			    "partition %d is \"unassigned\" but has a size "
859 			    "of %llu\n", i, vtoc->efi_parts[i].p_size);
860 		}
861 		if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
862 			continue;
863 		}
864 		if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
865 			if (resv_part != -1) {
866 				(void) fprintf(stderr,
867 				    "found duplicate reserved partition at "
868 				    "%d\n", i);
869 			}
870 			resv_part = i;
871 			if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
872 				(void) fprintf(stderr,
873 				    "Warning: reserved partition size must "
874 				    "be %d sectors\n", EFI_MIN_RESV_SIZE);
875 		}
876 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
877 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
878 			(void) fprintf(stderr,
879 			    "Partition %d starts at %llu\n",
880 			    i,
881 			    vtoc->efi_parts[i].p_start);
882 			(void) fprintf(stderr,
883 			    "It must be between %llu and %llu.\n",
884 			    vtoc->efi_first_u_lba,
885 			    vtoc->efi_last_u_lba);
886 		}
887 		if ((vtoc->efi_parts[i].p_start +
888 		    vtoc->efi_parts[i].p_size <
889 		    vtoc->efi_first_u_lba) ||
890 		    (vtoc->efi_parts[i].p_start +
891 		    vtoc->efi_parts[i].p_size >
892 		    vtoc->efi_last_u_lba + 1)) {
893 			(void) fprintf(stderr,
894 			    "Partition %d ends at %llu\n",
895 			    i,
896 			    vtoc->efi_parts[i].p_start +
897 			    vtoc->efi_parts[i].p_size);
898 			(void) fprintf(stderr,
899 			    "It must be between %llu and %llu.\n",
900 			    vtoc->efi_first_u_lba,
901 			    vtoc->efi_last_u_lba);
902 		}
903 
904 		for (j = 0; j < vtoc->efi_nparts; j++) {
905 			isize = vtoc->efi_parts[i].p_size;
906 			jsize = vtoc->efi_parts[j].p_size;
907 			istart = vtoc->efi_parts[i].p_start;
908 			jstart = vtoc->efi_parts[j].p_start;
909 			if ((i != j) && (isize != 0) && (jsize != 0)) {
910 				endsect = jstart + jsize -1;
911 				if ((jstart <= istart) &&
912 				    (istart <= endsect)) {
913 					if (!overlap) {
914 					(void) fprintf(stderr,
915 					    "label error: EFI Labels do not "
916 					    "support overlapping partitions\n");
917 					}
918 					(void) fprintf(stderr,
919 					    "Partition %d overlaps partition "
920 					    "%d.\n", i, j);
921 					overlap = 1;
922 				}
923 			}
924 		}
925 	}
926 	/* make sure there is a reserved partition */
927 	if (resv_part == -1) {
928 		(void) fprintf(stderr,
929 			"no reserved partition found\n");
930 	}
931 }
932 
933 /*
934  * We need to get information necessary to construct a *new* efi
935  * label type
936  */
937 int
938 efi_auto_sense(int fd, struct dk_gpt **vtoc)
939 {
940 
941 	int	i;
942 
943 	/*
944 	 * Now build the default partition table
945 	 */
946 	if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
947 		if (efi_debug) {
948 			(void) fprintf(stderr, "efi_alloc_and_init failed.\n");
949 		}
950 		return (-1);
951 	}
952 
953 	for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
954 		(*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
955 		(*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
956 		(*vtoc)->efi_parts[i].p_start = 0;
957 		(*vtoc)->efi_parts[i].p_size = 0;
958 	}
959 	/*
960 	 * Make constants first
961 	 * and variable partitions later
962 	 */
963 
964 	/* root partition - s0 128 MB */
965 	(*vtoc)->efi_parts[0].p_start = 34;
966 	(*vtoc)->efi_parts[0].p_size = 262144;
967 
968 	/* partition - s1  128 MB */
969 	(*vtoc)->efi_parts[1].p_start = 262178;
970 	(*vtoc)->efi_parts[1].p_size = 262144;
971 
972 	/* partition -s2 is NOT the Backup disk */
973 	(*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
974 
975 	/* partition -s6 /usr partition - HOG */
976 	(*vtoc)->efi_parts[6].p_start = 524322;
977 	(*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
978 	    - (1024 * 16);
979 
980 	/* efi reserved partition - s9 16K */
981 	(*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
982 	(*vtoc)->efi_parts[8].p_size = (1024 * 16);
983 	(*vtoc)->efi_parts[8].p_tag = V_RESERVED;
984 	return (0);
985 }
986