4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
36 #include "spdk/crc32.h"
37 #include "spdk/endian.h"
38 #include "spdk/event.h"
40 #include "spdk_internal/log.h"
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
48 spdk_gpt_get_expected_head_lba(struct spdk_gpt
*gpt
)
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
:
61 static struct spdk_gpt_header
*
62 spdk_gpt_get_header_buf(struct spdk_gpt
*gpt
)
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
));
77 static struct spdk_gpt_partition_entry
*
78 spdk_gpt_get_partitions_buf(struct spdk_gpt
*gpt
, uint64_t total_partition_size
,
79 uint64_t partition_start_lba
)
81 uint64_t secondary_total_size
;
83 switch (gpt
->parse_phase
) {
84 case SPDK_GPT_PARSE_PHASE_PRIMARY
:
85 if ((total_partition_size
+ partition_start_lba
* gpt
->sector_size
) >
87 SPDK_ERRLOG("Buffer size is not enough\n");
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");
98 return (struct spdk_gpt_partition_entry
*)
99 (gpt
->buf
+ (gpt
->buf_size
- secondary_total_size
));
107 spdk_gpt_read_partitions(struct spdk_gpt
*gpt
)
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
;
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
);
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
));
128 total_partition_size
= num_partition_entries
* partition_entry_size
;
129 partition_start_lba
= from_le64(&head
->partition_entry_lba
);
130 gpt
->partitions
= spdk_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");
137 crc32
= spdk_crc32_ieee_update(gpt
->partitions
, total_partition_size
, ~0);
140 if (crc32
!= from_le32(&head
->partition_entry_array_crc32
)) {
141 SPDK_ERRLOG("GPT partition entry array crc32 did not match\n");
149 spdk_gpt_lba_range_check(struct spdk_gpt_header
*head
, uint64_t lba_end
)
151 uint64_t usable_lba_start
, usable_lba_end
;
153 usable_lba_start
= from_le64(&head
->first_usable_lba
);
154 usable_lba_end
= from_le64(&head
->last_usable_lba
);
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
);
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
);
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");
178 spdk_gpt_read_header(struct spdk_gpt
*gpt
)
181 uint32_t new_crc
, original_crc
;
182 uint64_t my_lba
, head_lba
;
183 struct spdk_gpt_header
*head
;
185 head
= spdk_gpt_get_header_buf(gpt
);
187 SPDK_ERRLOG("Failed to get gpt header buf\n");
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
);
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);
201 /* restore header crc32 */
202 to_le32(&head
->header_crc32
, original_crc
);
204 if (new_crc
!= original_crc
) {
205 SPDK_ERRLOG("head crc32 does not match, provided=%u, caculated=%u\n",
206 original_crc
, new_crc
);
210 if (memcmp(SPDK_GPT_SIGNATURE
, head
->gpt_signature
,
211 sizeof(head
->gpt_signature
))) {
212 SPDK_ERRLOG("signature did not match\n");
216 head_lba
= spdk_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",
224 if (spdk_gpt_lba_range_check(head
, gpt
->lba_end
)) {
225 SPDK_ERRLOG("lba range check error\n");
234 spdk_gpt_check_mbr(struct spdk_gpt
*gpt
)
236 int i
, primary_partition
= 0;
237 uint32_t total_lba_size
= 0, ret
= 0, expected_start_lba
;
238 struct spdk_mbr
*mbr
;
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
),
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
;
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
),
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);
274 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE
, "Currently only support GPT Protective MBR format\n");
282 spdk_gpt_parse_mbr(struct spdk_gpt
*gpt
)
286 if (!gpt
|| !gpt
->buf
) {
287 SPDK_ERRLOG("Gpt and the related buffer should not be NULL\n");
291 rc
= spdk_gpt_check_mbr(gpt
);
293 SPDK_DEBUGLOG(SPDK_LOG_GPT_PARSE
, "Failed to detect gpt in MBR\n");
301 spdk_gpt_parse_partition_table(struct spdk_gpt
*gpt
)
305 rc
= spdk_gpt_read_header(gpt
);
307 SPDK_ERRLOG("Failed to read gpt header\n");
311 rc
= spdk_gpt_read_partitions(gpt
);
313 SPDK_ERRLOG("Failed to read gpt partitions\n");
320 SPDK_LOG_REGISTER_COMPONENT("gpt_parse", SPDK_LOG_GPT_PARSE
)