xref: /freebsd/usr.bin/mkimg/gpt.c (revision 9b42d3e12ffc6896fcb4e60c1b239ddf60705831)
1a5eb4ea3SMarcel Moolenaar /*-
2a5eb4ea3SMarcel Moolenaar  * Copyright (c) 2014 Juniper Networks, Inc.
3a5eb4ea3SMarcel Moolenaar  * All rights reserved.
4a5eb4ea3SMarcel Moolenaar  *
5a5eb4ea3SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
6a5eb4ea3SMarcel Moolenaar  * modification, are permitted provided that the following conditions
7a5eb4ea3SMarcel Moolenaar  * are met:
8a5eb4ea3SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
9a5eb4ea3SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
10a5eb4ea3SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
11a5eb4ea3SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
12a5eb4ea3SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
13a5eb4ea3SMarcel Moolenaar  *
14a5eb4ea3SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a5eb4ea3SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a5eb4ea3SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a5eb4ea3SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a5eb4ea3SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a5eb4ea3SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a5eb4ea3SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a5eb4ea3SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a5eb4ea3SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a5eb4ea3SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a5eb4ea3SMarcel Moolenaar  * SUCH DAMAGE.
25a5eb4ea3SMarcel Moolenaar  */
26a5eb4ea3SMarcel Moolenaar 
27*9b42d3e1SWarner Losh #include <sys/param.h>
28a5eb4ea3SMarcel Moolenaar #include <sys/errno.h>
29a5eb4ea3SMarcel Moolenaar #include <stddef.h>
30a5eb4ea3SMarcel Moolenaar #include <stdint.h>
31a5eb4ea3SMarcel Moolenaar #include <stdlib.h>
32a5eb4ea3SMarcel Moolenaar #include <string.h>
33a5eb4ea3SMarcel Moolenaar 
3442997114SMarcel Moolenaar #include <gpt.h>
3542997114SMarcel Moolenaar #include <mbr.h>
366b123571SMarcel Moolenaar 
375aad7d9aSMarcel Moolenaar #include "endian.h"
38f0e9dcedSMarcel Moolenaar #include "image.h"
39a5eb4ea3SMarcel Moolenaar #include "mkimg.h"
40a5eb4ea3SMarcel Moolenaar #include "scheme.h"
41a5eb4ea3SMarcel Moolenaar 
4242997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI;
4342997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD;
4442997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
4542997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
4642997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
4742997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
4842997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM;
4942997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
5042997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
5142997114SMarcel Moolenaar static mkimg_uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
52f7aebfbeSNathan Whitehorn static mkimg_uuid_t gpt_uuid_prep_boot = GPT_ENT_TYPE_PREP_BOOT;
53a5eb4ea3SMarcel Moolenaar 
54a5eb4ea3SMarcel Moolenaar static struct mkimg_alias gpt_aliases[] = {
55a5eb4ea3SMarcel Moolenaar     {	ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) },
56a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD, ALIAS_PTR2TYPE(&gpt_uuid_freebsd) },
57a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_boot) },
58a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_nandfs) },
59a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_swap) },
60a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_ufs) },
61a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD_VINUM, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_vinum) },
62a5eb4ea3SMarcel Moolenaar     {	ALIAS_FREEBSD_ZFS, ALIAS_PTR2TYPE(&gpt_uuid_freebsd_zfs) },
63a5eb4ea3SMarcel Moolenaar     {	ALIAS_MBR, ALIAS_PTR2TYPE(&gpt_uuid_mbr) },
648adccff3SMarcel Moolenaar     {	ALIAS_NTFS, ALIAS_PTR2TYPE(&gpt_uuid_ms_basic_data) },
65f7aebfbeSNathan Whitehorn     {	ALIAS_PPCBOOT, ALIAS_PTR2TYPE(&gpt_uuid_prep_boot) },
66a5eb4ea3SMarcel Moolenaar     {	ALIAS_NONE, 0 }		/* Keep last! */
67a5eb4ea3SMarcel Moolenaar };
68a5eb4ea3SMarcel Moolenaar 
69a5eb4ea3SMarcel Moolenaar /* CRC32 code derived from work by Gary S. Brown. */
70a5eb4ea3SMarcel Moolenaar static const uint32_t crc32_tab[] = {
71a5eb4ea3SMarcel Moolenaar 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
72a5eb4ea3SMarcel Moolenaar 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
73a5eb4ea3SMarcel Moolenaar 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
74a5eb4ea3SMarcel Moolenaar 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
75a5eb4ea3SMarcel Moolenaar 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
76a5eb4ea3SMarcel Moolenaar 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
77a5eb4ea3SMarcel Moolenaar 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
78a5eb4ea3SMarcel Moolenaar 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
79a5eb4ea3SMarcel Moolenaar 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
80a5eb4ea3SMarcel Moolenaar 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
81a5eb4ea3SMarcel Moolenaar 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
82a5eb4ea3SMarcel Moolenaar 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
83a5eb4ea3SMarcel Moolenaar 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
84a5eb4ea3SMarcel Moolenaar 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
85a5eb4ea3SMarcel Moolenaar 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
86a5eb4ea3SMarcel Moolenaar 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
87a5eb4ea3SMarcel Moolenaar 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
88a5eb4ea3SMarcel Moolenaar 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
89a5eb4ea3SMarcel Moolenaar 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
90a5eb4ea3SMarcel Moolenaar 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
91a5eb4ea3SMarcel Moolenaar 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
92a5eb4ea3SMarcel Moolenaar 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
93a5eb4ea3SMarcel Moolenaar 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
94a5eb4ea3SMarcel Moolenaar 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
95a5eb4ea3SMarcel Moolenaar 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
96a5eb4ea3SMarcel Moolenaar 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
97a5eb4ea3SMarcel Moolenaar 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
98a5eb4ea3SMarcel Moolenaar 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
99a5eb4ea3SMarcel Moolenaar 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
100a5eb4ea3SMarcel Moolenaar 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
101a5eb4ea3SMarcel Moolenaar 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
102a5eb4ea3SMarcel Moolenaar 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
103a5eb4ea3SMarcel Moolenaar 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
104a5eb4ea3SMarcel Moolenaar 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
105a5eb4ea3SMarcel Moolenaar 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
106a5eb4ea3SMarcel Moolenaar 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
107a5eb4ea3SMarcel Moolenaar 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
108a5eb4ea3SMarcel Moolenaar 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
109a5eb4ea3SMarcel Moolenaar 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
110a5eb4ea3SMarcel Moolenaar 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
111a5eb4ea3SMarcel Moolenaar 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
112a5eb4ea3SMarcel Moolenaar 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
113a5eb4ea3SMarcel Moolenaar 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
114a5eb4ea3SMarcel Moolenaar };
115a5eb4ea3SMarcel Moolenaar 
116a5eb4ea3SMarcel Moolenaar static uint32_t
crc32(const void * buf,size_t sz)117a5eb4ea3SMarcel Moolenaar crc32(const void *buf, size_t sz)
118a5eb4ea3SMarcel Moolenaar {
119a5eb4ea3SMarcel Moolenaar 	const uint8_t *p = (const uint8_t *)buf;
120a5eb4ea3SMarcel Moolenaar 	uint32_t crc = ~0U;
121a5eb4ea3SMarcel Moolenaar 
122a5eb4ea3SMarcel Moolenaar 	while (sz--)
123a5eb4ea3SMarcel Moolenaar 		crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
124a5eb4ea3SMarcel Moolenaar 	return (crc ^ ~0U);
125a5eb4ea3SMarcel Moolenaar }
126a5eb4ea3SMarcel Moolenaar 
127*9b42d3e1SWarner Losh /*
128*9b42d3e1SWarner Losh  * Return the number of sectors needed to store the partition table.
129*9b42d3e1SWarner Losh  */
130a5eb4ea3SMarcel Moolenaar static u_int
gpt_tblsz(void)131a5eb4ea3SMarcel Moolenaar gpt_tblsz(void)
132a5eb4ea3SMarcel Moolenaar {
133*9b42d3e1SWarner Losh 	u_int eps;		/* Entries per Sector */
134a5eb4ea3SMarcel Moolenaar 
135*9b42d3e1SWarner Losh 	/*
136*9b42d3e1SWarner Losh 	 * Count the number of sectors needed for the GPT Entry Array to store
137*9b42d3e1SWarner Losh 	 * the number of partitions defined for this image.  Enforce the 16kB
138*9b42d3e1SWarner Losh 	 * minimum space for the GPT Entry Array per UEFI v2.10 Section 5.3.
139*9b42d3e1SWarner Losh 	 */
140*9b42d3e1SWarner Losh 	eps = secsz / sizeof(struct gpt_ent);
141*9b42d3e1SWarner Losh 	return (MAX(howmany(GPT_MIN_RESERVED, secsz), howmany(nparts, eps)));
142a5eb4ea3SMarcel Moolenaar }
143a5eb4ea3SMarcel Moolenaar 
14453fcdb2dSMarcel Moolenaar static lba_t
gpt_metadata(u_int where,lba_t blk)14553fcdb2dSMarcel Moolenaar gpt_metadata(u_int where, lba_t blk)
146a5eb4ea3SMarcel Moolenaar {
147a5eb4ea3SMarcel Moolenaar 
14853fcdb2dSMarcel Moolenaar 	if (where == SCHEME_META_IMG_START || where == SCHEME_META_IMG_END) {
14953fcdb2dSMarcel Moolenaar 		blk += gpt_tblsz();
15053fcdb2dSMarcel Moolenaar 		blk += (where == SCHEME_META_IMG_START) ? 2 : 1;
15153fcdb2dSMarcel Moolenaar 	}
15253fcdb2dSMarcel Moolenaar 	return (round_block(blk));
153a5eb4ea3SMarcel Moolenaar }
154a5eb4ea3SMarcel Moolenaar 
155a5eb4ea3SMarcel Moolenaar static int
gpt_write_pmbr(lba_t blks,void * bootcode)156f0e9dcedSMarcel Moolenaar gpt_write_pmbr(lba_t blks, void *bootcode)
157a5eb4ea3SMarcel Moolenaar {
158a5eb4ea3SMarcel Moolenaar 	u_char *pmbr;
159a5eb4ea3SMarcel Moolenaar 	uint32_t secs;
160a5eb4ea3SMarcel Moolenaar 	int error;
161a5eb4ea3SMarcel Moolenaar 
1626b14aecaSEmmanuel Vadot 	secs = (blks > UINT32_MAX) ? UINT32_MAX : (uint32_t)blks - 1;
163a5eb4ea3SMarcel Moolenaar 
164a5eb4ea3SMarcel Moolenaar 	pmbr = malloc(secsz);
165a5eb4ea3SMarcel Moolenaar 	if (pmbr == NULL)
166a5eb4ea3SMarcel Moolenaar 		return (errno);
167a5eb4ea3SMarcel Moolenaar 	if (bootcode != NULL) {
168a5eb4ea3SMarcel Moolenaar 		memcpy(pmbr, bootcode, DOSPARTOFF);
169a5eb4ea3SMarcel Moolenaar 		memset(pmbr + DOSPARTOFF, 0, secsz - DOSPARTOFF);
170a5eb4ea3SMarcel Moolenaar 	} else
171a5eb4ea3SMarcel Moolenaar 		memset(pmbr, 0, secsz);
172a5eb4ea3SMarcel Moolenaar 	pmbr[DOSPARTOFF + 2] = 2;
173a5eb4ea3SMarcel Moolenaar 	pmbr[DOSPARTOFF + 4] = 0xee;
174a5eb4ea3SMarcel Moolenaar 	pmbr[DOSPARTOFF + 5] = 0xff;
175a5eb4ea3SMarcel Moolenaar 	pmbr[DOSPARTOFF + 6] = 0xff;
176a5eb4ea3SMarcel Moolenaar 	pmbr[DOSPARTOFF + 7] = 0xff;
177a5eb4ea3SMarcel Moolenaar 	le32enc(pmbr + DOSPARTOFF + 8, 1);
178a5eb4ea3SMarcel Moolenaar 	le32enc(pmbr + DOSPARTOFF + 12, secs);
179a5eb4ea3SMarcel Moolenaar 	le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC);
180f0e9dcedSMarcel Moolenaar 	error = image_write(0, pmbr, 1);
181a5eb4ea3SMarcel Moolenaar 	free(pmbr);
182a5eb4ea3SMarcel Moolenaar 	return (error);
183a5eb4ea3SMarcel Moolenaar }
184a5eb4ea3SMarcel Moolenaar 
185a5eb4ea3SMarcel Moolenaar static struct gpt_ent *
gpt_mktbl(u_int tblsz)186a5eb4ea3SMarcel Moolenaar gpt_mktbl(u_int tblsz)
187a5eb4ea3SMarcel Moolenaar {
18842997114SMarcel Moolenaar 	mkimg_uuid_t uuid;
189a5eb4ea3SMarcel Moolenaar 	struct gpt_ent *tbl, *ent;
190a5eb4ea3SMarcel Moolenaar 	struct part *part;
191a5eb4ea3SMarcel Moolenaar 	int c, idx;
192a5eb4ea3SMarcel Moolenaar 
193a5eb4ea3SMarcel Moolenaar 	tbl = calloc(tblsz, secsz);
194a5eb4ea3SMarcel Moolenaar 	if (tbl == NULL)
195a5eb4ea3SMarcel Moolenaar 		return (NULL);
196a5eb4ea3SMarcel Moolenaar 
1971080fb19SMarcel Moolenaar 	TAILQ_FOREACH(part, &partlist, link) {
198a5eb4ea3SMarcel Moolenaar 		ent = tbl + part->index;
19942997114SMarcel Moolenaar 		mkimg_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type));
200f3582a72SMarcel Moolenaar 		mkimg_uuid(&uuid);
20142997114SMarcel Moolenaar 		mkimg_uuid_enc(&ent->ent_uuid, &uuid);
202a5eb4ea3SMarcel Moolenaar 		le64enc(&ent->ent_lba_start, part->block);
203a5eb4ea3SMarcel Moolenaar 		le64enc(&ent->ent_lba_end, part->block + part->size - 1);
204a5eb4ea3SMarcel Moolenaar 		if (part->label != NULL) {
205a5eb4ea3SMarcel Moolenaar 			idx = 0;
206a5eb4ea3SMarcel Moolenaar 			while ((c = part->label[idx]) != '\0') {
207a5eb4ea3SMarcel Moolenaar 				le16enc(ent->ent_name + idx, c);
208a5eb4ea3SMarcel Moolenaar 				idx++;
209a5eb4ea3SMarcel Moolenaar 			}
210a5eb4ea3SMarcel Moolenaar 		}
211a5eb4ea3SMarcel Moolenaar 	}
212a5eb4ea3SMarcel Moolenaar 	return (tbl);
213a5eb4ea3SMarcel Moolenaar }
214a5eb4ea3SMarcel Moolenaar 
215a5eb4ea3SMarcel Moolenaar static int
gpt_write_hdr(struct gpt_hdr * hdr,uint64_t self,uint64_t alt,uint64_t tbl)216f0e9dcedSMarcel Moolenaar gpt_write_hdr(struct gpt_hdr *hdr, uint64_t self, uint64_t alt, uint64_t tbl)
217a5eb4ea3SMarcel Moolenaar {
218a5eb4ea3SMarcel Moolenaar 	uint32_t crc;
219a5eb4ea3SMarcel Moolenaar 
220a5eb4ea3SMarcel Moolenaar 	le64enc(&hdr->hdr_lba_self, self);
221a5eb4ea3SMarcel Moolenaar 	le64enc(&hdr->hdr_lba_alt, alt);
222a5eb4ea3SMarcel Moolenaar 	le64enc(&hdr->hdr_lba_table, tbl);
223a5eb4ea3SMarcel Moolenaar 	hdr->hdr_crc_self = 0;
224a5eb4ea3SMarcel Moolenaar 	crc = crc32(hdr, offsetof(struct gpt_hdr, padding));
225a5eb4ea3SMarcel Moolenaar 	le64enc(&hdr->hdr_crc_self, crc);
226f0e9dcedSMarcel Moolenaar 	return (image_write(self, hdr, 1));
227a5eb4ea3SMarcel Moolenaar }
228a5eb4ea3SMarcel Moolenaar 
229a5eb4ea3SMarcel Moolenaar static int
gpt_write(lba_t imgsz,void * bootcode)230f0e9dcedSMarcel Moolenaar gpt_write(lba_t imgsz, void *bootcode)
231a5eb4ea3SMarcel Moolenaar {
23242997114SMarcel Moolenaar 	mkimg_uuid_t uuid;
233a5eb4ea3SMarcel Moolenaar 	struct gpt_ent *tbl;
234a5eb4ea3SMarcel Moolenaar 	struct gpt_hdr *hdr;
235a5eb4ea3SMarcel Moolenaar 	uint32_t crc;
236a5eb4ea3SMarcel Moolenaar 	u_int tblsz;
237a5eb4ea3SMarcel Moolenaar 	int error;
238a5eb4ea3SMarcel Moolenaar 
239a5eb4ea3SMarcel Moolenaar 	/* PMBR */
240f0e9dcedSMarcel Moolenaar 	error = gpt_write_pmbr(imgsz, bootcode);
241a5eb4ea3SMarcel Moolenaar 	if (error)
242a5eb4ea3SMarcel Moolenaar 		return (error);
243a5eb4ea3SMarcel Moolenaar 
244a5eb4ea3SMarcel Moolenaar 	/* GPT table(s) */
245a5eb4ea3SMarcel Moolenaar 	tblsz = gpt_tblsz();
246a5eb4ea3SMarcel Moolenaar 	tbl = gpt_mktbl(tblsz);
247a5eb4ea3SMarcel Moolenaar 	if (tbl == NULL)
248a5eb4ea3SMarcel Moolenaar 		return (errno);
249f0e9dcedSMarcel Moolenaar 	error = image_write(2, tbl, tblsz);
250a5eb4ea3SMarcel Moolenaar 	if (error)
251a5eb4ea3SMarcel Moolenaar 		goto out;
252f0e9dcedSMarcel Moolenaar 	error = image_write(imgsz - (tblsz + 1), tbl, tblsz);
253a5eb4ea3SMarcel Moolenaar 	if (error)
254a5eb4ea3SMarcel Moolenaar 		goto out;
255a5eb4ea3SMarcel Moolenaar 
256a5eb4ea3SMarcel Moolenaar 	/* GPT header(s) */
257a5eb4ea3SMarcel Moolenaar 	hdr = malloc(secsz);
258a5eb4ea3SMarcel Moolenaar 	if (hdr == NULL) {
259a5eb4ea3SMarcel Moolenaar 		error = errno;
260a5eb4ea3SMarcel Moolenaar 		goto out;
261a5eb4ea3SMarcel Moolenaar 	}
262a5eb4ea3SMarcel Moolenaar 	memset(hdr, 0, secsz);
263a5eb4ea3SMarcel Moolenaar 	memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
264a5eb4ea3SMarcel Moolenaar 	le32enc(&hdr->hdr_revision, GPT_HDR_REVISION);
265a5eb4ea3SMarcel Moolenaar 	le32enc(&hdr->hdr_size, offsetof(struct gpt_hdr, padding));
266a5eb4ea3SMarcel Moolenaar 	le64enc(&hdr->hdr_lba_start, 2 + tblsz);
267a5eb4ea3SMarcel Moolenaar 	le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2);
268f3582a72SMarcel Moolenaar 	mkimg_uuid(&uuid);
26942997114SMarcel Moolenaar 	mkimg_uuid_enc(&hdr->hdr_uuid, &uuid);
270835adc68SMarcel Moolenaar 	le32enc(&hdr->hdr_entries, tblsz * secsz / sizeof(struct gpt_ent));
271a5eb4ea3SMarcel Moolenaar 	le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent));
272835adc68SMarcel Moolenaar 	crc = crc32(tbl, tblsz * secsz);
273a5eb4ea3SMarcel Moolenaar 	le32enc(&hdr->hdr_crc_table, crc);
274f0e9dcedSMarcel Moolenaar 	error = gpt_write_hdr(hdr, 1, imgsz - 1, 2);
275a5eb4ea3SMarcel Moolenaar 	if (!error)
276f0e9dcedSMarcel Moolenaar 		error = gpt_write_hdr(hdr, imgsz - 1, 1, imgsz - tblsz - 1);
277a5eb4ea3SMarcel Moolenaar 	free(hdr);
278a5eb4ea3SMarcel Moolenaar 
279a5eb4ea3SMarcel Moolenaar  out:
280a5eb4ea3SMarcel Moolenaar 	free(tbl);
281a5eb4ea3SMarcel Moolenaar 	return (error);
282a5eb4ea3SMarcel Moolenaar }
283a5eb4ea3SMarcel Moolenaar 
284a5eb4ea3SMarcel Moolenaar static struct mkimg_scheme gpt_scheme = {
285a5eb4ea3SMarcel Moolenaar 	.name = "gpt",
286a5eb4ea3SMarcel Moolenaar 	.description = "GUID Partition Table",
287a5eb4ea3SMarcel Moolenaar 	.aliases = gpt_aliases,
288a5eb4ea3SMarcel Moolenaar 	.metadata = gpt_metadata,
289a5eb4ea3SMarcel Moolenaar 	.write = gpt_write,
290a5eb4ea3SMarcel Moolenaar 	.nparts = 4096,
291a5eb4ea3SMarcel Moolenaar 	.labellen = 36,
292a5eb4ea3SMarcel Moolenaar 	.bootcode = 512,
293a5eb4ea3SMarcel Moolenaar 	.maxsecsz = 4096
294a5eb4ea3SMarcel Moolenaar };
295a5eb4ea3SMarcel Moolenaar 
296a5eb4ea3SMarcel Moolenaar SCHEME_DEFINE(gpt_scheme);
297