]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/geom/part/g_part_gpt.c
MFC r362623:
[FreeBSD/stable/8.git] / sys / geom / part / g_part_gpt.c
1 /*-
2  * Copyright (c) 2002, 2005, 2006, 2007 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/bio.h>
32 #include <sys/diskmbr.h>
33 #include <sys/endian.h>
34 #include <sys/gpt.h>
35 #include <sys/kernel.h>
36 #include <sys/kobj.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/queue.h>
42 #include <sys/sbuf.h>
43 #include <sys/systm.h>
44 #include <sys/uuid.h>
45 #include <geom/geom.h>
46 #include <geom/part/g_part.h>
47
48 #include "g_part_if.h"
49
50 CTASSERT(offsetof(struct gpt_hdr, padding) == 92);
51 CTASSERT(sizeof(struct gpt_ent) == 128);
52
53 #define EQUUID(a,b)     (memcmp(a, b, sizeof(struct uuid)) == 0)
54
55 #define MBRSIZE         512
56
57 enum gpt_elt {
58         GPT_ELT_PRIHDR,
59         GPT_ELT_PRITBL,
60         GPT_ELT_SECHDR,
61         GPT_ELT_SECTBL,
62         GPT_ELT_COUNT
63 };
64
65 enum gpt_state {
66         GPT_STATE_UNKNOWN,      /* Not determined. */
67         GPT_STATE_MISSING,      /* No signature found. */
68         GPT_STATE_CORRUPT,      /* Checksum mismatch. */
69         GPT_STATE_INVALID,      /* Nonconformant/invalid. */
70         GPT_STATE_OK            /* Perfectly fine. */
71 };
72
73 struct g_part_gpt_table {
74         struct g_part_table     base;
75         u_char                  mbr[MBRSIZE];
76         struct gpt_hdr          *hdr;
77         quad_t                  lba[GPT_ELT_COUNT];
78         enum gpt_state          state[GPT_ELT_COUNT];
79 };
80
81 struct g_part_gpt_entry {
82         struct g_part_entry     base;
83         struct gpt_ent          ent;
84 };
85
86 static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t);
87 static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t);
88 static void g_gpt_set_defaults(struct g_part_table *, struct g_provider *);
89
90 static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *,
91     struct g_part_parms *);
92 static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *);
93 static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *);
94 static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *);
95 static void g_part_gpt_dumpconf(struct g_part_table *, struct g_part_entry *,
96     struct sbuf *, const char *);
97 static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *);
98 static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *,
99     struct g_part_parms *);
100 static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *,
101     char *, size_t);
102 static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *);
103 static int g_part_gpt_read(struct g_part_table *, struct g_consumer *);
104 static int g_part_gpt_setunset(struct g_part_table *table,
105     struct g_part_entry *baseentry, const char *attrib, unsigned int set);
106 static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *,
107     char *, size_t);
108 static int g_part_gpt_write(struct g_part_table *, struct g_consumer *);
109 static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *,
110     struct g_part_parms *);
111 static int g_part_gpt_recover(struct g_part_table *);
112
113 static kobj_method_t g_part_gpt_methods[] = {
114         KOBJMETHOD(g_part_add,          g_part_gpt_add),
115         KOBJMETHOD(g_part_bootcode,     g_part_gpt_bootcode),
116         KOBJMETHOD(g_part_create,       g_part_gpt_create),
117         KOBJMETHOD(g_part_destroy,      g_part_gpt_destroy),
118         KOBJMETHOD(g_part_dumpconf,     g_part_gpt_dumpconf),
119         KOBJMETHOD(g_part_dumpto,       g_part_gpt_dumpto),
120         KOBJMETHOD(g_part_modify,       g_part_gpt_modify),
121         KOBJMETHOD(g_part_resize,       g_part_gpt_resize),
122         KOBJMETHOD(g_part_name,         g_part_gpt_name),
123         KOBJMETHOD(g_part_probe,        g_part_gpt_probe),
124         KOBJMETHOD(g_part_read,         g_part_gpt_read),
125         KOBJMETHOD(g_part_recover,      g_part_gpt_recover),
126         KOBJMETHOD(g_part_setunset,     g_part_gpt_setunset),
127         KOBJMETHOD(g_part_type,         g_part_gpt_type),
128         KOBJMETHOD(g_part_write,        g_part_gpt_write),
129         { 0, 0 }
130 };
131
132 static struct g_part_scheme g_part_gpt_scheme = {
133         "GPT",
134         g_part_gpt_methods,
135         sizeof(struct g_part_gpt_table),
136         .gps_entrysz = sizeof(struct g_part_gpt_entry),
137         .gps_minent = 128,
138         .gps_maxent = 4096,
139         .gps_bootcodesz = MBRSIZE,
140 };
141 G_PART_SCHEME_DECLARE(g_part_gpt);
142
143 static struct uuid gpt_uuid_apple_boot = GPT_ENT_TYPE_APPLE_BOOT;
144 static struct uuid gpt_uuid_apple_hfs = GPT_ENT_TYPE_APPLE_HFS;
145 static struct uuid gpt_uuid_apple_label = GPT_ENT_TYPE_APPLE_LABEL;
146 static struct uuid gpt_uuid_apple_raid = GPT_ENT_TYPE_APPLE_RAID;
147 static struct uuid gpt_uuid_apple_raid_offline = GPT_ENT_TYPE_APPLE_RAID_OFFLINE;
148 static struct uuid gpt_uuid_apple_tv_recovery = GPT_ENT_TYPE_APPLE_TV_RECOVERY;
149 static struct uuid gpt_uuid_apple_ufs = GPT_ENT_TYPE_APPLE_UFS;
150 static struct uuid gpt_uuid_bios_boot = GPT_ENT_TYPE_BIOS_BOOT;
151 static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI;
152 static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
153 static struct uuid gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
154 static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
155 static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
156 static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
157 static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
158 static struct uuid gpt_uuid_linux_data = GPT_ENT_TYPE_LINUX_DATA;
159 static struct uuid gpt_uuid_linux_lvm = GPT_ENT_TYPE_LINUX_LVM;
160 static struct uuid gpt_uuid_linux_raid = GPT_ENT_TYPE_LINUX_RAID;
161 static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP;
162 static struct uuid gpt_uuid_vmfs = GPT_ENT_TYPE_VMFS;
163 static struct uuid gpt_uuid_vmkdiag = GPT_ENT_TYPE_VMKDIAG;
164 static struct uuid gpt_uuid_vmreserved = GPT_ENT_TYPE_VMRESERVED;
165 static struct uuid gpt_uuid_vmvsanhdr = GPT_ENT_TYPE_VMVSANHDR;
166 static struct uuid gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
167 static struct uuid gpt_uuid_ms_reserved = GPT_ENT_TYPE_MS_RESERVED;
168 static struct uuid gpt_uuid_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA;
169 static struct uuid gpt_uuid_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA;
170 static struct uuid gpt_uuid_netbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD;
171 static struct uuid gpt_uuid_netbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD;
172 static struct uuid gpt_uuid_netbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS;
173 static struct uuid gpt_uuid_netbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS;
174 static struct uuid gpt_uuid_netbsd_raid = GPT_ENT_TYPE_NETBSD_RAID;
175 static struct uuid gpt_uuid_netbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP;
176 static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
177 static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
178
179 static struct g_part_uuid_alias {
180         struct uuid *uuid;
181         int alias;
182 } gpt_uuid_alias_match[] = {
183         { &gpt_uuid_apple_boot,         G_PART_ALIAS_APPLE_BOOT },
184         { &gpt_uuid_apple_hfs,          G_PART_ALIAS_APPLE_HFS },
185         { &gpt_uuid_apple_label,        G_PART_ALIAS_APPLE_LABEL },
186         { &gpt_uuid_apple_raid,         G_PART_ALIAS_APPLE_RAID },
187         { &gpt_uuid_apple_raid_offline, G_PART_ALIAS_APPLE_RAID_OFFLINE },
188         { &gpt_uuid_apple_tv_recovery,  G_PART_ALIAS_APPLE_TV_RECOVERY },
189         { &gpt_uuid_apple_ufs,          G_PART_ALIAS_APPLE_UFS },
190         { &gpt_uuid_bios_boot,          G_PART_ALIAS_BIOS_BOOT },
191         { &gpt_uuid_efi,                G_PART_ALIAS_EFI },
192         { &gpt_uuid_freebsd,            G_PART_ALIAS_FREEBSD },
193         { &gpt_uuid_freebsd_boot,       G_PART_ALIAS_FREEBSD_BOOT },
194         { &gpt_uuid_freebsd_swap,       G_PART_ALIAS_FREEBSD_SWAP },
195         { &gpt_uuid_freebsd_ufs,        G_PART_ALIAS_FREEBSD_UFS },
196         { &gpt_uuid_freebsd_vinum,      G_PART_ALIAS_FREEBSD_VINUM },
197         { &gpt_uuid_freebsd_zfs,        G_PART_ALIAS_FREEBSD_ZFS },
198         { &gpt_uuid_linux_data,         G_PART_ALIAS_LINUX_DATA },
199         { &gpt_uuid_linux_lvm,          G_PART_ALIAS_LINUX_LVM },
200         { &gpt_uuid_linux_raid,         G_PART_ALIAS_LINUX_RAID },
201         { &gpt_uuid_linux_swap,         G_PART_ALIAS_LINUX_SWAP },
202         { &gpt_uuid_vmfs,               G_PART_ALIAS_VMFS },
203         { &gpt_uuid_vmkdiag,            G_PART_ALIAS_VMKDIAG },
204         { &gpt_uuid_vmreserved,         G_PART_ALIAS_VMRESERVED },
205         { &gpt_uuid_vmvsanhdr,          G_PART_ALIAS_VMVSANHDR },
206         { &gpt_uuid_mbr,                G_PART_ALIAS_MBR },
207         { &gpt_uuid_ms_basic_data,      G_PART_ALIAS_MS_BASIC_DATA },
208         { &gpt_uuid_ms_ldm_data,        G_PART_ALIAS_MS_LDM_DATA },
209         { &gpt_uuid_ms_ldm_metadata,    G_PART_ALIAS_MS_LDM_METADATA },
210         { &gpt_uuid_ms_reserved,        G_PART_ALIAS_MS_RESERVED },
211         { &gpt_uuid_netbsd_ccd,         G_PART_ALIAS_NETBSD_CCD },
212         { &gpt_uuid_netbsd_cgd,         G_PART_ALIAS_NETBSD_CGD },
213         { &gpt_uuid_netbsd_ffs,         G_PART_ALIAS_NETBSD_FFS },
214         { &gpt_uuid_netbsd_lfs,         G_PART_ALIAS_NETBSD_LFS },
215         { &gpt_uuid_netbsd_raid,        G_PART_ALIAS_NETBSD_RAID },
216         { &gpt_uuid_netbsd_swap,        G_PART_ALIAS_NETBSD_SWAP },
217
218         { NULL, 0 }
219 };
220
221 static struct gpt_hdr *
222 gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
223     enum gpt_elt elt)
224 {
225         struct gpt_hdr *buf, *hdr;
226         struct g_provider *pp;
227         quad_t lba, last;
228         int error;
229         uint32_t crc, sz;
230
231         pp = cp->provider;
232         last = (pp->mediasize / pp->sectorsize) - 1;
233         table->state[elt] = GPT_STATE_MISSING;
234         /*
235          * If the primary header is valid look for secondary
236          * header in AlternateLBA, otherwise in the last medium's LBA.
237          */
238         if (elt == GPT_ELT_SECHDR) {
239                 if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK)
240                         table->lba[elt] = last;
241         } else
242                 table->lba[elt] = 1;
243         buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
244             &error);
245         if (buf == NULL)
246                 return (NULL);
247         hdr = NULL;
248         if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0)
249                 goto fail;
250
251         table->state[elt] = GPT_STATE_CORRUPT;
252         sz = le32toh(buf->hdr_size);
253         if (sz < 92 || sz > pp->sectorsize)
254                 goto fail;
255
256         hdr = g_malloc(sz, M_WAITOK | M_ZERO);
257         bcopy(buf, hdr, sz);
258         hdr->hdr_size = sz;
259
260         crc = le32toh(buf->hdr_crc_self);
261         buf->hdr_crc_self = 0;
262         if (crc32(buf, sz) != crc)
263                 goto fail;
264         hdr->hdr_crc_self = crc;
265
266         table->state[elt] = GPT_STATE_INVALID;
267         hdr->hdr_revision = le32toh(buf->hdr_revision);
268         if (hdr->hdr_revision < GPT_HDR_REVISION)
269                 goto fail;
270         hdr->hdr_lba_self = le64toh(buf->hdr_lba_self);
271         if (hdr->hdr_lba_self != table->lba[elt])
272                 goto fail;
273         hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt);
274         if (hdr->hdr_lba_alt == hdr->hdr_lba_self ||
275             hdr->hdr_lba_alt > last)
276                 goto fail;
277
278         /* Check the managed area. */
279         hdr->hdr_lba_start = le64toh(buf->hdr_lba_start);
280         if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
281                 goto fail;
282         hdr->hdr_lba_end = le64toh(buf->hdr_lba_end);
283         if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
284                 goto fail;
285
286         /* Check the table location and size of the table. */
287         hdr->hdr_entries = le32toh(buf->hdr_entries);
288         hdr->hdr_entsz = le32toh(buf->hdr_entsz);
289         if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
290             (hdr->hdr_entsz & 7) != 0)
291                 goto fail;
292         hdr->hdr_lba_table = le64toh(buf->hdr_lba_table);
293         if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
294                 goto fail;
295         if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
296             hdr->hdr_lba_table <= hdr->hdr_lba_end)
297                 goto fail;
298         lba = hdr->hdr_lba_table +
299             (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
300             pp->sectorsize - 1;
301         if (lba >= last)
302                 goto fail;
303         if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
304                 goto fail;
305
306         table->state[elt] = GPT_STATE_OK;
307         le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid);
308         hdr->hdr_crc_table = le32toh(buf->hdr_crc_table);
309
310         /* save LBA for secondary header */
311         if (elt == GPT_ELT_PRIHDR)
312                 table->lba[GPT_ELT_SECHDR] = hdr->hdr_lba_alt;
313
314         g_free(buf);
315         return (hdr);
316
317  fail:
318         if (hdr != NULL)
319                 g_free(hdr);
320         g_free(buf);
321         return (NULL);
322 }
323
324 static struct gpt_ent *
325 gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp,
326     enum gpt_elt elt, struct gpt_hdr *hdr)
327 {
328         struct g_provider *pp;
329         struct gpt_ent *ent, *tbl;
330         char *buf, *p;
331         unsigned int idx, sectors, tblsz, size;
332         int error;
333
334         if (hdr == NULL)
335                 return (NULL);
336
337         pp = cp->provider;
338         table->lba[elt] = hdr->hdr_lba_table;
339
340         table->state[elt] = GPT_STATE_MISSING;
341         tblsz = hdr->hdr_entries * hdr->hdr_entsz;
342         sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
343         buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO);
344         for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) {
345                 size = (sectors - idx > MAXPHYS / pp->sectorsize) ?  MAXPHYS:
346                     (sectors - idx) * pp->sectorsize;
347                 p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize,
348                     size, &error);
349                 if (p == NULL) {
350                         g_free(buf);
351                         return (NULL);
352                 }
353                 bcopy(p, buf + idx * pp->sectorsize, size);
354                 g_free(p);
355         }
356         table->state[elt] = GPT_STATE_CORRUPT;
357         if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
358                 g_free(buf);
359                 return (NULL);
360         }
361
362         table->state[elt] = GPT_STATE_OK;
363         tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent),
364             M_WAITOK | M_ZERO);
365
366         for (idx = 0, ent = tbl, p = buf;
367              idx < hdr->hdr_entries;
368              idx++, ent++, p += hdr->hdr_entsz) {
369                 le_uuid_dec(p, &ent->ent_type);
370                 le_uuid_dec(p + 16, &ent->ent_uuid);
371                 ent->ent_lba_start = le64dec(p + 32);
372                 ent->ent_lba_end = le64dec(p + 40);
373                 ent->ent_attr = le64dec(p + 48);
374                 /* Keep UTF-16 in little-endian. */
375                 bcopy(p + 56, ent->ent_name, sizeof(ent->ent_name));
376         }
377
378         g_free(buf);
379         return (tbl);
380 }
381
382 static int
383 gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
384 {
385
386         if (pri == NULL || sec == NULL)
387                 return (0);
388
389         if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
390                 return (0);
391         return ((pri->hdr_revision == sec->hdr_revision &&
392             pri->hdr_size == sec->hdr_size &&
393             pri->hdr_lba_start == sec->hdr_lba_start &&
394             pri->hdr_lba_end == sec->hdr_lba_end &&
395             pri->hdr_entries == sec->hdr_entries &&
396             pri->hdr_entsz == sec->hdr_entsz &&
397             pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0);
398 }
399
400 static int
401 gpt_parse_type(const char *type, struct uuid *uuid)
402 {
403         struct uuid tmp;
404         const char *alias;
405         int error;
406         struct g_part_uuid_alias *uap;
407
408         if (type[0] == '!') {
409                 error = parse_uuid(type + 1, &tmp);
410                 if (error)
411                         return (error);
412                 if (EQUUID(&tmp, &gpt_uuid_unused))
413                         return (EINVAL);
414                 *uuid = tmp;
415                 return (0);
416         }
417         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) {
418                 alias = g_part_alias_name(uap->alias);
419                 if (!strcasecmp(type, alias)) {
420                         *uuid = *uap->uuid;
421                         return (0);
422                 }
423         }
424         return (EINVAL);
425 }
426
427 static int
428 g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
429     struct g_part_parms *gpp)
430 {
431         struct g_part_gpt_entry *entry;
432         int error;
433
434         entry = (struct g_part_gpt_entry *)baseentry;
435         error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
436         if (error)
437                 return (error);
438         kern_uuidgen(&entry->ent.ent_uuid, 1);
439         entry->ent.ent_lba_start = baseentry->gpe_start;
440         entry->ent.ent_lba_end = baseentry->gpe_end;
441         if (baseentry->gpe_deleted) {
442                 entry->ent.ent_attr = 0;
443                 bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
444         }
445         if (gpp->gpp_parms & G_PART_PARM_LABEL)
446                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
447                     sizeof(entry->ent.ent_name) /
448                     sizeof(entry->ent.ent_name[0]));
449         return (0);
450 }
451
452 static int
453 g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
454 {
455         struct g_part_gpt_table *table;
456         size_t codesz;
457
458         codesz = DOSPARTOFF;
459         table = (struct g_part_gpt_table *)basetable;
460         bzero(table->mbr, codesz);
461         codesz = MIN(codesz, gpp->gpp_codesize);
462         if (codesz > 0)
463                 bcopy(gpp->gpp_codeptr, table->mbr, codesz);
464
465         /* Mark the PMBR active since some BIOS require it */
466         table->mbr[DOSPARTOFF] = 0x80;          /* status */
467         return (0);
468 }
469
470 static int
471 g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp)
472 {
473         struct g_provider *pp;
474         struct g_part_gpt_table *table;
475         quad_t last;
476         size_t tblsz;
477
478         /* We don't nest, which means that our depth should be 0. */
479         if (basetable->gpt_depth != 0)
480                 return (ENXIO);
481
482         table = (struct g_part_gpt_table *)basetable;
483         pp = gpp->gpp_provider;
484         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
485             pp->sectorsize - 1) / pp->sectorsize;
486         if (pp->sectorsize < MBRSIZE ||
487             pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) *
488             pp->sectorsize)
489                 return (ENOSPC);
490
491         last = (pp->mediasize / pp->sectorsize) - 1;
492
493         le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC);
494         table->mbr[DOSPARTOFF + 1] = 0x01;              /* shd */
495         table->mbr[DOSPARTOFF + 2] = 0x01;              /* ssect */
496         table->mbr[DOSPARTOFF + 3] = 0x00;              /* scyl */
497         table->mbr[DOSPARTOFF + 4] = 0xee;              /* typ */
498         table->mbr[DOSPARTOFF + 5] = 0xff;              /* ehd */
499         table->mbr[DOSPARTOFF + 6] = 0xff;              /* esect */
500         table->mbr[DOSPARTOFF + 7] = 0xff;              /* ecyl */
501         le32enc(table->mbr + DOSPARTOFF + 8, 1);        /* start */
502         le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, UINT32_MAX));
503
504         /* Allocate space for the header */
505         table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO);
506
507         bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
508         table->hdr->hdr_revision = GPT_HDR_REVISION;
509         table->hdr->hdr_size = offsetof(struct gpt_hdr, padding);
510         kern_uuidgen(&table->hdr->hdr_uuid, 1);
511         table->hdr->hdr_entries = basetable->gpt_entries;
512         table->hdr->hdr_entsz = sizeof(struct gpt_ent);
513
514         g_gpt_set_defaults(basetable, pp);
515         return (0);
516 }
517
518 static int
519 g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
520 {
521         struct g_part_gpt_table *table;
522         struct g_provider *pp;
523
524         table = (struct g_part_gpt_table *)basetable;
525         pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
526         g_free(table->hdr);
527         table->hdr = NULL;
528
529         /*
530          * Wipe the first 2 sectors to clear the partitioning. Wipe the last
531          * sector only if it has valid secondary header.
532          */
533         basetable->gpt_smhead |= 3;
534         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
535             table->lba[GPT_ELT_SECHDR] == pp->mediasize / pp->sectorsize - 1)
536                 basetable->gpt_smtail |= 1;
537         return (0);
538 }
539
540 static void
541 g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 
542     struct sbuf *sb, const char *indent)
543 {
544         struct g_part_gpt_entry *entry;
545  
546         entry = (struct g_part_gpt_entry *)baseentry;
547         if (indent == NULL) {
548                 /* conftxt: libdisk compatibility */
549                 sbuf_printf(sb, " xs GPT xt ");
550                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
551         } else if (entry != NULL) {
552                 /* confxml: partition entry information */
553                 sbuf_printf(sb, "%s<label>", indent);
554                 g_gpt_printf_utf16(sb, entry->ent.ent_name,
555                     sizeof(entry->ent.ent_name) >> 1);
556                 sbuf_printf(sb, "</label>\n");
557                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)
558                         sbuf_printf(sb, "%s<attrib>bootme</attrib>\n", indent);
559                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE) {
560                         sbuf_printf(sb, "%s<attrib>bootonce</attrib>\n",
561                             indent);
562                 }
563                 if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED) {
564                         sbuf_printf(sb, "%s<attrib>bootfailed</attrib>\n",
565                             indent);
566                 }
567                 sbuf_printf(sb, "%s<rawtype>", indent);
568                 sbuf_printf_uuid(sb, &entry->ent.ent_type);
569                 sbuf_printf(sb, "</rawtype>\n");
570                 sbuf_printf(sb, "%s<rawuuid>", indent);
571                 sbuf_printf_uuid(sb, &entry->ent.ent_uuid);
572                 sbuf_printf(sb, "</rawuuid>\n");
573         } else {
574                 /* confxml: scheme information */
575         }
576 }
577
578 static int
579 g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)  
580 {
581         struct g_part_gpt_entry *entry;
582
583         entry = (struct g_part_gpt_entry *)baseentry;
584         return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) ||
585             EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0);
586 }
587
588 static int
589 g_part_gpt_modify(struct g_part_table *basetable,
590     struct g_part_entry *baseentry, struct g_part_parms *gpp)
591 {
592         struct g_part_gpt_entry *entry;
593         int error;
594
595         entry = (struct g_part_gpt_entry *)baseentry;
596         if (gpp->gpp_parms & G_PART_PARM_TYPE) {
597                 error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type);
598                 if (error)
599                         return (error);
600         }
601         if (gpp->gpp_parms & G_PART_PARM_LABEL)
602                 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name,
603                     sizeof(entry->ent.ent_name) /
604                     sizeof(entry->ent.ent_name[0]));
605         return (0);
606 }
607
608 static int
609 g_part_gpt_resize(struct g_part_table *basetable,
610     struct g_part_entry *baseentry, struct g_part_parms *gpp)
611 {
612         struct g_part_gpt_entry *entry;
613         entry = (struct g_part_gpt_entry *)baseentry;
614
615         baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
616         entry->ent.ent_lba_end = baseentry->gpe_end;
617
618         return (0);
619 }
620
621 static const char *
622 g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry,
623     char *buf, size_t bufsz)
624 {
625         struct g_part_gpt_entry *entry;
626         char c;
627
628         entry = (struct g_part_gpt_entry *)baseentry;
629         c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p';
630         snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index);
631         return (buf);
632 }
633
634 static int
635 g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp)
636 {
637         struct g_provider *pp;
638         char *buf;
639         int error, res;
640
641         /* We don't nest, which means that our depth should be 0. */
642         if (table->gpt_depth != 0)
643                 return (ENXIO);
644
645         pp = cp->provider;
646
647         /*
648          * Sanity-check the provider. Since the first sector on the provider
649          * must be a PMBR and a PMBR is 512 bytes large, the sector size
650          * must be at least 512 bytes.  Also, since the theoretical minimum
651          * number of sectors needed by GPT is 6, any medium that has less
652          * than 6 sectors is never going to be able to hold a GPT. The
653          * number 6 comes from:
654          *      1 sector for the PMBR
655          *      2 sectors for the GPT headers (each 1 sector)
656          *      2 sectors for the GPT tables (each 1 sector)
657          *      1 sector for an actual partition
658          * It's better to catch this pathological case early than behaving
659          * pathologically later on...
660          */
661         if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize)
662                 return (ENOSPC);
663
664         /* Check that there's a MBR. */
665         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
666         if (buf == NULL)
667                 return (error);
668         res = le16dec(buf + DOSMAGICOFFSET);
669         g_free(buf);
670         if (res != DOSMAGIC) 
671                 return (ENXIO);
672
673         /* Check that there's a primary header. */
674         buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
675         if (buf == NULL)
676                 return (error);
677         res = memcmp(buf, GPT_HDR_SIG, 8);
678         g_free(buf);
679         if (res == 0)
680                 return (G_PART_PROBE_PRI_HIGH);
681
682         /* No primary? Check that there's a secondary. */
683         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
684             &error);
685         if (buf == NULL)
686                 return (error);
687         res = memcmp(buf, GPT_HDR_SIG, 8); 
688         g_free(buf);
689         return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO);
690 }
691
692 static int
693 g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
694 {
695         struct gpt_hdr *prihdr, *sechdr;
696         struct gpt_ent *tbl, *pritbl, *sectbl;
697         struct g_provider *pp;
698         struct g_part_gpt_table *table;
699         struct g_part_gpt_entry *entry;
700         u_char *buf;
701         uint64_t last;
702         int error, index;
703
704         table = (struct g_part_gpt_table *)basetable;
705         pp = cp->provider;
706         last = (pp->mediasize / pp->sectorsize) - 1;
707
708         /* Read the PMBR */
709         buf = g_read_data(cp, 0, pp->sectorsize, &error);
710         if (buf == NULL)
711                 return (error);
712         bcopy(buf, table->mbr, MBRSIZE);
713         g_free(buf);
714
715         /* Read the primary header and table. */
716         prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR);
717         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
718                 pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr);
719         } else {
720                 table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
721                 pritbl = NULL;
722         }
723
724         /* Read the secondary header and table. */
725         sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR);
726         if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
727                 sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr);
728         } else {
729                 table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
730                 sectbl = NULL;
731         }
732
733         /* Fail if we haven't got any good tables at all. */
734         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK &&
735             table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
736                 printf("GEOM: %s: corrupt or invalid GPT detected.\n",
737                     pp->name);
738                 printf("GEOM: %s: GPT rejected -- may not be recoverable.\n",
739                     pp->name);
740                 return (EINVAL);
741         }
742
743         /*
744          * If both headers are good but they disagree with each other,
745          * then invalidate one. We prefer to keep the primary header,
746          * unless the primary table is corrupt.
747          */
748         if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
749             table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
750             !gpt_matched_hdrs(prihdr, sechdr)) {
751                 if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) {
752                         table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
753                         table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
754                         g_free(sechdr);
755                         sechdr = NULL;
756                 } else {
757                         table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
758                         table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
759                         g_free(prihdr);
760                         prihdr = NULL;
761                 }
762         }
763
764         if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK) {
765                 printf("GEOM: %s: the primary GPT table is corrupt or "
766                     "invalid.\n", pp->name);
767                 printf("GEOM: %s: using the secondary instead -- recovery "
768                     "strongly advised.\n", pp->name);
769                 table->hdr = sechdr;
770                 basetable->gpt_corrupt = 1;
771                 if (prihdr != NULL)
772                         g_free(prihdr);
773                 tbl = sectbl;
774                 if (pritbl != NULL)
775                         g_free(pritbl);
776         } else {
777                 if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) {
778                         printf("GEOM: %s: the secondary GPT table is corrupt "
779                             "or invalid.\n", pp->name);
780                         printf("GEOM: %s: using the primary only -- recovery "
781                             "suggested.\n", pp->name);
782                         basetable->gpt_corrupt = 1;
783                 } else if (table->lba[GPT_ELT_SECHDR] != last) {
784                         printf( "GEOM: %s: the secondary GPT header is not in "
785                             "the last LBA.\n", pp->name);
786                         basetable->gpt_corrupt = 1;
787                 }
788                 table->hdr = prihdr;
789                 if (sechdr != NULL)
790                         g_free(sechdr);
791                 tbl = pritbl;
792                 if (sectbl != NULL)
793                         g_free(sectbl);
794         }
795
796         basetable->gpt_first = table->hdr->hdr_lba_start;
797         basetable->gpt_last = table->hdr->hdr_lba_end;
798         basetable->gpt_entries = (table->hdr->hdr_lba_start - 2) *
799             pp->sectorsize / table->hdr->hdr_entsz;
800
801         for (index = table->hdr->hdr_entries - 1; index >= 0; index--) {
802                 if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
803                         continue;
804                 entry = (struct g_part_gpt_entry *)g_part_new_entry(
805                     basetable, index + 1, tbl[index].ent_lba_start,
806                     tbl[index].ent_lba_end);
807                 entry->ent = tbl[index];
808         }
809
810         g_free(tbl);
811         return (0);
812 }
813
814 static int
815 g_part_gpt_recover(struct g_part_table *basetable)
816 {
817
818         g_gpt_set_defaults(basetable,
819             LIST_FIRST(&basetable->gpt_gp->consumer)->provider);
820         basetable->gpt_corrupt = 0;
821         return (0);
822 }
823
824 static int
825 g_part_gpt_setunset(struct g_part_table *table, struct g_part_entry *baseentry,
826     const char *attrib, unsigned int set)
827 {
828         struct g_part_entry *iter;
829         struct g_part_gpt_entry *entry;
830         int changed, bootme, bootonce, bootfailed;
831
832         bootme = bootonce = bootfailed = 0;
833         if (strcasecmp(attrib, "bootme") == 0) {
834                 bootme = 1;
835         } else if (strcasecmp(attrib, "bootonce") == 0) {
836                 /* BOOTME is set automatically with BOOTONCE, but not unset. */
837                 bootonce = 1;
838                 if (set)
839                         bootme = 1;
840         } else if (strcasecmp(attrib, "bootfailed") == 0) {
841                 /*
842                  * It should only be possible to unset BOOTFAILED, but it might
843                  * be useful for test purposes to also be able to set it.
844                  */
845                 bootfailed = 1;
846         }
847         if (!bootme && !bootonce && !bootfailed)
848                 return (EINVAL);
849
850         LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) {
851                 if (iter->gpe_deleted)
852                         continue;
853                 if (iter != baseentry)
854                         continue;
855                 changed = 0;
856                 entry = (struct g_part_gpt_entry *)iter;
857                 if (set) {
858                         if (bootme &&
859                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) {
860                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTME;
861                                 changed = 1;
862                         }
863                         if (bootonce &&
864                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) {
865                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTONCE;
866                                 changed = 1;
867                         }
868                         if (bootfailed &&
869                             !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) {
870                                 entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTFAILED;
871                                 changed = 1;
872                         }
873                 } else {
874                         if (bootme &&
875                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) {
876                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTME;
877                                 changed = 1;
878                         }
879                         if (bootonce &&
880                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) {
881                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTONCE;
882                                 changed = 1;
883                         }
884                         if (bootfailed &&
885                             (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) {
886                                 entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTFAILED;
887                                 changed = 1;
888                         }
889                 }
890                 if (changed && !iter->gpe_created)
891                         iter->gpe_modified = 1;
892         }
893         return (0);
894 }
895
896 static const char *
897 g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 
898     char *buf, size_t bufsz)
899 {
900         struct g_part_gpt_entry *entry;
901         struct uuid *type;
902         struct g_part_uuid_alias *uap;
903  
904         entry = (struct g_part_gpt_entry *)baseentry;
905         type = &entry->ent.ent_type;
906         for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++)
907                 if (EQUUID(type, uap->uuid))
908                         return (g_part_alias_name(uap->alias));
909         buf[0] = '!';
910         snprintf_uuid(buf + 1, bufsz - 1, type);
911
912         return (buf);
913 }
914
915 static int
916 g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp)
917 {
918         unsigned char *buf, *bp;
919         struct g_provider *pp;
920         struct g_part_entry *baseentry;
921         struct g_part_gpt_entry *entry;
922         struct g_part_gpt_table *table;
923         size_t tblsz;
924         uint32_t crc;
925         int error, index;
926
927         pp = cp->provider;
928         table = (struct g_part_gpt_table *)basetable;
929         tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz +
930             pp->sectorsize - 1) / pp->sectorsize;
931
932         /* Write the PMBR */
933         buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
934         bcopy(table->mbr, buf, MBRSIZE);
935         error = g_write_data(cp, 0, buf, pp->sectorsize);
936         g_free(buf);
937         if (error)
938                 return (error);
939
940         /* Allocate space for the header and entries. */
941         buf = g_malloc((tblsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
942
943         memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
944         le32enc(buf + 8, table->hdr->hdr_revision);
945         le32enc(buf + 12, table->hdr->hdr_size);
946         le64enc(buf + 40, table->hdr->hdr_lba_start);
947         le64enc(buf + 48, table->hdr->hdr_lba_end);
948         le_uuid_enc(buf + 56, &table->hdr->hdr_uuid);
949         le32enc(buf + 80, table->hdr->hdr_entries);
950         le32enc(buf + 84, table->hdr->hdr_entsz);
951
952         LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
953                 if (baseentry->gpe_deleted)
954                         continue;
955                 entry = (struct g_part_gpt_entry *)baseentry;
956                 index = baseentry->gpe_index - 1;
957                 bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index;
958                 le_uuid_enc(bp, &entry->ent.ent_type);
959                 le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
960                 le64enc(bp + 32, entry->ent.ent_lba_start);
961                 le64enc(bp + 40, entry->ent.ent_lba_end);
962                 le64enc(bp + 48, entry->ent.ent_attr);
963                 memcpy(bp + 56, entry->ent.ent_name,
964                     sizeof(entry->ent.ent_name));
965         }
966
967         crc = crc32(buf + pp->sectorsize,
968             table->hdr->hdr_entries * table->hdr->hdr_entsz);
969         le32enc(buf + 88, crc);
970
971         /* Write primary meta-data. */
972         le32enc(buf + 16, 0);   /* hdr_crc_self. */
973         le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_self. */
974         le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_alt. */
975         le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]);  /* hdr_lba_table. */
976         crc = crc32(buf, table->hdr->hdr_size);
977         le32enc(buf + 16, crc);
978
979         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
980                 error = g_write_data(cp,
981                     (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize,
982                     buf + (index + 1) * pp->sectorsize,
983                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
984                     (tblsz - index) * pp->sectorsize);
985                 if (error)
986                         goto out;
987         }
988         error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
989             buf, pp->sectorsize);
990         if (error)
991                 goto out;
992
993         /* Write secondary meta-data. */
994         le32enc(buf + 16, 0);   /* hdr_crc_self. */
995         le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]);  /* hdr_lba_self. */
996         le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]);  /* hdr_lba_alt. */
997         le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]);  /* hdr_lba_table. */
998         crc = crc32(buf, table->hdr->hdr_size);
999         le32enc(buf + 16, crc);
1000
1001         for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
1002                 error = g_write_data(cp,
1003                     (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize,
1004                     buf + (index + 1) * pp->sectorsize,
1005                     (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
1006                     (tblsz - index) * pp->sectorsize);
1007                 if (error)
1008                         goto out;
1009         }
1010         error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
1011             buf, pp->sectorsize);
1012
1013  out:
1014         g_free(buf);
1015         return (error);
1016 }
1017
1018 static void
1019 g_gpt_set_defaults(struct g_part_table *basetable, struct g_provider *pp)
1020 {
1021         struct g_part_gpt_table *table;
1022         quad_t last;
1023         size_t tblsz;
1024
1025         table = (struct g_part_gpt_table *)basetable;
1026         last = pp->mediasize / pp->sectorsize - 1;
1027         tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) +
1028             pp->sectorsize - 1) / pp->sectorsize;
1029
1030         table->lba[GPT_ELT_PRIHDR] = 1;
1031         table->lba[GPT_ELT_PRITBL] = 2;
1032         table->lba[GPT_ELT_SECHDR] = last;
1033         table->lba[GPT_ELT_SECTBL] = last - tblsz;
1034         table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK;
1035         table->state[GPT_ELT_PRITBL] = GPT_STATE_OK;
1036         table->state[GPT_ELT_SECHDR] = GPT_STATE_OK;
1037         table->state[GPT_ELT_SECTBL] = GPT_STATE_OK;
1038
1039         table->hdr->hdr_lba_start = 2 + tblsz;
1040         table->hdr->hdr_lba_end = last - tblsz - 1;
1041
1042         basetable->gpt_first = table->hdr->hdr_lba_start;
1043         basetable->gpt_last = table->hdr->hdr_lba_end;
1044 }
1045
1046 static void
1047 g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len)
1048 {
1049         u_int bo;
1050         uint32_t ch;
1051         uint16_t c;
1052
1053         bo = LITTLE_ENDIAN;     /* GPT is little-endian */
1054         while (len > 0 && *str != 0) {
1055                 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str);
1056                 str++, len--;
1057                 if ((ch & 0xf800) == 0xd800) {
1058                         if (len > 0) {
1059                                 c = (bo == BIG_ENDIAN) ? be16toh(*str)
1060                                     : le16toh(*str);
1061                                 str++, len--;
1062                         } else
1063                                 c = 0xfffd;
1064                         if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) {
1065                                 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff);
1066                                 ch += 0x10000;
1067                         } else
1068                                 ch = 0xfffd;
1069                 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */
1070                         bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN;
1071                         continue;
1072                 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */
1073                         continue;
1074
1075                 /* Write the Unicode character in UTF-8 */
1076                 if (ch < 0x80)
1077                         sbuf_printf(sb, "%c", ch);
1078                 else if (ch < 0x800)
1079                         sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6),
1080                             0x80 | (ch & 0x3f));
1081                 else if (ch < 0x10000)
1082                         sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12),
1083                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
1084                 else if (ch < 0x200000)
1085                         sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18),
1086                             0x80 | ((ch >> 12) & 0x3f),
1087                             0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f));
1088         }
1089 }
1090
1091 static void
1092 g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
1093 {
1094         size_t s16idx, s8idx;
1095         uint32_t utfchar;
1096         unsigned int c, utfbytes;
1097
1098         s8idx = s16idx = 0;
1099         utfchar = 0;
1100         utfbytes = 0;
1101         bzero(s16, s16len << 1);
1102         while (s8[s8idx] != 0 && s16idx < s16len) {
1103                 c = s8[s8idx++];
1104                 if ((c & 0xc0) != 0x80) {
1105                         /* Initial characters. */
1106                         if (utfbytes != 0) {
1107                                 /* Incomplete encoding of previous char. */
1108                                 s16[s16idx++] = htole16(0xfffd);
1109                         }
1110                         if ((c & 0xf8) == 0xf0) {
1111                                 utfchar = c & 0x07;
1112                                 utfbytes = 3;
1113                         } else if ((c & 0xf0) == 0xe0) {
1114                                 utfchar = c & 0x0f;
1115                                 utfbytes = 2;
1116                         } else if ((c & 0xe0) == 0xc0) {
1117                                 utfchar = c & 0x1f;
1118                                 utfbytes = 1;
1119                         } else {
1120                                 utfchar = c & 0x7f;
1121                                 utfbytes = 0;
1122                         }
1123                 } else {
1124                         /* Followup characters. */
1125                         if (utfbytes > 0) {
1126                                 utfchar = (utfchar << 6) + (c & 0x3f);
1127                                 utfbytes--;
1128                         } else if (utfbytes == 0)
1129                                 utfbytes = ~0;
1130                 }
1131                 /*
1132                  * Write the complete Unicode character as UTF-16 when we
1133                  * have all the UTF-8 charactars collected.
1134                  */
1135                 if (utfbytes == 0) {
1136                         /*
1137                          * If we need to write 2 UTF-16 characters, but
1138                          * we only have room for 1, then we truncate the
1139                          * string by writing a 0 instead.
1140                          */
1141                         if (utfchar >= 0x10000 && s16idx < s16len - 1) {
1142                                 s16[s16idx++] =
1143                                     htole16(0xd800 | ((utfchar >> 10) - 0x40));
1144                                 s16[s16idx++] =
1145                                     htole16(0xdc00 | (utfchar & 0x3ff));
1146                         } else
1147                                 s16[s16idx++] = (utfchar >= 0x10000) ? 0 :
1148                                     htole16(utfchar);
1149                 }
1150         }
1151         /*
1152          * If our input string was truncated, append an invalid encoding
1153          * character to the output string.
1154          */
1155         if (utfbytes != 0 && s16idx < s16len)
1156                 s16[s16idx++] = htole16(0xfffd);
1157 }