xref: /spdk/module/bdev/gpt/gpt.c (revision 45a053c5777494f4e8ce4bc1191c9de3920377f7)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "gpt.h"
7 
8 #include "spdk/crc32.h"
9 #include "spdk/endian.h"
10 #include "spdk/event.h"
11 
12 #include "spdk/log.h"
13 
14 #define GPT_PRIMARY_PARTITION_TABLE_LBA 0x1
15 #define PRIMARY_PARTITION_NUMBER 4
16 #define GPT_PROTECTIVE_MBR 1
17 #define SPDK_MAX_NUM_PARTITION_ENTRIES 128
18 
19 static uint64_t
20 gpt_get_expected_head_lba(struct spdk_gpt *gpt)
21 {
22 	switch (gpt->parse_phase) {
23 	case SPDK_GPT_PARSE_PHASE_PRIMARY:
24 		return GPT_PRIMARY_PARTITION_TABLE_LBA;
25 	case SPDK_GPT_PARSE_PHASE_SECONDARY:
26 		return gpt->lba_end;
27 	default:
28 		assert(false);
29 	}
30 	return 0;
31 }
32 
33 static struct spdk_gpt_header *
34 gpt_get_header_buf(struct spdk_gpt *gpt)
35 {
36 	switch (gpt->parse_phase) {
37 	case SPDK_GPT_PARSE_PHASE_PRIMARY:
38 		return (struct spdk_gpt_header *)
39 		       (gpt->buf + GPT_PRIMARY_PARTITION_TABLE_LBA * gpt->sector_size);
40 	case SPDK_GPT_PARSE_PHASE_SECONDARY:
41 		return (struct spdk_gpt_header *)
42 		       (gpt->buf + (gpt->buf_size - gpt->sector_size));
43 	default:
44 		assert(false);
45 	}
46 	return NULL;
47 }
48 
49 static struct spdk_gpt_partition_entry *
50 gpt_get_partitions_buf(struct spdk_gpt *gpt, uint64_t total_partition_size,
51 		       uint64_t partition_start_lba)
52 {
53 	uint64_t secondary_total_size;
54 
55 	switch (gpt->parse_phase) {
56 	case SPDK_GPT_PARSE_PHASE_PRIMARY:
57 		if ((total_partition_size + partition_start_lba * gpt->sector_size) >
58 		    gpt->buf_size) {
59 			SPDK_ERRLOG("Buffer size is not enough\n");
60 			return NULL;
61 		}
62 		return (struct spdk_gpt_partition_entry *)
63 		       (gpt->buf + partition_start_lba * gpt->sector_size);
64 	case SPDK_GPT_PARSE_PHASE_SECONDARY:
65 		secondary_total_size = (gpt->lba_end - partition_start_lba + 1) * gpt->sector_size;
66 		if (secondary_total_size > gpt->buf_size) {
67 			SPDK_ERRLOG("Buffer size is not enough\n");
68 			return NULL;
69 		}
70 		return (struct spdk_gpt_partition_entry *)
71 		       (gpt->buf + (gpt->buf_size - secondary_total_size));
72 	default:
73 		assert(false);
74 	}
75 	return NULL;
76 }
77 
78 static int
79 gpt_read_partitions(struct spdk_gpt *gpt)
80 {
81 	uint32_t total_partition_size, num_partition_entries, partition_entry_size;
82 	uint64_t partition_start_lba;
83 	struct spdk_gpt_header *head = gpt->header;
84 	uint32_t crc32;
85 
86 	num_partition_entries = from_le32(&head->num_partition_entries);
87 	if (num_partition_entries > SPDK_MAX_NUM_PARTITION_ENTRIES) {
88 		SPDK_ERRLOG("Num_partition_entries=%u which exceeds max=%u\n",
89 			    num_partition_entries, SPDK_MAX_NUM_PARTITION_ENTRIES);
90 		return -1;
91 	}
92 
93 	partition_entry_size = from_le32(&head->size_of_partition_entry);
94 	if (partition_entry_size != sizeof(struct spdk_gpt_partition_entry)) {
95 		SPDK_ERRLOG("Partition_entry_size(%x) != expected(%zx)\n",
96 			    partition_entry_size, sizeof(struct spdk_gpt_partition_entry));
97 		return -1;
98 	}
99 
100 	total_partition_size = num_partition_entries * partition_entry_size;
101 	partition_start_lba = from_le64(&head->partition_entry_lba);
102 	gpt->partitions = gpt_get_partitions_buf(gpt, total_partition_size,
103 			  partition_start_lba);
104 	if (!gpt->partitions) {
105 		SPDK_ERRLOG("Failed to get gpt partitions buf\n");
106 		return -1;
107 	}
108 
109 	crc32 = spdk_crc32_ieee_update(gpt->partitions, total_partition_size, ~0);
110 	crc32 ^= ~0;
111 
112 	if (crc32 != from_le32(&head->partition_entry_array_crc32)) {
113 		SPDK_ERRLOG("GPT partition entry array crc32 did not match\n");
114 		return -1;
115 	}
116 
117 	return 0;
118 }
119 
120 static int
121 gpt_lba_range_check(struct spdk_gpt_header *head, uint64_t lba_end)
122 {
123 	uint64_t usable_lba_start, usable_lba_end;
124 
125 	usable_lba_start = from_le64(&head->first_usable_lba);
126 	usable_lba_end = from_le64(&head->last_usable_lba);
127 
128 	if (usable_lba_end < usable_lba_start) {
129 		SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") < usable_lba_start(%" PRIu64 ")\n",
130 			    usable_lba_end, usable_lba_start);
131 		return -1;
132 	}
133 
134 	if (usable_lba_end > lba_end) {
135 		SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") > lba_end(%" PRIu64 ")\n",
136 			    usable_lba_end, lba_end);
137 		return -1;
138 	}
139 
140 	if ((usable_lba_start < GPT_PRIMARY_PARTITION_TABLE_LBA) &&
141 	    (GPT_PRIMARY_PARTITION_TABLE_LBA < usable_lba_end)) {
142 		SPDK_ERRLOG("Head lba is not in the usable range\n");
143 		return -1;
144 	}
145 
146 	return 0;
147 }
148 
149 static int
150 gpt_read_header(struct spdk_gpt *gpt)
151 {
152 	uint32_t head_size;
153 	uint32_t new_crc, original_crc;
154 	uint64_t my_lba, head_lba;
155 	struct spdk_gpt_header *head;
156 
157 	head = gpt_get_header_buf(gpt);
158 	if (!head) {
159 		SPDK_ERRLOG("Failed to get gpt header buf\n");
160 		return -1;
161 	}
162 
163 	head_size = from_le32(&head->header_size);
164 	if (head_size < sizeof(*head) || head_size > gpt->sector_size) {
165 		SPDK_ERRLOG("head_size=%u\n", head_size);
166 		return -1;
167 	}
168 
169 	original_crc = from_le32(&head->header_crc32);
170 	head->header_crc32 = 0;
171 	new_crc = spdk_crc32_ieee_update(head, from_le32(&head->header_size), ~0);
172 	new_crc ^= ~0;
173 	/* restore header crc32 */
174 	to_le32(&head->header_crc32, original_crc);
175 
176 	if (new_crc != original_crc) {
177 		SPDK_ERRLOG("head crc32 does not match, provided=%u, calculated=%u\n",
178 			    original_crc, new_crc);
179 		return -1;
180 	}
181 
182 	if (memcmp(SPDK_GPT_SIGNATURE, head->gpt_signature,
183 		   sizeof(head->gpt_signature))) {
184 		SPDK_ERRLOG("signature did not match\n");
185 		return -1;
186 	}
187 
188 	head_lba = gpt_get_expected_head_lba(gpt);
189 	my_lba = from_le64(&head->my_lba);
190 	if (my_lba != head_lba) {
191 		SPDK_ERRLOG("head my_lba(%" PRIu64 ") != expected(%" PRIu64 ")\n",
192 			    my_lba, head_lba);
193 		return -1;
194 	}
195 
196 	if (gpt_lba_range_check(head, gpt->lba_end)) {
197 		SPDK_ERRLOG("lba range check error\n");
198 		return -1;
199 	}
200 
201 	gpt->header = head;
202 	return 0;
203 }
204 
205 static int
206 gpt_check_mbr(struct spdk_gpt *gpt)
207 {
208 	int i, primary_partition = 0;
209 	uint32_t total_lba_size = 0, ret = 0, expected_start_lba;
210 	struct spdk_mbr *mbr;
211 
212 	mbr = (struct spdk_mbr *)gpt->buf;
213 	if (from_le16(&mbr->mbr_signature) != SPDK_MBR_SIGNATURE) {
214 		SPDK_DEBUGLOG(gpt_parse, "Signature mismatch, provided=%x,"
215 			      "expected=%x\n", from_le16(&mbr->disk_signature),
216 			      SPDK_MBR_SIGNATURE);
217 		return -1;
218 	}
219 
220 	for (i = 0; i < PRIMARY_PARTITION_NUMBER; i++) {
221 		if (mbr->partitions[i].os_type == SPDK_MBR_OS_TYPE_GPT_PROTECTIVE) {
222 			primary_partition = i;
223 			ret = GPT_PROTECTIVE_MBR;
224 			break;
225 		}
226 	}
227 
228 	if (ret == GPT_PROTECTIVE_MBR) {
229 		expected_start_lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
230 		if (from_le32(&mbr->partitions[primary_partition].start_lba) != expected_start_lba) {
231 			SPDK_DEBUGLOG(gpt_parse, "start lba mismatch, provided=%u, expected=%u\n",
232 				      from_le32(&mbr->partitions[primary_partition].start_lba),
233 				      expected_start_lba);
234 			return -1;
235 		}
236 
237 		total_lba_size = from_le32(&mbr->partitions[primary_partition].size_lba);
238 		if ((total_lba_size != ((uint32_t) gpt->total_sectors - 1)) &&
239 		    (total_lba_size != 0xFFFFFFFF)) {
240 			SPDK_DEBUGLOG(gpt_parse,
241 				      "GPT Primary MBR size does not equal: (record_size %u != actual_size %u)!\n",
242 				      total_lba_size, (uint32_t) gpt->total_sectors - 1);
243 			return -1;
244 		}
245 	} else {
246 		SPDK_DEBUGLOG(gpt_parse, "Currently only support GPT Protective MBR format\n");
247 		return -1;
248 	}
249 
250 	return 0;
251 }
252 
253 int
254 gpt_parse_mbr(struct spdk_gpt *gpt)
255 {
256 	int rc;
257 
258 	if (!gpt || !gpt->buf) {
259 		SPDK_ERRLOG("Gpt and the related buffer should not be NULL\n");
260 		return -1;
261 	}
262 
263 	rc = gpt_check_mbr(gpt);
264 	if (rc) {
265 		SPDK_DEBUGLOG(gpt_parse, "Failed to detect gpt in MBR\n");
266 		return rc;
267 	}
268 
269 	return 0;
270 }
271 
272 int
273 gpt_parse_partition_table(struct spdk_gpt *gpt)
274 {
275 	int rc;
276 
277 	rc = gpt_read_header(gpt);
278 	if (rc) {
279 		SPDK_ERRLOG("Failed to read gpt header\n");
280 		return rc;
281 	}
282 
283 	rc = gpt_read_partitions(gpt);
284 	if (rc) {
285 		SPDK_ERRLOG("Failed to read gpt partitions\n");
286 		return rc;
287 	}
288 
289 	return 0;
290 }
291 
292 SPDK_LOG_REGISTER_COMPONENT(gpt_parse)
293