11d3aed33SMarcel Moolenaar /*- 21d3aed33SMarcel Moolenaar * Copyright (c) 2002, 2005, 2006, 2007 Marcel Moolenaar 31d3aed33SMarcel Moolenaar * All rights reserved. 41d3aed33SMarcel Moolenaar * 51d3aed33SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 61d3aed33SMarcel Moolenaar * modification, are permitted provided that the following conditions 71d3aed33SMarcel Moolenaar * are met: 81d3aed33SMarcel Moolenaar * 91d3aed33SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 101d3aed33SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 111d3aed33SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 121d3aed33SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 131d3aed33SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 141d3aed33SMarcel Moolenaar * 151d3aed33SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161d3aed33SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171d3aed33SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181d3aed33SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191d3aed33SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 201d3aed33SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 211d3aed33SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 221d3aed33SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231d3aed33SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 241d3aed33SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251d3aed33SMarcel Moolenaar */ 261d3aed33SMarcel Moolenaar 271d3aed33SMarcel Moolenaar #include <sys/cdefs.h> 281d3aed33SMarcel Moolenaar __FBSDID("$FreeBSD$"); 291d3aed33SMarcel Moolenaar 301d3aed33SMarcel Moolenaar #include <sys/param.h> 311d3aed33SMarcel Moolenaar #include <sys/bio.h> 321d3aed33SMarcel Moolenaar #include <sys/diskmbr.h> 331d3aed33SMarcel Moolenaar #include <sys/endian.h> 341d3aed33SMarcel Moolenaar #include <sys/gpt.h> 351d3aed33SMarcel Moolenaar #include <sys/kernel.h> 361d3aed33SMarcel Moolenaar #include <sys/kobj.h> 371d3aed33SMarcel Moolenaar #include <sys/limits.h> 381d3aed33SMarcel Moolenaar #include <sys/lock.h> 391d3aed33SMarcel Moolenaar #include <sys/malloc.h> 401d3aed33SMarcel Moolenaar #include <sys/mutex.h> 411d3aed33SMarcel Moolenaar #include <sys/queue.h> 421d3aed33SMarcel Moolenaar #include <sys/sbuf.h> 431d3aed33SMarcel Moolenaar #include <sys/systm.h> 441d3aed33SMarcel Moolenaar #include <sys/uuid.h> 451d3aed33SMarcel Moolenaar #include <geom/geom.h> 461d3aed33SMarcel Moolenaar #include <geom/part/g_part.h> 471d3aed33SMarcel Moolenaar 481d3aed33SMarcel Moolenaar #include "g_part_if.h" 491d3aed33SMarcel Moolenaar 501d3aed33SMarcel Moolenaar CTASSERT(offsetof(struct gpt_hdr, padding) == 92); 511d3aed33SMarcel Moolenaar CTASSERT(sizeof(struct gpt_ent) == 128); 521d3aed33SMarcel Moolenaar 531d3aed33SMarcel Moolenaar #define EQUUID(a,b) (memcmp(a, b, sizeof(struct uuid)) == 0) 541d3aed33SMarcel Moolenaar 554d32fcb4SMarcel Moolenaar #define MBRSIZE 512 564d32fcb4SMarcel Moolenaar 571d3aed33SMarcel Moolenaar enum gpt_elt { 581d3aed33SMarcel Moolenaar GPT_ELT_PRIHDR, 591d3aed33SMarcel Moolenaar GPT_ELT_PRITBL, 601d3aed33SMarcel Moolenaar GPT_ELT_SECHDR, 611d3aed33SMarcel Moolenaar GPT_ELT_SECTBL, 621d3aed33SMarcel Moolenaar GPT_ELT_COUNT 631d3aed33SMarcel Moolenaar }; 641d3aed33SMarcel Moolenaar 651d3aed33SMarcel Moolenaar enum gpt_state { 661d3aed33SMarcel Moolenaar GPT_STATE_UNKNOWN, /* Not determined. */ 671d3aed33SMarcel Moolenaar GPT_STATE_MISSING, /* No signature found. */ 681d3aed33SMarcel Moolenaar GPT_STATE_CORRUPT, /* Checksum mismatch. */ 691d3aed33SMarcel Moolenaar GPT_STATE_INVALID, /* Nonconformant/invalid. */ 701d3aed33SMarcel Moolenaar GPT_STATE_OK /* Perfectly fine. */ 711d3aed33SMarcel Moolenaar }; 721d3aed33SMarcel Moolenaar 731d3aed33SMarcel Moolenaar struct g_part_gpt_table { 741d3aed33SMarcel Moolenaar struct g_part_table base; 754d32fcb4SMarcel Moolenaar u_char mbr[MBRSIZE]; 761c2dee3cSRobert Noland struct gpt_hdr *hdr; 771d3aed33SMarcel Moolenaar quad_t lba[GPT_ELT_COUNT]; 781d3aed33SMarcel Moolenaar enum gpt_state state[GPT_ELT_COUNT]; 791d3aed33SMarcel Moolenaar }; 801d3aed33SMarcel Moolenaar 811d3aed33SMarcel Moolenaar struct g_part_gpt_entry { 821d3aed33SMarcel Moolenaar struct g_part_entry base; 831d3aed33SMarcel Moolenaar struct gpt_ent ent; 841d3aed33SMarcel Moolenaar }; 851d3aed33SMarcel Moolenaar 86d3532631SMarcel Moolenaar static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t); 87d3532631SMarcel Moolenaar static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t); 88d3532631SMarcel Moolenaar 891d3aed33SMarcel Moolenaar static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *, 901d3aed33SMarcel Moolenaar struct g_part_parms *); 914d32fcb4SMarcel Moolenaar static int g_part_gpt_bootcode(struct g_part_table *, struct g_part_parms *); 921d3aed33SMarcel Moolenaar static int g_part_gpt_create(struct g_part_table *, struct g_part_parms *); 931d3aed33SMarcel Moolenaar static int g_part_gpt_destroy(struct g_part_table *, struct g_part_parms *); 9451f53a08SWarner Losh static void g_part_gpt_dumpconf(struct g_part_table *, struct g_part_entry *, 955db67052SMarcel Moolenaar struct sbuf *, const char *); 961d3aed33SMarcel Moolenaar static int g_part_gpt_dumpto(struct g_part_table *, struct g_part_entry *); 971d3aed33SMarcel Moolenaar static int g_part_gpt_modify(struct g_part_table *, struct g_part_entry *, 981d3aed33SMarcel Moolenaar struct g_part_parms *); 9951f53a08SWarner Losh static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *, 1001d3aed33SMarcel Moolenaar char *, size_t); 1011d3aed33SMarcel Moolenaar static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *); 1021d3aed33SMarcel Moolenaar static int g_part_gpt_read(struct g_part_table *, struct g_consumer *); 103cec283baSPawel Jakub Dawidek static int g_part_gpt_setunset(struct g_part_table *table, 104cec283baSPawel Jakub Dawidek struct g_part_entry *baseentry, const char *attrib, unsigned int set); 1051d3aed33SMarcel Moolenaar static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *, 1061d3aed33SMarcel Moolenaar char *, size_t); 1071d3aed33SMarcel Moolenaar static int g_part_gpt_write(struct g_part_table *, struct g_consumer *); 1083f71c319SMarcel Moolenaar static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *, 1093f71c319SMarcel Moolenaar struct g_part_parms *); 110*e7926a37SAndrey V. Elsukov static int g_part_gpt_recover(struct g_part_table *); 1111d3aed33SMarcel Moolenaar 1121d3aed33SMarcel Moolenaar static kobj_method_t g_part_gpt_methods[] = { 1131d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_add, g_part_gpt_add), 1144d32fcb4SMarcel Moolenaar KOBJMETHOD(g_part_bootcode, g_part_gpt_bootcode), 1151d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_create, g_part_gpt_create), 1161d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_destroy, g_part_gpt_destroy), 1175db67052SMarcel Moolenaar KOBJMETHOD(g_part_dumpconf, g_part_gpt_dumpconf), 1181d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_dumpto, g_part_gpt_dumpto), 1191d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_modify, g_part_gpt_modify), 1203f71c319SMarcel Moolenaar KOBJMETHOD(g_part_resize, g_part_gpt_resize), 1211d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_name, g_part_gpt_name), 1221d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_probe, g_part_gpt_probe), 1231d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_read, g_part_gpt_read), 124*e7926a37SAndrey V. Elsukov KOBJMETHOD(g_part_recover, g_part_gpt_recover), 125cec283baSPawel Jakub Dawidek KOBJMETHOD(g_part_setunset, g_part_gpt_setunset), 1261d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_type, g_part_gpt_type), 1271d3aed33SMarcel Moolenaar KOBJMETHOD(g_part_write, g_part_gpt_write), 1281d3aed33SMarcel Moolenaar { 0, 0 } 1291d3aed33SMarcel Moolenaar }; 1301d3aed33SMarcel Moolenaar 1311d3aed33SMarcel Moolenaar static struct g_part_scheme g_part_gpt_scheme = { 1321d3aed33SMarcel Moolenaar "GPT", 1331d3aed33SMarcel Moolenaar g_part_gpt_methods, 1341d3aed33SMarcel Moolenaar sizeof(struct g_part_gpt_table), 1351d3aed33SMarcel Moolenaar .gps_entrysz = sizeof(struct g_part_gpt_entry), 1361d3aed33SMarcel Moolenaar .gps_minent = 128, 1371d3aed33SMarcel Moolenaar .gps_maxent = INT_MAX, 1384d32fcb4SMarcel Moolenaar .gps_bootcodesz = MBRSIZE, 1391d3aed33SMarcel Moolenaar }; 1404ffca444SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_gpt); 1411d3aed33SMarcel Moolenaar 142f1317430SRui Paulo static struct uuid gpt_uuid_apple_boot = GPT_ENT_TYPE_APPLE_BOOT; 14387662ab3SRui Paulo static struct uuid gpt_uuid_apple_hfs = GPT_ENT_TYPE_APPLE_HFS; 144f1317430SRui Paulo static struct uuid gpt_uuid_apple_label = GPT_ENT_TYPE_APPLE_LABEL; 145f1317430SRui Paulo static struct uuid gpt_uuid_apple_raid = GPT_ENT_TYPE_APPLE_RAID; 146f1317430SRui Paulo static struct uuid gpt_uuid_apple_raid_offline = GPT_ENT_TYPE_APPLE_RAID_OFFLINE; 147f1317430SRui Paulo static struct uuid gpt_uuid_apple_tv_recovery = GPT_ENT_TYPE_APPLE_TV_RECOVERY; 148f1317430SRui Paulo static struct uuid gpt_uuid_apple_ufs = GPT_ENT_TYPE_APPLE_UFS; 1491d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_efi = GPT_ENT_TYPE_EFI; 1501d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; 151f352a0d4SJohn Baldwin static struct uuid gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 1521d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 1531d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 1541d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 155a1fedf91SMarcel Moolenaar static struct uuid gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 156f1317430SRui Paulo static struct uuid gpt_uuid_linux_data = GPT_ENT_TYPE_LINUX_DATA; 157f1317430SRui Paulo static struct uuid gpt_uuid_linux_lvm = GPT_ENT_TYPE_LINUX_LVM; 158f1317430SRui Paulo static struct uuid gpt_uuid_linux_raid = GPT_ENT_TYPE_LINUX_RAID; 1591d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_linux_swap = GPT_ENT_TYPE_LINUX_SWAP; 16033f7a412SRui Paulo static struct uuid gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; 16133f7a412SRui Paulo static struct uuid gpt_uuid_ms_reserved = GPT_ENT_TYPE_MS_RESERVED; 16233f7a412SRui Paulo static struct uuid gpt_uuid_ms_ldm_data = GPT_ENT_TYPE_MS_LDM_DATA; 16333f7a412SRui Paulo static struct uuid gpt_uuid_ms_ldm_metadata = GPT_ENT_TYPE_MS_LDM_METADATA; 16433f7a412SRui Paulo static struct uuid gpt_uuid_netbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD; 16533f7a412SRui Paulo static struct uuid gpt_uuid_netbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD; 16633f7a412SRui Paulo static struct uuid gpt_uuid_netbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS; 16733f7a412SRui Paulo static struct uuid gpt_uuid_netbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS; 16833f7a412SRui Paulo static struct uuid gpt_uuid_netbsd_raid = GPT_ENT_TYPE_NETBSD_RAID; 16933f7a412SRui Paulo static struct uuid gpt_uuid_netbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP; 1701d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR; 1711d3aed33SMarcel Moolenaar static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED; 1721d3aed33SMarcel Moolenaar 173f1317430SRui Paulo static struct g_part_uuid_alias { 174f1317430SRui Paulo struct uuid *uuid; 175f1317430SRui Paulo int alias; 176f1317430SRui Paulo } gpt_uuid_alias_match[] = { 177f1317430SRui Paulo { &gpt_uuid_apple_boot, G_PART_ALIAS_APPLE_BOOT }, 178f1317430SRui Paulo { &gpt_uuid_apple_hfs, G_PART_ALIAS_APPLE_HFS }, 179f1317430SRui Paulo { &gpt_uuid_apple_label, G_PART_ALIAS_APPLE_LABEL }, 180f1317430SRui Paulo { &gpt_uuid_apple_raid, G_PART_ALIAS_APPLE_RAID }, 181f1317430SRui Paulo { &gpt_uuid_apple_raid_offline, G_PART_ALIAS_APPLE_RAID_OFFLINE }, 182f1317430SRui Paulo { &gpt_uuid_apple_tv_recovery, G_PART_ALIAS_APPLE_TV_RECOVERY }, 183f1317430SRui Paulo { &gpt_uuid_apple_ufs, G_PART_ALIAS_APPLE_UFS }, 184f1317430SRui Paulo { &gpt_uuid_efi, G_PART_ALIAS_EFI }, 185f1317430SRui Paulo { &gpt_uuid_freebsd, G_PART_ALIAS_FREEBSD }, 186f1317430SRui Paulo { &gpt_uuid_freebsd_boot, G_PART_ALIAS_FREEBSD_BOOT }, 187f1317430SRui Paulo { &gpt_uuid_freebsd_swap, G_PART_ALIAS_FREEBSD_SWAP }, 188f1317430SRui Paulo { &gpt_uuid_freebsd_ufs, G_PART_ALIAS_FREEBSD_UFS }, 189f1317430SRui Paulo { &gpt_uuid_freebsd_vinum, G_PART_ALIAS_FREEBSD_VINUM }, 190f1317430SRui Paulo { &gpt_uuid_freebsd_zfs, G_PART_ALIAS_FREEBSD_ZFS }, 191f1317430SRui Paulo { &gpt_uuid_linux_data, G_PART_ALIAS_LINUX_DATA }, 192f1317430SRui Paulo { &gpt_uuid_linux_lvm, G_PART_ALIAS_LINUX_LVM }, 193f1317430SRui Paulo { &gpt_uuid_linux_raid, G_PART_ALIAS_LINUX_RAID }, 194f1317430SRui Paulo { &gpt_uuid_linux_swap, G_PART_ALIAS_LINUX_SWAP }, 195f1317430SRui Paulo { &gpt_uuid_mbr, G_PART_ALIAS_MBR }, 19633f7a412SRui Paulo { &gpt_uuid_ms_basic_data, G_PART_ALIAS_MS_BASIC_DATA }, 19733f7a412SRui Paulo { &gpt_uuid_ms_ldm_data, G_PART_ALIAS_MS_LDM_DATA }, 19833f7a412SRui Paulo { &gpt_uuid_ms_ldm_metadata, G_PART_ALIAS_MS_LDM_METADATA }, 19933f7a412SRui Paulo { &gpt_uuid_ms_reserved, G_PART_ALIAS_MS_RESERVED }, 20033f7a412SRui Paulo { &gpt_uuid_netbsd_ccd, G_PART_ALIAS_NETBSD_CCD }, 20133f7a412SRui Paulo { &gpt_uuid_netbsd_cgd, G_PART_ALIAS_NETBSD_CGD }, 20233f7a412SRui Paulo { &gpt_uuid_netbsd_ffs, G_PART_ALIAS_NETBSD_FFS }, 20333f7a412SRui Paulo { &gpt_uuid_netbsd_lfs, G_PART_ALIAS_NETBSD_LFS }, 20433f7a412SRui Paulo { &gpt_uuid_netbsd_raid, G_PART_ALIAS_NETBSD_RAID }, 20533f7a412SRui Paulo { &gpt_uuid_netbsd_swap, G_PART_ALIAS_NETBSD_SWAP }, 20633f7a412SRui Paulo 207f1317430SRui Paulo { NULL, 0 } 208f1317430SRui Paulo }; 209f1317430SRui Paulo 2101c2dee3cSRobert Noland static struct gpt_hdr * 2111d3aed33SMarcel Moolenaar gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp, 2121c2dee3cSRobert Noland enum gpt_elt elt) 2131d3aed33SMarcel Moolenaar { 2141c2dee3cSRobert Noland struct gpt_hdr *buf, *hdr; 2151d3aed33SMarcel Moolenaar struct g_provider *pp; 2161d3aed33SMarcel Moolenaar quad_t lba, last; 2171d3aed33SMarcel Moolenaar int error; 2181d3aed33SMarcel Moolenaar uint32_t crc, sz; 2191d3aed33SMarcel Moolenaar 2201d3aed33SMarcel Moolenaar pp = cp->provider; 2211d3aed33SMarcel Moolenaar last = (pp->mediasize / pp->sectorsize) - 1; 2221d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_MISSING; 223*e7926a37SAndrey V. Elsukov /* 224*e7926a37SAndrey V. Elsukov * If the primary header is valid look for secondary 225*e7926a37SAndrey V. Elsukov * header in AlternateLBA, otherwise in the last medium's LBA. 226*e7926a37SAndrey V. Elsukov */ 227*e7926a37SAndrey V. Elsukov if (elt == GPT_ELT_SECHDR) { 228*e7926a37SAndrey V. Elsukov if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK) 229*e7926a37SAndrey V. Elsukov table->lba[elt] = last; 230*e7926a37SAndrey V. Elsukov } else 231*e7926a37SAndrey V. Elsukov table->lba[elt] = 1; 2321d3aed33SMarcel Moolenaar buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize, 2331d3aed33SMarcel Moolenaar &error); 2341d3aed33SMarcel Moolenaar if (buf == NULL) 2351c2dee3cSRobert Noland return (NULL); 2361c2dee3cSRobert Noland hdr = NULL; 2371c2dee3cSRobert Noland if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0) 2381c2dee3cSRobert Noland goto fail; 2391d3aed33SMarcel Moolenaar 2401d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_CORRUPT; 2411c2dee3cSRobert Noland sz = le32toh(buf->hdr_size); 2421d3aed33SMarcel Moolenaar if (sz < 92 || sz > pp->sectorsize) 2431c2dee3cSRobert Noland goto fail; 2441c2dee3cSRobert Noland 2451c2dee3cSRobert Noland hdr = g_malloc(sz, M_WAITOK | M_ZERO); 2461c2dee3cSRobert Noland bcopy(buf, hdr, sz); 2471d3aed33SMarcel Moolenaar hdr->hdr_size = sz; 2481c2dee3cSRobert Noland 2491c2dee3cSRobert Noland crc = le32toh(buf->hdr_crc_self); 2501c2dee3cSRobert Noland buf->hdr_crc_self = 0; 2511c2dee3cSRobert Noland if (crc32(buf, sz) != crc) 2521c2dee3cSRobert Noland goto fail; 2531d3aed33SMarcel Moolenaar hdr->hdr_crc_self = crc; 2541d3aed33SMarcel Moolenaar 2551d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_INVALID; 2561c2dee3cSRobert Noland hdr->hdr_revision = le32toh(buf->hdr_revision); 257*e7926a37SAndrey V. Elsukov if (hdr->hdr_revision < GPT_HDR_REVISION) 2581c2dee3cSRobert Noland goto fail; 2591c2dee3cSRobert Noland hdr->hdr_lba_self = le64toh(buf->hdr_lba_self); 2601d3aed33SMarcel Moolenaar if (hdr->hdr_lba_self != table->lba[elt]) 2611c2dee3cSRobert Noland goto fail; 2621c2dee3cSRobert Noland hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt); 263*e7926a37SAndrey V. Elsukov if (hdr->hdr_lba_alt == hdr->hdr_lba_self || 264*e7926a37SAndrey V. Elsukov hdr->hdr_lba_alt > last) 265*e7926a37SAndrey V. Elsukov goto fail; 2661d3aed33SMarcel Moolenaar 2671d3aed33SMarcel Moolenaar /* Check the managed area. */ 2681c2dee3cSRobert Noland hdr->hdr_lba_start = le64toh(buf->hdr_lba_start); 2691d3aed33SMarcel Moolenaar if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last) 2701c2dee3cSRobert Noland goto fail; 2711c2dee3cSRobert Noland hdr->hdr_lba_end = le64toh(buf->hdr_lba_end); 2721d3aed33SMarcel Moolenaar if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last) 2731c2dee3cSRobert Noland goto fail; 2741d3aed33SMarcel Moolenaar 2751d3aed33SMarcel Moolenaar /* Check the table location and size of the table. */ 2761c2dee3cSRobert Noland hdr->hdr_entries = le32toh(buf->hdr_entries); 2771c2dee3cSRobert Noland hdr->hdr_entsz = le32toh(buf->hdr_entsz); 2781d3aed33SMarcel Moolenaar if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 || 2791d3aed33SMarcel Moolenaar (hdr->hdr_entsz & 7) != 0) 2801c2dee3cSRobert Noland goto fail; 2811c2dee3cSRobert Noland hdr->hdr_lba_table = le64toh(buf->hdr_lba_table); 2821d3aed33SMarcel Moolenaar if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last) 2831c2dee3cSRobert Noland goto fail; 2841d3aed33SMarcel Moolenaar if (hdr->hdr_lba_table >= hdr->hdr_lba_start && 2851d3aed33SMarcel Moolenaar hdr->hdr_lba_table <= hdr->hdr_lba_end) 2861c2dee3cSRobert Noland goto fail; 2871d3aed33SMarcel Moolenaar lba = hdr->hdr_lba_table + 2881d3aed33SMarcel Moolenaar (hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) / 2891d3aed33SMarcel Moolenaar pp->sectorsize - 1; 2901d3aed33SMarcel Moolenaar if (lba >= last) 2911c2dee3cSRobert Noland goto fail; 2921d3aed33SMarcel Moolenaar if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end) 2931c2dee3cSRobert Noland goto fail; 2941d3aed33SMarcel Moolenaar 2951d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_OK; 2961c2dee3cSRobert Noland le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid); 2971c2dee3cSRobert Noland hdr->hdr_crc_table = le32toh(buf->hdr_crc_table); 2981c2dee3cSRobert Noland 299*e7926a37SAndrey V. Elsukov /* save LBA for secondary header */ 300*e7926a37SAndrey V. Elsukov if (elt == GPT_ELT_PRIHDR) 301*e7926a37SAndrey V. Elsukov table->lba[GPT_ELT_SECHDR] = hdr->hdr_lba_alt; 302*e7926a37SAndrey V. Elsukov 3031c2dee3cSRobert Noland g_free(buf); 3041c2dee3cSRobert Noland return (hdr); 3051c2dee3cSRobert Noland 3061c2dee3cSRobert Noland fail: 3071c2dee3cSRobert Noland if (hdr != NULL) 3081c2dee3cSRobert Noland g_free(hdr); 3091c2dee3cSRobert Noland g_free(buf); 3101c2dee3cSRobert Noland return (NULL); 3111d3aed33SMarcel Moolenaar } 3121d3aed33SMarcel Moolenaar 3131d3aed33SMarcel Moolenaar static struct gpt_ent * 3141d3aed33SMarcel Moolenaar gpt_read_tbl(struct g_part_gpt_table *table, struct g_consumer *cp, 3151d3aed33SMarcel Moolenaar enum gpt_elt elt, struct gpt_hdr *hdr) 3161d3aed33SMarcel Moolenaar { 3171d3aed33SMarcel Moolenaar struct g_provider *pp; 3181d3aed33SMarcel Moolenaar struct gpt_ent *ent, *tbl; 3191d3aed33SMarcel Moolenaar char *buf, *p; 3201d3aed33SMarcel Moolenaar unsigned int idx, sectors, tblsz; 3211d3aed33SMarcel Moolenaar int error; 3221d3aed33SMarcel Moolenaar 3231c2dee3cSRobert Noland if (hdr == NULL) 3241c2dee3cSRobert Noland return (NULL); 3251c2dee3cSRobert Noland 3261d3aed33SMarcel Moolenaar pp = cp->provider; 3271d3aed33SMarcel Moolenaar table->lba[elt] = hdr->hdr_lba_table; 3281d3aed33SMarcel Moolenaar 3291d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_MISSING; 3301d3aed33SMarcel Moolenaar tblsz = hdr->hdr_entries * hdr->hdr_entsz; 3311d3aed33SMarcel Moolenaar sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize; 3321d3aed33SMarcel Moolenaar buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, 3331d3aed33SMarcel Moolenaar sectors * pp->sectorsize, &error); 3341d3aed33SMarcel Moolenaar if (buf == NULL) 3351d3aed33SMarcel Moolenaar return (NULL); 3361d3aed33SMarcel Moolenaar 3371d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_CORRUPT; 3381d3aed33SMarcel Moolenaar if (crc32(buf, tblsz) != hdr->hdr_crc_table) { 3391d3aed33SMarcel Moolenaar g_free(buf); 3401d3aed33SMarcel Moolenaar return (NULL); 3411d3aed33SMarcel Moolenaar } 3421d3aed33SMarcel Moolenaar 3431d3aed33SMarcel Moolenaar table->state[elt] = GPT_STATE_OK; 3441d3aed33SMarcel Moolenaar tbl = g_malloc(hdr->hdr_entries * sizeof(struct gpt_ent), 3451d3aed33SMarcel Moolenaar M_WAITOK | M_ZERO); 3461d3aed33SMarcel Moolenaar 3471d3aed33SMarcel Moolenaar for (idx = 0, ent = tbl, p = buf; 3481d3aed33SMarcel Moolenaar idx < hdr->hdr_entries; 3491d3aed33SMarcel Moolenaar idx++, ent++, p += hdr->hdr_entsz) { 3501d3aed33SMarcel Moolenaar le_uuid_dec(p, &ent->ent_type); 3511d3aed33SMarcel Moolenaar le_uuid_dec(p + 16, &ent->ent_uuid); 3521d3aed33SMarcel Moolenaar ent->ent_lba_start = le64dec(p + 32); 3531d3aed33SMarcel Moolenaar ent->ent_lba_end = le64dec(p + 40); 3541d3aed33SMarcel Moolenaar ent->ent_attr = le64dec(p + 48); 355d3532631SMarcel Moolenaar /* Keep UTF-16 in little-endian. */ 356d3532631SMarcel Moolenaar bcopy(p + 56, ent->ent_name, sizeof(ent->ent_name)); 3571d3aed33SMarcel Moolenaar } 3581d3aed33SMarcel Moolenaar 3591d3aed33SMarcel Moolenaar g_free(buf); 3601d3aed33SMarcel Moolenaar return (tbl); 3611d3aed33SMarcel Moolenaar } 3621d3aed33SMarcel Moolenaar 3631d3aed33SMarcel Moolenaar static int 3641d3aed33SMarcel Moolenaar gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec) 3651d3aed33SMarcel Moolenaar { 3661d3aed33SMarcel Moolenaar 3671c2dee3cSRobert Noland if (pri == NULL || sec == NULL) 3681c2dee3cSRobert Noland return (0); 3691c2dee3cSRobert Noland 3701d3aed33SMarcel Moolenaar if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid)) 3711d3aed33SMarcel Moolenaar return (0); 3721d3aed33SMarcel Moolenaar return ((pri->hdr_revision == sec->hdr_revision && 3731d3aed33SMarcel Moolenaar pri->hdr_size == sec->hdr_size && 3741d3aed33SMarcel Moolenaar pri->hdr_lba_start == sec->hdr_lba_start && 3751d3aed33SMarcel Moolenaar pri->hdr_lba_end == sec->hdr_lba_end && 3761d3aed33SMarcel Moolenaar pri->hdr_entries == sec->hdr_entries && 3771d3aed33SMarcel Moolenaar pri->hdr_entsz == sec->hdr_entsz && 3781d3aed33SMarcel Moolenaar pri->hdr_crc_table == sec->hdr_crc_table) ? 1 : 0); 3791d3aed33SMarcel Moolenaar } 3801d3aed33SMarcel Moolenaar 3811d3aed33SMarcel Moolenaar static int 3821d3aed33SMarcel Moolenaar gpt_parse_type(const char *type, struct uuid *uuid) 3831d3aed33SMarcel Moolenaar { 3841d3aed33SMarcel Moolenaar struct uuid tmp; 385d287f590SMarcel Moolenaar const char *alias; 3861d3aed33SMarcel Moolenaar int error; 387f1317430SRui Paulo struct g_part_uuid_alias *uap; 3881d3aed33SMarcel Moolenaar 389d287f590SMarcel Moolenaar if (type[0] == '!') { 390d287f590SMarcel Moolenaar error = parse_uuid(type + 1, &tmp); 3911d3aed33SMarcel Moolenaar if (error) 3921d3aed33SMarcel Moolenaar return (error); 3931d3aed33SMarcel Moolenaar if (EQUUID(&tmp, &gpt_uuid_unused)) 3941d3aed33SMarcel Moolenaar return (EINVAL); 3951d3aed33SMarcel Moolenaar *uuid = tmp; 3961d3aed33SMarcel Moolenaar return (0); 3971d3aed33SMarcel Moolenaar } 398f1317430SRui Paulo for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) { 399f1317430SRui Paulo alias = g_part_alias_name(uap->alias); 400d287f590SMarcel Moolenaar if (!strcasecmp(type, alias)) { 401665bb830SMarcel Moolenaar *uuid = *uap->uuid; 4021d3aed33SMarcel Moolenaar return (0); 4031d3aed33SMarcel Moolenaar } 404d7255ff4SRui Paulo } 405d287f590SMarcel Moolenaar return (EINVAL); 406d287f590SMarcel Moolenaar } 4071d3aed33SMarcel Moolenaar 4081d3aed33SMarcel Moolenaar static int 4091d3aed33SMarcel Moolenaar g_part_gpt_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 4101d3aed33SMarcel Moolenaar struct g_part_parms *gpp) 4111d3aed33SMarcel Moolenaar { 4121d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 4131d3aed33SMarcel Moolenaar int error; 4141d3aed33SMarcel Moolenaar 4151d3aed33SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 4161d3aed33SMarcel Moolenaar error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type); 4171d3aed33SMarcel Moolenaar if (error) 4181d3aed33SMarcel Moolenaar return (error); 4191d3aed33SMarcel Moolenaar kern_uuidgen(&entry->ent.ent_uuid, 1); 4201d3aed33SMarcel Moolenaar entry->ent.ent_lba_start = baseentry->gpe_start; 4211d3aed33SMarcel Moolenaar entry->ent.ent_lba_end = baseentry->gpe_end; 4221d3aed33SMarcel Moolenaar if (baseentry->gpe_deleted) { 4231d3aed33SMarcel Moolenaar entry->ent.ent_attr = 0; 4241d3aed33SMarcel Moolenaar bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name)); 4251d3aed33SMarcel Moolenaar } 426d3532631SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) 427d3532631SMarcel Moolenaar g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name, 428d3532631SMarcel Moolenaar sizeof(entry->ent.ent_name)); 4291d3aed33SMarcel Moolenaar return (0); 4301d3aed33SMarcel Moolenaar } 4311d3aed33SMarcel Moolenaar 4321d3aed33SMarcel Moolenaar static int 4334d32fcb4SMarcel Moolenaar g_part_gpt_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 4344d32fcb4SMarcel Moolenaar { 4354d32fcb4SMarcel Moolenaar struct g_part_gpt_table *table; 43666477112SMarcel Moolenaar size_t codesz; 4374d32fcb4SMarcel Moolenaar 43866477112SMarcel Moolenaar codesz = DOSPARTOFF; 4394d32fcb4SMarcel Moolenaar table = (struct g_part_gpt_table *)basetable; 44066477112SMarcel Moolenaar bzero(table->mbr, codesz); 44166477112SMarcel Moolenaar codesz = MIN(codesz, gpp->gpp_codesize); 44266477112SMarcel Moolenaar if (codesz > 0) 44366477112SMarcel Moolenaar bcopy(gpp->gpp_codeptr, table->mbr, codesz); 444e80d42ddSRobert Noland 445e80d42ddSRobert Noland /* Mark the PMBR active since some BIOS require it */ 446e80d42ddSRobert Noland table->mbr[DOSPARTOFF] = 0x80; /* status */ 4474d32fcb4SMarcel Moolenaar return (0); 4484d32fcb4SMarcel Moolenaar } 4494d32fcb4SMarcel Moolenaar 4504d32fcb4SMarcel Moolenaar static int 4511d3aed33SMarcel Moolenaar g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp) 4521d3aed33SMarcel Moolenaar { 4531d3aed33SMarcel Moolenaar struct g_provider *pp; 4541d3aed33SMarcel Moolenaar struct g_part_gpt_table *table; 4551d3aed33SMarcel Moolenaar quad_t last; 4561d3aed33SMarcel Moolenaar size_t tblsz; 4571d3aed33SMarcel Moolenaar 4582a1c00ffSMarcel Moolenaar /* We don't nest, which means that our depth should be 0. */ 4592a1c00ffSMarcel Moolenaar if (basetable->gpt_depth != 0) 4602a1c00ffSMarcel Moolenaar return (ENXIO); 4612a1c00ffSMarcel Moolenaar 4621d3aed33SMarcel Moolenaar table = (struct g_part_gpt_table *)basetable; 4631d3aed33SMarcel Moolenaar pp = gpp->gpp_provider; 4641d3aed33SMarcel Moolenaar tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) + 4651d3aed33SMarcel Moolenaar pp->sectorsize - 1) / pp->sectorsize; 4664d32fcb4SMarcel Moolenaar if (pp->sectorsize < MBRSIZE || 4671d3aed33SMarcel Moolenaar pp->mediasize < (3 + 2 * tblsz + basetable->gpt_entries) * 4681d3aed33SMarcel Moolenaar pp->sectorsize) 4691d3aed33SMarcel Moolenaar return (ENOSPC); 4701d3aed33SMarcel Moolenaar 4711d3aed33SMarcel Moolenaar last = (pp->mediasize / pp->sectorsize) - 1; 4721d3aed33SMarcel Moolenaar 4734d32fcb4SMarcel Moolenaar le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC); 47485301372SMarcel Moolenaar table->mbr[DOSPARTOFF + 1] = 0x01; /* shd */ 47585301372SMarcel Moolenaar table->mbr[DOSPARTOFF + 2] = 0x01; /* ssect */ 47685301372SMarcel Moolenaar table->mbr[DOSPARTOFF + 3] = 0x00; /* scyl */ 4774d32fcb4SMarcel Moolenaar table->mbr[DOSPARTOFF + 4] = 0xee; /* typ */ 4784d32fcb4SMarcel Moolenaar table->mbr[DOSPARTOFF + 5] = 0xff; /* ehd */ 4794d32fcb4SMarcel Moolenaar table->mbr[DOSPARTOFF + 6] = 0xff; /* esect */ 4804d32fcb4SMarcel Moolenaar table->mbr[DOSPARTOFF + 7] = 0xff; /* ecyl */ 4814d32fcb4SMarcel Moolenaar le32enc(table->mbr + DOSPARTOFF + 8, 1); /* start */ 4824d32fcb4SMarcel Moolenaar le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, 0xffffffffLL)); 4834d32fcb4SMarcel Moolenaar 4841d3aed33SMarcel Moolenaar table->lba[GPT_ELT_PRIHDR] = 1; 4851d3aed33SMarcel Moolenaar table->lba[GPT_ELT_PRITBL] = 2; 4861d3aed33SMarcel Moolenaar table->lba[GPT_ELT_SECHDR] = last; 4871d3aed33SMarcel Moolenaar table->lba[GPT_ELT_SECTBL] = last - tblsz; 4881d3aed33SMarcel Moolenaar 489a59a1310SRobert Noland /* Allocate space for the header */ 490a59a1310SRobert Noland table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO); 491a59a1310SRobert Noland 4921c2dee3cSRobert Noland bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig)); 4931c2dee3cSRobert Noland table->hdr->hdr_revision = GPT_HDR_REVISION; 4941c2dee3cSRobert Noland table->hdr->hdr_size = offsetof(struct gpt_hdr, padding); 4951c2dee3cSRobert Noland table->hdr->hdr_lba_start = 2 + tblsz; 4961c2dee3cSRobert Noland table->hdr->hdr_lba_end = last - tblsz - 1; 4971c2dee3cSRobert Noland kern_uuidgen(&table->hdr->hdr_uuid, 1); 4981c2dee3cSRobert Noland table->hdr->hdr_entries = basetable->gpt_entries; 4991c2dee3cSRobert Noland table->hdr->hdr_entsz = sizeof(struct gpt_ent); 5001d3aed33SMarcel Moolenaar 5011c2dee3cSRobert Noland basetable->gpt_first = table->hdr->hdr_lba_start; 5021c2dee3cSRobert Noland basetable->gpt_last = table->hdr->hdr_lba_end; 5031d3aed33SMarcel Moolenaar return (0); 5041d3aed33SMarcel Moolenaar } 5051d3aed33SMarcel Moolenaar 5061d3aed33SMarcel Moolenaar static int 5071d3aed33SMarcel Moolenaar g_part_gpt_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 5081d3aed33SMarcel Moolenaar { 50936066952SMarius Strobl struct g_part_gpt_table *table; 510*e7926a37SAndrey V. Elsukov struct g_provider *pp; 51136066952SMarius Strobl 51236066952SMarius Strobl table = (struct g_part_gpt_table *)basetable; 513*e7926a37SAndrey V. Elsukov pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 51436066952SMarius Strobl g_free(table->hdr); 51536066952SMarius Strobl table->hdr = NULL; 5161d3aed33SMarcel Moolenaar 5171d3aed33SMarcel Moolenaar /* 518*e7926a37SAndrey V. Elsukov * Wipe the first 2 sectors to clear the partitioning. Wipe the last 519*e7926a37SAndrey V. Elsukov * sector only if it has valid secondary header. 5201d3aed33SMarcel Moolenaar */ 5211d3aed33SMarcel Moolenaar basetable->gpt_smhead |= 3; 522*e7926a37SAndrey V. Elsukov if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK && 523*e7926a37SAndrey V. Elsukov table->lba[GPT_ELT_SECHDR] == pp->mediasize / pp->sectorsize - 1) 5241d3aed33SMarcel Moolenaar basetable->gpt_smtail |= 1; 5251d3aed33SMarcel Moolenaar return (0); 5261d3aed33SMarcel Moolenaar } 5271d3aed33SMarcel Moolenaar 52851f53a08SWarner Losh static void 5295db67052SMarcel Moolenaar g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 5305db67052SMarcel Moolenaar struct sbuf *sb, const char *indent) 5315db67052SMarcel Moolenaar { 5325db67052SMarcel Moolenaar struct g_part_gpt_entry *entry; 5335db67052SMarcel Moolenaar 5345db67052SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 5350c132595SMarcel Moolenaar if (indent == NULL) { 5360c132595SMarcel Moolenaar /* conftxt: libdisk compatibility */ 5375db67052SMarcel Moolenaar sbuf_printf(sb, " xs GPT xt "); 5385db67052SMarcel Moolenaar sbuf_printf_uuid(sb, &entry->ent.ent_type); 5390c132595SMarcel Moolenaar } else if (entry != NULL) { 5400c132595SMarcel Moolenaar /* confxml: partition entry information */ 541d3532631SMarcel Moolenaar sbuf_printf(sb, "%s<label>", indent); 542d3532631SMarcel Moolenaar g_gpt_printf_utf16(sb, entry->ent.ent_name, 543d3532631SMarcel Moolenaar sizeof(entry->ent.ent_name) >> 1); 544d3532631SMarcel Moolenaar sbuf_printf(sb, "</label>\n"); 545cec283baSPawel Jakub Dawidek if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME) 546cec283baSPawel Jakub Dawidek sbuf_printf(sb, "%s<attrib>bootme</attrib>\n", indent); 547cec283baSPawel Jakub Dawidek if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE) { 548cec283baSPawel Jakub Dawidek sbuf_printf(sb, "%s<attrib>bootonce</attrib>\n", 549cec283baSPawel Jakub Dawidek indent); 550cec283baSPawel Jakub Dawidek } 551cec283baSPawel Jakub Dawidek if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED) { 552cec283baSPawel Jakub Dawidek sbuf_printf(sb, "%s<attrib>bootfailed</attrib>\n", 553cec283baSPawel Jakub Dawidek indent); 554cec283baSPawel Jakub Dawidek } 5550c132595SMarcel Moolenaar sbuf_printf(sb, "%s<rawtype>", indent); 5560c132595SMarcel Moolenaar sbuf_printf_uuid(sb, &entry->ent.ent_type); 5570c132595SMarcel Moolenaar sbuf_printf(sb, "</rawtype>\n"); 558cd18ad83SMarcel Moolenaar sbuf_printf(sb, "%s<rawuuid>", indent); 559cd18ad83SMarcel Moolenaar sbuf_printf_uuid(sb, &entry->ent.ent_uuid); 560cd18ad83SMarcel Moolenaar sbuf_printf(sb, "</rawuuid>\n"); 5610c132595SMarcel Moolenaar } else { 5620c132595SMarcel Moolenaar /* confxml: scheme information */ 5630c132595SMarcel Moolenaar } 5645db67052SMarcel Moolenaar } 5655db67052SMarcel Moolenaar 5665db67052SMarcel Moolenaar static int 5671d3aed33SMarcel Moolenaar g_part_gpt_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 5681d3aed33SMarcel Moolenaar { 5691d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 5701d3aed33SMarcel Moolenaar 5711d3aed33SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 5721d3aed33SMarcel Moolenaar return ((EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd_swap) || 5731d3aed33SMarcel Moolenaar EQUUID(&entry->ent.ent_type, &gpt_uuid_linux_swap)) ? 1 : 0); 5741d3aed33SMarcel Moolenaar } 5751d3aed33SMarcel Moolenaar 5761d3aed33SMarcel Moolenaar static int 5771d3aed33SMarcel Moolenaar g_part_gpt_modify(struct g_part_table *basetable, 5781d3aed33SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 5791d3aed33SMarcel Moolenaar { 5801d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 5811d3aed33SMarcel Moolenaar int error; 5821d3aed33SMarcel Moolenaar 5831d3aed33SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 584d287f590SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_TYPE) { 5851d3aed33SMarcel Moolenaar error = gpt_parse_type(gpp->gpp_type, &entry->ent.ent_type); 5861d3aed33SMarcel Moolenaar if (error) 5871d3aed33SMarcel Moolenaar return (error); 588d287f590SMarcel Moolenaar } 589d3532631SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL) 590d3532631SMarcel Moolenaar g_gpt_utf8_to_utf16(gpp->gpp_label, entry->ent.ent_name, 591d3532631SMarcel Moolenaar sizeof(entry->ent.ent_name)); 5921d3aed33SMarcel Moolenaar return (0); 5931d3aed33SMarcel Moolenaar } 5941d3aed33SMarcel Moolenaar 5953f71c319SMarcel Moolenaar static int 5963f71c319SMarcel Moolenaar g_part_gpt_resize(struct g_part_table *basetable, 5973f71c319SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp) 5983f71c319SMarcel Moolenaar { 5993f71c319SMarcel Moolenaar struct g_part_gpt_entry *entry; 6003f71c319SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 6013f71c319SMarcel Moolenaar 6023f71c319SMarcel Moolenaar baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 6033f71c319SMarcel Moolenaar entry->ent.ent_lba_end = baseentry->gpe_end; 6043f71c319SMarcel Moolenaar 6053f71c319SMarcel Moolenaar return (0); 6063f71c319SMarcel Moolenaar } 6073f71c319SMarcel Moolenaar 60851f53a08SWarner Losh static const char * 6091d3aed33SMarcel Moolenaar g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry, 6101d3aed33SMarcel Moolenaar char *buf, size_t bufsz) 6111d3aed33SMarcel Moolenaar { 6121d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 6131d3aed33SMarcel Moolenaar char c; 6141d3aed33SMarcel Moolenaar 6151d3aed33SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 6161d3aed33SMarcel Moolenaar c = (EQUUID(&entry->ent.ent_type, &gpt_uuid_freebsd)) ? 's' : 'p'; 6171d3aed33SMarcel Moolenaar snprintf(buf, bufsz, "%c%d", c, baseentry->gpe_index); 6181d3aed33SMarcel Moolenaar return (buf); 6191d3aed33SMarcel Moolenaar } 6201d3aed33SMarcel Moolenaar 6211d3aed33SMarcel Moolenaar static int 6221d3aed33SMarcel Moolenaar g_part_gpt_probe(struct g_part_table *table, struct g_consumer *cp) 6231d3aed33SMarcel Moolenaar { 6241d3aed33SMarcel Moolenaar struct g_provider *pp; 6251d3aed33SMarcel Moolenaar char *buf; 6261d3aed33SMarcel Moolenaar int error, res; 6271d3aed33SMarcel Moolenaar 6281d3aed33SMarcel Moolenaar /* We don't nest, which means that our depth should be 0. */ 6291d3aed33SMarcel Moolenaar if (table->gpt_depth != 0) 6301d3aed33SMarcel Moolenaar return (ENXIO); 6311d3aed33SMarcel Moolenaar 6321d3aed33SMarcel Moolenaar pp = cp->provider; 6331d3aed33SMarcel Moolenaar 6341d3aed33SMarcel Moolenaar /* 6351d3aed33SMarcel Moolenaar * Sanity-check the provider. Since the first sector on the provider 6361d3aed33SMarcel Moolenaar * must be a PMBR and a PMBR is 512 bytes large, the sector size 6371d3aed33SMarcel Moolenaar * must be at least 512 bytes. Also, since the theoretical minimum 6381d3aed33SMarcel Moolenaar * number of sectors needed by GPT is 6, any medium that has less 6391d3aed33SMarcel Moolenaar * than 6 sectors is never going to be able to hold a GPT. The 6401d3aed33SMarcel Moolenaar * number 6 comes from: 6411d3aed33SMarcel Moolenaar * 1 sector for the PMBR 6421d3aed33SMarcel Moolenaar * 2 sectors for the GPT headers (each 1 sector) 6431d3aed33SMarcel Moolenaar * 2 sectors for the GPT tables (each 1 sector) 6441d3aed33SMarcel Moolenaar * 1 sector for an actual partition 6451d3aed33SMarcel Moolenaar * It's better to catch this pathological case early than behaving 6461d3aed33SMarcel Moolenaar * pathologically later on... 6471d3aed33SMarcel Moolenaar */ 6484d32fcb4SMarcel Moolenaar if (pp->sectorsize < MBRSIZE || pp->mediasize < 6 * pp->sectorsize) 6491d3aed33SMarcel Moolenaar return (ENOSPC); 6501d3aed33SMarcel Moolenaar 6511d3aed33SMarcel Moolenaar /* Check that there's a MBR. */ 6521d3aed33SMarcel Moolenaar buf = g_read_data(cp, 0L, pp->sectorsize, &error); 6531d3aed33SMarcel Moolenaar if (buf == NULL) 6541d3aed33SMarcel Moolenaar return (error); 6551d3aed33SMarcel Moolenaar res = le16dec(buf + DOSMAGICOFFSET); 6561d3aed33SMarcel Moolenaar g_free(buf); 6571d3aed33SMarcel Moolenaar if (res != DOSMAGIC) 6581d3aed33SMarcel Moolenaar return (ENXIO); 6591d3aed33SMarcel Moolenaar 6601d3aed33SMarcel Moolenaar /* Check that there's a primary header. */ 6611d3aed33SMarcel Moolenaar buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); 6621d3aed33SMarcel Moolenaar if (buf == NULL) 6631d3aed33SMarcel Moolenaar return (error); 6641d3aed33SMarcel Moolenaar res = memcmp(buf, GPT_HDR_SIG, 8); 6651d3aed33SMarcel Moolenaar g_free(buf); 6661d3aed33SMarcel Moolenaar if (res == 0) 6671d3aed33SMarcel Moolenaar return (G_PART_PROBE_PRI_HIGH); 6681d3aed33SMarcel Moolenaar 6691d3aed33SMarcel Moolenaar /* No primary? Check that there's a secondary. */ 6701d3aed33SMarcel Moolenaar buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 6711d3aed33SMarcel Moolenaar &error); 6721d3aed33SMarcel Moolenaar if (buf == NULL) 6731d3aed33SMarcel Moolenaar return (error); 6741d3aed33SMarcel Moolenaar res = memcmp(buf, GPT_HDR_SIG, 8); 6751d3aed33SMarcel Moolenaar g_free(buf); 6761d3aed33SMarcel Moolenaar return ((res == 0) ? G_PART_PROBE_PRI_HIGH : ENXIO); 6771d3aed33SMarcel Moolenaar } 6781d3aed33SMarcel Moolenaar 6791d3aed33SMarcel Moolenaar static int 6801d3aed33SMarcel Moolenaar g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp) 6811d3aed33SMarcel Moolenaar { 6821c2dee3cSRobert Noland struct gpt_hdr *prihdr, *sechdr; 6831d3aed33SMarcel Moolenaar struct gpt_ent *tbl, *pritbl, *sectbl; 6841d3aed33SMarcel Moolenaar struct g_provider *pp; 6851d3aed33SMarcel Moolenaar struct g_part_gpt_table *table; 6861d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 6874d32fcb4SMarcel Moolenaar u_char *buf; 688*e7926a37SAndrey V. Elsukov uint64_t last; 6894d32fcb4SMarcel Moolenaar int error, index; 6901d3aed33SMarcel Moolenaar 6911d3aed33SMarcel Moolenaar table = (struct g_part_gpt_table *)basetable; 6921d3aed33SMarcel Moolenaar pp = cp->provider; 693*e7926a37SAndrey V. Elsukov last = (pp->mediasize / pp->sectorsize) - 1; 6941d3aed33SMarcel Moolenaar 6954d32fcb4SMarcel Moolenaar /* Read the PMBR */ 6964d32fcb4SMarcel Moolenaar buf = g_read_data(cp, 0, pp->sectorsize, &error); 6974d32fcb4SMarcel Moolenaar if (buf == NULL) 6984d32fcb4SMarcel Moolenaar return (error); 6994d32fcb4SMarcel Moolenaar bcopy(buf, table->mbr, MBRSIZE); 7004d32fcb4SMarcel Moolenaar g_free(buf); 7014d32fcb4SMarcel Moolenaar 7021d3aed33SMarcel Moolenaar /* Read the primary header and table. */ 7031c2dee3cSRobert Noland prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR); 7041d3aed33SMarcel Moolenaar if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) { 7051c2dee3cSRobert Noland pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr); 7061d3aed33SMarcel Moolenaar } else { 7071d3aed33SMarcel Moolenaar table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING; 7081d3aed33SMarcel Moolenaar pritbl = NULL; 7091d3aed33SMarcel Moolenaar } 7101d3aed33SMarcel Moolenaar 7111d3aed33SMarcel Moolenaar /* Read the secondary header and table. */ 7121c2dee3cSRobert Noland sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR); 7131d3aed33SMarcel Moolenaar if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) { 7141c2dee3cSRobert Noland sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr); 7151d3aed33SMarcel Moolenaar } else { 7161d3aed33SMarcel Moolenaar table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING; 7171d3aed33SMarcel Moolenaar sectbl = NULL; 7181d3aed33SMarcel Moolenaar } 7191d3aed33SMarcel Moolenaar 7201d3aed33SMarcel Moolenaar /* Fail if we haven't got any good tables at all. */ 7211d3aed33SMarcel Moolenaar if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK && 7221d3aed33SMarcel Moolenaar table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) { 7231d3aed33SMarcel Moolenaar printf("GEOM: %s: corrupt or invalid GPT detected.\n", 7241d3aed33SMarcel Moolenaar pp->name); 7251d3aed33SMarcel Moolenaar printf("GEOM: %s: GPT rejected -- may not be recoverable.\n", 7261d3aed33SMarcel Moolenaar pp->name); 7271d3aed33SMarcel Moolenaar return (EINVAL); 7281d3aed33SMarcel Moolenaar } 7291d3aed33SMarcel Moolenaar 7301d3aed33SMarcel Moolenaar /* 7311d3aed33SMarcel Moolenaar * If both headers are good but they disagree with each other, 7321d3aed33SMarcel Moolenaar * then invalidate one. We prefer to keep the primary header, 7331d3aed33SMarcel Moolenaar * unless the primary table is corrupt. 7341d3aed33SMarcel Moolenaar */ 7351d3aed33SMarcel Moolenaar if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK && 7361d3aed33SMarcel Moolenaar table->state[GPT_ELT_SECHDR] == GPT_STATE_OK && 7371c2dee3cSRobert Noland !gpt_matched_hdrs(prihdr, sechdr)) { 738dd0db05dSMarcel Moolenaar if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) { 7391d3aed33SMarcel Moolenaar table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID; 740dd0db05dSMarcel Moolenaar table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING; 7411c2dee3cSRobert Noland g_free(sechdr); 7421c2dee3cSRobert Noland sechdr = NULL; 743dd0db05dSMarcel Moolenaar } else { 7441d3aed33SMarcel Moolenaar table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID; 745dd0db05dSMarcel Moolenaar table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING; 7461c2dee3cSRobert Noland g_free(prihdr); 7471c2dee3cSRobert Noland prihdr = NULL; 748dd0db05dSMarcel Moolenaar } 7491d3aed33SMarcel Moolenaar } 7501d3aed33SMarcel Moolenaar 751dd0db05dSMarcel Moolenaar if (table->state[GPT_ELT_PRITBL] != GPT_STATE_OK) { 7521d3aed33SMarcel Moolenaar printf("GEOM: %s: the primary GPT table is corrupt or " 7531d3aed33SMarcel Moolenaar "invalid.\n", pp->name); 7541d3aed33SMarcel Moolenaar printf("GEOM: %s: using the secondary instead -- recovery " 7551d3aed33SMarcel Moolenaar "strongly advised.\n", pp->name); 7561d3aed33SMarcel Moolenaar table->hdr = sechdr; 757*e7926a37SAndrey V. Elsukov basetable->gpt_corrupt = 1; 7581c2dee3cSRobert Noland if (prihdr != NULL) 7591c2dee3cSRobert Noland g_free(prihdr); 7601d3aed33SMarcel Moolenaar tbl = sectbl; 7611d3aed33SMarcel Moolenaar if (pritbl != NULL) 7621d3aed33SMarcel Moolenaar g_free(pritbl); 7631d3aed33SMarcel Moolenaar } else { 764dd0db05dSMarcel Moolenaar if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) { 7651d3aed33SMarcel Moolenaar printf("GEOM: %s: the secondary GPT table is corrupt " 7661d3aed33SMarcel Moolenaar "or invalid.\n", pp->name); 7671d3aed33SMarcel Moolenaar printf("GEOM: %s: using the primary only -- recovery " 7681d3aed33SMarcel Moolenaar "suggested.\n", pp->name); 769*e7926a37SAndrey V. Elsukov basetable->gpt_corrupt = 1; 770*e7926a37SAndrey V. Elsukov } else if (table->lba[GPT_ELT_SECHDR] != last) { 771*e7926a37SAndrey V. Elsukov printf( "GEOM: %s: the secondary GPT header is not in " 772*e7926a37SAndrey V. Elsukov "the last LBA.\n", pp->name); 773*e7926a37SAndrey V. Elsukov basetable->gpt_corrupt = 1; 7741d3aed33SMarcel Moolenaar } 7751d3aed33SMarcel Moolenaar table->hdr = prihdr; 7761c2dee3cSRobert Noland if (sechdr != NULL) 7771c2dee3cSRobert Noland g_free(sechdr); 7781d3aed33SMarcel Moolenaar tbl = pritbl; 7791d3aed33SMarcel Moolenaar if (sectbl != NULL) 7801d3aed33SMarcel Moolenaar g_free(sectbl); 7811d3aed33SMarcel Moolenaar } 7821d3aed33SMarcel Moolenaar 7831c2dee3cSRobert Noland basetable->gpt_first = table->hdr->hdr_lba_start; 7841c2dee3cSRobert Noland basetable->gpt_last = table->hdr->hdr_lba_end; 7851c2dee3cSRobert Noland basetable->gpt_entries = table->hdr->hdr_entries; 7861d3aed33SMarcel Moolenaar 7871d3aed33SMarcel Moolenaar for (index = basetable->gpt_entries - 1; index >= 0; index--) { 7881d3aed33SMarcel Moolenaar if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused)) 7891d3aed33SMarcel Moolenaar continue; 790*e7926a37SAndrey V. Elsukov entry = (struct g_part_gpt_entry *)g_part_new_entry( 791*e7926a37SAndrey V. Elsukov basetable, index + 1, tbl[index].ent_lba_start, 792*e7926a37SAndrey V. Elsukov tbl[index].ent_lba_end); 7931d3aed33SMarcel Moolenaar entry->ent = tbl[index]; 7941d3aed33SMarcel Moolenaar } 7951d3aed33SMarcel Moolenaar 7961d3aed33SMarcel Moolenaar g_free(tbl); 7971d3aed33SMarcel Moolenaar return (0); 7981d3aed33SMarcel Moolenaar } 7991d3aed33SMarcel Moolenaar 800cec283baSPawel Jakub Dawidek static int 801*e7926a37SAndrey V. Elsukov g_part_gpt_recover(struct g_part_table *basetable) 802*e7926a37SAndrey V. Elsukov { 803*e7926a37SAndrey V. Elsukov struct g_part_gpt_table *table; 804*e7926a37SAndrey V. Elsukov struct g_provider *pp; 805*e7926a37SAndrey V. Elsukov uint64_t last; 806*e7926a37SAndrey V. Elsukov size_t tblsz; 807*e7926a37SAndrey V. Elsukov 808*e7926a37SAndrey V. Elsukov table = (struct g_part_gpt_table *)basetable; 809*e7926a37SAndrey V. Elsukov pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; 810*e7926a37SAndrey V. Elsukov last = pp->mediasize / pp->sectorsize - 1; 811*e7926a37SAndrey V. Elsukov tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz + 812*e7926a37SAndrey V. Elsukov pp->sectorsize - 1) / pp->sectorsize; 813*e7926a37SAndrey V. Elsukov 814*e7926a37SAndrey V. Elsukov table->lba[GPT_ELT_PRIHDR] = 1; 815*e7926a37SAndrey V. Elsukov table->lba[GPT_ELT_PRITBL] = 2; 816*e7926a37SAndrey V. Elsukov table->lba[GPT_ELT_SECHDR] = last; 817*e7926a37SAndrey V. Elsukov table->lba[GPT_ELT_SECTBL] = last - tblsz; 818*e7926a37SAndrey V. Elsukov table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK; 819*e7926a37SAndrey V. Elsukov table->state[GPT_ELT_PRITBL] = GPT_STATE_OK; 820*e7926a37SAndrey V. Elsukov table->state[GPT_ELT_SECHDR] = GPT_STATE_OK; 821*e7926a37SAndrey V. Elsukov table->state[GPT_ELT_SECTBL] = GPT_STATE_OK; 822*e7926a37SAndrey V. Elsukov table->hdr->hdr_lba_start = 2 + tblsz; 823*e7926a37SAndrey V. Elsukov table->hdr->hdr_lba_end = last - tblsz - 1; 824*e7926a37SAndrey V. Elsukov 825*e7926a37SAndrey V. Elsukov basetable->gpt_first = table->hdr->hdr_lba_start; 826*e7926a37SAndrey V. Elsukov basetable->gpt_last = table->hdr->hdr_lba_end; 827*e7926a37SAndrey V. Elsukov basetable->gpt_corrupt = 0; 828*e7926a37SAndrey V. Elsukov 829*e7926a37SAndrey V. Elsukov return (0); 830*e7926a37SAndrey V. Elsukov } 831*e7926a37SAndrey V. Elsukov 832*e7926a37SAndrey V. Elsukov static int 833cec283baSPawel Jakub Dawidek g_part_gpt_setunset(struct g_part_table *table, struct g_part_entry *baseentry, 834cec283baSPawel Jakub Dawidek const char *attrib, unsigned int set) 835cec283baSPawel Jakub Dawidek { 836cec283baSPawel Jakub Dawidek struct g_part_entry *iter; 837cec283baSPawel Jakub Dawidek struct g_part_gpt_entry *entry; 838cec283baSPawel Jakub Dawidek int changed, bootme, bootonce, bootfailed; 839cec283baSPawel Jakub Dawidek 840cec283baSPawel Jakub Dawidek bootme = bootonce = bootfailed = 0; 841cec283baSPawel Jakub Dawidek if (strcasecmp(attrib, "bootme") == 0) { 842cec283baSPawel Jakub Dawidek bootme = 1; 843cec283baSPawel Jakub Dawidek } else if (strcasecmp(attrib, "bootonce") == 0) { 844cec283baSPawel Jakub Dawidek /* BOOTME is set automatically with BOOTONCE, but not unset. */ 845cec283baSPawel Jakub Dawidek bootonce = 1; 846cec283baSPawel Jakub Dawidek if (set) 847cec283baSPawel Jakub Dawidek bootme = 1; 848cec283baSPawel Jakub Dawidek } else if (strcasecmp(attrib, "bootfailed") == 0) { 849cec283baSPawel Jakub Dawidek /* 850cec283baSPawel Jakub Dawidek * It should only be possible to unset BOOTFAILED, but it might 851cec283baSPawel Jakub Dawidek * be useful for test purposes to also be able to set it. 852cec283baSPawel Jakub Dawidek */ 853cec283baSPawel Jakub Dawidek bootfailed = 1; 854cec283baSPawel Jakub Dawidek } 855cec283baSPawel Jakub Dawidek if (!bootme && !bootonce && !bootfailed) 856cec283baSPawel Jakub Dawidek return (EINVAL); 857cec283baSPawel Jakub Dawidek 858cec283baSPawel Jakub Dawidek LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { 859cec283baSPawel Jakub Dawidek if (iter->gpe_deleted) 860cec283baSPawel Jakub Dawidek continue; 861cec283baSPawel Jakub Dawidek if (iter != baseentry) 862cec283baSPawel Jakub Dawidek continue; 863cec283baSPawel Jakub Dawidek changed = 0; 864cec283baSPawel Jakub Dawidek entry = (struct g_part_gpt_entry *)iter; 865cec283baSPawel Jakub Dawidek if (set) { 866cec283baSPawel Jakub Dawidek if (bootme && 867cec283baSPawel Jakub Dawidek !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) { 868cec283baSPawel Jakub Dawidek entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTME; 869cec283baSPawel Jakub Dawidek changed = 1; 870cec283baSPawel Jakub Dawidek } 871cec283baSPawel Jakub Dawidek if (bootonce && 872cec283baSPawel Jakub Dawidek !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) { 873cec283baSPawel Jakub Dawidek entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTONCE; 874cec283baSPawel Jakub Dawidek changed = 1; 875cec283baSPawel Jakub Dawidek } 876cec283baSPawel Jakub Dawidek if (bootfailed && 877cec283baSPawel Jakub Dawidek !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) { 878cec283baSPawel Jakub Dawidek entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTFAILED; 879cec283baSPawel Jakub Dawidek changed = 1; 880cec283baSPawel Jakub Dawidek } 881cec283baSPawel Jakub Dawidek } else { 882cec283baSPawel Jakub Dawidek if (bootme && 883cec283baSPawel Jakub Dawidek (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) { 884cec283baSPawel Jakub Dawidek entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTME; 885cec283baSPawel Jakub Dawidek changed = 1; 886cec283baSPawel Jakub Dawidek } 887cec283baSPawel Jakub Dawidek if (bootonce && 888cec283baSPawel Jakub Dawidek (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) { 889cec283baSPawel Jakub Dawidek entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; 890cec283baSPawel Jakub Dawidek changed = 1; 891cec283baSPawel Jakub Dawidek } 892cec283baSPawel Jakub Dawidek if (bootfailed && 893cec283baSPawel Jakub Dawidek (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) { 894cec283baSPawel Jakub Dawidek entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTFAILED; 895cec283baSPawel Jakub Dawidek changed = 1; 896cec283baSPawel Jakub Dawidek } 897cec283baSPawel Jakub Dawidek } 898cec283baSPawel Jakub Dawidek if (changed && !iter->gpe_created) 899cec283baSPawel Jakub Dawidek iter->gpe_modified = 1; 900cec283baSPawel Jakub Dawidek } 901cec283baSPawel Jakub Dawidek return (0); 902cec283baSPawel Jakub Dawidek } 903cec283baSPawel Jakub Dawidek 9041d3aed33SMarcel Moolenaar static const char * 9051d3aed33SMarcel Moolenaar g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 9061d3aed33SMarcel Moolenaar char *buf, size_t bufsz) 9071d3aed33SMarcel Moolenaar { 9081d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 9091d3aed33SMarcel Moolenaar struct uuid *type; 910f1317430SRui Paulo struct g_part_uuid_alias *uap; 9111d3aed33SMarcel Moolenaar 9121d3aed33SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 9131d3aed33SMarcel Moolenaar type = &entry->ent.ent_type; 914f1317430SRui Paulo for (uap = &gpt_uuid_alias_match[0]; uap->uuid; uap++) 915f1317430SRui Paulo if (EQUUID(type, uap->uuid)) 916f1317430SRui Paulo return (g_part_alias_name(uap->alias)); 917cf231470SMarcel Moolenaar buf[0] = '!'; 918cf231470SMarcel Moolenaar snprintf_uuid(buf + 1, bufsz - 1, type); 919f1317430SRui Paulo 9201d3aed33SMarcel Moolenaar return (buf); 9211d3aed33SMarcel Moolenaar } 9221d3aed33SMarcel Moolenaar 9231d3aed33SMarcel Moolenaar static int 9241d3aed33SMarcel Moolenaar g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp) 9251d3aed33SMarcel Moolenaar { 9261d3aed33SMarcel Moolenaar unsigned char *buf, *bp; 9271d3aed33SMarcel Moolenaar struct g_provider *pp; 9281d3aed33SMarcel Moolenaar struct g_part_entry *baseentry; 9291d3aed33SMarcel Moolenaar struct g_part_gpt_entry *entry; 9301d3aed33SMarcel Moolenaar struct g_part_gpt_table *table; 931*e7926a37SAndrey V. Elsukov size_t tblsz; 9321d3aed33SMarcel Moolenaar uint32_t crc; 9331d3aed33SMarcel Moolenaar int error, index; 9341d3aed33SMarcel Moolenaar 9351d3aed33SMarcel Moolenaar pp = cp->provider; 9361d3aed33SMarcel Moolenaar table = (struct g_part_gpt_table *)basetable; 937*e7926a37SAndrey V. Elsukov tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz + 9381d3aed33SMarcel Moolenaar pp->sectorsize - 1) / pp->sectorsize; 9391d3aed33SMarcel Moolenaar 9404d32fcb4SMarcel Moolenaar /* Write the PMBR */ 9411d3aed33SMarcel Moolenaar buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); 9424d32fcb4SMarcel Moolenaar bcopy(table->mbr, buf, MBRSIZE); 9431d3aed33SMarcel Moolenaar error = g_write_data(cp, 0, buf, pp->sectorsize); 9441d3aed33SMarcel Moolenaar g_free(buf); 9451d3aed33SMarcel Moolenaar if (error) 9461d3aed33SMarcel Moolenaar return (error); 9471d3aed33SMarcel Moolenaar 9481d3aed33SMarcel Moolenaar /* Allocate space for the header and entries. */ 949*e7926a37SAndrey V. Elsukov buf = g_malloc((tblsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO); 9501d3aed33SMarcel Moolenaar 9511c2dee3cSRobert Noland memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig)); 9521c2dee3cSRobert Noland le32enc(buf + 8, table->hdr->hdr_revision); 9531c2dee3cSRobert Noland le32enc(buf + 12, table->hdr->hdr_size); 9541c2dee3cSRobert Noland le64enc(buf + 40, table->hdr->hdr_lba_start); 9551c2dee3cSRobert Noland le64enc(buf + 48, table->hdr->hdr_lba_end); 9561c2dee3cSRobert Noland le_uuid_enc(buf + 56, &table->hdr->hdr_uuid); 9571c2dee3cSRobert Noland le32enc(buf + 80, table->hdr->hdr_entries); 9581c2dee3cSRobert Noland le32enc(buf + 84, table->hdr->hdr_entsz); 9591d3aed33SMarcel Moolenaar 9601d3aed33SMarcel Moolenaar LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { 961d287f590SMarcel Moolenaar if (baseentry->gpe_deleted) 962d287f590SMarcel Moolenaar continue; 9631d3aed33SMarcel Moolenaar entry = (struct g_part_gpt_entry *)baseentry; 9641d3aed33SMarcel Moolenaar index = baseentry->gpe_index - 1; 9651c2dee3cSRobert Noland bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index; 9661d3aed33SMarcel Moolenaar le_uuid_enc(bp, &entry->ent.ent_type); 9671d3aed33SMarcel Moolenaar le_uuid_enc(bp + 16, &entry->ent.ent_uuid); 9681d3aed33SMarcel Moolenaar le64enc(bp + 32, entry->ent.ent_lba_start); 9691d3aed33SMarcel Moolenaar le64enc(bp + 40, entry->ent.ent_lba_end); 9701d3aed33SMarcel Moolenaar le64enc(bp + 48, entry->ent.ent_attr); 9711d3aed33SMarcel Moolenaar memcpy(bp + 56, entry->ent.ent_name, 9721d3aed33SMarcel Moolenaar sizeof(entry->ent.ent_name)); 9731d3aed33SMarcel Moolenaar } 9741d3aed33SMarcel Moolenaar 9751d3aed33SMarcel Moolenaar crc = crc32(buf + pp->sectorsize, 9761c2dee3cSRobert Noland table->hdr->hdr_entries * table->hdr->hdr_entsz); 9771d3aed33SMarcel Moolenaar le32enc(buf + 88, crc); 9781d3aed33SMarcel Moolenaar 9791d3aed33SMarcel Moolenaar /* Write primary meta-data. */ 9801d3aed33SMarcel Moolenaar le32enc(buf + 16, 0); /* hdr_crc_self. */ 9811d3aed33SMarcel Moolenaar le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_self. */ 9821d3aed33SMarcel Moolenaar le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_alt. */ 9831d3aed33SMarcel Moolenaar le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]); /* hdr_lba_table. */ 9841c2dee3cSRobert Noland crc = crc32(buf, table->hdr->hdr_size); 9851d3aed33SMarcel Moolenaar le32enc(buf + 16, crc); 9861d3aed33SMarcel Moolenaar 9871d3aed33SMarcel Moolenaar error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize, 988*e7926a37SAndrey V. Elsukov buf + pp->sectorsize, tblsz * pp->sectorsize); 9891d3aed33SMarcel Moolenaar if (error) 9901d3aed33SMarcel Moolenaar goto out; 9911d3aed33SMarcel Moolenaar error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize, 9921d3aed33SMarcel Moolenaar buf, pp->sectorsize); 9931d3aed33SMarcel Moolenaar if (error) 9941d3aed33SMarcel Moolenaar goto out; 9951d3aed33SMarcel Moolenaar 9961d3aed33SMarcel Moolenaar /* Write secondary meta-data. */ 9971d3aed33SMarcel Moolenaar le32enc(buf + 16, 0); /* hdr_crc_self. */ 9981d3aed33SMarcel Moolenaar le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_self. */ 9991d3aed33SMarcel Moolenaar le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_alt. */ 10001d3aed33SMarcel Moolenaar le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]); /* hdr_lba_table. */ 10011c2dee3cSRobert Noland crc = crc32(buf, table->hdr->hdr_size); 10021d3aed33SMarcel Moolenaar le32enc(buf + 16, crc); 10031d3aed33SMarcel Moolenaar 10041d3aed33SMarcel Moolenaar error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize, 1005*e7926a37SAndrey V. Elsukov buf + pp->sectorsize, tblsz * pp->sectorsize); 10061d3aed33SMarcel Moolenaar if (error) 10071d3aed33SMarcel Moolenaar goto out; 10081d3aed33SMarcel Moolenaar error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize, 10091d3aed33SMarcel Moolenaar buf, pp->sectorsize); 10101d3aed33SMarcel Moolenaar 10111d3aed33SMarcel Moolenaar out: 10121d3aed33SMarcel Moolenaar g_free(buf); 10131d3aed33SMarcel Moolenaar return (error); 10141d3aed33SMarcel Moolenaar } 10151d3aed33SMarcel Moolenaar 10161d3aed33SMarcel Moolenaar static void 1017d3532631SMarcel Moolenaar g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len) 10181d3aed33SMarcel Moolenaar { 10191d3aed33SMarcel Moolenaar u_int bo; 10201d3aed33SMarcel Moolenaar uint32_t ch; 10211d3aed33SMarcel Moolenaar uint16_t c; 10221d3aed33SMarcel Moolenaar 1023d3532631SMarcel Moolenaar bo = LITTLE_ENDIAN; /* GPT is little-endian */ 10241d3aed33SMarcel Moolenaar while (len > 0 && *str != 0) { 10251d3aed33SMarcel Moolenaar ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str); 10261d3aed33SMarcel Moolenaar str++, len--; 10271d3aed33SMarcel Moolenaar if ((ch & 0xf800) == 0xd800) { 10281d3aed33SMarcel Moolenaar if (len > 0) { 10291d3aed33SMarcel Moolenaar c = (bo == BIG_ENDIAN) ? be16toh(*str) 10301d3aed33SMarcel Moolenaar : le16toh(*str); 10311d3aed33SMarcel Moolenaar str++, len--; 10321d3aed33SMarcel Moolenaar } else 10331d3aed33SMarcel Moolenaar c = 0xfffd; 10341d3aed33SMarcel Moolenaar if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) { 10351d3aed33SMarcel Moolenaar ch = ((ch & 0x3ff) << 10) + (c & 0x3ff); 10361d3aed33SMarcel Moolenaar ch += 0x10000; 10371d3aed33SMarcel Moolenaar } else 10381d3aed33SMarcel Moolenaar ch = 0xfffd; 10391d3aed33SMarcel Moolenaar } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */ 10401d3aed33SMarcel Moolenaar bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN; 10411d3aed33SMarcel Moolenaar continue; 10421d3aed33SMarcel Moolenaar } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */ 10431d3aed33SMarcel Moolenaar continue; 10441d3aed33SMarcel Moolenaar 1045d3532631SMarcel Moolenaar /* Write the Unicode character in UTF-8 */ 10461d3aed33SMarcel Moolenaar if (ch < 0x80) 10471d3aed33SMarcel Moolenaar sbuf_printf(sb, "%c", ch); 10481d3aed33SMarcel Moolenaar else if (ch < 0x800) 10491d3aed33SMarcel Moolenaar sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6), 10501d3aed33SMarcel Moolenaar 0x80 | (ch & 0x3f)); 10511d3aed33SMarcel Moolenaar else if (ch < 0x10000) 10521d3aed33SMarcel Moolenaar sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12), 10531d3aed33SMarcel Moolenaar 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 10541d3aed33SMarcel Moolenaar else if (ch < 0x200000) 10551d3aed33SMarcel Moolenaar sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18), 10561d3aed33SMarcel Moolenaar 0x80 | ((ch >> 12) & 0x3f), 10571d3aed33SMarcel Moolenaar 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 10581d3aed33SMarcel Moolenaar } 10591d3aed33SMarcel Moolenaar } 1060d3532631SMarcel Moolenaar 1061d3532631SMarcel Moolenaar static void 1062d3532631SMarcel Moolenaar g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len) 1063d3532631SMarcel Moolenaar { 1064d3532631SMarcel Moolenaar size_t s16idx, s8idx; 1065d3532631SMarcel Moolenaar uint32_t utfchar; 1066d3532631SMarcel Moolenaar unsigned int c, utfbytes; 1067d3532631SMarcel Moolenaar 1068d3532631SMarcel Moolenaar s8idx = s16idx = 0; 1069d3532631SMarcel Moolenaar utfchar = 0; 1070d3532631SMarcel Moolenaar utfbytes = 0; 1071d3532631SMarcel Moolenaar bzero(s16, s16len << 1); 1072d3532631SMarcel Moolenaar while (s8[s8idx] != 0 && s16idx < s16len) { 1073d3532631SMarcel Moolenaar c = s8[s8idx++]; 1074d3532631SMarcel Moolenaar if ((c & 0xc0) != 0x80) { 1075d3532631SMarcel Moolenaar /* Initial characters. */ 1076d3532631SMarcel Moolenaar if (utfbytes != 0) { 1077d3532631SMarcel Moolenaar /* Incomplete encoding of previous char. */ 1078d3532631SMarcel Moolenaar s16[s16idx++] = htole16(0xfffd); 1079d3532631SMarcel Moolenaar } 1080d3532631SMarcel Moolenaar if ((c & 0xf8) == 0xf0) { 1081d3532631SMarcel Moolenaar utfchar = c & 0x07; 1082d3532631SMarcel Moolenaar utfbytes = 3; 1083d3532631SMarcel Moolenaar } else if ((c & 0xf0) == 0xe0) { 1084d3532631SMarcel Moolenaar utfchar = c & 0x0f; 1085d3532631SMarcel Moolenaar utfbytes = 2; 1086d3532631SMarcel Moolenaar } else if ((c & 0xe0) == 0xc0) { 1087d3532631SMarcel Moolenaar utfchar = c & 0x1f; 1088d3532631SMarcel Moolenaar utfbytes = 1; 1089d3532631SMarcel Moolenaar } else { 1090d3532631SMarcel Moolenaar utfchar = c & 0x7f; 1091d3532631SMarcel Moolenaar utfbytes = 0; 1092d3532631SMarcel Moolenaar } 1093d3532631SMarcel Moolenaar } else { 1094d3532631SMarcel Moolenaar /* Followup characters. */ 1095d3532631SMarcel Moolenaar if (utfbytes > 0) { 1096d3532631SMarcel Moolenaar utfchar = (utfchar << 6) + (c & 0x3f); 1097d3532631SMarcel Moolenaar utfbytes--; 1098d3532631SMarcel Moolenaar } else if (utfbytes == 0) 1099d3532631SMarcel Moolenaar utfbytes = ~0; 1100d3532631SMarcel Moolenaar } 1101d3532631SMarcel Moolenaar /* 1102d3532631SMarcel Moolenaar * Write the complete Unicode character as UTF-16 when we 1103d3532631SMarcel Moolenaar * have all the UTF-8 charactars collected. 1104d3532631SMarcel Moolenaar */ 1105d3532631SMarcel Moolenaar if (utfbytes == 0) { 1106d3532631SMarcel Moolenaar /* 1107d3532631SMarcel Moolenaar * If we need to write 2 UTF-16 characters, but 1108d3532631SMarcel Moolenaar * we only have room for 1, then we truncate the 1109d3532631SMarcel Moolenaar * string by writing a 0 instead. 1110d3532631SMarcel Moolenaar */ 1111d3532631SMarcel Moolenaar if (utfchar >= 0x10000 && s16idx < s16len - 1) { 1112d3532631SMarcel Moolenaar s16[s16idx++] = 1113d3532631SMarcel Moolenaar htole16(0xd800 | ((utfchar >> 10) - 0x40)); 1114d3532631SMarcel Moolenaar s16[s16idx++] = 1115d3532631SMarcel Moolenaar htole16(0xdc00 | (utfchar & 0x3ff)); 1116d3532631SMarcel Moolenaar } else 1117d3532631SMarcel Moolenaar s16[s16idx++] = (utfchar >= 0x10000) ? 0 : 1118d3532631SMarcel Moolenaar htole16(utfchar); 1119d3532631SMarcel Moolenaar } 1120d3532631SMarcel Moolenaar } 1121d3532631SMarcel Moolenaar /* 1122d3532631SMarcel Moolenaar * If our input string was truncated, append an invalid encoding 1123d3532631SMarcel Moolenaar * character to the output string. 1124d3532631SMarcel Moolenaar */ 1125d3532631SMarcel Moolenaar if (utfbytes != 0 && s16idx < s16len) 1126d3532631SMarcel Moolenaar s16[s16idx++] = htole16(0xfffd); 1127d3532631SMarcel Moolenaar } 1128