xref: /spdk/module/bdev/gpt/gpt.c (revision 0ed85362c8132a2d1927757fbcade66b6660d26a)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "gpt.h"
35 
36 #include "spdk/crc32.h"
37 #include "spdk/endian.h"
38 #include "spdk/event.h"
39 
40 #include "spdk_internal/log.h"
41 
42 #define GPT_PRIMARY_PARTITION_TABLE_LBA 0x1
43 #define PRIMARY_PARTITION_NUMBER 4
44 #define GPT_PROTECTIVE_MBR 1
45 #define SPDK_MAX_NUM_PARTITION_ENTRIES 128
46 
47 static uint64_t
48 gpt_get_expected_head_lba(struct spdk_gpt *gpt)
49 {
50 	switch (gpt->parse_phase) {
51 	case SPDK_GPT_PARSE_PHASE_PRIMARY:
52 		return GPT_PRIMARY_PARTITION_TABLE_LBA;
53 	case SPDK_GPT_PARSE_PHASE_SECONDARY:
54 		return gpt->lba_end;
55 	default:
56 		assert(false);
57 	}
58 	return 0;
59 }
60 
61 static struct spdk_gpt_header *
62 gpt_get_header_buf(struct spdk_gpt *gpt)
63 {
64 	switch (gpt->parse_phase) {
65 	case SPDK_GPT_PARSE_PHASE_PRIMARY:
66 		return (struct spdk_gpt_header *)
67 		       (gpt->buf + GPT_PRIMARY_PARTITION_TABLE_LBA * gpt->sector_size);
68 	case SPDK_GPT_PARSE_PHASE_SECONDARY:
69 		return (struct spdk_gpt_header *)
70 		       (gpt->buf + (gpt->buf_size - gpt->sector_size));
71 	default:
72 		assert(false);
73 	}
74 	return NULL;
75 }
76 
77 static struct spdk_gpt_partition_entry *
78 gpt_get_partitions_buf(struct spdk_gpt *gpt, uint64_t total_partition_size,
79 		       uint64_t partition_start_lba)
80 {
81 	uint64_t secondary_total_size;
82 
83 	switch (gpt->parse_phase) {
84 	case SPDK_GPT_PARSE_PHASE_PRIMARY:
85 		if ((total_partition_size + partition_start_lba * gpt->sector_size) >
86 		    gpt->buf_size) {
87 			SPDK_ERRLOG("Buffer size is not enough\n");
88 			return NULL;
89 		}
90 		return (struct spdk_gpt_partition_entry *)
91 		       (gpt->buf + partition_start_lba * gpt->sector_size);
92 	case SPDK_GPT_PARSE_PHASE_SECONDARY:
93 		secondary_total_size = (gpt->lba_end - partition_start_lba + 1) * gpt->sector_size;
94 		if (secondary_total_size > gpt->buf_size) {
95 			SPDK_ERRLOG("Buffer size is not enough\n");
96 			return NULL;
97 		}
98 		return (struct spdk_gpt_partition_entry *)
99 		       (gpt->buf + (gpt->buf_size - secondary_total_size));
100 	default:
101 		assert(false);
102 	}
103 	return NULL;
104 }
105 
106 static int
107 gpt_read_partitions(struct spdk_gpt *gpt)
108 {
109 	uint32_t total_partition_size, num_partition_entries, partition_entry_size;
110 	uint64_t partition_start_lba;
111 	struct spdk_gpt_header *head = gpt->header;
112 	uint32_t crc32;
113 
114 	num_partition_entries = from_le32(&head->num_partition_entries);
115 	if (num_partition_entries > SPDK_MAX_NUM_PARTITION_ENTRIES) {
116 		SPDK_ERRLOG("Num_partition_entries=%u which exceeds max=%u\n",
117 			    num_partition_entries, SPDK_MAX_NUM_PARTITION_ENTRIES);
118 		return -1;
119 	}
120 
121 	partition_entry_size = from_le32(&head->size_of_partition_entry);
122 	if (partition_entry_size != sizeof(struct spdk_gpt_partition_entry)) {
123 		SPDK_ERRLOG("Partition_entry_size(%x) != expected(%lx)\n",
124 			    partition_entry_size, sizeof(struct spdk_gpt_partition_entry));
125 		return -1;
126 	}
127 
128 	total_partition_size = num_partition_entries * partition_entry_size;
129 	partition_start_lba = from_le64(&head->partition_entry_lba);
130 	gpt->partitions = gpt_get_partitions_buf(gpt, total_partition_size,
131 			  partition_start_lba);
132 	if (!gpt->partitions) {
133 		SPDK_ERRLOG("Failed to get gpt partitions buf\n");
134 		return -1;
135 	}
136 
137 	crc32 = spdk_crc32_ieee_update(gpt->partitions, total_partition_size, ~0);
138 	crc32 ^= ~0;
139 
140 	if (crc32 != from_le32(&head->partition_entry_array_crc32)) {
141 		SPDK_ERRLOG("GPT partition entry array crc32 did not match\n");
142 		return -1;
143 	}
144 
145 	return 0;
146 }
147 
148 static int
149 gpt_lba_range_check(struct spdk_gpt_header *head, uint64_t lba_end)
150 {
151 	uint64_t usable_lba_start, usable_lba_end;
152 
153 	usable_lba_start = from_le64(&head->first_usable_lba);
154 	usable_lba_end = from_le64(&head->last_usable_lba);
155 
156 	if (usable_lba_end < usable_lba_start) {
157 		SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") < usable_lba_start(%" PRIu64 ")\n",
158 			    usable_lba_end, usable_lba_start);
159 		return -1;
160 	}
161 
162 	if (usable_lba_end > lba_end) {
163 		SPDK_ERRLOG("Head's usable_lba_end(%" PRIu64 ") > lba_end(%" PRIu64 ")\n",
164 			    usable_lba_end, lba_end);
165 		return -1;
166 	}
167 
168 	if ((usable_lba_start < GPT_PRIMARY_PARTITION_TABLE_LBA) &&
169 	    (GPT_PRIMARY_PARTITION_TABLE_LBA < usable_lba_end)) {
170 		SPDK_ERRLOG("Head lba is not in the usable range\n");
171 		return -1;
172 	}
173 
174 	return 0;
175 }
176 
177 static int
178 gpt_read_header(struct spdk_gpt *gpt)
179 {
180 	uint32_t head_size;
181 	uint32_t new_crc, original_crc;
182 	uint64_t my_lba, head_lba;
183 	struct spdk_gpt_header *head;
184 
185 	head = gpt_get_header_buf(gpt);
186 	if (!head) {
187 		SPDK_ERRLOG("Failed to get gpt header buf\n");
188 		return -1;
189 	}
190 
191 	head_size = from_le32(&head->header_size);
192 	if (head_size < sizeof(*head) || head_size > gpt->sector_size) {
193 		SPDK_ERRLOG("head_size=%u\n", head_size);
194 		return -1;
195 	}
196 
197 	original_crc = from_le32(&head->header_crc32);
198 	head->header_crc32 = 0;
199 	new_crc = spdk_crc32_ieee_update(head, from_le32(&head->header_size), ~0);
200 	new_crc ^= ~0;
201 	/* restore header crc32 */
202 	to_le32(&head->header_crc32, original_crc);
203 
204 	if (new_crc != original_crc) {
205 		SPDK_ERRLOG("head crc32 does not match, provided=%u, caculated=%u\n",
206 			    original_crc, new_crc);
207 		return -1;
208 	}
209 
210 	if (memcmp(SPDK_GPT_SIGNATURE, head->gpt_signature,
211 		   sizeof(head->gpt_signature))) {
212 		SPDK_ERRLOG("signature did not match\n");
213 		return -1;
214 	}
215 
216 	head_lba = gpt_get_expected_head_lba(gpt);
217 	my_lba = from_le64(&head->my_lba);
218 	if (my_lba != head_lba) {
219 		SPDK_ERRLOG("head my_lba(%" PRIu64 ") != expected(%" PRIu64 ")\n",
220 			    my_lba, head_lba);
221 		return -1;
222 	}
223 
224 	if (gpt_lba_range_check(head, gpt->lba_end)) {
225 		SPDK_ERRLOG("lba range check error\n");
226 		return -1;
227 	}
228 
229 	gpt->header = head;
230 	return 0;
231 }
232 
233 static int
234 gpt_check_mbr(struct spdk_gpt *gpt)
235 {
236 	int i, primary_partition = 0;
237 	uint32_t total_lba_size = 0, ret = 0, expected_start_lba;
238 	struct spdk_mbr *mbr;
239 
240 	mbr = (struct spdk_mbr *)gpt->buf;
241 	if (from_le16(&mbr->mbr_signature) != SPDK_MBR_SIGNATURE) {
242 		SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "Signature mismatch, provided=%x,"
243 			      "expected=%x\n", from_le16(&mbr->disk_signature),
244 			      SPDK_MBR_SIGNATURE);
245 		return -1;
246 	}
247 
248 	for (i = 0; i < PRIMARY_PARTITION_NUMBER; i++) {
249 		if (mbr->partitions[i].os_type == SPDK_MBR_OS_TYPE_GPT_PROTECTIVE) {
250 			primary_partition = i;
251 			ret = GPT_PROTECTIVE_MBR;
252 			break;
253 		}
254 	}
255 
256 	if (ret == GPT_PROTECTIVE_MBR) {
257 		expected_start_lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
258 		if (from_le32(&mbr->partitions[primary_partition].start_lba) != expected_start_lba) {
259 			SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "start lba mismatch, provided=%u, expected=%u\n",
260 				      from_le32(&mbr->partitions[primary_partition].start_lba),
261 				      expected_start_lba);
262 			return -1;
263 		}
264 
265 		total_lba_size = from_le32(&mbr->partitions[primary_partition].size_lba);
266 		if ((total_lba_size != ((uint32_t) gpt->total_sectors - 1)) &&
267 		    (total_lba_size != 0xFFFFFFFF)) {
268 			SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE,
269 				      "GPT Primary MBR size does not equal: (record_size %u != actual_size %u)!\n",
270 				      total_lba_size, (uint32_t) gpt->total_sectors - 1);
271 			return -1;
272 		}
273 	} else {
274 		SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "Currently only support GPT Protective MBR format\n");
275 		return -1;
276 	}
277 
278 	return 0;
279 }
280 
281 int
282 gpt_parse_mbr(struct spdk_gpt *gpt)
283 {
284 	int rc;
285 
286 	if (!gpt || !gpt->buf) {
287 		SPDK_ERRLOG("Gpt and the related buffer should not be NULL\n");
288 		return -1;
289 	}
290 
291 	rc = gpt_check_mbr(gpt);
292 	if (rc) {
293 		SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE, "Failed to detect gpt in MBR\n");
294 		return rc;
295 	}
296 
297 	return 0;
298 }
299 
300 int
301 gpt_parse_partition_table(struct spdk_gpt *gpt)
302 {
303 	int rc;
304 
305 	rc = gpt_read_header(gpt);
306 	if (rc) {
307 		SPDK_ERRLOG("Failed to read gpt header\n");
308 		return rc;
309 	}
310 
311 	rc = gpt_read_partitions(gpt);
312 	if (rc) {
313 		SPDK_ERRLOG("Failed to read gpt partitions\n");
314 		return rc;
315 	}
316 
317 	return 0;
318 }
319 
320 SPDK_LOG_REGISTER_COMPONENT("gpt_parse", SPDK_LOG_GPT_PARSE)
321