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