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