g_part_gpt.c revision 200534
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: head/sys/geom/part/g_part_gpt.c 200534 2009-12-14 20:04:06Z rpaulo $"); 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 50CTASSERT(offsetof(struct gpt_hdr, padding) == 92); 51CTASSERT(sizeof(struct gpt_ent) == 128); 52 53#define EQUUID(a,b) (memcmp(a, b, sizeof(struct uuid)) == 0) 54 55#define MBRSIZE 512 56 57enum gpt_elt { 58 GPT_ELT_PRIHDR, 59 GPT_ELT_PRITBL, 60 GPT_ELT_SECHDR, 61 GPT_ELT_SECTBL, 62 GPT_ELT_COUNT 63}; 64 65enum 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 73struct 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 81struct g_part_gpt_entry { 82 struct g_part_entry base; 83 struct gpt_ent ent; 84}; 85 86static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t); 87static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t); 88 89static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *, 90 struct g_part_parms *); 91static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *); 92static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *); 93static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *); 94static void g_part_gpt_dumpconf(struct g_part_table *, struct g_part_entry *, 95 struct sbuf *, const char *); 96static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *); 97static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *, 98 struct g_part_parms *); 99static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *, 100 char *, size_t); 101static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *); 102static int g_part_gpt_read(struct g_part_table *, struct g_consumer *); 103static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *, 104 char *, size_t); 105static int g_part_gpt_write(struct g_part_table *, struct g_consumer *); 106 107static kobj_method_t g_part_gpt_methods[] = { 108 KOBJMETHOD(g_part_add, g_part_gpt_add), 109 KOBJMETHOD(g_part_bootcode, g_part_gpt_bootcode), 110 KOBJMETHOD(g_part_create, g_part_gpt_create), 111 KOBJMETHOD(g_part_destroy, g_part_gpt_destroy), 112 KOBJMETHOD(g_part_dumpconf, g_part_gpt_dumpconf), 113 KOBJMETHOD(g_part_dumpto, g_part_gpt_dumpto), 114 KOBJMETHOD(g_part_modify, g_part_gpt_modify), 115 KOBJMETHOD(g_part_name, g_part_gpt_name), 116 KOBJMETHOD(g_part_probe, g_part_gpt_probe), 117 KOBJMETHOD(g_part_read, g_part_gpt_read), 118 KOBJMETHOD(g_part_type, g_part_gpt_type), 119 KOBJMETHOD(g_part_write, g_part_gpt_write), 120 { 0, 0 } 121}; 122 123static struct g_part_scheme g_part_gpt_scheme = { 124 "GPT", 125 g_part_gpt_methods, 126 sizeof(struct g_part_gpt_table), 127 .gps_entrysz = sizeof(struct g_part_gpt_entry), 128 .gps_minent = 128, 129 .gps_maxent = INT_MAX, 130 .gps_bootcodesz = MBRSIZE, 131}; 132G_PART_SCHEME_DECLARE(g_part_gpt); 133 134static struct uuid gpt_uuid_apple_boot = GPT_ENT_TYPE_APPLE_BOOT; 135static struct uuid gpt_uuid_apple_hfs = GPT_ENT_TYPE_APPLE_HFS; 136static struct uuid gpt_uuid_apple_label = GPT_ENT_TYPE_APPLE_LABEL; 137static struct uuid gpt_uuid_apple_raid = GPT_ENT_TYPE_APPLE_RAID; 138static struct uuid gpt_uuid_apple_raid_offline = GPT_ENT_TYPE_APPLE_RAID_OFFLINE; 139static struct uuid gpt_uuid_apple_tv_recovery = GPT_ENT_TYPE_APPLE_TV_RECOVERY; 140static struct uuid gpt_uuid_apple_ufs = GPT_ENT_TYPE_APPLE_UFS; 141static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI; 142static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; 143static struct uuid gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 144static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 145static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 146static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 147static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 148static struct uuid gpt_uuid_linux_data = GPT_ENT_TYPE_LINUX_DATA; 149static struct uuid gpt_uuid_linux_lvm = GPT_ENT_TYPE_LINUX_LVM; 150static struct uuid gpt_uuid_linux_raid = GPT_ENT_TYPE_LINUX_RAID; 151static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP; 152static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR; 153static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED; 154 155static struct g_part_uuid_alias { 156 struct uuid *uuid; 157 int alias; 158} gpt_uuid_alias_match[] = { 159 { &gpt_uuid_apple_boot, G_PART_ALIAS_APPLE_BOOT }, 160 { &gpt_uuid_apple_hfs, G_PART_ALIAS_APPLE_HFS }, 161 { &gpt_uuid_apple_label, G_PART_ALIAS_APPLE_LABEL }, 162 { &gpt_uuid_apple_raid, G_PART_ALIAS_APPLE_RAID }, 163 { &gpt_uuid_apple_raid_offline, G_PART_ALIAS_APPLE_RAID_OFFLINE }, 164 { &gpt_uuid_apple_tv_recovery, G_PART_ALIAS_APPLE_TV_RECOVERY }, 165 { &gpt_uuid_apple_ufs, G_PART_ALIAS_APPLE_UFS }, 166 { &gpt_uuid_efi, G_PART_ALIAS_EFI }, 167 { &gpt_uuid_freebsd, G_PART_ALIAS_FREEBSD }, 168 { &gpt_uuid_freebsd_boot, G_PART_ALIAS_FREEBSD_BOOT }, 169 { &gpt_uuid_freebsd_swap, G_PART_ALIAS_FREEBSD_SWAP }, 170 { &gpt_uuid_freebsd_ufs, G_PART_ALIAS_FREEBSD_UFS }, 171 { &gpt_uuid_freebsd_vinum, G_PART_ALIAS_FREEBSD_VINUM }, 172 { &gpt_uuid_freebsd_zfs, G_PART_ALIAS_FREEBSD_ZFS }, 173 { &gpt_uuid_linux_data, G_PART_ALIAS_LINUX_DATA }, 174 { &gpt_uuid_linux_lvm, G_PART_ALIAS_LINUX_LVM }, 175 { &gpt_uuid_linux_raid, G_PART_ALIAS_LINUX_RAID }, 176 { &gpt_uuid_linux_swap, G_PART_ALIAS_LINUX_SWAP }, 177 { &gpt_uuid_mbr, G_PART_ALIAS_MBR }, 178 { NULL, 0 } 179}; 180 181static struct gpt_hdr * 182gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp, 183 enum gpt_elt elt) 184{ 185 struct gpt_hdr *buf, *hdr; 186 struct g_provider *pp; 187 quad_t lba, last; 188 int error; 189 uint32_t crc, sz; 190 191 pp = cp->provider; 192 last = (pp->mediasize / pp->sectorsize) - 1; 193 table->lba[elt] = (elt == GPT_ELT_PRIHDR) ? 1 : last; 194 table->state[elt] = GPT_STATE_MISSING; 195 buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize, 196 &error); 197 if (buf == NULL) 198 return (NULL); 199 hdr = NULL; 200 if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0) 201 goto fail; 202 203 table->state[elt] = GPT_STATE_CORRUPT; 204 sz = le32toh(buf->hdr_size); 205 if (sz < 92 || sz > pp->sectorsize) 206 goto fail; 207 208 hdr = g_malloc(sz, M_WAITOK | M_ZERO); 209 bcopy(buf, hdr, sz); 210 hdr->hdr_size = sz; 211 212 crc = le32toh(buf->hdr_crc_self); 213 buf->hdr_crc_self = 0; 214 if (crc32(buf, sz) != crc) 215 goto fail; 216 hdr->hdr_crc_self = crc; 217 218 table->state[elt] = GPT_STATE_INVALID; 219 hdr->hdr_revision = le32toh(buf->hdr_revision); 220 if (hdr->hdr_revision < 0x00010000) 221 goto fail; 222 hdr->hdr_lba_self = le64toh(buf->hdr_lba_self); 223 if (hdr->hdr_lba_self != table->lba[elt]) 224 goto fail; 225 hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt); 226 227 /* Check the managed area. */ 228 hdr->hdr_lba_start = le64toh(buf->hdr_lba_start); 229 if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last) 230 goto fail; 231 hdr->hdr_lba_end = le64toh(buf->hdr_lba_end); 232 if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last) 233 goto fail; 234 235 /* Check the table location and size of the table. */ 236 hdr->hdr_entries = le32toh(buf->hdr_entries); 237 hdr->hdr_entsz = le32toh(buf->hdr_entsz); 238 if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 || 239 (hdr->hdr_entsz & 7) != 0) 240 goto fail; 241 hdr->hdr_lba_table = le64toh(buf->hdr_lba_table); 242 if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last) 243 goto fail; 244 if (hdr->hdr_lba_table >= hdr->hdr_lba_start && 245 hdr->hdr_lba_table <= hdr->hdr_lba_end) 246 goto fail; 247 lba = hdr->hdr_lba_table + 248 (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) / 249 pp->sectorsize - 1; 250 if (lba >= last) 251 goto fail; 252 if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end) 253 goto fail; 254 255 table->state[elt] = GPT_STATE_OK; 256 le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid); 257 hdr->hdr_crc_table = le32toh(buf->hdr_crc_table); 258 259 g_free(buf); 260 return (hdr); 261 262 fail: 263 if (hdr != NULL) 264 g_free(hdr); 265 g_free(buf); 266 return (NULL); 267} 268 269static struct gpt_ent * 270gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp, 271 enum gpt_elt elt, struct gpt_hdr *hdr) 272{ 273 struct g_provider *pp; 274 struct gpt_ent *ent, *tbl; 275 char *buf, *p; 276 unsigned int idx, sectors, tblsz; 277 int error; 278 279 if (hdr == NULL) 280 return (NULL); 281 282 pp = cp->provider; 283 table->lba[elt] = hdr->hdr_lba_table; 284 285 table->state[elt] = GPT_STATE_MISSING; 286 tblsz = hdr->hdr_entries * hdr->hdr_entsz; 287 sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize; 288 buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, 289 sectors * pp->sectorsize, &error); 290 if (buf == NULL) 291 return (NULL); 292 293 table->state[elt] = GPT_STATE_CORRUPT; 294 if (crc32(buf, tblsz) != hdr->hdr_crc_table) { 295 g_free(buf); 296 return (NULL); 297 } 298 299 table->state[elt] = GPT_STATE_OK; 300 tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent), 301 M_WAITOK | M_ZERO); 302 303 for (idx = 0, ent = tbl, p = buf; 304 idx < hdr->hdr_entries; 305 idx++, ent++, p += hdr->hdr_entsz) { 306 le_uuid_dec(p, &ent->ent_type); 307 le_uuid_dec(p + 16, &ent->ent_uuid); 308 ent->ent_lba_start = le64dec(p + 32); 309 ent->ent_lba_end = le64dec(p + 40); 310 ent->ent_attr = le64dec(p + 48); 311 /* Keep UTF-16 in little-endian. */ 312 bcopy(p + 56, ent->ent_name, sizeof(ent->ent_name)); 313 } 314 315 g_free(buf); 316 return (tbl); 317} 318 319static int 320gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec) 321{ 322 323 if (pri == NULL || sec == NULL) 324 return (0); 325 326 if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid)) 327 return (0); 328 return ((pri->hdr_revision == sec->hdr_revision && 329 pri->hdr_size == sec->hdr_size && 330 pri->hdr_lba_start == sec->hdr_lba_start && 331 pri->hdr_lba_end == sec->hdr_lba_end && 332 pri->hdr_entries == sec->hdr_entries && 333 pri->hdr_entsz == sec->hdr_entsz && 334 pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0); 335} 336 337static int 338gpt_parse_type(const char *type, struct uuid *uuid) 339{ 340 struct uuid tmp; 341 const char *alias; 342 int error; 343 struct g_part_uuid_alias *uap; 344 345 if (type[0] == '!') { 346 error = parse_uuid(type + 1, &tmp); 347 if (error) 348 return (error); 349 if (EQUUID(&tmp, &gpt_uuid_unused)) 350 return (EINVAL); 351 *uuid = tmp; 352 return (0); 353 } 354 for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) { 355 alias = g_part_alias_name(uap->alias); 356 if (!strcasecmp(type, alias)) { 357 uuid = uap->uuid; 358 return (0); 359 } 360 } 361 return (EINVAL); 362} 363 364static int 365g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 366 struct g_part_parms *gpp) 367{ 368 struct g_part_gpt_entry *entry; 369 int error; 370 371 entry = (struct g_part_gpt_entry *)baseentry; 372 error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type); 373 if (error) 374 return (error); 375 kern_uuidgen(&entry->ent.ent_uuid, 1); 376 entry->ent.ent_lba_start = baseentry->gpe_start; 377 entry->ent.ent_lba_end = baseentry->gpe_end; 378 if (baseentry->gpe_deleted) { 379 entry->ent.ent_attr = 0; 380 bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name)); 381 } 382 if (gpp->gpp_parms & G_PART_PARM_LABEL) 383 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name, 384 sizeof(entry->ent.ent_name)); 385 return (0); 386} 387 388static int 389g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 390{ 391 struct g_part_gpt_table *table; 392 size_t codesz; 393 394 codesz = DOSPARTOFF; 395 table = (struct g_part_gpt_table *)basetable; 396 bzero(table->mbr, codesz); 397 codesz = MIN(codesz, gpp->gpp_codesize); 398 if (codesz > 0) 399 bcopy(gpp->gpp_codeptr, table->mbr, codesz); 400 401 /* Mark the PMBR active since some BIOS require it */ 402 table->mbr[DOSPARTOFF] = 0x80; /* status */ 403 return (0); 404} 405 406static int 407g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp) 408{ 409 struct g_provider *pp; 410 struct g_part_gpt_table *table; 411 quad_t last; 412 size_t tblsz; 413 414 /* We don't nest, which means that our depth should be 0. */ 415 if (basetable->gpt_depth != 0) 416 return (ENXIO); 417 418 table = (struct g_part_gpt_table *)basetable; 419 pp = gpp->gpp_provider; 420 tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) + 421 pp->sectorsize - 1) / pp->sectorsize; 422 if (pp->sectorsize < MBRSIZE || 423 pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) * 424 pp->sectorsize) 425 return (ENOSPC); 426 427 last = (pp->mediasize / pp->sectorsize) - 1; 428 429 le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC); 430 table->mbr[DOSPARTOFF + 1] = 0x01; /* shd */ 431 table->mbr[DOSPARTOFF + 2] = 0x01; /* ssect */ 432 table->mbr[DOSPARTOFF + 3] = 0x00; /* scyl */ 433 table->mbr[DOSPARTOFF + 4] = 0xee; /* typ */ 434 table->mbr[DOSPARTOFF + 5] = 0xff; /* ehd */ 435 table->mbr[DOSPARTOFF + 6] = 0xff; /* esect */ 436 table->mbr[DOSPARTOFF + 7] = 0xff; /* ecyl */ 437 le32enc(table->mbr + DOSPARTOFF + 8, 1); /* start */ 438 le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, 0xffffffffLL)); 439 440 table->lba[GPT_ELT_PRIHDR] = 1; 441 table->lba[GPT_ELT_PRITBL] = 2; 442 table->lba[GPT_ELT_SECHDR] = last; 443 table->lba[GPT_ELT_SECTBL] = last - tblsz; 444 445 /* Allocate space for the header */ 446 table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO); 447 448 bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig)); 449 table->hdr->hdr_revision = GPT_HDR_REVISION; 450 table->hdr->hdr_size = offsetof(struct gpt_hdr, padding); 451 table->hdr->hdr_lba_start = 2 + tblsz; 452 table->hdr->hdr_lba_end = last - tblsz - 1; 453 kern_uuidgen(&table->hdr->hdr_uuid, 1); 454 table->hdr->hdr_entries = basetable->gpt_entries; 455 table->hdr->hdr_entsz = sizeof(struct gpt_ent); 456 457 basetable->gpt_first = table->hdr->hdr_lba_start; 458 basetable->gpt_last = table->hdr->hdr_lba_end; 459 return (0); 460} 461 462static int 463g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 464{ 465 466 /* 467 * Wipe the first 2 sectors as well as the last to clear the 468 * partitioning. 469 */ 470 basetable->gpt_smhead |= 3; 471 basetable->gpt_smtail |= 1; 472 return (0); 473} 474 475static void 476g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 477 struct sbuf *sb, const char *indent) 478{ 479 struct g_part_gpt_entry *entry; 480 481 entry = (struct g_part_gpt_entry *)baseentry; 482 if (indent == NULL) { 483 /* conftxt: libdisk compatibility */ 484 sbuf_printf(sb, " xs GPT xt "); 485 sbuf_printf_uuid(sb, &entry->ent.ent_type); 486 } else if (entry != NULL) { 487 /* confxml: partition entry information */ 488 sbuf_printf(sb, "%s<label>", indent); 489 g_gpt_printf_utf16(sb, entry->ent.ent_name, 490 sizeof(entry->ent.ent_name) >> 1); 491 sbuf_printf(sb, "</label>\n"); 492 sbuf_printf(sb, "%s<rawtype>", indent); 493 sbuf_printf_uuid(sb, &entry->ent.ent_type); 494 sbuf_printf(sb, "</rawtype>\n"); 495 } else { 496 /* confxml: scheme information */ 497 } 498} 499 500static int 501g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 502{ 503 struct g_part_gpt_entry *entry; 504 505 entry = (struct g_part_gpt_entry *)baseentry; 506 return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) || 507 EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0); 508} 509 510static int 511g_part_gpt_modify(struct g_part_table *basetable, 512 struct g_part_entry *baseentry, struct g_part_parms *gpp) 513{ 514 struct g_part_gpt_entry *entry; 515 int error; 516 517 entry = (struct g_part_gpt_entry *)baseentry; 518 if (gpp->gpp_parms & G_PART_PARM_TYPE) { 519 error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type); 520 if (error) 521 return (error); 522 } 523 if (gpp->gpp_parms & G_PART_PARM_LABEL) 524 g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name, 525 sizeof(entry->ent.ent_name)); 526 return (0); 527} 528 529static const char * 530g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry, 531 char *buf, size_t bufsz) 532{ 533 struct g_part_gpt_entry *entry; 534 char c; 535 536 entry = (struct g_part_gpt_entry *)baseentry; 537 c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p'; 538 snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index); 539 return (buf); 540} 541 542static int 543g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp) 544{ 545 struct g_provider *pp; 546 char *buf; 547 int error, res; 548 549 /* We don't nest, which means that our depth should be 0. */ 550 if (table->gpt_depth != 0) 551 return (ENXIO); 552 553 pp = cp->provider; 554 555 /* 556 * Sanity-check the provider. Since the first sector on the provider 557 * must be a PMBR and a PMBR is 512 bytes large, the sector size 558 * must be at least 512 bytes. Also, since the theoretical minimum 559 * number of sectors needed by GPT is 6, any medium that has less 560 * than 6 sectors is never going to be able to hold a GPT. The 561 * number 6 comes from: 562 * 1 sector for the PMBR 563 * 2 sectors for the GPT headers (each 1 sector) 564 * 2 sectors for the GPT tables (each 1 sector) 565 * 1 sector for an actual partition 566 * It's better to catch this pathological case early than behaving 567 * pathologically later on... 568 */ 569 if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize) 570 return (ENOSPC); 571 572 /* Check that there's a MBR. */ 573 buf = g_read_data(cp, 0L, pp->sectorsize, &error); 574 if (buf == NULL) 575 return (error); 576 res = le16dec(buf + DOSMAGICOFFSET); 577 g_free(buf); 578 if (res != DOSMAGIC) 579 return (ENXIO); 580 581 /* Check that there's a primary header. */ 582 buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); 583 if (buf == NULL) 584 return (error); 585 res = memcmp(buf, GPT_HDR_SIG, 8); 586 g_free(buf); 587 if (res == 0) 588 return (G_PART_PROBE_PRI_HIGH); 589 590 /* No primary? Check that there's a secondary. */ 591 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 592 &error); 593 if (buf == NULL) 594 return (error); 595 res = memcmp(buf, GPT_HDR_SIG, 8); 596 g_free(buf); 597 return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO); 598} 599 600static int 601g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp) 602{ 603 struct gpt_hdr *prihdr, *sechdr; 604 struct gpt_ent *tbl, *pritbl, *sectbl; 605 struct g_provider *pp; 606 struct g_part_gpt_table *table; 607 struct g_part_gpt_entry *entry; 608 u_char *buf; 609 int error, index; 610 611 table = (struct g_part_gpt_table *)basetable; 612 pp = cp->provider; 613 614 /* Read the PMBR */ 615 buf = g_read_data(cp, 0, pp->sectorsize, &error); 616 if (buf == NULL) 617 return (error); 618 bcopy(buf, table->mbr, MBRSIZE); 619 g_free(buf); 620 621 /* Read the primary header and table. */ 622 prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR); 623 if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) { 624 pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr); 625 } else { 626 table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING; 627 pritbl = NULL; 628 } 629 630 /* Read the secondary header and table. */ 631 sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR); 632 if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) { 633 sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr); 634 } else { 635 table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING; 636 sectbl = NULL; 637 } 638 639 /* Fail if we haven't got any good tables at all. */ 640 if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK && 641 table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) { 642 printf("GEOM: %s: corrupt or invalid GPT detected.\n", 643 pp->name); 644 printf("GEOM: %s: GPT rejected -- may not be recoverable.\n", 645 pp->name); 646 return (EINVAL); 647 } 648 649 /* 650 * If both headers are good but they disagree with each other, 651 * then invalidate one. We prefer to keep the primary header, 652 * unless the primary table is corrupt. 653 */ 654 if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK && 655 table->state[GPT_ELT_SECHDR] == GPT_STATE_OK && 656 !gpt_matched_hdrs(prihdr, sechdr)) { 657 if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) { 658 table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID; 659 table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING; 660 g_free(sechdr); 661 sechdr = NULL; 662 } else { 663 table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID; 664 table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING; 665 g_free(prihdr); 666 prihdr = NULL; 667 } 668 } 669 670 if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK) { 671 printf("GEOM: %s: the primary GPT table is corrupt or " 672 "invalid.\n", pp->name); 673 printf("GEOM: %s: using the secondary instead -- recovery " 674 "strongly advised.\n", pp->name); 675 table->hdr = sechdr; 676 if (prihdr != NULL) 677 g_free(prihdr); 678 tbl = sectbl; 679 if (pritbl != NULL) 680 g_free(pritbl); 681 } else { 682 if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) { 683 printf("GEOM: %s: the secondary GPT table is corrupt " 684 "or invalid.\n", pp->name); 685 printf("GEOM: %s: using the primary only -- recovery " 686 "suggested.\n", pp->name); 687 } 688 table->hdr = prihdr; 689 if (sechdr != NULL) 690 g_free(sechdr); 691 tbl = pritbl; 692 if (sectbl != NULL) 693 g_free(sectbl); 694 } 695 696 basetable->gpt_first = table->hdr->hdr_lba_start; 697 basetable->gpt_last = table->hdr->hdr_lba_end; 698 basetable->gpt_entries = table->hdr->hdr_entries; 699 700 for (index = basetable->gpt_entries - 1; index >= 0; index--) { 701 if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused)) 702 continue; 703 entry = (struct g_part_gpt_entry *)g_part_new_entry(basetable, 704 index+1, tbl[index].ent_lba_start, tbl[index].ent_lba_end); 705 entry->ent = tbl[index]; 706 } 707 708 g_free(tbl); 709 return (0); 710} 711 712static const char * 713g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 714 char *buf, size_t bufsz) 715{ 716 struct g_part_gpt_entry *entry; 717 struct uuid *type; 718 struct g_part_uuid_alias *uap; 719 720 entry = (struct g_part_gpt_entry *)baseentry; 721 type = &entry->ent.ent_type; 722 for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) 723 if (EQUUID(type, uap->uuid)) 724 return (g_part_alias_name(uap->alias)); 725 buf[0] = '!'; 726 snprintf_uuid(buf + 1, bufsz - 1, type); 727 728 return (buf); 729} 730 731static int 732g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp) 733{ 734 unsigned char *buf, *bp; 735 struct g_provider *pp; 736 struct g_part_entry *baseentry; 737 struct g_part_gpt_entry *entry; 738 struct g_part_gpt_table *table; 739 size_t tlbsz; 740 uint32_t crc; 741 int error, index; 742 743 pp = cp->provider; 744 table = (struct g_part_gpt_table *)basetable; 745 tlbsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz + 746 pp->sectorsize - 1) / pp->sectorsize; 747 748 /* Write the PMBR */ 749 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 750 bcopy(table->mbr, buf, MBRSIZE); 751 error = g_write_data(cp, 0, buf, pp->sectorsize); 752 g_free(buf); 753 if (error) 754 return (error); 755 756 /* Allocate space for the header and entries. */ 757 buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO); 758 759 memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig)); 760 le32enc(buf + 8, table->hdr->hdr_revision); 761 le32enc(buf + 12, table->hdr->hdr_size); 762 le64enc(buf + 40, table->hdr->hdr_lba_start); 763 le64enc(buf + 48, table->hdr->hdr_lba_end); 764 le_uuid_enc(buf + 56, &table->hdr->hdr_uuid); 765 le32enc(buf + 80, table->hdr->hdr_entries); 766 le32enc(buf + 84, table->hdr->hdr_entsz); 767 768 LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 769 if (baseentry->gpe_deleted) 770 continue; 771 entry = (struct g_part_gpt_entry *)baseentry; 772 index = baseentry->gpe_index - 1; 773 bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index; 774 le_uuid_enc(bp, &entry->ent.ent_type); 775 le_uuid_enc(bp + 16, &entry->ent.ent_uuid); 776 le64enc(bp + 32, entry->ent.ent_lba_start); 777 le64enc(bp + 40, entry->ent.ent_lba_end); 778 le64enc(bp + 48, entry->ent.ent_attr); 779 memcpy(bp + 56, entry->ent.ent_name, 780 sizeof(entry->ent.ent_name)); 781 } 782 783 crc = crc32(buf + pp->sectorsize, 784 table->hdr->hdr_entries * table->hdr->hdr_entsz); 785 le32enc(buf + 88, crc); 786 787 /* Write primary meta-data. */ 788 le32enc(buf + 16, 0); /* hdr_crc_self. */ 789 le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_self. */ 790 le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_alt. */ 791 le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]); /* hdr_lba_table. */ 792 crc = crc32(buf, table->hdr->hdr_size); 793 le32enc(buf + 16, crc); 794 795 error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize, 796 buf + pp->sectorsize, tlbsz * pp->sectorsize); 797 if (error) 798 goto out; 799 error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize, 800 buf, pp->sectorsize); 801 if (error) 802 goto out; 803 804 /* Write secondary meta-data. */ 805 le32enc(buf + 16, 0); /* hdr_crc_self. */ 806 le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_self. */ 807 le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_alt. */ 808 le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]); /* hdr_lba_table. */ 809 crc = crc32(buf, table->hdr->hdr_size); 810 le32enc(buf + 16, crc); 811 812 error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize, 813 buf + pp->sectorsize, tlbsz * pp->sectorsize); 814 if (error) 815 goto out; 816 error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize, 817 buf, pp->sectorsize); 818 819 out: 820 g_free(buf); 821 return (error); 822} 823 824static void 825g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len) 826{ 827 u_int bo; 828 uint32_t ch; 829 uint16_t c; 830 831 bo = LITTLE_ENDIAN; /* GPT is little-endian */ 832 while (len > 0 && *str != 0) { 833 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str); 834 str++, len--; 835 if ((ch & 0xf800) == 0xd800) { 836 if (len > 0) { 837 c = (bo == BIG_ENDIAN) ? be16toh(*str) 838 : le16toh(*str); 839 str++, len--; 840 } else 841 c = 0xfffd; 842 if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) { 843 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff); 844 ch += 0x10000; 845 } else 846 ch = 0xfffd; 847 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */ 848 bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN; 849 continue; 850 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */ 851 continue; 852 853 /* Write the Unicode character in UTF-8 */ 854 if (ch < 0x80) 855 sbuf_printf(sb, "%c", ch); 856 else if (ch < 0x800) 857 sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6), 858 0x80 | (ch & 0x3f)); 859 else if (ch < 0x10000) 860 sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12), 861 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 862 else if (ch < 0x200000) 863 sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18), 864 0x80 | ((ch >> 12) & 0x3f), 865 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 866 } 867} 868 869static void 870g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len) 871{ 872 size_t s16idx, s8idx; 873 uint32_t utfchar; 874 unsigned int c, utfbytes; 875 876 s8idx = s16idx = 0; 877 utfchar = 0; 878 utfbytes = 0; 879 bzero(s16, s16len << 1); 880 while (s8[s8idx] != 0 && s16idx < s16len) { 881 c = s8[s8idx++]; 882 if ((c & 0xc0) != 0x80) { 883 /* Initial characters. */ 884 if (utfbytes != 0) { 885 /* Incomplete encoding of previous char. */ 886 s16[s16idx++] = htole16(0xfffd); 887 } 888 if ((c & 0xf8) == 0xf0) { 889 utfchar = c & 0x07; 890 utfbytes = 3; 891 } else if ((c & 0xf0) == 0xe0) { 892 utfchar = c & 0x0f; 893 utfbytes = 2; 894 } else if ((c & 0xe0) == 0xc0) { 895 utfchar = c & 0x1f; 896 utfbytes = 1; 897 } else { 898 utfchar = c & 0x7f; 899 utfbytes = 0; 900 } 901 } else { 902 /* Followup characters. */ 903 if (utfbytes > 0) { 904 utfchar = (utfchar << 6) + (c & 0x3f); 905 utfbytes--; 906 } else if (utfbytes == 0) 907 utfbytes = ~0; 908 } 909 /* 910 * Write the complete Unicode character as UTF-16 when we 911 * have all the UTF-8 charactars collected. 912 */ 913 if (utfbytes == 0) { 914 /* 915 * If we need to write 2 UTF-16 characters, but 916 * we only have room for 1, then we truncate the 917 * string by writing a 0 instead. 918 */ 919 if (utfchar >= 0x10000 && s16idx < s16len - 1) { 920 s16[s16idx++] = 921 htole16(0xd800 | ((utfchar >> 10) - 0x40)); 922 s16[s16idx++] = 923 htole16(0xdc00 | (utfchar & 0x3ff)); 924 } else 925 s16[s16idx++] = (utfchar >= 0x10000) ? 0 : 926 htole16(utfchar); 927 } 928 } 929 /* 930 * If our input string was truncated, append an invalid encoding 931 * character to the output string. 932 */ 933 if (utfbytes != 0 && s16idx < s16len) 934 s16[s16idx++] = htole16(0xfffd); 935} 936