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