]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mkimg/gpt.c
Import tzdata 2018d
[FreeBSD/FreeBSD.git] / usr.bin / mkimg / gpt.c
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 - 1;
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);