]> CyberLeo.Net >> Repos - FreeBSD/releng/10.1.git/blob - sys/geom/part/g_part_gpt.c
Copy stable/10@r272459 to releng/10.1 as part of
[FreeBSD/releng/10.1.git] / sys / geom / part / g_part_gpt.c
1 /*-
2  * Copyright (c) 2002, 2005-2007, 2011 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/sysctl.h>
45 #include <sys/uuid.h>
46 #include <geom/geom.h>
47 #include <geom/geom_int.h>
48 #include <geom/part/g_part.h>
49
50 #include "g_part_if.h"
51
52 FEATURE(geom_part_gpt, "GEOM partitioning class for GPT partitions support");
53
54 CTASSERT(offsetof(struct gpt_hdr, padding) == 92);
55 CTASSERT(sizeof(struct gpt_ent) == 128);
56
57 #define EQUUID(a,b)     (memcmp(a, b, sizeof(struct uuid)) == 0)
58
59 #define MBRSIZE         512
60
61 enum gpt_elt {
62         GPT_ELT_PRIHDR,
63         GPT_ELT_PRITBL,
64         GPT_ELT_SECHDR,
65         GPT_ELT_SECTBL,
66         GPT_ELT_COUNT
67 };
68
69 enum gpt_state {
70         GPT_STATE_UNKNOWN,      /* Not determined. */
71         GPT_STATE_MISSING,      /* No signature found. */
72         GPT_STATE_CORRUPT,      /* Checksum mismatch. */
73         GPT_STATE_INVALID,      /* Nonconformant/invalid. */
74         GPT_STATE_OK            /* Perfectly fine. */
75 };
76
77 struct g_part_gpt_table {
78         struct g_part_table     base;
79         u_char                  mbr[MBRSIZE];
80         struct gpt_hdr          *hdr;
81         quad_t                  lba[GPT_ELT_COUNT];
82         enum gpt_state          state[GPT_ELT_COUNT];
83         int                     bootcamp;
84 };
85
86 struct g_part_gpt_entry {
87         struct g_part_entry     base;
88         struct gpt_ent          ent;
89 };
90
91 static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t);
92 static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t);
93 static void g_gpt_set_defaults(struct g_part_table *, struct g_provider *);
94
95 static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *,
96     struct g_part_parms *);
97 static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *);
98 static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *);
99 static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *);
100 static void g_part_gpt_dumpconf(struct g_part_table *, struct g_part_entry *,
101     struct sbuf *, const char *);
102 static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *);
103 static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *,
104     struct g_part_parms *);
105 static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *,
106     char *, size_t);
107 static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *);
108 static int g_part_gpt_read(struct g_part_table *, struct g_consumer *);
109 static int g_part_gpt_setunset(struct g_part_table *table,
110     struct g_part_entry *baseentry, const char *attrib, unsigned int set);
111 static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *,
112     char *, size_t);
113 static int g_part_gpt_write(struct g_part_table *, struct g_consumer *);
114 static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *,
115     struct g_part_parms *);
116 static int g_part_gpt_recover(struct g_part_table *);
117
118 static kobj_method_t g_part_gpt_methods[] = {
119         KOBJMETHOD(g_part_add,          g_part_gpt_add),
120         KOBJMETHOD(g_part_bootcode,     g_part_gpt_bootcode),
121         KOBJMETHOD(g_part_create,       g_part_gpt_create),
122         KOBJMETHOD(g_part_destroy,      g_part_gpt_destroy),
123         KOBJMETHOD(g_part_dumpconf,     g_part_gpt_dumpconf),
124         KOBJMETHOD(g_part_dumpto,       g_part_gpt_dumpto),
125         KOBJMETHOD(g_part_modify,       g_part_gpt_modify),
126         KOBJMETHOD(g_part_resize,       g_part_gpt_resize),
127         KOBJMETHOD(g_part_name,         g_part_gpt_name),
128         KOBJMETHOD(g_part_probe,        g_part_gpt_probe),
129         KOBJMETHOD(g_part_read,         g_part_gpt_read),
130         KOBJMETHOD(g_part_recover,      g_part_gpt_recover),
131         KOBJMETHOD(g_part_setunset,     g_part_gpt_setunset),
132         KOBJMETHOD(g_part_type,         g_part_gpt_type),
133         KOBJMETHOD(g_part_write,        g_part_gpt_write),
134         { 0, 0 }
135 };
136
137 static struct g_part_scheme g_part_gpt_scheme = {
138         "GPT",
139         g_part_gpt_methods,
140         sizeof(struct g_part_gpt_table),
141         .gps_entrysz = sizeof(struct g_part_gpt_entry),
142         .gps_minent = 128,
143         .gps_maxent = 4096,
144         .gps_bootcodesz = MBRSIZE,
145 };
146 G_PART_SCHEME_DECLARE(g_part_gpt);
147
148 static struct uuid gpt_uuid_apple_boot = GPT_ENT_TYPE_APPLE_BOOT;
149 static struct uuid gpt_uuid_apple_hfs = GPT_ENT_TYPE_APPLE_HFS;
150 static struct uuid gpt_uuid_apple_label = GPT_ENT_TYPE_APPLE_LABEL;
151 static struct uuid gpt_uuid_apple_raid = GPT_ENT_TYPE_APPLE_RAID;
152 static struct uuid gpt_uuid_apple_raid_offline = GPT_ENT_TYPE_APPLE_RAID_OFFLINE;
153 static struct uuid gpt_uuid_apple_tv_recovery = GPT_ENT_TYPE_APPLE_TV_RECOVERY;
154 static struct uuid gpt_uuid_apple_ufs = GPT_ENT_TYPE_APPLE_UFS;
155 static struct uuid gpt_uuid_bios_boot = GPT_ENT_TYPE_BIOS_BOOT;
156 static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI;
157 static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
158 static struct uuid gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
159 static struct uuid gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
160 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
161 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
162 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
163 static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
164 static struct uuid gpt_uuid_linux_data = GPT_ENT_TYPE_LINUX_DATA;
165 static struct uuid gpt_uuid_linux_lvm = GPT_ENT_TYPE_LINUX_LVM;
166 static struct uuid gpt_uuid_linux_raid = GPT_ENT_TYPE_LINUX_RAID;
167 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
168 static struct uuid gpt_uuid_vmfs = GPT_ENT_TYPE_VMFS;
169 static struct uuid gpt_uuid_vmkdiag = GPT_ENT_TYPE_VMKDIAG;
170 static struct uuid gpt_uuid_vmreserved = GPT_ENT_TYPE_VMRESERVED;
171 static struct uuid gpt_uuid_vmvsanhdr = GPT_ENT_TYPE_VMVSANHDR;
172 static struct uuid gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
173 static struct uuid gpt_uuid_ms_reserved = GPT_ENT_TYPE_MS_RESERVED;
174 static struct uuid gpt_uuid_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA;
175 static struct uuid gpt_uuid_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA;
176 static struct uuid gpt_uuid_netbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD;
177 static struct uuid gpt_uuid_netbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD;
178 static struct uuid gpt_uuid_netbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS;
179 static struct uuid gpt_uuid_netbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS;
180 static struct uuid gpt_uuid_netbsd_raid = GPT_ENT_TYPE_NETBSD_RAID;
181 static struct uuid gpt_uuid_netbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP;
182 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
183 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
184 static struct uuid gpt_uuid_dfbsd_swap = GPT_ENT_TYPE_DRAGONFLY_SWAP;
185 static struct uuid gpt_uuid_dfbsd_ufs1 = GPT_ENT_TYPE_DRAGONFLY_UFS1;
186 static struct uuid gpt_uuid_dfbsd_vinum = GPT_ENT_TYPE_DRAGONFLY_VINUM;
187 static struct uuid gpt_uuid_dfbsd_ccd = GPT_ENT_TYPE_DRAGONFLY_CCD;
188 static struct uuid gpt_uuid_dfbsd_legacy = GPT_ENT_TYPE_DRAGONFLY_LEGACY;
189 static struct uuid gpt_uuid_dfbsd_hammer = GPT_ENT_TYPE_DRAGONFLY_HAMMER;
190 static struct uuid gpt_uuid_dfbsd_hammer2 = GPT_ENT_TYPE_DRAGONFLY_HAMMER2;
191 static struct uuid gpt_uuid_dfbsd_label32 = GPT_ENT_TYPE_DRAGONFLY_LABEL32;
192 static struct uuid gpt_uuid_dfbsd_label64 = GPT_ENT_TYPE_DRAGONFLY_LABEL64;
193 static struct uuid gpt_uuid_prep_boot = GPT_ENT_TYPE_PREP_BOOT;
194
195 static struct g_part_uuid_alias {
196         struct uuid *uuid;
197         int alias;
198         int mbrtype;
199 } gpt_uuid_alias_match[] = {
200         { &gpt_uuid_apple_boot,         G_PART_ALIAS_APPLE_BOOT,         0xab },
201         { &gpt_uuid_apple_hfs,          G_PART_ALIAS_APPLE_HFS,          0xaf },
202         { &gpt_uuid_apple_label,        G_PART_ALIAS_APPLE_LABEL,        0 },
203         { &gpt_uuid_apple_raid,         G_PART_ALIAS_APPLE_RAID,         0 },
204         { &gpt_uuid_apple_raid_offline, G_PART_ALIAS_APPLE_RAID_OFFLINE, 0 },
205         { &gpt_uuid_apple_tv_recovery,  G_PART_ALIAS_APPLE_TV_RECOVERY,  0 },
206         { &gpt_uuid_apple_ufs,          G_PART_ALIAS_APPLE_UFS,          0 },
207         { &gpt_uuid_bios_boot,          G_PART_ALIAS_BIOS_BOOT,          0 },
208         { &gpt_uuid_efi,                G_PART_ALIAS_EFI,                0xee },
209         { &gpt_uuid_freebsd,            G_PART_ALIAS_FREEBSD,            0xa5 },
210         { &gpt_uuid_freebsd_boot,       G_PART_ALIAS_FREEBSD_BOOT,       0 },
211         { &gpt_uuid_freebsd_nandfs,     G_PART_ALIAS_FREEBSD_NANDFS,     0 },
212         { &gpt_uuid_freebsd_swap,       G_PART_ALIAS_FREEBSD_SWAP,       0 },
213         { &gpt_uuid_freebsd_ufs,        G_PART_ALIAS_FREEBSD_UFS,        0 },
214         { &gpt_uuid_freebsd_vinum,      G_PART_ALIAS_FREEBSD_VINUM,      0 },
215         { &gpt_uuid_freebsd_zfs,        G_PART_ALIAS_FREEBSD_ZFS,        0 },
216         { &gpt_uuid_linux_data,         G_PART_ALIAS_LINUX_DATA,         0x0b },
217         { &gpt_uuid_linux_lvm,          G_PART_ALIAS_LINUX_LVM,          0 },
218         { &gpt_uuid_linux_raid,         G_PART_ALIAS_LINUX_RAID,         0 },
219         { &gpt_uuid_linux_swap,         G_PART_ALIAS_LINUX_SWAP,         0 },
220         { &gpt_uuid_vmfs,               G_PART_ALIAS_VMFS,               0 },
221         { &gpt_uuid_vmkdiag,            G_PART_ALIAS_VMKDIAG,            0 },
222         { &gpt_uuid_vmreserved,         G_PART_ALIAS_VMRESERVED,         0 },
223         { &gpt_uuid_vmvsanhdr,          G_PART_ALIAS_VMVSANHDR,          0 },
224         { &gpt_uuid_mbr,                G_PART_ALIAS_MBR,                0 },
225         { &gpt_uuid_ms_basic_data,      G_PART_ALIAS_MS_BASIC_DATA,      0x0b },
226         { &gpt_uuid_ms_ldm_data,        G_PART_ALIAS_MS_LDM_DATA,        0 },
227         { &gpt_uuid_ms_ldm_metadata,    G_PART_ALIAS_MS_LDM_METADATA,    0 },
228         { &gpt_uuid_ms_reserved,        G_PART_ALIAS_MS_RESERVED,        0 },
229         { &gpt_uuid_netbsd_ccd,         G_PART_ALIAS_NETBSD_CCD,         0 },
230         { &gpt_uuid_netbsd_cgd,         G_PART_ALIAS_NETBSD_CGD,         0 },
231         { &gpt_uuid_netbsd_ffs,         G_PART_ALIAS_NETBSD_FFS,         0 },
232         { &gpt_uuid_netbsd_lfs,         G_PART_ALIAS_NETBSD_LFS,         0 },
233         { &gpt_uuid_netbsd_raid,        G_PART_ALIAS_NETBSD_RAID,        0 },
234         { &gpt_uuid_netbsd_swap,        G_PART_ALIAS_NETBSD_SWAP,        0 },
235         { &gpt_uuid_dfbsd_swap,         G_PART_ALIAS_DFBSD_SWAP,         0 },
236         { &gpt_uuid_dfbsd_ufs1,         G_PART_ALIAS_DFBSD_UFS,          0 },
237         { &gpt_uuid_dfbsd_vinum,        G_PART_ALIAS_DFBSD_VINUM,        0 },
238         { &gpt_uuid_dfbsd_ccd,          G_PART_ALIAS_DFBSD_CCD,          0 },
239         { &gpt_uuid_dfbsd_legacy,       G_PART_ALIAS_DFBSD_LEGACY,       0 },
240         { &gpt_uuid_dfbsd_hammer,       G_PART_ALIAS_DFBSD_HAMMER,       0 },
241         { &gpt_uuid_dfbsd_hammer2,      G_PART_ALIAS_DFBSD_HAMMER2,      0 },
242         { &gpt_uuid_dfbsd_label32,      G_PART_ALIAS_DFBSD,              0xa5 },
243         { &gpt_uuid_dfbsd_label64,      G_PART_ALIAS_DFBSD64,            0xa5 },
244         { &gpt_uuid_prep_boot,          G_PART_ALIAS_PREP_BOOT,          0x41 },
245         { NULL, 0, 0 }
246 };
247
248 static int
249 gpt_write_mbr_entry(u_char *mbr, int idx, int typ, quad_t start,
250     quad_t end)
251 {
252
253         if (typ == 0 || start > UINT32_MAX || end > UINT32_MAX)
254                 return (EINVAL);
255
256         mbr += DOSPARTOFF + idx * DOSPARTSIZE;
257         mbr[0] = 0;
258         if (start == 1) {
259                 /*
260                  * Treat the PMBR partition specially to maximize
261                  * interoperability with BIOSes.
262                  */
263                 mbr[1] = mbr[3] = 0;
264                 mbr[2] = 2;
265         } else
266                 mbr[1] = mbr[2] = mbr[3] = 0xff;
267         mbr[4] = typ;
268         mbr[5] = mbr[6] = mbr[7] = 0xff;
269         le32enc(mbr + 8, (uint32_t)start);
270         le32enc(mbr + 12, (uint32_t)(end - start + 1));
271         return (0);
272 }
273
274 static int
275 gpt_map_type(struct uuid *t)
276 {
277         struct g_part_uuid_alias *uap;
278
279         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) {
280                 if (EQUUID(t, uap->uuid))
281                         return (uap->mbrtype);
282         }
283         return (0);
284 }
285
286 static void
287 gpt_create_pmbr(struct g_part_gpt_table *table, struct g_provider *pp)
288 {
289
290         bzero(table->mbr + DOSPARTOFF, DOSPARTSIZE * NDOSPART);
291         gpt_write_mbr_entry(table->mbr, 0, 0xee, 1,
292             MIN(pp->mediasize / pp->sectorsize - 1, UINT32_MAX));
293         le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC);
294 }
295
296 /*
297  * Under Boot Camp the PMBR partition (type 0xEE) doesn't cover the
298  * whole disk anymore. Rather, it covers the GPT table and the EFI
299  * system partition only. This way the HFS+ partition and any FAT
300  * partitions can be added to the MBR without creating an overlap.
301  */
302 static int
303 gpt_is_bootcamp(struct g_part_gpt_table *table, const char *provname)
304 {
305         uint8_t *p;
306
307         p = table->mbr + DOSPARTOFF;
308         if (p[4] != 0xee || le32dec(p + 8) != 1)
309                 return (0);
310
311         p += DOSPARTSIZE;
312         if (p[4] != 0xaf)
313                 return (0);
314
315         printf("GEOM: %s: enabling Boot Camp\n", provname);
316         return (1);
317 }
318
319 static void
320 gpt_update_bootcamp(struct g_part_table *basetable, struct g_provider *pp)
321 {
322         struct g_part_entry *baseentry;
323         struct g_part_gpt_entry *entry;
324         struct g_part_gpt_table *table;
325         int bootable, error, index, slices, typ;
326
327         table = (struct g_part_gpt_table *)basetable;
328
329         bootable = -1;
330         for (index = 0; index < NDOSPART; index++) {
331                 if (table->mbr[DOSPARTOFF + DOSPARTSIZE * index])
332                         bootable = index;
333         }
334
335         bzero(table->mbr + DOSPARTOFF, DOSPARTSIZE * NDOSPART);
336         slices = 0;
337         LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
338                 if (baseentry->gpe_deleted)
339                         continue;
340                 index = baseentry->gpe_index - 1;
341                 if (index >= NDOSPART)
342                         continue;
343
344                 entry = (struct g_part_gpt_entry *)baseentry;
345
346                 switch (index) {
347                 case 0: /* This must be the EFI system partition. */
348                         if (!EQUUID(&entry->ent.ent_type, &gpt_uuid_efi))
349                                 goto disable;
350                         error = gpt_write_mbr_entry(table->mbr, index, 0xee,
351                             1ull, entry->ent.ent_lba_end);
352                         break;
353                 case 1: /* This must be the HFS+ partition. */
354                         if (!EQUUID(&entry->ent.ent_type, &gpt_uuid_apple_hfs))
355                                 goto disable;
356                         error = gpt_write_mbr_entry(table->mbr, index, 0xaf,
357                             entry->ent.ent_lba_start, entry->ent.ent_lba_end);
358                         break;
359                 default:
360                         typ = gpt_map_type(&entry->ent.ent_type);
361                         error = gpt_write_mbr_entry(table->mbr, index, typ,
362                             entry->ent.ent_lba_start, entry->ent.ent_lba_end);
363                         break;
364                 }
365                 if (error)
366                         continue;
367
368                 if (index == bootable)
369                         table->mbr[DOSPARTOFF + DOSPARTSIZE * index] = 0x80;
370                 slices |= 1 << index;
371         }
372         if ((slices & 3) == 3)
373                 return;
374
375  disable:
376         table->bootcamp = 0;
377         gpt_create_pmbr(table, pp);
378 }
379
380 static struct gpt_hdr *
381 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
382     enum gpt_elt elt)
383 {
384         struct gpt_hdr *buf, *hdr;
385         struct g_provider *pp;
386         quad_t lba, last;
387         int error;
388         uint32_t crc, sz;
389
390         pp = cp->provider;
391         last = (pp->mediasize / pp->sectorsize) - 1;
392         table->state[elt] = GPT_STATE_MISSING;
393         /*
394          * If the primary header is valid look for secondary
395          * header in AlternateLBA, otherwise in the last medium's LBA.
396          */
397         if (elt == GPT_ELT_SECHDR) {
398                 if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK)
399                         table->lba[elt] = last;
400         } else
401                 table->lba[elt] = 1;
402         buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
403             &error);
404         if (buf == NULL)
405                 return (NULL);
406         hdr = NULL;
407         if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0)
408                 goto fail;
409
410         table->state[elt] = GPT_STATE_CORRUPT;
411         sz = le32toh(buf->hdr_size);
412         if (sz < 92 || sz > pp->sectorsize)
413                 goto fail;
414
415         hdr = g_malloc(sz, M_WAITOK | M_ZERO);
416         bcopy(buf, hdr, sz);
417         hdr->hdr_size = sz;
418
419         crc = le32toh(buf->hdr_crc_self);
420         buf->hdr_crc_self = 0;
421         if (crc32(buf, sz) != crc)
422                 goto fail;
423         hdr->hdr_crc_self = crc;
424
425         table->state[elt] = GPT_STATE_INVALID;
426         hdr->hdr_revision = le32toh(buf->hdr_revision);
427         if (hdr->hdr_revision < GPT_HDR_REVISION)
428                 goto fail;
429         hdr->hdr_lba_self = le64toh(buf->hdr_lba_self);
430         if (hdr->hdr_lba_self != table->lba[elt])
431                 goto fail;
432         hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt);
433         if (hdr->hdr_lba_alt == hdr->hdr_lba_self ||
434             hdr->hdr_lba_alt > last)
435                 goto fail;
436
437         /* Check the managed area. */
438         hdr->hdr_lba_start = le64toh(buf->hdr_lba_start);
439         if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
440                 goto fail;
441         hdr->hdr_lba_end = le64toh(buf->hdr_lba_end);
442         if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
443                 goto fail;
444
445         /* Check the table location and size of the table. */
446         hdr->hdr_entries = le32toh(buf->hdr_entries);
447         hdr->hdr_entsz = le32toh(buf->hdr_entsz);
448         if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
449             (hdr->hdr_entsz & 7) != 0)
450                 goto fail;
451         hdr->hdr_lba_table = le64toh(buf->hdr_lba_table);
452         if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
453                 goto fail;
454         if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
455             hdr->hdr_lba_table <= hdr->hdr_lba_end)
456                 goto fail;
457         lba = hdr->hdr_lba_table +
458             (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
459             pp->sectorsize - 1;
460         if (lba >= last)
461                 goto fail;
462         if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
463                 goto fail;
464
465         table->state[elt] = GPT_STATE_OK;
466         le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid);
467         hdr->hdr_crc_table = le32toh(buf->hdr_crc_table);
468
469         /* save LBA for secondary header */
470         if (elt == GPT_ELT_PRIHDR)
471                 table->lba[GPT_ELT_SECHDR] = hdr->hdr_lba_alt;
472
473         g_free(buf);
474         return (hdr);
475
476  fail:
477         if (hdr != NULL)
478                 g_free(hdr);
479         g_free(buf);
480         return (NULL);
481 }
482
483 static struct gpt_ent *
484 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
485     enum gpt_elt elt, struct gpt_hdr *hdr)
486 {
487         struct g_provider *pp;
488         struct gpt_ent *ent, *tbl;
489         char *buf, *p;
490         unsigned int idx, sectors, tblsz, size;
491         int error;
492
493         if (hdr == NULL)
494                 return (NULL);
495
496         pp = cp->provider;
497         table->lba[elt] = hdr->hdr_lba_table;
498
499         table->state[elt] = GPT_STATE_MISSING;
500         tblsz = hdr->hdr_entries * hdr->hdr_entsz;
501         sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
502         buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO);
503         for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) {
504                 size = (sectors - idx > MAXPHYS / pp->sectorsize) ?  MAXPHYS:
505                     (sectors - idx) * pp->sectorsize;
506                 p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize,
507                     size, &error);
508                 if (p == NULL) {
509                         g_free(buf);
510                         return (NULL);
511                 }
512                 bcopy(p, buf + idx * pp->sectorsize, size);
513                 g_free(p);
514         }
515         table->state[elt] = GPT_STATE_CORRUPT;
516         if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
517                 g_free(buf);
518                 return (NULL);
519         }
520
521         table->state[elt] = GPT_STATE_OK;
522         tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
523             M_WAITOK | M_ZERO);
524
525         for (idx = 0, ent = tbl, p = buf;
526              idx < hdr->hdr_entries;
527              idx++, ent++, p += hdr->hdr_entsz) {
528                 le_uuid_dec(p, &ent->ent_type);
529                 le_uuid_dec(p + 16, &ent->ent_uuid);
530                 ent->ent_lba_start = le64dec(p + 32);
531                 ent->ent_lba_end = le64dec(p + 40);
532                 ent->ent_attr = le64dec(p + 48);
533                 /* Keep UTF-16 in little-endian. */
534                 bcopy(p + 56, ent->ent_name, sizeof(ent->ent_name));
535         }
536
537         g_free(buf);
538         return (tbl);
539 }
540
541 static int
542 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
543 {
544
545         if (pri == NULL || sec == NULL)
546                 return (0);
547
548         if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
549                 return (0);
550         return ((pri->hdr_revision == sec->hdr_revision &&
551             pri->hdr_size == sec->hdr_size &&
552             pri->hdr_lba_start == sec->hdr_lba_start &&
553             pri->hdr_lba_end == sec->hdr_lba_end &&
554             pri->hdr_entries == sec->hdr_entries &&
555             pri->hdr_entsz == sec->hdr_entsz &&
556             pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
557 }
558
559 static int
560 gpt_parse_type(const char *type, struct uuid *uuid)
561 {
562         struct uuid tmp;
563         const char *alias;
564         int error;
565         struct g_part_uuid_alias *uap;
566
567         if (type[0] == '!') {
568                 error = parse_uuid(type + 1, &tmp);
569                 if (error)
570                         return (error);
571                 if (EQUUID(&tmp, &gpt_uuid_unused))
572                         return (EINVAL);
573                 *uuid = tmp;
574                 return (0);
575         }
576         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) {
577                 alias = g_part_alias_name(uap->alias);
578                 if (!strcasecmp(type, alias)) {
579                         *uuid = *uap->uuid;
580                         return (0);
581                 }
582         }
583         return (EINVAL);
584 }
585
586 static int
587 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
588     struct g_part_parms *gpp)
589 {
590         struct g_part_gpt_entry *entry;
591         int error;
592
593         entry = (struct g_part_gpt_entry *)baseentry;
594         error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
595         if (error)
596                 return (error);
597         kern_uuidgen(&entry->ent.ent_uuid, 1);
598         entry->ent.ent_lba_start = baseentry->gpe_start;
599         entry->ent.ent_lba_end = baseentry->gpe_end;
600         if (baseentry->gpe_deleted) {
601                 entry->ent.ent_attr = 0;
602                 bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
603         }
604         if (gpp->gpp_parms & G_PART_PARM_LABEL)
605                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
606                     sizeof(entry->ent.ent_name) /
607                     sizeof(entry->ent.ent_name[0]));
608         return (0);
609 }
610
611 static int
612 g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
613 {
614         struct g_part_gpt_table *table;
615         size_t codesz;
616
617         codesz = DOSPARTOFF;
618         table = (struct g_part_gpt_table *)basetable;
619         bzero(table->mbr, codesz);
620         codesz = MIN(codesz, gpp->gpp_codesize);
621         if (codesz > 0)
622                 bcopy(gpp->gpp_codeptr, table->mbr, codesz);
623         return (0);
624 }
625
626 static int
627 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
628 {
629         struct g_provider *pp;
630         struct g_part_gpt_table *table;
631         size_t tblsz;
632
633         /* We don't nest, which means that our depth should be 0. */
634         if (basetable->gpt_depth != 0)
635                 return (ENXIO);
636
637         table = (struct g_part_gpt_table *)basetable;
638         pp = gpp->gpp_provider;
639         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
640             pp->sectorsize - 1) / pp->sectorsize;
641         if (pp->sectorsize < MBRSIZE ||
642             pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
643             pp->sectorsize)
644                 return (ENOSPC);
645
646         gpt_create_pmbr(table, pp);
647
648         /* Allocate space for the header */
649         table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO);
650
651         bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
652         table->hdr->hdr_revision = GPT_HDR_REVISION;
653         table->hdr->hdr_size = offsetof(struct gpt_hdr, padding);
654         kern_uuidgen(&table->hdr->hdr_uuid, 1);
655         table->hdr->hdr_entries = basetable->gpt_entries;
656         table->hdr->hdr_entsz = sizeof(struct gpt_ent);
657
658         g_gpt_set_defaults(basetable, pp);
659         return (0);
660 }
661
662 static int
663 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
664 {
665         struct g_part_gpt_table *table;
666         struct g_provider *pp;
667
668         table = (struct g_part_gpt_table *)basetable;
669         pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
670         g_free(table->hdr);
671         table->hdr = NULL;
672
673         /*
674          * Wipe the first 2 sectors to clear the partitioning. Wipe the last
675          * sector only if it has valid secondary header.
676          */
677         basetable->gpt_smhead |= 3;
678         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
679             table->lba[GPT_ELT_SECHDR] == pp->mediasize / pp->sectorsize - 1)
680                 basetable->gpt_smtail |= 1;
681         return (0);
682 }
683
684 static void
685 g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 
686     struct sbuf *sb, const char *indent)
687 {
688         struct g_part_gpt_entry *entry;
689  
690         entry = (struct g_part_gpt_entry *)baseentry;
691         if (indent == NULL) {
692                 /* conftxt: libdisk compatibility */
693                 sbuf_printf(sb, " xs GPT xt ");
694                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
695         } else if (entry != NULL) {
696                 /* confxml: partition entry information */
697                 sbuf_printf(sb, "%s<label>", indent);
698                 g_gpt_printf_utf16(sb, entry->ent.ent_name,
699                     sizeof(entry->ent.ent_name) >> 1);
700                 sbuf_printf(sb, "</label>\n");
701                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)
702                         sbuf_printf(sb, "%s<attrib>bootme</attrib>\n", indent);
703                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE) {
704                         sbuf_printf(sb, "%s<attrib>bootonce</attrib>\n",
705                             indent);
706                 }
707                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED) {
708                         sbuf_printf(sb, "%s<attrib>bootfailed</attrib>\n",
709                             indent);
710                 }
711                 sbuf_printf(sb, "%s<rawtype>", indent);
712                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
713                 sbuf_printf(sb, "</rawtype>\n");
714                 sbuf_printf(sb, "%s<rawuuid>", indent);
715                 sbuf_printf_uuid(sb, &entry->ent.ent_uuid);
716                 sbuf_printf(sb, "</rawuuid>\n");
717         } else {
718                 /* confxml: scheme information */
719         }
720 }
721
722 static int
723 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)  
724 {
725         struct g_part_gpt_entry *entry;
726
727         entry = (struct g_part_gpt_entry *)baseentry;
728         return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
729             EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap) ||
730             EQUUID(&entry->ent.ent_type, &gpt_uuid_dfbsd_swap)) ? 1 : 0);
731 }
732
733 static int
734 g_part_gpt_modify(struct g_part_table *basetable,
735     struct g_part_entry *baseentry, struct g_part_parms *gpp)
736 {
737         struct g_part_gpt_entry *entry;
738         int error;
739
740         entry = (struct g_part_gpt_entry *)baseentry;
741         if (gpp->gpp_parms & G_PART_PARM_TYPE) {
742                 error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
743                 if (error)
744                         return (error);
745         }
746         if (gpp->gpp_parms & G_PART_PARM_LABEL)
747                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
748                     sizeof(entry->ent.ent_name) /
749                     sizeof(entry->ent.ent_name[0]));
750         return (0);
751 }
752
753 static int
754 g_part_gpt_resize(struct g_part_table *basetable,
755     struct g_part_entry *baseentry, struct g_part_parms *gpp)
756 {
757         struct g_part_gpt_entry *entry;
758
759         if (baseentry == NULL)
760                 return (EOPNOTSUPP);
761
762         entry = (struct g_part_gpt_entry *)baseentry;
763         baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
764         entry->ent.ent_lba_end = baseentry->gpe_end;
765
766         return (0);
767 }
768
769 static const char *
770 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
771     char *buf, size_t bufsz)
772 {
773         struct g_part_gpt_entry *entry;
774         char c;
775
776         entry = (struct g_part_gpt_entry *)baseentry;
777         c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
778         snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
779         return (buf);
780 }
781
782 static int
783 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
784 {
785         struct g_provider *pp;
786         u_char *buf;
787         int error, index, pri, res;
788
789         /* We don't nest, which means that our depth should be 0. */
790         if (table->gpt_depth != 0)
791                 return (ENXIO);
792
793         pp = cp->provider;
794
795         /*
796          * Sanity-check the provider. Since the first sector on the provider
797          * must be a PMBR and a PMBR is 512 bytes large, the sector size
798          * must be at least 512 bytes.  Also, since the theoretical minimum
799          * number of sectors needed by GPT is 6, any medium that has less
800          * than 6 sectors is never going to be able to hold a GPT. The
801          * number 6 comes from:
802          *      1 sector for the PMBR
803          *      2 sectors for the GPT headers (each 1 sector)
804          *      2 sectors for the GPT tables (each 1 sector)
805          *      1 sector for an actual partition
806          * It's better to catch this pathological case early than behaving
807          * pathologically later on...
808          */
809         if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize)
810                 return (ENOSPC);
811
812         /*
813          * Check that there's a MBR or a PMBR. If it's a PMBR, we return
814          * as the highest priority on a match, otherwise we assume some
815          * GPT-unaware tool has destroyed the GPT by recreating a MBR and
816          * we really want the MBR scheme to take precedence.
817          */
818         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
819         if (buf == NULL)
820                 return (error);
821         res = le16dec(buf + DOSMAGICOFFSET);
822         pri = G_PART_PROBE_PRI_LOW;
823         for (index = 0; index < NDOSPART; index++) {
824                 if (buf[DOSPARTOFF + DOSPARTSIZE * index + 4] == 0xee)
825                         pri = G_PART_PROBE_PRI_HIGH;
826         }
827         g_free(buf);
828         if (res != DOSMAGIC) 
829                 return (ENXIO);
830
831         /* Check that there's a primary header. */
832         buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
833         if (buf == NULL)
834                 return (error);
835         res = memcmp(buf, GPT_HDR_SIG, 8);
836         g_free(buf);
837         if (res == 0)
838                 return (pri);
839
840         /* No primary? Check that there's a secondary. */
841         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
842             &error);
843         if (buf == NULL)
844                 return (error);
845         res = memcmp(buf, GPT_HDR_SIG, 8); 
846         g_free(buf);
847         return ((res == 0) ? pri : ENXIO);
848 }
849
850 static int
851 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
852 {
853         struct gpt_hdr *prihdr, *sechdr;
854         struct gpt_ent *tbl, *pritbl, *sectbl;
855         struct g_provider *pp;
856         struct g_part_gpt_table *table;
857         struct g_part_gpt_entry *entry;
858         u_char *buf;
859         uint64_t last;
860         int error, index;
861
862         table = (struct g_part_gpt_table *)basetable;
863         pp = cp->provider;
864         last = (pp->mediasize / pp->sectorsize) - 1;
865
866         /* Read the PMBR */
867         buf = g_read_data(cp, 0, pp->sectorsize, &error);
868         if (buf == NULL)
869                 return (error);
870         bcopy(buf, table->mbr, MBRSIZE);
871         g_free(buf);
872
873         /* Read the primary header and table. */
874         prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR);
875         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
876                 pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr);
877         } else {
878                 table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
879                 pritbl = NULL;
880         }
881
882         /* Read the secondary header and table. */
883         sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR);
884         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
885                 sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr);
886         } else {
887                 table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
888                 sectbl = NULL;
889         }
890
891         /* Fail if we haven't got any good tables at all. */
892         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
893             table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
894                 printf("GEOM: %s: corrupt or invalid GPT detected.\n",
895                     pp->name);
896                 printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
897                     pp->name);
898                 return (EINVAL);
899         }
900
901         /*
902          * If both headers are good but they disagree with each other,
903          * then invalidate one. We prefer to keep the primary header,
904          * unless the primary table is corrupt.
905          */
906         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
907             table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
908             !gpt_matched_hdrs(prihdr, sechdr)) {
909                 if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) {
910                         table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
911                         table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
912                         g_free(sechdr);
913                         sechdr = NULL;
914                 } else {
915                         table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
916                         table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
917                         g_free(prihdr);
918                         prihdr = NULL;
919                 }
920         }
921
922         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK) {
923                 printf("GEOM: %s: the primary GPT table is corrupt or "
924                     "invalid.\n", pp->name);
925                 printf("GEOM: %s: using the secondary instead -- recovery "
926                     "strongly advised.\n", pp->name);
927                 table->hdr = sechdr;
928                 basetable->gpt_corrupt = 1;
929                 if (prihdr != NULL)
930                         g_free(prihdr);
931                 tbl = sectbl;
932                 if (pritbl != NULL)
933                         g_free(pritbl);
934         } else {
935                 if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
936                         printf("GEOM: %s: the secondary GPT table is corrupt "
937                             "or invalid.\n", pp->name);
938                         printf("GEOM: %s: using the primary only -- recovery "
939                             "suggested.\n", pp->name);
940                         basetable->gpt_corrupt = 1;
941                 } else if (table->lba[GPT_ELT_SECHDR] != last) {
942                         printf( "GEOM: %s: the secondary GPT header is not in "
943                             "the last LBA.\n", pp->name);
944                         basetable->gpt_corrupt = 1;
945                 }
946                 table->hdr = prihdr;
947                 if (sechdr != NULL)
948                         g_free(sechdr);
949                 tbl = pritbl;
950                 if (sectbl != NULL)
951                         g_free(sectbl);
952         }
953
954         basetable->gpt_first = table->hdr->hdr_lba_start;
955         basetable->gpt_last = table->hdr->hdr_lba_end;
956         basetable->gpt_entries = (table->hdr->hdr_lba_start - 2) *
957             pp->sectorsize / table->hdr->hdr_entsz;
958
959         for (index = table->hdr->hdr_entries - 1; index >= 0; index--) {
960                 if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
961                         continue;
962                 entry = (struct g_part_gpt_entry *)g_part_new_entry(
963                     basetable, index + 1, tbl[index].ent_lba_start,
964                     tbl[index].ent_lba_end);
965                 entry->ent = tbl[index];
966         }
967
968         g_free(tbl);
969
970         /*
971          * Under Mac OS X, the MBR mirrors the first 4 GPT partitions
972          * if (and only if) any FAT32 or FAT16 partitions have been
973          * created. This happens irrespective of whether Boot Camp is
974          * used/enabled, though it's generally understood to be done
975          * to support legacy Windows under Boot Camp. We refer to this
976          * mirroring simply as Boot Camp. We try to detect Boot Camp
977          * so that we can update the MBR if and when GPT changes have
978          * been made. Note that we do not enable Boot Camp if not
979          * previously enabled because we can't assume that we're on a
980          * Mac alongside Mac OS X.
981          */
982         table->bootcamp = gpt_is_bootcamp(table, pp->name);
983
984         return (0);
985 }
986
987 static int
988 g_part_gpt_recover(struct g_part_table *basetable)
989 {
990         struct g_part_gpt_table *table;
991         struct g_provider *pp;
992
993         table = (struct g_part_gpt_table *)basetable;
994         pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
995         gpt_create_pmbr(table, pp);
996         g_gpt_set_defaults(basetable, pp);
997         basetable->gpt_corrupt = 0;
998         return (0);
999 }
1000
1001 static int
1002 g_part_gpt_setunset(struct g_part_table *basetable,
1003     struct g_part_entry *baseentry, const char *attrib, unsigned int set)
1004 {
1005         struct g_part_gpt_entry *entry;
1006         struct g_part_gpt_table *table;
1007         uint8_t *p;
1008         uint64_t attr;
1009         int i;
1010
1011         table = (struct g_part_gpt_table *)basetable;
1012         entry = (struct g_part_gpt_entry *)baseentry;
1013
1014         if (strcasecmp(attrib, "active") == 0) {
1015                 if (table->bootcamp) {
1016                         /* The active flag must be set on a valid entry. */
1017                         if (entry == NULL)
1018                                 return (ENXIO);
1019                         if (baseentry->gpe_index > NDOSPART)
1020                                 return (EINVAL);
1021                         for (i = 0; i < NDOSPART; i++) {
1022                                 p = &table->mbr[DOSPARTOFF + i * DOSPARTSIZE];
1023                                 p[0] = (i == baseentry->gpe_index - 1)
1024                                     ? ((set) ? 0x80 : 0) : 0;
1025                         }
1026                 } else {
1027                         /* The PMBR is marked as active without an entry. */
1028                         if (entry != NULL)
1029                                 return (ENXIO);
1030                         for (i = 0; i < NDOSPART; i++) {
1031                                 p = &table->mbr[DOSPARTOFF + i * DOSPARTSIZE];
1032                                 p[0] = (p[4] == 0xee) ? ((set) ? 0x80 : 0) : 0;
1033                         }
1034                 }
1035                 return (0);
1036         }
1037
1038         if (entry == NULL)
1039                 return (ENODEV);
1040
1041         attr = 0;
1042         if (strcasecmp(attrib, "bootme") == 0) {
1043                 attr |= GPT_ENT_ATTR_BOOTME;
1044         } else if (strcasecmp(attrib, "bootonce") == 0) {
1045                 attr |= GPT_ENT_ATTR_BOOTONCE;
1046                 if (set)
1047                         attr |= GPT_ENT_ATTR_BOOTME;
1048         } else if (strcasecmp(attrib, "bootfailed") == 0) {
1049                 /*
1050                  * It should only be possible to unset BOOTFAILED, but it might
1051                  * be useful for test purposes to also be able to set it.
1052                  */
1053                 attr |= GPT_ENT_ATTR_BOOTFAILED;
1054         }
1055         if (attr == 0)
1056                 return (EINVAL);
1057
1058         if (set)
1059                 attr = entry->ent.ent_attr | attr;
1060         else
1061                 attr = entry->ent.ent_attr & ~attr;
1062         if (attr != entry->ent.ent_attr) {
1063                 entry->ent.ent_attr = attr;
1064                 if (!baseentry->gpe_created)
1065                         baseentry->gpe_modified = 1;
1066         }
1067         return (0);
1068 }
1069
1070 static const char *
1071 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 
1072     char *buf, size_t bufsz)
1073 {
1074         struct g_part_gpt_entry *entry;
1075         struct uuid *type;
1076         struct g_part_uuid_alias *uap;
1077  
1078         entry = (struct g_part_gpt_entry *)baseentry;
1079         type = &entry->ent.ent_type;
1080         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++)
1081                 if (EQUUID(type, uap->uuid))
1082                         return (g_part_alias_name(uap->alias));
1083         buf[0] = '!';
1084         snprintf_uuid(buf + 1, bufsz - 1, type);
1085
1086         return (buf);
1087 }
1088
1089 static int
1090 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
1091 {
1092         unsigned char *buf, *bp;
1093         struct g_provider *pp;
1094         struct g_part_entry *baseentry;
1095         struct g_part_gpt_entry *entry;
1096         struct g_part_gpt_table *table;
1097         size_t tblsz;
1098         uint32_t crc;
1099         int error, index;
1100
1101         pp = cp->provider;
1102         table = (struct g_part_gpt_table *)basetable;
1103         tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz +
1104             pp->sectorsize - 1) / pp->sectorsize;
1105
1106         /* Reconstruct the MBR from the GPT if under Boot Camp. */
1107         if (table->bootcamp)
1108                 gpt_update_bootcamp(basetable, pp);
1109
1110         /* Write the PMBR */
1111         buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1112         bcopy(table->mbr, buf, MBRSIZE);
1113         error = g_write_data(cp, 0, buf, pp->sectorsize);
1114         g_free(buf);
1115         if (error)
1116                 return (error);
1117
1118         /* Allocate space for the header and entries. */
1119         buf = g_malloc((tblsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
1120
1121         memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
1122         le32enc(buf + 8, table->hdr->hdr_revision);
1123         le32enc(buf + 12, table->hdr->hdr_size);
1124         le64enc(buf + 40, table->hdr->hdr_lba_start);
1125         le64enc(buf + 48, table->hdr->hdr_lba_end);
1126         le_uuid_enc(buf + 56, &table->hdr->hdr_uuid);
1127         le32enc(buf + 80, table->hdr->hdr_entries);
1128         le32enc(buf + 84, table->hdr->hdr_entsz);
1129
1130         LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
1131                 if (baseentry->gpe_deleted)
1132                         continue;
1133                 entry = (struct g_part_gpt_entry *)baseentry;
1134                 index = baseentry->gpe_index - 1;
1135                 bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index;
1136                 le_uuid_enc(bp, &entry->ent.ent_type);
1137                 le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
1138                 le64enc(bp + 32, entry->ent.ent_lba_start);
1139                 le64enc(bp + 40, entry->ent.ent_lba_end);
1140                 le64enc(bp + 48, entry->ent.ent_attr);
1141                 memcpy(bp + 56, entry->ent.ent_name,
1142                     sizeof(entry->ent.ent_name));
1143         }
1144
1145         crc = crc32(buf + pp->sectorsize,
1146             table->hdr->hdr_entries * table->hdr->hdr_entsz);
1147         le32enc(buf + 88, crc);
1148
1149         /* Write primary meta-data. */
1150         le32enc(buf + 16, 0);   /* hdr_crc_self. */
1151         le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_self. */
1152         le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_alt. */
1153         le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);  /* hdr_lba_table. */
1154         crc = crc32(buf, table->hdr->hdr_size);
1155         le32enc(buf + 16, crc);
1156
1157         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
1158                 error = g_write_data(cp,
1159                     (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize,
1160                     buf + (index + 1) * pp->sectorsize,
1161                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
1162                     (tblsz - index) * pp->sectorsize);
1163                 if (error)
1164                         goto out;
1165         }
1166         error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
1167             buf, pp->sectorsize);
1168         if (error)
1169                 goto out;
1170
1171         /* Write secondary meta-data. */
1172         le32enc(buf + 16, 0);   /* hdr_crc_self. */
1173         le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_self. */
1174         le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_alt. */
1175         le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);  /* hdr_lba_table. */
1176         crc = crc32(buf, table->hdr->hdr_size);
1177         le32enc(buf + 16, crc);
1178
1179         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
1180                 error = g_write_data(cp,
1181                     (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize,
1182                     buf + (index + 1) * pp->sectorsize,
1183                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
1184                     (tblsz - index) * pp->sectorsize);
1185                 if (error)
1186                         goto out;
1187         }
1188         error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
1189             buf, pp->sectorsize);
1190
1191  out:
1192         g_free(buf);
1193         return (error);
1194 }
1195
1196 static void
1197 g_gpt_set_defaults(struct g_part_table *basetable, struct g_provider *pp)
1198 {
1199         struct g_part_gpt_table *table;
1200         quad_t last;
1201         size_t tblsz;
1202
1203         table = (struct g_part_gpt_table *)basetable;
1204         last = pp->mediasize / pp->sectorsize - 1;
1205         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
1206             pp->sectorsize - 1) / pp->sectorsize;
1207
1208         table->lba[GPT_ELT_PRIHDR] = 1;
1209         table->lba[GPT_ELT_PRITBL] = 2;
1210         table->lba[GPT_ELT_SECHDR] = last;
1211         table->lba[GPT_ELT_SECTBL] = last - tblsz;
1212         table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK;
1213         table->state[GPT_ELT_PRITBL] = GPT_STATE_OK;
1214         table->state[GPT_ELT_SECHDR] = GPT_STATE_OK;
1215         table->state[GPT_ELT_SECTBL] = GPT_STATE_OK;
1216
1217         table->hdr->hdr_lba_start = 2 + tblsz;
1218         table->hdr->hdr_lba_end = last - tblsz - 1;
1219
1220         basetable->gpt_first = table->hdr->hdr_lba_start;
1221         basetable->gpt_last = table->hdr->hdr_lba_end;
1222 }
1223
1224 static void
1225 g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len)
1226 {
1227         u_int bo;
1228         uint32_t ch;
1229         uint16_t c;
1230
1231         bo = LITTLE_ENDIAN;     /* GPT is little-endian */
1232         while (len > 0 && *str != 0) {
1233                 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
1234                 str++, len--;
1235                 if ((ch & 0xf800) == 0xd800) {
1236                         if (len > 0) {
1237                                 c = (bo == BIG_ENDIAN) ? be16toh(*str)
1238                                     : le16toh(*str);
1239                                 str++, len--;
1240                         } else
1241                                 c = 0xfffd;
1242                         if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
1243                                 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
1244                                 ch += 0x10000;
1245                         } else
1246                                 ch = 0xfffd;
1247                 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
1248                         bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
1249                         continue;
1250                 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
1251                         continue;
1252
1253                 /* Write the Unicode character in UTF-8 */
1254                 if (ch < 0x80)
1255                         g_conf_printf_escaped(sb, "%c", ch);
1256                 else if (ch < 0x800)
1257                         g_conf_printf_escaped(sb, "%c%c", 0xc0 | (ch >> 6),
1258                             0x80 | (ch & 0x3f));
1259                 else if (ch < 0x10000)
1260                         g_conf_printf_escaped(sb, "%c%c%c", 0xe0 | (ch >> 12),
1261                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
1262                 else if (ch < 0x200000)
1263                         g_conf_printf_escaped(sb, "%c%c%c%c", 0xf0 |
1264                             (ch >> 18), 0x80 | ((ch >> 12) & 0x3f),
1265                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
1266         }
1267 }
1268
1269 static void
1270 g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
1271 {
1272         size_t s16idx, s8idx;
1273         uint32_t utfchar;
1274         unsigned int c, utfbytes;
1275
1276         s8idx = s16idx = 0;
1277         utfchar = 0;
1278         utfbytes = 0;
1279         bzero(s16, s16len << 1);
1280         while (s8[s8idx] != 0 && s16idx < s16len) {
1281                 c = s8[s8idx++];
1282                 if ((c & 0xc0) != 0x80) {
1283                         /* Initial characters. */
1284                         if (utfbytes != 0) {
1285                                 /* Incomplete encoding of previous char. */
1286                                 s16[s16idx++] = htole16(0xfffd);
1287                         }
1288                         if ((c & 0xf8) == 0xf0) {
1289                                 utfchar = c & 0x07;
1290                                 utfbytes = 3;
1291                         } else if ((c & 0xf0) == 0xe0) {
1292                                 utfchar = c & 0x0f;
1293                                 utfbytes = 2;
1294                         } else if ((c & 0xe0) == 0xc0) {
1295                                 utfchar = c & 0x1f;
1296                                 utfbytes = 1;
1297                         } else {
1298                                 utfchar = c & 0x7f;
1299                                 utfbytes = 0;
1300                         }
1301                 } else {
1302                         /* Followup characters. */
1303                         if (utfbytes > 0) {
1304                                 utfchar = (utfchar << 6) + (c & 0x3f);
1305                                 utfbytes--;
1306                         } else if (utfbytes == 0)
1307                                 utfbytes = ~0;
1308                 }
1309                 /*
1310                  * Write the complete Unicode character as UTF-16 when we
1311                  * have all the UTF-8 charactars collected.
1312                  */
1313                 if (utfbytes == 0) {
1314                         /*
1315                          * If we need to write 2 UTF-16 characters, but
1316                          * we only have room for 1, then we truncate the
1317                          * string by writing a 0 instead.
1318                          */
1319                         if (utfchar >= 0x10000 && s16idx < s16len - 1) {
1320                                 s16[s16idx++] =
1321                                     htole16(0xd800 | ((utfchar >> 10) - 0x40));
1322                                 s16[s16idx++] =
1323                                     htole16(0xdc00 | (utfchar & 0x3ff));
1324                         } else
1325                                 s16[s16idx++] = (utfchar >= 0x10000) ? 0 :
1326                                     htole16(utfchar);
1327                 }
1328         }
1329         /*
1330          * If our input string was truncated, append an invalid encoding
1331          * character to the output string.
1332          */
1333         if (utfbytes != 0 && s16idx < s16len)
1334                 s16[s16idx++] = htole16(0xfffd);
1335 }