1 /*- 2 * Copyright (c) 2014 Juniper Networks, Inc. 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 * 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 #include <sys/diskmbr.h> 32 #include <sys/endian.h> 33 #include <sys/errno.h> 34 #include <sys/gpt.h> 35 #include <stddef.h> 36 #include <stdint.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <uuid.h> 41 42 #include "mkimg.h" 43 #include "scheme.h" 44 45 #ifndef GPT_ENT_TYPE_FREEBSD_NANDFS 46 #define GPT_ENT_TYPE_FREEBSD_NANDFS \ 47 {0x74ba7dd9,0xa689,0x11e1,0xbd,0x04,{0x00,0xe0,0x81,0x28,0x6a,0xcf}} 48 #endif 49 50 static uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; 51 static uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; 52 static uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 53 static uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; 54 static uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 55 static uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 56 static uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; 57 static uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 58 static uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR; 59 60 static struct mkimg_alias gpt_aliases[] = { 61 { ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) }, 62 { ALIAS_FREEBSD, ALIAS_PTR2TYPE(&gpt_uuid_freebsd) }, 63 { ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_boot) }, 64 { ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_nandfs) }, 65 { ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_swap) }, 66 { ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_ufs) }, 67 { ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) }, 68 { ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) }, 69 { ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) }, 70 { ALIAS_NONE, 0 } /* Keep last! */ 71 }; 72 73 /* CRC32 code derived from work by Gary S. Brown. */ 74 static const uint32_t crc32_tab[] = { 75 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 76 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 77 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 78 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 79 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 80 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 81 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 82 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 83 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 84 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 85 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 86 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 87 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 88 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 89 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 90 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 91 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 92 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 93 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 94 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 95 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 96 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 97 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 98 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 99 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 100 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 101 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 102 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 103 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 104 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 105 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 106 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 107 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 108 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 109 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 110 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 111 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 112 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 113 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 114 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 115 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 116 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 117 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 118 }; 119 120 static uint32_t 121 crc32(const void *buf, size_t sz) 122 { 123 const uint8_t *p = (const uint8_t *)buf; 124 uint32_t crc = ~0U; 125 126 while (sz--) 127 crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); 128 return (crc ^ ~0U); 129 } 130 131 static void 132 gpt_uuid_enc(void *buf, const uuid_t *uuid) 133 { 134 uint8_t *p = buf; 135 int i; 136 137 le32enc(p, uuid->time_low); 138 le16enc(p + 4, uuid->time_mid); 139 le16enc(p + 6, uuid->time_hi_and_version); 140 p[8] = uuid->clock_seq_hi_and_reserved; 141 p[9] = uuid->clock_seq_low; 142 for (i = 0; i < _UUID_NODE_LEN; i++) 143 p[10 + i] = uuid->node[i]; 144 } 145 146 static u_int 147 gpt_tblsz(void) 148 { 149 u_int ents; 150 151 ents = secsz / sizeof(struct gpt_ent); 152 return ((nparts + ents - 1) / ents); 153 } 154 155 static u_int 156 gpt_metadata(u_int where) 157 { 158 u_int secs; 159 160 if (where != SCHEME_META_IMG_START && where != SCHEME_META_IMG_END) 161 return (0); 162 163 secs = gpt_tblsz(); 164 secs += (where == SCHEME_META_IMG_START) ? 2 : 1; 165 return (secs); 166 } 167 168 static int 169 gpt_filewrite(int fd, lba_t blk, void *buf, ssize_t bufsz) 170 { 171 int error; 172 173 error = mkimg_seek(fd, blk); 174 if (error == 0) { 175 if (write(fd, buf, bufsz) != bufsz) 176 error = errno; 177 } 178 return (error); 179 } 180 181 static int 182 gpt_write_pmbr(int fd, lba_t blks, void *bootcode) 183 { 184 u_char *pmbr; 185 uint32_t secs; 186 int error; 187 188 secs = (blks > UINT32_MAX) ? UINT32_MAX : (uint32_t)blks; 189 190 pmbr = malloc(secsz); 191 if (pmbr == NULL) 192 return (errno); 193 if (bootcode != NULL) { 194 memcpy(pmbr, bootcode, DOSPARTOFF); 195 memset(pmbr + DOSPARTOFF, 0, secsz - DOSPARTOFF); 196 } else 197 memset(pmbr, 0, secsz); 198 pmbr[DOSPARTOFF + 2] = 2; 199 pmbr[DOSPARTOFF + 4] = 0xee; 200 pmbr[DOSPARTOFF + 5] = 0xff; 201 pmbr[DOSPARTOFF + 6] = 0xff; 202 pmbr[DOSPARTOFF + 7] = 0xff; 203 le32enc(pmbr + DOSPARTOFF + 8, 1); 204 le32enc(pmbr + DOSPARTOFF + 12, secs); 205 le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC); 206 error = gpt_filewrite(fd, 0, pmbr, secsz); 207 free(pmbr); 208 return (error); 209 } 210 211 static struct gpt_ent * 212 gpt_mktbl(u_int tblsz) 213 { 214 uuid_t uuid; 215 struct gpt_ent *tbl, *ent; 216 struct part *part; 217 int c, idx; 218 219 tbl = calloc(tblsz, secsz); 220 if (tbl == NULL) 221 return (NULL); 222 223 STAILQ_FOREACH(part, &partlist, link) { 224 ent = tbl + part->index; 225 gpt_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type)); 226 uuidgen(&uuid, 1); 227 gpt_uuid_enc(&ent->ent_uuid, &uuid); 228 le64enc(&ent->ent_lba_start, part->block); 229 le64enc(&ent->ent_lba_end, part->block + part->size - 1); 230 if (part->label != NULL) { 231 idx = 0; 232 while ((c = part->label[idx]) != '\0') { 233 le16enc(ent->ent_name + idx, c); 234 idx++; 235 } 236 } 237 } 238 return (tbl); 239 } 240 241 static int 242 gpt_write_hdr(int fd, struct gpt_hdr *hdr, uint64_t self, uint64_t alt, 243 uint64_t tbl) 244 { 245 uint32_t crc; 246 247 le64enc(&hdr->hdr_lba_self, self); 248 le64enc(&hdr->hdr_lba_alt, alt); 249 le64enc(&hdr->hdr_lba_table, tbl); 250 hdr->hdr_crc_self = 0; 251 crc = crc32(hdr, offsetof(struct gpt_hdr, padding)); 252 le64enc(&hdr->hdr_crc_self, crc); 253 return (gpt_filewrite(fd, self, hdr, secsz)); 254 } 255 256 static int 257 gpt_write(int fd, lba_t imgsz, void *bootcode) 258 { 259 uuid_t uuid; 260 struct gpt_ent *tbl; 261 struct gpt_hdr *hdr; 262 uint32_t crc; 263 u_int tblsz; 264 int error; 265 266 /* PMBR */ 267 error = gpt_write_pmbr(fd, imgsz, bootcode); 268 if (error) 269 return (error); 270 271 /* GPT table(s) */ 272 tblsz = gpt_tblsz(); 273 tbl = gpt_mktbl(tblsz); 274 if (tbl == NULL) 275 return (errno); 276 error = gpt_filewrite(fd, 2, tbl, tblsz * secsz); 277 if (error) 278 goto out; 279 error = gpt_filewrite(fd, imgsz - (tblsz + 1), tbl, tblsz * secsz); 280 if (error) 281 goto out; 282 283 /* GPT header(s) */ 284 hdr = malloc(secsz); 285 if (hdr == NULL) { 286 error = errno; 287 goto out; 288 } 289 memset(hdr, 0, secsz); 290 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 291 le32enc(&hdr->hdr_revision, GPT_HDR_REVISION); 292 le32enc(&hdr->hdr_size, offsetof(struct gpt_hdr, padding)); 293 le64enc(&hdr->hdr_lba_start, 2 + tblsz); 294 le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2); 295 uuidgen(&uuid, 1); 296 gpt_uuid_enc(&hdr->hdr_uuid, &uuid); 297 le32enc(&hdr->hdr_entries, nparts); 298 le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent)); 299 crc = crc32(tbl, nparts * sizeof(struct gpt_ent)); 300 le32enc(&hdr->hdr_crc_table, crc); 301 error = gpt_write_hdr(fd, hdr, 1, imgsz - 1, 2); 302 if (!error) 303 error = gpt_write_hdr(fd, hdr, imgsz - 1, 1, imgsz - tblsz - 1); 304 free(hdr); 305 306 out: 307 free(tbl); 308 return (error); 309 } 310 311 static struct mkimg_scheme gpt_scheme = { 312 .name = "gpt", 313 .description = "GUID Partition Table", 314 .aliases = gpt_aliases, 315 .metadata = gpt_metadata, 316 .write = gpt_write, 317 .nparts = 4096, 318 .labellen = 36, 319 .bootcode = 512, 320 .maxsecsz = 4096 321 }; 322 323 SCHEME_DEFINE(gpt_scheme); 324