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