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