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