LCOV - code coverage report
Current view: top level - module/bdev/gpt - gpt.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 136 150 90.7 %
Date: 2024-12-02 08:25:18 Functions: 10 10 100.0 %

          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             :         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             :         uint32_t total_partition_size, num_partition_entries, partition_entry_size;
      82             :         uint64_t partition_start_lba;
      83           9 :         struct spdk_gpt_header *head = gpt->header;
      84             :         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             :         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             :         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          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             :         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             :         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             :         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)

Generated by: LCOV version 1.15