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