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