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