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