xref: /freebsd/sys/geom/part/g_part_gpt.c (revision bfe691b2f75de2224c7ceb304ebcdef2b42d4179)
1 /*-
2  * Copyright (c) 2002, 2005, 2006, 2007 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/bio.h>
32 #include <sys/diskmbr.h>
33 #include <sys/endian.h>
34 #include <sys/gpt.h>
35 #include <sys/kernel.h>
36 #include <sys/kobj.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/queue.h>
42 #include <sys/sbuf.h>
43 #include <sys/systm.h>
44 #include <sys/uuid.h>
45 #include <geom/geom.h>
46 #include <geom/part/g_part.h>
47 
48 #include "g_part_if.h"
49 
50 CTASSERT(offsetof(struct gpt_hdr, padding) == 92);
51 CTASSERT(sizeof(struct gpt_ent) == 128);
52 
53 #define	EQUUID(a,b)	(memcmp(a, b, sizeof(struct uuid)) == 0)
54 
55 enum gpt_elt {
56 	GPT_ELT_PRIHDR,
57 	GPT_ELT_PRITBL,
58 	GPT_ELT_SECHDR,
59 	GPT_ELT_SECTBL,
60 	GPT_ELT_COUNT
61 };
62 
63 enum gpt_state {
64 	GPT_STATE_UNKNOWN,	/* Not determined. */
65 	GPT_STATE_MISSING,	/* No signature found. */
66 	GPT_STATE_CORRUPT,	/* Checksum mismatch. */
67 	GPT_STATE_INVALID,	/* Nonconformant/invalid. */
68 	GPT_STATE_OK		/* Perfectly fine. */
69 };
70 
71 struct g_part_gpt_table {
72 	struct g_part_table	base;
73 	struct gpt_hdr		hdr;
74 	quad_t			lba[GPT_ELT_COUNT];
75 	enum gpt_state		state[GPT_ELT_COUNT];
76 };
77 
78 struct g_part_gpt_entry {
79 	struct g_part_entry	base;
80 	struct gpt_ent		ent;
81 };
82 
83 static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *,
84     struct g_part_parms *);
85 static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *);
86 static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *);
87 static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *);
88 static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *,
89     struct g_part_parms *);
90 static char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *,
91     char *, size_t);
92 static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *);
93 static int g_part_gpt_read(struct g_part_table *, struct g_consumer *);
94 static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *,
95     char *, size_t);
96 static int g_part_gpt_write(struct g_part_table *, struct g_consumer *);
97 
98 static kobj_method_t g_part_gpt_methods[] = {
99 	KOBJMETHOD(g_part_add,		g_part_gpt_add),
100 	KOBJMETHOD(g_part_create,	g_part_gpt_create),
101 	KOBJMETHOD(g_part_destroy,	g_part_gpt_destroy),
102 	KOBJMETHOD(g_part_dumpto,	g_part_gpt_dumpto),
103 	KOBJMETHOD(g_part_modify,	g_part_gpt_modify),
104 	KOBJMETHOD(g_part_name,		g_part_gpt_name),
105 	KOBJMETHOD(g_part_probe,	g_part_gpt_probe),
106 	KOBJMETHOD(g_part_read,		g_part_gpt_read),
107 	KOBJMETHOD(g_part_type,		g_part_gpt_type),
108 	KOBJMETHOD(g_part_write,	g_part_gpt_write),
109 	{ 0, 0 }
110 };
111 
112 static struct g_part_scheme g_part_gpt_scheme = {
113 	"GPT",
114 	g_part_gpt_methods,
115 	sizeof(struct g_part_gpt_table),
116 	.gps_entrysz = sizeof(struct g_part_gpt_entry),
117 	.gps_minent = 128,
118 	.gps_maxent = INT_MAX,
119 };
120 G_PART_SCHEME_DECLARE(g_part_gpt_scheme);
121 
122 static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI;
123 static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
124 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
125 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
126 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
127 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
128 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
129 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
130 
131 static void
132 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
133     enum gpt_elt elt, struct gpt_hdr *hdr)
134 {
135 	struct uuid uuid;
136 	struct g_provider *pp;
137 	char *buf;
138 	quad_t lba, last;
139 	int error;
140 	uint32_t crc, sz;
141 
142 	pp = cp->provider;
143 	last = (pp->mediasize / pp->sectorsize) - 1;
144 	table->lba[elt] = (elt == GPT_ELT_PRIHDR) ? 1 : last;
145 	table->state[elt] = GPT_STATE_MISSING;
146 	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
147 	    &error);
148 	if (buf == NULL)
149 		return;
150 	bcopy(buf, hdr, sizeof(*hdr));
151 	if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0)
152 		return;
153 
154 	table->state[elt] = GPT_STATE_CORRUPT;
155 	sz = le32toh(hdr->hdr_size);
156 	if (sz < 92 || sz > pp->sectorsize)
157 		return;
158 	crc = le32toh(hdr->hdr_crc_self);
159 	hdr->hdr_crc_self = 0;
160 	if (crc32(hdr, sz) != crc)
161 		return;
162 	hdr->hdr_size = sz;
163 	hdr->hdr_crc_self = crc;
164 
165 	table->state[elt] = GPT_STATE_INVALID;
166 	hdr->hdr_revision = le32toh(hdr->hdr_revision);
167 	if (hdr->hdr_revision < 0x00010000)
168 		return;
169 	hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self);
170 	if (hdr->hdr_lba_self != table->lba[elt])
171 		return;
172 	hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt);
173 
174 	/* Check the managed area. */
175 	hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start);
176 	if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
177 		return;
178 	hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end);
179 	if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
180 		return;
181 
182 	/* Check the table location and size of the table. */
183 	hdr->hdr_entries = le32toh(hdr->hdr_entries);
184 	hdr->hdr_entsz = le32toh(hdr->hdr_entsz);
185 	if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
186 	    (hdr->hdr_entsz & 7) != 0)
187 		return;
188 	hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table);
189 	if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
190 		return;
191 	if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
192 	    hdr->hdr_lba_table <= hdr->hdr_lba_end)
193 		return;
194 	lba = hdr->hdr_lba_table +
195 	    (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
196 	    pp->sectorsize - 1;
197 	if (lba >= last)
198 		return;
199 	if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
200 		return;
201 
202 	table->state[elt] = GPT_STATE_OK;
203 	le_uuid_dec(&hdr->hdr_uuid, &uuid);
204 	hdr->hdr_uuid = uuid;
205 	hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table);
206 }
207 
208 static struct gpt_ent *
209 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
210     enum gpt_elt elt, struct gpt_hdr *hdr)
211 {
212 	struct g_provider *pp;
213 	struct gpt_ent *ent, *tbl;
214 	char *buf, *p;
215 	unsigned int idx, sectors, tblsz;
216 	int error;
217 	uint16_t ch;
218 
219 	pp = cp->provider;
220 	table->lba[elt] = hdr->hdr_lba_table;
221 
222 	table->state[elt] = GPT_STATE_MISSING;
223 	tblsz = hdr->hdr_entries * hdr->hdr_entsz;
224 	sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
225 	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize,
226 	    sectors * pp->sectorsize, &error);
227 	if (buf == NULL)
228 		return (NULL);
229 
230 	table->state[elt] = GPT_STATE_CORRUPT;
231 	if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
232 		g_free(buf);
233 		return (NULL);
234 	}
235 
236 	table->state[elt] = GPT_STATE_OK;
237 	tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
238 	    M_WAITOK | M_ZERO);
239 
240 	for (idx = 0, ent = tbl, p = buf;
241 	     idx < hdr->hdr_entries;
242 	     idx++, ent++, p += hdr->hdr_entsz) {
243 		le_uuid_dec(p, &ent->ent_type);
244 		le_uuid_dec(p + 16, &ent->ent_uuid);
245 		ent->ent_lba_start = le64dec(p + 32);
246 		ent->ent_lba_end = le64dec(p + 40);
247 		ent->ent_attr = le64dec(p + 48);
248 		for (ch = 0; ch < sizeof(ent->ent_name)/2; ch++)
249 			ent->ent_name[ch] = le16dec(p + 56 + ch * 2);
250 	}
251 
252 	g_free(buf);
253 	return (tbl);
254 }
255 
256 static int
257 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
258 {
259 
260 	if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
261 		return (0);
262 	return ((pri->hdr_revision == sec->hdr_revision &&
263 	    pri->hdr_size == sec->hdr_size &&
264 	    pri->hdr_lba_start == sec->hdr_lba_start &&
265 	    pri->hdr_lba_end == sec->hdr_lba_end &&
266 	    pri->hdr_entries == sec->hdr_entries &&
267 	    pri->hdr_entsz == sec->hdr_entsz &&
268 	    pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
269 }
270 
271 static int
272 gpt_parse_type(const char *type, struct uuid *uuid)
273 {
274 	struct uuid tmp;
275 	int error;
276 
277 	if (type[0] != '@') {
278 		error = parse_uuid(type, &tmp);
279 		if (error)
280 			return (error);
281 		if (EQUUID(&tmp, &gpt_uuid_unused))
282 			return (EINVAL);
283 		*uuid = tmp;
284 		return (0);
285 	}
286 	if (!strcmp(type, g_part_alias_name(G_PART_ALIAS_EFI)))
287 		*uuid = gpt_uuid_efi;
288 	else if (!strcmp(type, g_part_alias_name(G_PART_ALIAS_FREEBSD)))
289 		*uuid = gpt_uuid_freebsd;
290 	else if (!strcmp(type, g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)))
291 		*uuid = gpt_uuid_freebsd_swap;
292 	else if (!strcmp(type, g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)))
293 		*uuid = gpt_uuid_freebsd_ufs;
294 	else if (!strcmp(type, g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)))
295 		*uuid = gpt_uuid_freebsd_vinum;
296 	else if (!strcmp(type, g_part_alias_name(G_PART_ALIAS_MBR)))
297 		*uuid = gpt_uuid_mbr;
298 	else
299 		return (EINVAL);
300 	return (0);
301 }
302 
303 static int
304 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
305     struct g_part_parms *gpp)
306 {
307 	struct g_part_gpt_entry *entry;
308 	int error;
309 
310 	entry = (struct g_part_gpt_entry *)baseentry;
311 	error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
312 	if (error)
313 		return (error);
314 	kern_uuidgen(&entry->ent.ent_uuid, 1);
315 	entry->ent.ent_lba_start = baseentry->gpe_start;
316 	entry->ent.ent_lba_end = baseentry->gpe_end;
317 	if (baseentry->gpe_deleted) {
318 		entry->ent.ent_attr = 0;
319 		bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
320 	}
321 	/* XXX label */
322 	return (0);
323 }
324 
325 static int
326 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
327 {
328 	struct g_provider *pp;
329 	struct g_part_gpt_table *table;
330 	quad_t last;
331 	size_t tblsz;
332 
333 	table = (struct g_part_gpt_table *)basetable;
334 	pp = gpp->gpp_provider;
335 	tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
336 	    pp->sectorsize - 1) / pp->sectorsize;
337 	if (pp->sectorsize < 512 ||
338 	    pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
339 	    pp->sectorsize)
340 		return (ENOSPC);
341 
342 	last = (pp->mediasize / pp->sectorsize) - 1;
343 
344 	table->lba[GPT_ELT_PRIHDR] = 1;
345 	table->lba[GPT_ELT_PRITBL] = 2;
346 	table->lba[GPT_ELT_SECHDR] = last;
347 	table->lba[GPT_ELT_SECTBL] = last - tblsz;
348 
349 	bcopy(GPT_HDR_SIG, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
350 	table->hdr.hdr_revision = GPT_HDR_REVISION;
351 	table->hdr.hdr_size = offsetof(struct gpt_hdr, padding);
352 	table->hdr.hdr_lba_start = 2 + tblsz;
353 	table->hdr.hdr_lba_end = last - tblsz - 1;
354 	kern_uuidgen(&table->hdr.hdr_uuid, 1);
355 	table->hdr.hdr_entries = basetable->gpt_entries;
356 	table->hdr.hdr_entsz = sizeof(struct gpt_ent);
357 
358 	basetable->gpt_first = table->hdr.hdr_lba_start;
359 	basetable->gpt_last = table->hdr.hdr_lba_end;
360 	return (0);
361 }
362 
363 static int
364 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
365 {
366 
367 	/*
368 	 * Wipe the first 2 sectors as well as the last to clear the
369 	 * partitioning.
370 	 */
371 	basetable->gpt_smhead |= 3;
372 	basetable->gpt_smtail |= 1;
373 	return (0);
374 }
375 
376 static int
377 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
378 {
379 	struct g_part_gpt_entry *entry;
380 
381 	entry = (struct g_part_gpt_entry *)baseentry;
382 	return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
383 	    EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0);
384 }
385 
386 static int
387 g_part_gpt_modify(struct g_part_table *basetable,
388     struct g_part_entry *baseentry, struct g_part_parms *gpp)
389 {
390 	struct g_part_gpt_entry *entry;
391 	int error;
392 
393 	entry = (struct g_part_gpt_entry *)baseentry;
394 	error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
395 	if (error)
396 		return (error);
397 	/* XXX label */
398 	return (0);
399 }
400 
401 static char *
402 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
403     char *buf, size_t bufsz)
404 {
405 	struct g_part_gpt_entry *entry;
406 	char c;
407 
408 	entry = (struct g_part_gpt_entry *)baseentry;
409 	c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
410 	snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
411 	return (buf);
412 }
413 
414 static int
415 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
416 {
417 	struct g_provider *pp;
418 	char *buf;
419 	int error, res;
420 
421 	/* We don't nest, which means that our depth should be 0. */
422 	if (table->gpt_depth != 0)
423 		return (ENXIO);
424 
425 	pp = cp->provider;
426 
427 	/*
428 	 * Sanity-check the provider. Since the first sector on the provider
429 	 * must be a PMBR and a PMBR is 512 bytes large, the sector size
430 	 * must be at least 512 bytes.  Also, since the theoretical minimum
431 	 * number of sectors needed by GPT is 6, any medium that has less
432 	 * than 6 sectors is never going to be able to hold a GPT. The
433 	 * number 6 comes from:
434 	 *	1 sector for the PMBR
435 	 *	2 sectors for the GPT headers (each 1 sector)
436 	 *	2 sectors for the GPT tables (each 1 sector)
437 	 *	1 sector for an actual partition
438 	 * It's better to catch this pathological case early than behaving
439 	 * pathologically later on...
440 	 */
441 	if (pp->sectorsize < 512 || pp->mediasize < 6 * pp->sectorsize)
442 		return (ENOSPC);
443 
444 	/* Check that there's a MBR. */
445 	buf = g_read_data(cp, 0L, pp->sectorsize, &error);
446 	if (buf == NULL)
447 		return (error);
448 	res = le16dec(buf + DOSMAGICOFFSET);
449 	g_free(buf);
450 	if (res != DOSMAGIC)
451 		return (ENXIO);
452 
453 	/* Check that there's a primary header. */
454 	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
455 	if (buf == NULL)
456 		return (error);
457 	res = memcmp(buf, GPT_HDR_SIG, 8);
458 	g_free(buf);
459 	if (res == 0)
460 		return (G_PART_PROBE_PRI_HIGH);
461 
462 	/* No primary? Check that there's a secondary. */
463 	buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
464 	    &error);
465 	if (buf == NULL)
466 		return (error);
467 	res = memcmp(buf, GPT_HDR_SIG, 8);
468 	g_free(buf);
469 	return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO);
470 }
471 
472 static int
473 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
474 {
475 	struct gpt_hdr prihdr, sechdr;
476 	struct gpt_ent *tbl, *pritbl, *sectbl;
477 	struct g_provider *pp;
478 	struct g_part_gpt_table *table;
479 	struct g_part_gpt_entry *entry;
480 	int index;
481 
482 	table = (struct g_part_gpt_table *)basetable;
483 	pp = cp->provider;
484 
485 	/* Read the primary header and table. */
486 	gpt_read_hdr(table, cp, GPT_ELT_PRIHDR, &prihdr);
487 	if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
488 		pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, &prihdr);
489 	} else {
490 		table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
491 		pritbl = NULL;
492 	}
493 
494 	/* Read the secondary header and table. */
495 	gpt_read_hdr(table, cp, GPT_ELT_SECHDR, &sechdr);
496 	if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
497 		sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, &sechdr);
498 	} else {
499 		table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
500 		sectbl = NULL;
501 	}
502 
503 	/* Fail if we haven't got any good tables at all. */
504 	if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
505 	    table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
506 		printf("GEOM: %s: corrupt or invalid GPT detected.\n",
507 		    pp->name);
508 		printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
509 		    pp->name);
510 		return (EINVAL);
511 	}
512 
513 	/*
514 	 * If both headers are good but they disagree with each other,
515 	 * then invalidate one. We prefer to keep the primary header,
516 	 * unless the primary table is corrupt.
517 	 */
518 	if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
519 	    table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
520 	    !gpt_matched_hdrs(&prihdr, &sechdr)) {
521 		if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK)
522 			table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
523 		else
524 			table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
525 	}
526 
527 	if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK) {
528 		printf("GEOM: %s: the primary GPT table is corrupt or "
529 		    "invalid.\n", pp->name);
530 		printf("GEOM: %s: using the secondary instead -- recovery "
531 		    "strongly advised.\n", pp->name);
532 		table->hdr = sechdr;
533 		tbl = sectbl;
534 		if (pritbl != NULL)
535 			g_free(pritbl);
536 	} else {
537 		if (table->state[GPT_ELT_SECHDR] != GPT_STATE_OK) {
538 			printf("GEOM: %s: the secondary GPT table is corrupt "
539 			    "or invalid.\n", pp->name);
540 			printf("GEOM: %s: using the primary only -- recovery "
541 			    "suggested.\n", pp->name);
542 		}
543 		table->hdr = prihdr;
544 		tbl = pritbl;
545 		if (sectbl != NULL)
546 			g_free(sectbl);
547 	}
548 
549 	basetable->gpt_first = table->hdr.hdr_lba_start;
550 	basetable->gpt_last = table->hdr.hdr_lba_end;
551 	basetable->gpt_entries = table->hdr.hdr_entries;
552 
553 	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
554 		if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
555 			continue;
556 		entry = (struct g_part_gpt_entry *)g_part_new_entry(basetable,
557 		    index+1, tbl[index].ent_lba_start, tbl[index].ent_lba_end);
558 		entry->ent = tbl[index];
559 	}
560 
561 	g_free(tbl);
562 	return (0);
563 }
564 
565 static const char *
566 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
567     char *buf, size_t bufsz)
568 {
569 	struct g_part_gpt_entry *entry;
570 	struct uuid *type;
571 
572 	entry = (struct g_part_gpt_entry *)baseentry;
573 	type = &entry->ent.ent_type;
574 	if (EQUUID(type, &gpt_uuid_efi))
575 		return (g_part_alias_name(G_PART_ALIAS_EFI));
576 	if (EQUUID(type, &gpt_uuid_freebsd))
577 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
578 	if (EQUUID(type, &gpt_uuid_freebsd_swap))
579 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
580 	if (EQUUID(type, &gpt_uuid_freebsd_ufs))
581 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
582 	if (EQUUID(type, &gpt_uuid_freebsd_vinum))
583 		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
584 	if (EQUUID(type, &gpt_uuid_mbr))
585 		return (g_part_alias_name(G_PART_ALIAS_MBR));
586 	snprintf_uuid(buf, bufsz, type);
587 	return (buf);
588 }
589 
590 static int
591 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
592 {
593 	unsigned char *buf, *bp;
594 	struct g_provider *pp;
595 	struct g_part_entry *baseentry;
596 	struct g_part_gpt_entry *entry;
597 	struct g_part_gpt_table *table;
598 	size_t tlbsz;
599 	uint32_t crc;
600 	int error, index;
601 
602 	pp = cp->provider;
603 	table = (struct g_part_gpt_table *)basetable;
604 	tlbsz = (table->hdr.hdr_entries * table->hdr.hdr_entsz +
605 	    pp->sectorsize - 1) / pp->sectorsize;
606 
607 	if (basetable->gpt_created) {
608 		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
609 		le16enc(buf + DOSMAGICOFFSET, DOSMAGIC);
610 		buf[DOSPARTOFF + 1] = 0xff;		/* shd */
611 		buf[DOSPARTOFF + 2] = 0xff;		/* ssect */
612 		buf[DOSPARTOFF + 3] = 0xff;		/* scyl */
613 		buf[DOSPARTOFF + 4] = 0xee;		/* typ */
614 		buf[DOSPARTOFF + 5] = 0xff;		/* ehd */
615 		buf[DOSPARTOFF + 6] = 0xff;		/* esect */
616 		buf[DOSPARTOFF + 7] = 0xff;		/* ecyl */
617 		le32enc(buf + DOSPARTOFF + 8, 1);	/* start */
618 		le32enc(buf + DOSPARTOFF + 12,
619 		    MIN(pp->mediasize / pp->sectorsize - 1, 0xffffffffLL));
620 		error = g_write_data(cp, 0, buf, pp->sectorsize);
621 		g_free(buf);
622 		if (error)
623 			return (error);
624 	}
625 
626 	/* Allocate space for the header and entries. */
627 	buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
628 
629 	memcpy(buf, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
630 	le32enc(buf + 8, table->hdr.hdr_revision);
631 	le32enc(buf + 12, table->hdr.hdr_size);
632 	le64enc(buf + 40, table->hdr.hdr_lba_start);
633 	le64enc(buf + 48, table->hdr.hdr_lba_end);
634 	le_uuid_enc(buf + 56, &table->hdr.hdr_uuid);
635 	le32enc(buf + 80, table->hdr.hdr_entries);
636 	le32enc(buf + 84, table->hdr.hdr_entsz);
637 
638 	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
639 		entry = (struct g_part_gpt_entry *)baseentry;
640 		index = baseentry->gpe_index - 1;
641 		bp = buf + pp->sectorsize + table->hdr.hdr_entsz * index;
642 		le_uuid_enc(bp, &entry->ent.ent_type);
643 		le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
644 		le64enc(bp + 32, entry->ent.ent_lba_start);
645 		le64enc(bp + 40, entry->ent.ent_lba_end);
646 		le64enc(bp + 48, entry->ent.ent_attr);
647 		memcpy(bp + 56, entry->ent.ent_name,
648 		    sizeof(entry->ent.ent_name));
649 	}
650 
651 	crc = crc32(buf + pp->sectorsize,
652 	    table->hdr.hdr_entries * table->hdr.hdr_entsz);
653 	le32enc(buf + 88, crc);
654 
655 	/* Write primary meta-data. */
656 	le32enc(buf + 16, 0);	/* hdr_crc_self. */
657 	le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);	/* hdr_lba_self. */
658 	le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);	/* hdr_lba_alt. */
659 	le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);	/* hdr_lba_table. */
660 	crc = crc32(buf, table->hdr.hdr_size);
661 	le32enc(buf + 16, crc);
662 
663 	error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
664 	    buf + pp->sectorsize, tlbsz * pp->sectorsize);
665 	if (error)
666 		goto out;
667 	error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
668 	    buf, pp->sectorsize);
669 	if (error)
670 		goto out;
671 
672 	/* Write secondary meta-data. */
673 	le32enc(buf + 16, 0);	/* hdr_crc_self. */
674 	le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);	/* hdr_lba_self. */
675 	le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);	/* hdr_lba_alt. */
676 	le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);	/* hdr_lba_table. */
677 	crc = crc32(buf, table->hdr.hdr_size);
678 	le32enc(buf + 16, crc);
679 
680 	error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
681 	    buf + pp->sectorsize, tlbsz * pp->sectorsize);
682 	if (error)
683 		goto out;
684 	error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
685 	    buf, pp->sectorsize);
686 
687  out:
688 	g_free(buf);
689 	return (error);
690 }
691 
692 #if 0
693 static void
694 g_gpt_to_utf8(struct sbuf *sb, uint16_t *str, size_t len)
695 {
696 	u_int bo;
697 	uint32_t ch;
698 	uint16_t c;
699 
700 	bo = BYTE_ORDER;
701 	while (len > 0 && *str != 0) {
702 		ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
703 		str++, len--;
704 		if ((ch & 0xf800) == 0xd800) {
705 			if (len > 0) {
706 				c = (bo == BIG_ENDIAN) ? be16toh(*str)
707 				    : le16toh(*str);
708 				str++, len--;
709 			} else
710 				c = 0xfffd;
711 			if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
712 				ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
713 				ch += 0x10000;
714 			} else
715 				ch = 0xfffd;
716 		} else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
717 			bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
718 			continue;
719 		} else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
720 			continue;
721 
722 		if (ch < 0x80)
723 			sbuf_printf(sb, "%c", ch);
724 		else if (ch < 0x800)
725 			sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6),
726 			    0x80 | (ch & 0x3f));
727 		else if (ch < 0x10000)
728 			sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12),
729 			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
730 		else if (ch < 0x200000)
731 			sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18),
732 			    0x80 | ((ch >> 12) & 0x3f),
733 			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
734 	}
735 }
736 #endif
737