1 #if ENABLE_FEATURE_GPT_LABEL
2 /*
3  * Copyright (C) 2010 Kevin Cernekee <cernekee@gmail.com>
4  *
5  * Licensed under GPLv2, see file LICENSE in this source tree.
6  */
7 
8 #define GPT_MAGIC 0x5452415020494645ULL
9 enum {
10 	LEGACY_GPT_TYPE = 0xee,
11 	GPT_MAX_PARTS   = 256,
12 	GPT_MAX_PART_ENTRY_LEN = 4096,
13 	GUID_LEN        = 16,
14 };
15 
16 typedef struct {
17 	uint64_t magic;
18 	uint32_t revision;
19 	uint32_t hdr_size;
20 	uint32_t hdr_crc32;
21 	uint32_t reserved;
22 	uint64_t current_lba;
23 	uint64_t backup_lba;
24 	uint64_t first_usable_lba;
25 	uint64_t last_usable_lba;
26 	uint8_t  disk_guid[GUID_LEN];
27 	uint64_t first_part_lba;
28 	uint32_t n_parts;
29 	uint32_t part_entry_len;
30 	uint32_t part_array_crc32;
31 } gpt_header;
32 
33 typedef struct {
34 	uint8_t  type_guid[GUID_LEN];
35 	uint8_t  part_guid[GUID_LEN];
36 	uint64_t lba_start;
37 	uint64_t lba_end;
38 	uint64_t flags;
39 	uint16_t name36[36];
40 } gpt_partition;
41 
42 static gpt_header *gpt_hdr;
43 
44 static char *part_array;
45 static unsigned int n_parts;
46 static unsigned int part_entry_len;
47 
48 static inline gpt_partition *
gpt_part(int i)49 gpt_part(int i)
50 {
51 	if (i >= n_parts) {
52 		return NULL;
53 	}
54 	return (gpt_partition *)&part_array[i * part_entry_len];
55 }
56 
57 static uint32_t
gpt_crc32(void * buf,int len)58 gpt_crc32(void *buf, int len)
59 {
60 	return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
61 }
62 
63 static void
gpt_print_guid(uint8_t * buf)64 gpt_print_guid(uint8_t *buf)
65 {
66 	printf(
67 		"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
68 		buf[3], buf[2], buf[1], buf[0],
69 		buf[5], buf[4],
70 		buf[7], buf[6],
71 		buf[8], buf[9],
72 		buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
73 }
74 
75 static void
gpt_print_wide36(uint16_t * s)76 gpt_print_wide36(uint16_t *s)
77 {
78 #if ENABLE_UNICODE_SUPPORT
79 	char buf[37 * 4];
80 	wchar_t wc[37];
81 	int i = 0;
82 	while (i < ARRAY_SIZE(wc)-1) {
83 		if (s[i] == 0)
84 			break;
85 		wc[i] = s[i];
86 		i++;
87 	}
88 	wc[i] = 0;
89 	if (wcstombs(buf, wc, sizeof(buf)) <= sizeof(buf)-1)
90 		fputs_stdout(printable_string(buf));
91 #else
92 	char buf[37];
93 	int i = 0;
94 	while (i < ARRAY_SIZE(buf)-1) {
95 		if (s[i] == 0)
96 			break;
97 		buf[i] = (0x20 <= s[i] && s[i] < 0x7f) ? s[i] : '?';
98 		i++;
99 	}
100 	buf[i] = '\0';
101 	fputs_stdout(buf);
102 #endif
103 }
104 
105 static void
gpt_list_table(int xtra UNUSED_PARAM)106 gpt_list_table(int xtra UNUSED_PARAM)
107 {
108 	int i;
109 	char numstr6[6];
110 
111 	smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
112 	printf("Disk %s: %llu sectors, %s\n", disk_device,
113 		(unsigned long long)total_number_of_sectors,
114 		numstr6);
115 	printf("Logical sector size: %u\n", sector_size);
116 	printf("Disk identifier (GUID): ");
117 	gpt_print_guid(gpt_hdr->disk_guid);
118 	printf("\nPartition table holds up to %u entries\n",
119 		(int)SWAP_LE32(gpt_hdr->n_parts));
120 	printf("First usable sector is %llu, last usable sector is %llu\n\n",
121 		(unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
122 		(unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
123 
124 /* "GPT fdisk" has a concept of 16-bit extension of the original MBR 8-bit type codes,
125  * which it displays here: its output columns are ... Size Code Name
126  * They are their own invention and are not stored on disk.
127  * Looks like they use them to support "hybrid" GPT: for example, they have
128  *   AddType(0x8307, "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", "Linux ARM32 root (/)");
129  * and then (code>>8) matches what you need to put into MBR's type field for such a partition.
130  * To print those codes, we'd need a GUID lookup table. Lets just drop the "Code" column instead:
131  */
132 	puts("Number  Start (sector)    End (sector)  Size Name");
133 	//    123456 123456789012345 123456789012345 12345 abc
134 	for (i = 0; i < n_parts; i++) {
135 		gpt_partition *p = gpt_part(i);
136 		if (p->lba_start) {
137 			smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
138 				numstr6, " KMGTPEZY")[0] = '\0';
139 			printf("%6u %15llu %15llu %s ",
140 				i + 1,
141 				(unsigned long long)SWAP_LE64(p->lba_start),
142 				(unsigned long long)SWAP_LE64(p->lba_end),
143 				numstr6
144 			);
145 			gpt_print_wide36(p->name36);
146 			bb_putchar('\n');
147 		}
148 	}
149 }
150 
151 static int
check_gpt_label(void)152 check_gpt_label(void)
153 {
154 	unsigned part_array_len;
155 	struct partition *first = pt_offset(MBRbuffer, 0);
156 	struct pte pe;
157 	uint32_t crc;
158 
159 	/* LBA 0 contains the legacy MBR */
160 
161 	if (!valid_part_table_flag(MBRbuffer)
162 	 || first->sys_ind != LEGACY_GPT_TYPE
163 	) {
164 		current_label_type = LABEL_DOS;
165 		return 0;
166 	}
167 
168 	/* LBA 1 contains the GPT header */
169 
170 	read_pte(&pe, 1);
171 	gpt_hdr = (void *)pe.sectorbuffer;
172 
173 	if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) {
174 		current_label_type = LABEL_DOS;
175 		return 0;
176 	}
177 
178 	init_unicode();
179 	if (!global_crc32_table) {
180 		global_crc32_new_table_le();
181 	}
182 
183 	crc = SWAP_LE32(gpt_hdr->hdr_crc32);
184 	gpt_hdr->hdr_crc32 = 0;
185 	if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) {
186 		/* FIXME: read the backup table */
187 		puts("\nwarning: GPT header CRC is invalid\n");
188 	}
189 
190 	n_parts = SWAP_LE32(gpt_hdr->n_parts);
191 	part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len);
192 	if (n_parts > GPT_MAX_PARTS
193 	 || part_entry_len > GPT_MAX_PART_ENTRY_LEN
194 	 || SWAP_LE32(gpt_hdr->hdr_size) > sector_size
195 	) {
196 		puts("\nwarning: unable to parse GPT disklabel\n");
197 		current_label_type = LABEL_DOS;
198 		return 0;
199 	}
200 
201 	part_array_len = n_parts * part_entry_len;
202 	part_array = xmalloc(part_array_len);
203 	seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
204 	if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
205 		fdisk_fatal(unable_to_read);
206 	}
207 
208 	if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) {
209 		/* FIXME: read the backup table */
210 		puts("\nwarning: GPT array CRC is invalid\n");
211 	}
212 
213 	puts("Found valid GPT with protective MBR; using GPT\n");
214 
215 	current_label_type = LABEL_GPT;
216 	return 1;
217 }
218 
219 #endif /* GPT_LABEL */
220