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