1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2014 Juniper Networks, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
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 static mkimg_uuid_t gpt_uuid_prep_boot = GPT_ENT_TYPE_PREP_BOOT;
55 static mkimg_uuid_t gpt_uuid_hifive_bbl = GPT_ENT_TYPE_HIFIVE_BBL;
56 static mkimg_uuid_t gpt_uuid_xbootldr = GPT_ENT_TYPE_XBOOTLDR;
57 static mkimg_uuid_t gpt_uuid_hifive_fsbl = GPT_ENT_TYPE_HIFIVE_FSBL;
58
59 static struct mkimg_alias gpt_aliases[] = {
60 { ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) },
61 { ALIAS_FREEBSD, ALIAS_PTR2TYPE(&gpt_uuid_freebsd) },
62 { ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_boot) },
63 { ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_nandfs) },
64 { ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_swap) },
65 { ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_ufs) },
66 { ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) },
67 { ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) },
68 { ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) },
69 { ALIAS_NTFS, ALIAS_PTR2TYPE(&gpt_uuid_ms_basic_data) },
70 { ALIAS_PPCBOOT, ALIAS_PTR2TYPE(&gpt_uuid_prep_boot) },
71 { ALIAS_HIFIVE_BBL, ALIAS_PTR2TYPE(&gpt_uuid_hifive_bbl) },
72 { ALIAS_XBOOTLDR, ALIAS_PTR2TYPE(&gpt_uuid_xbootldr) },
73 { ALIAS_HIFIVE_FSBL, ALIAS_PTR2TYPE(&gpt_uuid_hifive_fsbl) },
74 { ALIAS_NONE, 0 } /* Keep last! */
75 };
76
77 /* CRC32 code derived from work by Gary S. Brown. */
78 static const uint32_t crc32_tab[] = {
79 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
80 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
81 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
82 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
83 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
84 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
85 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
86 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
87 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
88 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
89 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
90 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
91 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
92 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
93 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
94 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
95 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
96 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
97 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
98 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
99 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
100 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
101 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
102 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
103 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
104 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
105 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
106 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
107 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
108 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
109 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
110 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
111 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
112 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
113 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
114 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
115 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
116 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
117 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
118 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
119 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
120 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
121 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
122 };
123
124 static uint32_t
crc32(const void * buf,size_t sz)125 crc32(const void *buf, size_t sz)
126 {
127 const uint8_t *p = (const uint8_t *)buf;
128 uint32_t crc = ~0U;
129
130 while (sz--)
131 crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
132 return (crc ^ ~0U);
133 }
134
135 /*
136 * Return the number of sectors needed to store the partition table.
137 */
138 static u_int
gpt_tblsz(void)139 gpt_tblsz(void)
140 {
141 u_int eps; /* Entries per Sector */
142
143 /*
144 * Count the number of sectors needed for the GPT Entry Array to store
145 * the number of partitions defined for this image. Enforce the 16kB
146 * minimum space for the GPT Entry Array per UEFI v2.10 Section 5.3.
147 */
148 eps = secsz / sizeof(struct gpt_ent);
149 return (MAX(howmany(GPT_MIN_RESERVED, secsz), howmany(nparts, eps)));
150 }
151
152 static lba_t
gpt_metadata(u_int where,lba_t blk)153 gpt_metadata(u_int where, lba_t blk)
154 {
155
156 if (where == SCHEME_META_IMG_START || where == SCHEME_META_IMG_END) {
157 blk += gpt_tblsz();
158 blk += (where == SCHEME_META_IMG_START) ? 2 : 1;
159 }
160 return (round_block(blk));
161 }
162
163 static int
gpt_write_pmbr(lba_t blks,void * bootcode)164 gpt_write_pmbr(lba_t blks, void *bootcode)
165 {
166 u_char *pmbr;
167 uint32_t secs;
168 int error;
169
170 secs = (blks > UINT32_MAX) ? UINT32_MAX : (uint32_t)blks - 1;
171
172 pmbr = malloc(secsz);
173 if (pmbr == NULL)
174 return (errno);
175 if (bootcode != NULL) {
176 memcpy(pmbr, bootcode, DOSPARTOFF);
177 memset(pmbr + DOSPARTOFF, 0, secsz - DOSPARTOFF);
178 } else
179 memset(pmbr, 0, secsz);
180 pmbr[DOSPARTOFF + 2] = 2;
181 pmbr[DOSPARTOFF + 4] = 0xee;
182 pmbr[DOSPARTOFF + 5] = 0xff;
183 pmbr[DOSPARTOFF + 6] = 0xff;
184 pmbr[DOSPARTOFF + 7] = 0xff;
185 le32enc(pmbr + DOSPARTOFF + 8, 1);
186 le32enc(pmbr + DOSPARTOFF + 12, secs);
187 le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC);
188 error = image_write(0, pmbr, 1);
189 free(pmbr);
190 return (error);
191 }
192
193 static struct gpt_ent *
gpt_mktbl(u_int tblsz)194 gpt_mktbl(u_int tblsz)
195 {
196 mkimg_uuid_t uuid;
197 struct gpt_ent *tbl, *ent;
198 struct part *part;
199 int c, idx;
200
201 tbl = calloc(tblsz, secsz);
202 if (tbl == NULL)
203 return (NULL);
204
205 TAILQ_FOREACH(part, &partlist, link) {
206 ent = tbl + part->index;
207 mkimg_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type));
208 mkimg_uuid(&uuid);
209 mkimg_uuid_enc(&ent->ent_uuid, &uuid);
210 le64enc(&ent->ent_lba_start, part->block);
211 le64enc(&ent->ent_lba_end, part->block + part->size - 1);
212 if (part->label != NULL) {
213 idx = 0;
214 while ((c = part->label[idx]) != '\0') {
215 le16enc(ent->ent_name + idx, c);
216 idx++;
217 }
218 }
219 }
220 return (tbl);
221 }
222
223 static int
gpt_write_hdr(struct gpt_hdr * hdr,uint64_t self,uint64_t alt,uint64_t tbl)224 gpt_write_hdr(struct gpt_hdr *hdr, uint64_t self, uint64_t alt, uint64_t tbl)
225 {
226 uint32_t crc;
227
228 le64enc(&hdr->hdr_lba_self, self);
229 le64enc(&hdr->hdr_lba_alt, alt);
230 le64enc(&hdr->hdr_lba_table, tbl);
231 hdr->hdr_crc_self = 0;
232 crc = crc32(hdr, offsetof(struct gpt_hdr, padding));
233 le64enc(&hdr->hdr_crc_self, crc);
234 return (image_write(self, hdr, 1));
235 }
236
237 static int
gpt_write(lba_t imgsz,void * bootcode)238 gpt_write(lba_t imgsz, void *bootcode)
239 {
240 mkimg_uuid_t uuid;
241 struct gpt_ent *tbl;
242 struct gpt_hdr *hdr;
243 uint32_t crc;
244 u_int tblsz;
245 int error;
246
247 /* PMBR */
248 error = gpt_write_pmbr(imgsz, bootcode);
249 if (error)
250 return (error);
251
252 /* GPT table(s) */
253 tblsz = gpt_tblsz();
254 tbl = gpt_mktbl(tblsz);
255 if (tbl == NULL)
256 return (errno);
257 error = image_write(2, tbl, tblsz);
258 if (error)
259 goto out;
260 error = image_write(imgsz - (tblsz + 1), tbl, tblsz);
261 if (error)
262 goto out;
263
264 /* GPT header(s) */
265 hdr = malloc(secsz);
266 if (hdr == NULL) {
267 error = errno;
268 goto out;
269 }
270 memset(hdr, 0, secsz);
271 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
272 le32enc(&hdr->hdr_revision, GPT_HDR_REVISION);
273 le32enc(&hdr->hdr_size, offsetof(struct gpt_hdr, padding));
274 le64enc(&hdr->hdr_lba_start, 2 + tblsz);
275 le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2);
276 mkimg_uuid(&uuid);
277 mkimg_uuid_enc(&hdr->hdr_uuid, &uuid);
278 le32enc(&hdr->hdr_entries, tblsz * secsz / sizeof(struct gpt_ent));
279 le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent));
280 crc = crc32(tbl, tblsz * secsz);
281 le32enc(&hdr->hdr_crc_table, crc);
282 error = gpt_write_hdr(hdr, 1, imgsz - 1, 2);
283 if (!error)
284 error = gpt_write_hdr(hdr, imgsz - 1, 1, imgsz - tblsz - 1);
285 free(hdr);
286
287 out:
288 free(tbl);
289 return (error);
290 }
291
292 static struct mkimg_scheme gpt_scheme = {
293 .name = "gpt",
294 .description = "GUID Partition Table",
295 .aliases = gpt_aliases,
296 .metadata = gpt_metadata,
297 .write = gpt_write,
298 .nparts = 4096,
299 .labellen = 36,
300 .bootcode = 512,
301 .maxsecsz = 4096
302 };
303
304 SCHEME_DEFINE(gpt_scheme);
305