Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
9259 libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
| 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
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 */
27 27
28 28 #include <stdio.h>
29 29 #include <stdlib.h>
30 30 #include <errno.h>
31 31 #include <strings.h>
32 32 #include <unistd.h>
33 33 #include <uuid/uuid.h>
34 34 #include <libintl.h>
35 35 #include <sys/types.h>
36 36 #include <sys/dkio.h>
37 37 #include <sys/vtoc.h>
38 38 #include <sys/mhd.h>
39 39 #include <sys/param.h>
40 40 #include <sys/dktp/fdisk.h>
41 41 #include <sys/efi_partition.h>
42 42 #include <sys/byteorder.h>
43 43 #include <sys/ddi.h>
44 44
45 45 static struct uuid_to_ptag {
46 46 struct uuid uuid;
47 47 } conversion_array[] = {
48 48 { EFI_UNUSED },
49 49 { EFI_BOOT },
50 50 { EFI_ROOT },
51 51 { EFI_SWAP },
52 52 { EFI_USR },
53 53 { EFI_BACKUP },
54 54 { 0 }, /* STAND is never used */
55 55 { EFI_VAR },
56 56 { EFI_HOME },
57 57 { EFI_ALTSCTR },
58 58 { 0 }, /* CACHE is never used */
59 59 { EFI_RESERVED },
60 60 { EFI_SYSTEM },
61 61 { EFI_LEGACY_MBR },
62 62 { EFI_SYMC_PUB },
63 63 { EFI_SYMC_CDS },
64 64 { EFI_MSFT_RESV },
65 65 { EFI_DELL_BASIC },
66 66 { EFI_DELL_RAID },
67 67 { EFI_DELL_SWAP },
68 68 { EFI_DELL_LVM },
69 69 { EFI_DELL_RESV },
70 70 { EFI_AAPL_HFS },
71 71 { EFI_AAPL_UFS },
72 72 { EFI_BIOS_BOOT },
73 73 { EFI_FREEBSD_BOOT },
74 74 { EFI_FREEBSD_SWAP },
75 75 { EFI_FREEBSD_UFS },
76 76 { EFI_FREEBSD_VINUM },
77 77 { EFI_FREEBSD_ZFS }
78 78 };
79 79
80 80 /*
81 81 * Default vtoc information for non-SVr4 partitions
82 82 */
83 83 struct dk_map2 default_vtoc_map[NDKMAP] = {
84 84 { V_ROOT, 0 }, /* a - 0 */
85 85 { V_SWAP, V_UNMNT }, /* b - 1 */
86 86 { V_BACKUP, V_UNMNT }, /* c - 2 */
87 87 { V_UNASSIGNED, 0 }, /* d - 3 */
88 88 { V_UNASSIGNED, 0 }, /* e - 4 */
89 89 { V_UNASSIGNED, 0 }, /* f - 5 */
90 90 { V_USR, 0 }, /* g - 6 */
91 91 { V_UNASSIGNED, 0 }, /* h - 7 */
92 92
93 93 #if defined(_SUNOS_VTOC_16)
94 94
95 95 #if defined(i386) || defined(__amd64)
96 96 { V_BOOT, V_UNMNT }, /* i - 8 */
97 97 { V_ALTSCTR, 0 }, /* j - 9 */
98 98
99 99 #else
100 100 #error No VTOC format defined.
101 101 #endif /* defined(i386) */
102 102
103 103 { V_UNASSIGNED, 0 }, /* k - 10 */
104 104 { V_UNASSIGNED, 0 }, /* l - 11 */
105 105 { V_UNASSIGNED, 0 }, /* m - 12 */
106 106 { V_UNASSIGNED, 0 }, /* n - 13 */
107 107 { V_UNASSIGNED, 0 }, /* o - 14 */
108 108 { V_UNASSIGNED, 0 }, /* p - 15 */
109 109 #endif /* defined(_SUNOS_VTOC_16) */
110 110 };
111 111
112 112 #ifdef DEBUG
113 113 int efi_debug = 1;
114 114 #else
115 115 int efi_debug = 0;
116 116 #endif
117 117
118 118 extern unsigned int efi_crc32(const unsigned char *, unsigned int);
119 119 static int efi_read(int, struct dk_gpt *);
120 120
121 121 static int
122 122 read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
123 123 {
124 124 struct dk_minfo disk_info;
125 125
126 126 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
127 127 return (errno);
128 128 *capacity = disk_info.dki_capacity;
129 129 *lbsize = disk_info.dki_lbsize;
130 130 return (0);
131 131 }
132 132
133 133 /*
134 134 * the number of blocks the EFI label takes up (round up to nearest
135 135 * block)
136 136 */
137 137 #define NBLOCKS(p, l) (1 + ((((p) * (int)sizeof (efi_gpe_t)) + \
138 138 ((l) - 1)) / (l)))
139 139 /* number of partitions -- limited by what we can malloc */
140 140 #define MAX_PARTS ((4294967295UL - sizeof (struct dk_gpt)) / \
141 141 sizeof (struct dk_part))
142 142
143 143 int
144 144 efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
145 145 {
146 146 diskaddr_t capacity;
147 147 uint_t lbsize;
148 148 uint_t nblocks;
149 149 size_t length;
150 150 struct dk_gpt *vptr;
151 151 struct uuid uuid;
152 152
153 153 if (read_disk_info(fd, &capacity, &lbsize) != 0) {
154 154 if (efi_debug)
155 155 (void) fprintf(stderr,
156 156 "couldn't read disk information\n");
157 157 return (-1);
158 158 }
159 159
160 160 nblocks = NBLOCKS(nparts, lbsize);
161 161 if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
162 162 /* 16K plus one block for the GPT */
163 163 nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
164 164 }
165 165
166 166 if (nparts > MAX_PARTS) {
167 167 if (efi_debug) {
168 168 (void) fprintf(stderr,
169 169 "the maximum number of partitions supported is %lu\n",
170 170 MAX_PARTS);
171 171 }
172 172 return (-1);
173 173 }
174 174
175 175 length = sizeof (struct dk_gpt) +
176 176 sizeof (struct dk_part) * (nparts - 1);
177 177
178 178 if ((*vtoc = calloc(length, 1)) == NULL)
179 179 return (-1);
180 180
181 181 vptr = *vtoc;
182 182
183 183 vptr->efi_version = EFI_VERSION_CURRENT;
184 184 vptr->efi_lbasize = lbsize;
185 185 vptr->efi_nparts = nparts;
186 186 /*
187 187 * add one block here for the PMBR; on disks with a 512 byte
188 188 * block size and 128 or fewer partitions, efi_first_u_lba
189 189 * should work out to "34"
190 190 */
191 191 vptr->efi_first_u_lba = nblocks + 1;
192 192 vptr->efi_last_lba = capacity - 1;
193 193 vptr->efi_altern_lba = capacity -1;
194 194 vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
195 195
196 196 (void) uuid_generate((uchar_t *)&uuid);
197 197 UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
198 198 return (0);
199 199 }
|
↓ open down ↓ |
199 lines elided |
↑ open up ↑ |
200 200
201 201 /*
202 202 * Read EFI - return partition number upon success.
203 203 */
204 204 int
205 205 efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
206 206 {
207 207 int rval;
208 208 uint32_t nparts;
209 209 int length;
210 + struct mboot *mbr;
211 + struct ipart *ipart;
212 + diskaddr_t capacity;
213 + uint_t lbsize;
214 + int i;
210 215
216 + if (read_disk_info(fd, &capacity, &lbsize) != 0)
217 + return (VT_ERROR);
218 +
219 + if ((mbr = calloc(lbsize, 1)) == NULL)
220 + return (VT_ERROR);
221 +
222 + if ((ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) {
223 + free(mbr);
224 + return (VT_ERROR);
225 + }
226 +
227 + if (mbr->signature != MBB_MAGIC) {
228 + free(mbr);
229 + return (VT_EINVAL);
230 + }
231 + ipart = (struct ipart *)(uintptr_t)mbr->parts;
232 +
233 + /* Check if we have partition with ID EFI_PMBR */
234 + for (i = 0; i < FD_NUMPART; i++) {
235 + if (ipart[i].systid == EFI_PMBR)
236 + break;
237 + }
238 + free(mbr);
239 + if (i == FD_NUMPART)
240 + return (VT_EINVAL);
241 +
211 242 /* figure out the number of entries that would fit into 16K */
212 243 nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
213 244 length = (int) sizeof (struct dk_gpt) +
214 245 (int) sizeof (struct dk_part) * (nparts - 1);
215 246 if ((*vtoc = calloc(length, 1)) == NULL)
216 247 return (VT_ERROR);
217 248
218 249 (*vtoc)->efi_nparts = nparts;
219 250 rval = efi_read(fd, *vtoc);
220 251
221 252 if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
222 253 void *tmp;
223 254 length = (int) sizeof (struct dk_gpt) +
224 255 (int) sizeof (struct dk_part) *
225 256 ((*vtoc)->efi_nparts - 1);
226 257 nparts = (*vtoc)->efi_nparts;
227 258 if ((tmp = realloc(*vtoc, length)) == NULL) {
228 259 free (*vtoc);
229 260 *vtoc = NULL;
230 261 return (VT_ERROR);
231 262 } else {
232 263 *vtoc = tmp;
233 264 rval = efi_read(fd, *vtoc);
234 265 }
235 266 }
236 267
237 268 if (rval < 0) {
238 269 if (efi_debug) {
239 270 (void) fprintf(stderr,
240 271 "read of EFI table failed, rval=%d\n", rval);
241 272 }
242 273 free (*vtoc);
243 274 *vtoc = NULL;
244 275 }
245 276
246 277 return (rval);
247 278 }
248 279
249 280 static int
250 281 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
251 282 {
252 283 void *data = dk_ioc->dki_data;
253 284 int error;
254 285
255 286 dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
256 287 error = ioctl(fd, cmd, (void *)dk_ioc);
257 288 dk_ioc->dki_data = data;
258 289
259 290 return (error);
260 291 }
261 292
262 293 static int
263 294 check_label(int fd, dk_efi_t *dk_ioc)
264 295 {
265 296 efi_gpt_t *efi;
266 297 uint_t crc;
267 298
268 299 if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
269 300 switch (errno) {
270 301 case EIO:
271 302 return (VT_EIO);
272 303 default:
273 304 return (VT_ERROR);
274 305 }
275 306 }
276 307 efi = dk_ioc->dki_data;
277 308 if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
278 309 if (efi_debug)
279 310 (void) fprintf(stderr,
280 311 "Bad EFI signature: 0x%llx != 0x%llx\n",
281 312 (long long)efi->efi_gpt_Signature,
282 313 (long long)LE_64(EFI_SIGNATURE));
283 314 return (VT_EINVAL);
284 315 }
285 316
286 317 /*
287 318 * check CRC of the header; the size of the header should
288 319 * never be larger than one block
289 320 */
290 321 crc = efi->efi_gpt_HeaderCRC32;
291 322 efi->efi_gpt_HeaderCRC32 = 0;
292 323
293 324 if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
294 325 crc != LE_32(efi_crc32((unsigned char *)efi,
295 326 LE_32(efi->efi_gpt_HeaderSize)))) {
296 327 if (efi_debug)
297 328 (void) fprintf(stderr,
298 329 "Bad EFI CRC: 0x%x != 0x%x\n",
299 330 crc,
300 331 LE_32(efi_crc32((unsigned char *)efi,
301 332 sizeof (struct efi_gpt))));
302 333 return (VT_EINVAL);
303 334 }
304 335
305 336 return (0);
306 337 }
307 338
308 339 static int
309 340 efi_read(int fd, struct dk_gpt *vtoc)
310 341 {
311 342 int i, j;
312 343 int label_len;
313 344 int rval = 0;
314 345 int vdc_flag = 0;
315 346 struct dk_minfo disk_info;
316 347 dk_efi_t dk_ioc;
317 348 efi_gpt_t *efi;
318 349 efi_gpe_t *efi_parts;
319 350 struct dk_cinfo dki_info;
320 351 uint32_t user_length;
321 352 boolean_t legacy_label = B_FALSE;
322 353
323 354 /*
324 355 * get the partition number for this file descriptor.
325 356 */
326 357 if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
327 358 if (efi_debug) {
328 359 (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
329 360 }
330 361 switch (errno) {
331 362 case EIO:
332 363 return (VT_EIO);
333 364 case EINVAL:
334 365 return (VT_EINVAL);
335 366 default:
336 367 return (VT_ERROR);
337 368 }
338 369 }
339 370
340 371 if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
341 372 (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
342 373 /*
343 374 * The controller and drive name "vdc" (virtual disk client)
344 375 * indicates a LDoms virtual disk.
345 376 */
346 377 vdc_flag++;
347 378 }
348 379
349 380 /* get the LBA size */
350 381 if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
351 382 if (efi_debug) {
352 383 (void) fprintf(stderr,
353 384 "assuming LBA 512 bytes %d\n",
354 385 errno);
355 386 }
356 387 disk_info.dki_lbsize = DEV_BSIZE;
357 388 }
358 389 if (disk_info.dki_lbsize == 0) {
359 390 if (efi_debug) {
360 391 (void) fprintf(stderr,
361 392 "efi_read: assuming LBA 512 bytes\n");
362 393 }
363 394 disk_info.dki_lbsize = DEV_BSIZE;
364 395 }
365 396 /*
366 397 * Read the EFI GPT to figure out how many partitions we need
367 398 * to deal with.
368 399 */
369 400 dk_ioc.dki_lba = 1;
370 401 if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
371 402 label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
372 403 } else {
373 404 label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
374 405 disk_info.dki_lbsize;
375 406 if (label_len % disk_info.dki_lbsize) {
376 407 /* pad to physical sector size */
377 408 label_len += disk_info.dki_lbsize;
378 409 label_len &= ~(disk_info.dki_lbsize - 1);
379 410 }
380 411 }
381 412
382 413 if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
383 414 return (VT_ERROR);
384 415
385 416 dk_ioc.dki_length = disk_info.dki_lbsize;
386 417 user_length = vtoc->efi_nparts;
387 418 efi = dk_ioc.dki_data;
388 419 if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
389 420 /*
390 421 * No valid label here; try the alternate. Note that here
391 422 * we just read GPT header and save it into dk_ioc.data,
392 423 * Later, we will read GUID partition entry array if we
393 424 * can get valid GPT header.
394 425 */
395 426
396 427 /*
397 428 * This is a workaround for legacy systems. In the past, the
398 429 * last sector of SCSI disk was invisible on x86 platform. At
399 430 * that time, backup label was saved on the next to the last
400 431 * sector. It is possible for users to move a disk from previous
401 432 * solaris system to present system. Here, we attempt to search
402 433 * legacy backup EFI label first.
403 434 */
404 435 dk_ioc.dki_lba = disk_info.dki_capacity - 2;
405 436 dk_ioc.dki_length = disk_info.dki_lbsize;
406 437 rval = check_label(fd, &dk_ioc);
407 438 if (rval == VT_EINVAL) {
408 439 /*
409 440 * we didn't find legacy backup EFI label, try to
410 441 * search backup EFI label in the last block.
411 442 */
412 443 dk_ioc.dki_lba = disk_info.dki_capacity - 1;
413 444 dk_ioc.dki_length = disk_info.dki_lbsize;
414 445 rval = check_label(fd, &dk_ioc);
415 446 if (rval == 0) {
416 447 legacy_label = B_TRUE;
417 448 if (efi_debug)
418 449 (void) fprintf(stderr,
419 450 "efi_read: primary label corrupt; "
420 451 "using EFI backup label located on"
421 452 " the last block\n");
422 453 }
423 454 } else {
424 455 if ((efi_debug) && (rval == 0))
425 456 (void) fprintf(stderr, "efi_read: primary label"
426 457 " corrupt; using legacy EFI backup label "
427 458 " located on the next to last block\n");
428 459 }
429 460
430 461 if (rval == 0) {
431 462 dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
432 463 vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
433 464 vtoc->efi_nparts =
434 465 LE_32(efi->efi_gpt_NumberOfPartitionEntries);
435 466 /*
436 467 * Partition tables are between backup GPT header
437 468 * table and ParitionEntryLBA (the starting LBA of
438 469 * the GUID partition entries array). Now that we
439 470 * already got valid GPT header and saved it in
440 471 * dk_ioc.dki_data, we try to get GUID partition
441 472 * entry array here.
442 473 */
443 474 /* LINTED */
444 475 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
445 476 + disk_info.dki_lbsize);
446 477 if (legacy_label)
447 478 dk_ioc.dki_length = disk_info.dki_capacity - 1 -
448 479 dk_ioc.dki_lba;
449 480 else
450 481 dk_ioc.dki_length = disk_info.dki_capacity - 2 -
451 482 dk_ioc.dki_lba;
452 483 dk_ioc.dki_length *= disk_info.dki_lbsize;
453 484 if (dk_ioc.dki_length >
454 485 ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
455 486 rval = VT_EINVAL;
456 487 } else {
457 488 /*
458 489 * read GUID partition entry array
459 490 */
460 491 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
461 492 }
462 493 }
463 494
464 495 } else if (rval == 0) {
465 496
466 497 dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
467 498 /* LINTED */
468 499 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
469 500 + disk_info.dki_lbsize);
470 501 dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
471 502 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
472 503
473 504 } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
474 505 /*
475 506 * When the device is a LDoms virtual disk, the DKIOCGETEFI
476 507 * ioctl can fail with EINVAL if the virtual disk backend
477 508 * is a ZFS volume serviced by a domain running an old version
478 509 * of Solaris. This is because the DKIOCGETEFI ioctl was
479 510 * initially incorrectly implemented for a ZFS volume and it
480 511 * expected the GPT and GPE to be retrieved with a single ioctl.
481 512 * So we try to read the GPT and the GPE using that old style
482 513 * ioctl.
483 514 */
484 515 dk_ioc.dki_lba = 1;
485 516 dk_ioc.dki_length = label_len;
486 517 rval = check_label(fd, &dk_ioc);
487 518 }
488 519
489 520 if (rval < 0) {
490 521 free(efi);
491 522 return (rval);
492 523 }
493 524
494 525 /* LINTED -- always longlong aligned */
495 526 efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
496 527
497 528 /*
498 529 * Assemble this into a "dk_gpt" struct for easier
499 530 * digestibility by applications.
500 531 */
501 532 vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
502 533 vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
503 534 vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
504 535 vtoc->efi_lbasize = disk_info.dki_lbsize;
505 536 vtoc->efi_last_lba = disk_info.dki_capacity - 1;
506 537 vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
507 538 vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
508 539 vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
509 540 UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
510 541
511 542 /*
512 543 * If the array the user passed in is too small, set the length
513 544 * to what it needs to be and return
514 545 */
515 546 if (user_length < vtoc->efi_nparts) {
516 547 return (VT_EINVAL);
517 548 }
518 549
519 550 for (i = 0; i < vtoc->efi_nparts; i++) {
520 551
521 552 UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
522 553 efi_parts[i].efi_gpe_PartitionTypeGUID);
523 554
524 555 for (j = 0;
525 556 j < sizeof (conversion_array)
526 557 / sizeof (struct uuid_to_ptag); j++) {
527 558
528 559 if (bcmp(&vtoc->efi_parts[i].p_guid,
529 560 &conversion_array[j].uuid,
530 561 sizeof (struct uuid)) == 0) {
531 562 vtoc->efi_parts[i].p_tag = j;
532 563 break;
533 564 }
534 565 }
535 566 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
536 567 continue;
537 568 vtoc->efi_parts[i].p_flag =
538 569 LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
539 570 vtoc->efi_parts[i].p_start =
540 571 LE_64(efi_parts[i].efi_gpe_StartingLBA);
541 572 vtoc->efi_parts[i].p_size =
542 573 LE_64(efi_parts[i].efi_gpe_EndingLBA) -
543 574 vtoc->efi_parts[i].p_start + 1;
544 575 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
545 576 vtoc->efi_parts[i].p_name[j] =
546 577 (uchar_t)LE_16(
547 578 efi_parts[i].efi_gpe_PartitionName[j]);
548 579 }
549 580
550 581 UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
551 582 efi_parts[i].efi_gpe_UniquePartitionGUID);
552 583 }
553 584 free(efi);
554 585
555 586 return (dki_info.dki_partition);
556 587 }
557 588
558 589 /* writes a "protective" MBR */
559 590 static int
560 591 write_pmbr(int fd, struct dk_gpt *vtoc)
561 592 {
562 593 dk_efi_t dk_ioc;
563 594 struct mboot mb;
564 595 uchar_t *cp;
565 596 diskaddr_t size_in_lba;
566 597 uchar_t *buf;
567 598 int len;
568 599
569 600 len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
570 601 buf = calloc(len, 1);
571 602
572 603 /*
573 604 * Preserve any boot code and disk signature if the first block is
574 605 * already an MBR.
575 606 */
576 607 dk_ioc.dki_lba = 0;
577 608 dk_ioc.dki_length = len;
578 609 /* LINTED -- always longlong aligned */
579 610 dk_ioc.dki_data = (efi_gpt_t *)buf;
580 611 if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
581 612 (void) memcpy(&mb, buf, sizeof (mb));
582 613 bzero(&mb, sizeof (mb));
583 614 mb.signature = LE_16(MBB_MAGIC);
584 615 } else {
585 616 (void) memcpy(&mb, buf, sizeof (mb));
586 617 if (mb.signature != LE_16(MBB_MAGIC)) {
587 618 bzero(&mb, sizeof (mb));
588 619 mb.signature = LE_16(MBB_MAGIC);
589 620 }
590 621 }
591 622
592 623 bzero(&mb.parts, sizeof (mb.parts));
593 624 cp = (uchar_t *)&mb.parts[0];
594 625 /* bootable or not */
595 626 *cp++ = 0;
596 627 /* beginning CHS; 0xffffff if not representable */
597 628 *cp++ = 0xff;
598 629 *cp++ = 0xff;
599 630 *cp++ = 0xff;
600 631 /* OS type */
601 632 *cp++ = EFI_PMBR;
602 633 /* ending CHS; 0xffffff if not representable */
603 634 *cp++ = 0xff;
604 635 *cp++ = 0xff;
605 636 *cp++ = 0xff;
606 637 /* starting LBA: 1 (little endian format) by EFI definition */
607 638 *cp++ = 0x01;
608 639 *cp++ = 0x00;
609 640 *cp++ = 0x00;
610 641 *cp++ = 0x00;
611 642 /* ending LBA: last block on the disk (little endian format) */
612 643 size_in_lba = vtoc->efi_last_lba;
613 644 if (size_in_lba < 0xffffffff) {
614 645 *cp++ = (size_in_lba & 0x000000ff);
615 646 *cp++ = (size_in_lba & 0x0000ff00) >> 8;
616 647 *cp++ = (size_in_lba & 0x00ff0000) >> 16;
617 648 *cp++ = (size_in_lba & 0xff000000) >> 24;
618 649 } else {
619 650 *cp++ = 0xff;
620 651 *cp++ = 0xff;
621 652 *cp++ = 0xff;
622 653 *cp++ = 0xff;
623 654 }
624 655
625 656 (void) memcpy(buf, &mb, sizeof (mb));
626 657 /* LINTED -- always longlong aligned */
627 658 dk_ioc.dki_data = (efi_gpt_t *)buf;
628 659 dk_ioc.dki_lba = 0;
629 660 dk_ioc.dki_length = len;
630 661 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
631 662 free(buf);
632 663 switch (errno) {
633 664 case EIO:
634 665 return (VT_EIO);
635 666 case EINVAL:
636 667 return (VT_EINVAL);
637 668 default:
638 669 return (VT_ERROR);
639 670 }
640 671 }
641 672 free(buf);
642 673 return (0);
643 674 }
644 675
645 676 /* make sure the user specified something reasonable */
646 677 static int
647 678 check_input(struct dk_gpt *vtoc)
648 679 {
649 680 int resv_part = -1;
650 681 int i, j;
651 682 diskaddr_t istart, jstart, isize, jsize, endsect;
652 683
653 684 /*
654 685 * Sanity-check the input (make sure no partitions overlap)
655 686 */
656 687 for (i = 0; i < vtoc->efi_nparts; i++) {
657 688 /* It can't be unassigned and have an actual size */
658 689 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
659 690 (vtoc->efi_parts[i].p_size != 0)) {
660 691 if (efi_debug) {
661 692 (void) fprintf(stderr,
662 693 "partition %d is \"unassigned\" but has a size of %llu",
663 694 i,
664 695 vtoc->efi_parts[i].p_size);
665 696 }
666 697 return (VT_EINVAL);
667 698 }
668 699 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
669 700 if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
670 701 continue;
671 702 /* we have encountered an unknown uuid */
672 703 vtoc->efi_parts[i].p_tag = 0xff;
673 704 }
674 705 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
675 706 if (resv_part != -1) {
676 707 if (efi_debug) {
677 708 (void) fprintf(stderr,
678 709 "found duplicate reserved partition at %d\n",
679 710 i);
680 711 }
681 712 return (VT_EINVAL);
682 713 }
683 714 resv_part = i;
684 715 }
685 716 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
686 717 (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
687 718 if (efi_debug) {
688 719 (void) fprintf(stderr,
689 720 "Partition %d starts at %llu. ",
690 721 i,
691 722 vtoc->efi_parts[i].p_start);
692 723 (void) fprintf(stderr,
693 724 "It must be between %llu and %llu.\n",
694 725 vtoc->efi_first_u_lba,
695 726 vtoc->efi_last_u_lba);
696 727 }
697 728 return (VT_EINVAL);
698 729 }
699 730 if ((vtoc->efi_parts[i].p_start +
700 731 vtoc->efi_parts[i].p_size <
701 732 vtoc->efi_first_u_lba) ||
702 733 (vtoc->efi_parts[i].p_start +
703 734 vtoc->efi_parts[i].p_size >
704 735 vtoc->efi_last_u_lba + 1)) {
705 736 if (efi_debug) {
706 737 (void) fprintf(stderr,
707 738 "Partition %d ends at %llu. ",
708 739 i,
709 740 vtoc->efi_parts[i].p_start +
710 741 vtoc->efi_parts[i].p_size);
711 742 (void) fprintf(stderr,
712 743 "It must be between %llu and %llu.\n",
713 744 vtoc->efi_first_u_lba,
714 745 vtoc->efi_last_u_lba);
715 746 }
716 747 return (VT_EINVAL);
717 748 }
718 749
719 750 for (j = 0; j < vtoc->efi_nparts; j++) {
720 751 isize = vtoc->efi_parts[i].p_size;
721 752 jsize = vtoc->efi_parts[j].p_size;
722 753 istart = vtoc->efi_parts[i].p_start;
723 754 jstart = vtoc->efi_parts[j].p_start;
724 755 if ((i != j) && (isize != 0) && (jsize != 0)) {
725 756 endsect = jstart + jsize -1;
726 757 if ((jstart <= istart) &&
727 758 (istart <= endsect)) {
728 759 if (efi_debug) {
729 760 (void) fprintf(stderr,
730 761 "Partition %d overlaps partition %d.",
731 762 i, j);
732 763 }
733 764 return (VT_EINVAL);
734 765 }
735 766 }
736 767 }
737 768 }
738 769 /* just a warning for now */
739 770 if ((resv_part == -1) && efi_debug) {
740 771 (void) fprintf(stderr,
741 772 "no reserved partition found\n");
742 773 }
743 774 return (0);
744 775 }
745 776
746 777 /*
747 778 * add all the unallocated space to the current label
748 779 */
749 780 int
750 781 efi_use_whole_disk(int fd)
751 782 {
752 783 struct dk_gpt *efi_label;
753 784 int rval;
754 785 int i;
755 786 uint_t phy_last_slice = 0;
756 787 diskaddr_t pl_start = 0;
757 788 diskaddr_t pl_size;
758 789
759 790 rval = efi_alloc_and_read(fd, &efi_label);
760 791 if (rval < 0) {
761 792 return (rval);
762 793 }
763 794
764 795 /* find the last physically non-zero partition */
765 796 for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
766 797 if (pl_start < efi_label->efi_parts[i].p_start) {
767 798 pl_start = efi_label->efi_parts[i].p_start;
768 799 phy_last_slice = i;
769 800 }
770 801 }
771 802 pl_size = efi_label->efi_parts[phy_last_slice].p_size;
772 803
773 804 /*
774 805 * If alter_lba is 1, we are using the backup label.
775 806 * Since we can locate the backup label by disk capacity,
776 807 * there must be no unallocated space.
777 808 */
778 809 if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba
779 810 >= efi_label->efi_last_lba)) {
780 811 if (efi_debug) {
781 812 (void) fprintf(stderr,
782 813 "efi_use_whole_disk: requested space not found\n");
783 814 }
784 815 efi_free(efi_label);
785 816 return (VT_ENOSPC);
786 817 }
787 818
788 819 /*
789 820 * If there is space between the last physically non-zero partition
790 821 * and the reserved partition, just add the unallocated space to this
791 822 * area. Otherwise, the unallocated space is added to the last
792 823 * physically non-zero partition.
793 824 */
794 825 if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
795 826 EFI_MIN_RESV_SIZE) {
796 827 efi_label->efi_parts[phy_last_slice].p_size +=
797 828 efi_label->efi_last_lba - efi_label->efi_altern_lba;
798 829 }
799 830
800 831 /*
801 832 * Move the reserved partition. There is currently no data in
802 833 * here except fabricated devids (which get generated via
803 834 * efi_write()). So there is no need to copy data.
804 835 */
805 836 efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
806 837 efi_label->efi_last_lba - efi_label->efi_altern_lba;
807 838 efi_label->efi_last_u_lba += efi_label->efi_last_lba
808 839 - efi_label->efi_altern_lba;
809 840
810 841 rval = efi_write(fd, efi_label);
811 842 if (rval < 0) {
812 843 if (efi_debug) {
813 844 (void) fprintf(stderr,
814 845 "efi_use_whole_disk:fail to write label, rval=%d\n",
815 846 rval);
816 847 }
817 848 efi_free(efi_label);
818 849 return (rval);
819 850 }
820 851
821 852 efi_free(efi_label);
822 853 return (0);
823 854 }
824 855
825 856
826 857 /*
827 858 * write EFI label and backup label
828 859 */
829 860 int
830 861 efi_write(int fd, struct dk_gpt *vtoc)
831 862 {
832 863 dk_efi_t dk_ioc;
833 864 efi_gpt_t *efi;
834 865 efi_gpe_t *efi_parts;
835 866 int i, j;
836 867 struct dk_cinfo dki_info;
837 868 int nblocks;
838 869 diskaddr_t lba_backup_gpt_hdr;
839 870
840 871 if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
841 872 if (efi_debug)
842 873 (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
843 874 switch (errno) {
844 875 case EIO:
845 876 return (VT_EIO);
846 877 case EINVAL:
847 878 return (VT_EINVAL);
848 879 default:
849 880 return (VT_ERROR);
850 881 }
851 882 }
852 883
853 884 if (check_input(vtoc))
854 885 return (VT_EINVAL);
855 886
856 887 dk_ioc.dki_lba = 1;
857 888 if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
858 889 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
859 890 } else {
860 891 dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
861 892 vtoc->efi_lbasize) *
862 893 vtoc->efi_lbasize;
863 894 }
864 895
865 896 /*
866 897 * the number of blocks occupied by GUID partition entry array
867 898 */
868 899 nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
869 900
870 901 /*
871 902 * Backup GPT header is located on the block after GUID
872 903 * partition entry array. Here, we calculate the address
873 904 * for backup GPT header.
874 905 */
875 906 lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
876 907 if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL)
877 908 return (VT_ERROR);
878 909
879 910 efi = dk_ioc.dki_data;
880 911
881 912 /* stuff user's input into EFI struct */
882 913 efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
883 914 efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
884 915 efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
885 916 efi->efi_gpt_Reserved1 = 0;
886 917 efi->efi_gpt_MyLBA = LE_64(1ULL);
887 918 efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
888 919 efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
889 920 efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
890 921 efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
891 922 efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
892 923 efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
893 924 UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
894 925
895 926 /* LINTED -- always longlong aligned */
896 927 efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
897 928
898 929 for (i = 0; i < vtoc->efi_nparts; i++) {
899 930 for (j = 0;
900 931 j < sizeof (conversion_array) /
901 932 sizeof (struct uuid_to_ptag); j++) {
902 933
903 934 if (vtoc->efi_parts[i].p_tag == j) {
904 935 UUID_LE_CONVERT(
905 936 efi_parts[i].efi_gpe_PartitionTypeGUID,
906 937 conversion_array[j].uuid);
907 938 break;
908 939 }
909 940 }
910 941
911 942 if (j == sizeof (conversion_array) /
912 943 sizeof (struct uuid_to_ptag)) {
913 944 /*
914 945 * If we didn't have a matching uuid match, bail here.
915 946 * Don't write a label with unknown uuid.
916 947 */
917 948 if (efi_debug) {
918 949 (void) fprintf(stderr,
919 950 "Unknown uuid for p_tag %d\n",
920 951 vtoc->efi_parts[i].p_tag);
921 952 }
922 953 return (VT_EINVAL);
923 954 }
924 955
925 956 efi_parts[i].efi_gpe_StartingLBA =
926 957 LE_64(vtoc->efi_parts[i].p_start);
927 958 efi_parts[i].efi_gpe_EndingLBA =
928 959 LE_64(vtoc->efi_parts[i].p_start +
929 960 vtoc->efi_parts[i].p_size - 1);
930 961 efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
931 962 LE_16(vtoc->efi_parts[i].p_flag);
932 963 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
933 964 efi_parts[i].efi_gpe_PartitionName[j] =
934 965 LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
935 966 }
936 967 if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
937 968 uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
938 969 (void) uuid_generate((uchar_t *)
939 970 &vtoc->efi_parts[i].p_uguid);
940 971 }
941 972 bcopy(&vtoc->efi_parts[i].p_uguid,
942 973 &efi_parts[i].efi_gpe_UniquePartitionGUID,
943 974 sizeof (uuid_t));
944 975 }
945 976 efi->efi_gpt_PartitionEntryArrayCRC32 =
946 977 LE_32(efi_crc32((unsigned char *)efi_parts,
947 978 vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
948 979 efi->efi_gpt_HeaderCRC32 =
949 980 LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
950 981
951 982 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
952 983 free(dk_ioc.dki_data);
953 984 switch (errno) {
954 985 case EIO:
955 986 return (VT_EIO);
956 987 case EINVAL:
957 988 return (VT_EINVAL);
958 989 default:
959 990 return (VT_ERROR);
960 991 }
961 992 }
962 993
963 994 /* write backup partition array */
964 995 dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
965 996 dk_ioc.dki_length -= vtoc->efi_lbasize;
966 997 /* LINTED */
967 998 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
968 999 vtoc->efi_lbasize);
969 1000
970 1001 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
971 1002 /*
972 1003 * we wrote the primary label okay, so don't fail
973 1004 */
974 1005 if (efi_debug) {
975 1006 (void) fprintf(stderr,
976 1007 "write of backup partitions to block %llu "
977 1008 "failed, errno %d\n",
978 1009 vtoc->efi_last_u_lba + 1,
979 1010 errno);
980 1011 }
981 1012 }
982 1013 /*
983 1014 * now swap MyLBA and AlternateLBA fields and write backup
984 1015 * partition table header
985 1016 */
986 1017 dk_ioc.dki_lba = lba_backup_gpt_hdr;
987 1018 dk_ioc.dki_length = vtoc->efi_lbasize;
988 1019 /* LINTED */
989 1020 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
990 1021 vtoc->efi_lbasize);
991 1022 efi->efi_gpt_AlternateLBA = LE_64(1ULL);
992 1023 efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
993 1024 efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
994 1025 efi->efi_gpt_HeaderCRC32 = 0;
995 1026 efi->efi_gpt_HeaderCRC32 =
996 1027 LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
997 1028 sizeof (struct efi_gpt)));
998 1029
999 1030 if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1000 1031 if (efi_debug) {
1001 1032 (void) fprintf(stderr,
1002 1033 "write of backup header to block %llu failed, "
1003 1034 "errno %d\n",
1004 1035 lba_backup_gpt_hdr,
1005 1036 errno);
1006 1037 }
1007 1038 }
1008 1039 /* write the PMBR */
1009 1040 (void) write_pmbr(fd, vtoc);
1010 1041 free(dk_ioc.dki_data);
1011 1042 return (0);
1012 1043 }
1013 1044
1014 1045 void
1015 1046 efi_free(struct dk_gpt *ptr)
1016 1047 {
1017 1048 free(ptr);
1018 1049 }
1019 1050
1020 1051 /*
1021 1052 * Input: File descriptor
1022 1053 * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
1023 1054 * Otherwise 0.
1024 1055 */
1025 1056 int
1026 1057 efi_type(int fd)
1027 1058 {
1028 1059 struct vtoc vtoc;
1029 1060 struct extvtoc extvtoc;
1030 1061
1031 1062 if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) {
1032 1063 if (errno == ENOTSUP)
1033 1064 return (1);
1034 1065 else if (errno == ENOTTY) {
1035 1066 if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1)
1036 1067 if (errno == ENOTSUP)
1037 1068 return (1);
1038 1069 }
1039 1070 }
1040 1071 return (0);
1041 1072 }
1042 1073
1043 1074 void
1044 1075 efi_err_check(struct dk_gpt *vtoc)
1045 1076 {
1046 1077 int resv_part = -1;
1047 1078 int i, j;
1048 1079 diskaddr_t istart, jstart, isize, jsize, endsect;
1049 1080 int overlap = 0;
1050 1081
1051 1082 /*
1052 1083 * make sure no partitions overlap
1053 1084 */
1054 1085 for (i = 0; i < vtoc->efi_nparts; i++) {
1055 1086 /* It can't be unassigned and have an actual size */
1056 1087 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
1057 1088 (vtoc->efi_parts[i].p_size != 0)) {
1058 1089 (void) fprintf(stderr,
1059 1090 "partition %d is \"unassigned\" but has a size "
1060 1091 "of %llu\n", i, vtoc->efi_parts[i].p_size);
1061 1092 }
1062 1093 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
1063 1094 continue;
1064 1095 }
1065 1096 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
1066 1097 if (resv_part != -1) {
1067 1098 (void) fprintf(stderr,
1068 1099 "found duplicate reserved partition at "
1069 1100 "%d\n", i);
1070 1101 }
1071 1102 resv_part = i;
1072 1103 if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
1073 1104 (void) fprintf(stderr,
1074 1105 "Warning: reserved partition size must "
1075 1106 "be %d sectors\n", EFI_MIN_RESV_SIZE);
1076 1107 }
1077 1108 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
1078 1109 (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
1079 1110 (void) fprintf(stderr,
1080 1111 "Partition %d starts at %llu\n",
1081 1112 i,
1082 1113 vtoc->efi_parts[i].p_start);
1083 1114 (void) fprintf(stderr,
1084 1115 "It must be between %llu and %llu.\n",
1085 1116 vtoc->efi_first_u_lba,
1086 1117 vtoc->efi_last_u_lba);
1087 1118 }
1088 1119 if ((vtoc->efi_parts[i].p_start +
1089 1120 vtoc->efi_parts[i].p_size <
1090 1121 vtoc->efi_first_u_lba) ||
1091 1122 (vtoc->efi_parts[i].p_start +
1092 1123 vtoc->efi_parts[i].p_size >
1093 1124 vtoc->efi_last_u_lba + 1)) {
1094 1125 (void) fprintf(stderr,
1095 1126 "Partition %d ends at %llu\n",
1096 1127 i,
1097 1128 vtoc->efi_parts[i].p_start +
1098 1129 vtoc->efi_parts[i].p_size);
1099 1130 (void) fprintf(stderr,
1100 1131 "It must be between %llu and %llu.\n",
1101 1132 vtoc->efi_first_u_lba,
1102 1133 vtoc->efi_last_u_lba);
1103 1134 }
1104 1135
1105 1136 for (j = 0; j < vtoc->efi_nparts; j++) {
1106 1137 isize = vtoc->efi_parts[i].p_size;
1107 1138 jsize = vtoc->efi_parts[j].p_size;
1108 1139 istart = vtoc->efi_parts[i].p_start;
1109 1140 jstart = vtoc->efi_parts[j].p_start;
1110 1141 if ((i != j) && (isize != 0) && (jsize != 0)) {
1111 1142 endsect = jstart + jsize -1;
1112 1143 if ((jstart <= istart) &&
1113 1144 (istart <= endsect)) {
1114 1145 if (!overlap) {
1115 1146 (void) fprintf(stderr,
1116 1147 "label error: EFI Labels do not "
1117 1148 "support overlapping partitions\n");
1118 1149 }
1119 1150 (void) fprintf(stderr,
1120 1151 "Partition %d overlaps partition "
1121 1152 "%d.\n", i, j);
1122 1153 overlap = 1;
1123 1154 }
1124 1155 }
1125 1156 }
1126 1157 }
1127 1158 /* make sure there is a reserved partition */
1128 1159 if (resv_part == -1) {
1129 1160 (void) fprintf(stderr,
1130 1161 "no reserved partition found\n");
1131 1162 }
1132 1163 }
1133 1164
1134 1165 /*
1135 1166 * We need to get information necessary to construct a *new* efi
1136 1167 * label type
1137 1168 */
1138 1169 int
1139 1170 efi_auto_sense(int fd, struct dk_gpt **vtoc)
1140 1171 {
1141 1172
1142 1173 int i;
1143 1174
1144 1175 /*
1145 1176 * Now build the default partition table
1146 1177 */
1147 1178 if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
1148 1179 if (efi_debug) {
1149 1180 (void) fprintf(stderr, "efi_alloc_and_init failed.\n");
1150 1181 }
1151 1182 return (-1);
1152 1183 }
1153 1184
1154 1185 for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
1155 1186 (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
1156 1187 (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
1157 1188 (*vtoc)->efi_parts[i].p_start = 0;
1158 1189 (*vtoc)->efi_parts[i].p_size = 0;
1159 1190 }
1160 1191 /*
1161 1192 * Make constants first
1162 1193 * and variable partitions later
1163 1194 */
1164 1195
1165 1196 /* root partition - s0 128 MB */
1166 1197 (*vtoc)->efi_parts[0].p_start = 34;
1167 1198 (*vtoc)->efi_parts[0].p_size = 262144;
1168 1199
1169 1200 /* partition - s1 128 MB */
1170 1201 (*vtoc)->efi_parts[1].p_start = 262178;
1171 1202 (*vtoc)->efi_parts[1].p_size = 262144;
1172 1203
1173 1204 /* partition -s2 is NOT the Backup disk */
1174 1205 (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
1175 1206
1176 1207 /* partition -s6 /usr partition - HOG */
1177 1208 (*vtoc)->efi_parts[6].p_start = 524322;
1178 1209 (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
1179 1210 - (1024 * 16);
1180 1211
1181 1212 /* efi reserved partition - s9 16K */
1182 1213 (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
1183 1214 (*vtoc)->efi_parts[8].p_size = (1024 * 16);
1184 1215 (*vtoc)->efi_parts[8].p_tag = V_RESERVED;
1185 1216 return (0);
1186 1217 }
|
↓ open down ↓ |
966 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX