2 * Copyright (c) 2014 Juniper Networks, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
31 #include <sys/diskmbr.h>
32 #include <sys/endian.h>
33 #include <sys/errno.h>
46 #ifndef GPT_ENT_TYPE_FREEBSD_NANDFS
47 #define GPT_ENT_TYPE_FREEBSD_NANDFS \
48 {0x74ba7dd9,0xa689,0x11e1,0xbd,0x04,{0x00,0xe0,0x81,0x28,0x6a,0xcf}}
51 static uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI;
52 static uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
53 static uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
54 static uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
55 static uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
56 static uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
57 static uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
58 static uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
59 static uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
61 static struct mkimg_alias gpt_aliases[] = {
62 { ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) },
63 { ALIAS_FREEBSD, ALIAS_PTR2TYPE(&gpt_uuid_freebsd) },
64 { ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_boot) },
65 { ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_nandfs) },
66 { ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_swap) },
67 { ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_ufs) },
68 { ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) },
69 { ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) },
70 { ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) },
71 { ALIAS_NONE, 0 } /* Keep last! */
74 /* CRC32 code derived from work by Gary S. Brown. */
75 static const uint32_t crc32_tab[] = {
76 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
77 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
78 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
79 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
80 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
81 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
82 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
83 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
84 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
85 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
86 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
87 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
88 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
89 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
90 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
91 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
92 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
93 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
94 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
95 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
96 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
97 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
98 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
99 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
100 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
101 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
102 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
103 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
104 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
105 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
106 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
107 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
108 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
109 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
110 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
111 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
112 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
113 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
114 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
115 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
116 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
117 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
118 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
122 crc32(const void *buf, size_t sz)
124 const uint8_t *p = (const uint8_t *)buf;
128 crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
133 gpt_uuid_enc(void *buf, const uuid_t *uuid)
138 le32enc(p, uuid->time_low);
139 le16enc(p + 4, uuid->time_mid);
140 le16enc(p + 6, uuid->time_hi_and_version);
141 p[8] = uuid->clock_seq_hi_and_reserved;
142 p[9] = uuid->clock_seq_low;
143 for (i = 0; i < _UUID_NODE_LEN; i++)
144 p[10 + i] = uuid->node[i];
152 ents = secsz / sizeof(struct gpt_ent);
153 return ((nparts + ents - 1) / ents);
157 gpt_metadata(u_int where, lba_t blk)
160 if (where == SCHEME_META_IMG_START || where == SCHEME_META_IMG_END) {
162 blk += (where == SCHEME_META_IMG_START) ? 2 : 1;
164 return (round_block(blk));
168 gpt_write_pmbr(lba_t blks, void *bootcode)
174 secs = (blks > UINT32_MAX) ? UINT32_MAX : (uint32_t)blks;
176 pmbr = malloc(secsz);
179 if (bootcode != NULL) {
180 memcpy(pmbr, bootcode, DOSPARTOFF);
181 memset(pmbr + DOSPARTOFF, 0, secsz - DOSPARTOFF);
183 memset(pmbr, 0, secsz);
184 pmbr[DOSPARTOFF + 2] = 2;
185 pmbr[DOSPARTOFF + 4] = 0xee;
186 pmbr[DOSPARTOFF + 5] = 0xff;
187 pmbr[DOSPARTOFF + 6] = 0xff;
188 pmbr[DOSPARTOFF + 7] = 0xff;
189 le32enc(pmbr + DOSPARTOFF + 8, 1);
190 le32enc(pmbr + DOSPARTOFF + 12, secs);
191 le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC);
192 error = image_write(0, pmbr, 1);
197 static struct gpt_ent *
198 gpt_mktbl(u_int tblsz)
201 struct gpt_ent *tbl, *ent;
205 tbl = calloc(tblsz, secsz);
209 STAILQ_FOREACH(part, &partlist, link) {
210 ent = tbl + part->index;
211 gpt_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type));
213 gpt_uuid_enc(&ent->ent_uuid, &uuid);
214 le64enc(&ent->ent_lba_start, part->block);
215 le64enc(&ent->ent_lba_end, part->block + part->size - 1);
216 if (part->label != NULL) {
218 while ((c = part->label[idx]) != '\0') {
219 le16enc(ent->ent_name + idx, c);
228 gpt_write_hdr(struct gpt_hdr *hdr, uint64_t self, uint64_t alt, uint64_t tbl)
232 le64enc(&hdr->hdr_lba_self, self);
233 le64enc(&hdr->hdr_lba_alt, alt);
234 le64enc(&hdr->hdr_lba_table, tbl);
235 hdr->hdr_crc_self = 0;
236 crc = crc32(hdr, offsetof(struct gpt_hdr, padding));
237 le64enc(&hdr->hdr_crc_self, crc);
238 return (image_write(self, hdr, 1));
242 gpt_write(lba_t imgsz, void *bootcode)
252 error = gpt_write_pmbr(imgsz, bootcode);
258 tbl = gpt_mktbl(tblsz);
261 error = image_write(2, tbl, tblsz);
264 error = image_write(imgsz - (tblsz + 1), tbl, tblsz);
274 memset(hdr, 0, secsz);
275 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
276 le32enc(&hdr->hdr_revision, GPT_HDR_REVISION);
277 le32enc(&hdr->hdr_size, offsetof(struct gpt_hdr, padding));
278 le64enc(&hdr->hdr_lba_start, 2 + tblsz);
279 le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2);
281 gpt_uuid_enc(&hdr->hdr_uuid, &uuid);
282 le32enc(&hdr->hdr_entries, nparts);
283 le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent));
284 crc = crc32(tbl, nparts * sizeof(struct gpt_ent));
285 le32enc(&hdr->hdr_crc_table, crc);
286 error = gpt_write_hdr(hdr, 1, imgsz - 1, 2);
288 error = gpt_write_hdr(hdr, imgsz - 1, 1, imgsz - tblsz - 1);
296 static struct mkimg_scheme gpt_scheme = {
298 .description = "GUID Partition Table",
299 .aliases = gpt_aliases,
300 .metadata = gpt_metadata,
308 SCHEME_DEFINE(gpt_scheme);