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