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