diff --git a/components/drivers/include/drivers/gpt.h b/components/drivers/include/drivers/gpt.h new file mode 100644 index 0000000000000000000000000000000000000000..c1bdcb732a4c8d7f3ce09948c46c291591e9d13d --- /dev/null +++ b/components/drivers/include/drivers/gpt.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-05-05 linzhenxing first version + */ +#ifndef __GPT_H +#define __GPT_H + +#include +#include + +typedef struct +{ + uint8_t b[16]; /* GUID 16 bytes*/ +} guid_t; + +#define MSDOS_MBR_SIGNATURE 0xaa55 +#define EFI_PMBR_OSTYPE_EFI 0xEF +#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE + +#define GPT_MBR_PROTECTIVE 1 +#define GPT_MBR_HYBRID 2 + +#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL +#define GPT_HEADER_REVISION_V1 0x00010000 +#define GPT_PRIMARY_PARTITION_TABLE_LBA 1 + +typedef guid_t gpt_guid_t __attribute__ ((aligned (4))); +#define EFI_GUID(a, b, c, d...) (gpt_guid_t){ { \ + (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, d } } + +#define NULL_GUID \ + EFI_GUID(0x00000000, 0x0000, 0x0000,\ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) +#define PARTITION_SYSTEM_GUID \ + EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ + 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) +#define LEGACY_MBR_PARTITION_GUID \ + EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \ + 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F) +#define PARTITION_MSFT_RESERVED_GUID \ + EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \ + 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE) +#define PARTITION_BASIC_DATA_GUID \ + EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \ + 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) +#define PARTITION_LINUX_RAID_GUID \ + EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \ + 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e) +#define PARTITION_LINUX_SWAP_GUID \ + EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \ + 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f) +#define PARTITION_LINUX_LVM_GUID \ + EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ + 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) +#pragma pack(push, 1) +typedef struct _gpt_header +{ + uint64_t signature; + uint32_t revision; + uint32_t header_size; + uint32_t header_crc32; + uint32_t reserved1; + uint64_t start_lba; /*GPT head start sector*/ + uint64_t alternate_lba; /*GPT head alternate sector*/ + uint64_t first_usable_lba; + uint64_t last_usable_lba; + gpt_guid_t disk_guid; + uint64_t partition_entry_lba; + uint32_t num_partition_entries; + uint32_t sizeof_partition_entry; + uint32_t partition_entry_array_crc32; + + /* The rest of the logical block is reserved by UEFI and must be zero. + * EFI standard handles this by: + * + * uint8_t reserved2[ BlockSize - 92 ]; + */ +} gpt_header; + +typedef struct _gpt_entry_attributes +{ + uint64_t required_to_function:1; + uint64_t reserved:47; + uint64_t type_guid_specific:16; +} gpt_entry_attributes; + +typedef struct _gpt_entry +{ + gpt_guid_t partition_type_guid; + gpt_guid_t unique_partition_guid; + uint64_t starting_lba; + uint64_t ending_lba; + gpt_entry_attributes attributes; + uint16_t partition_name[72/sizeof(uint16_t)]; +} gpt_entry; + +typedef struct _gpt_mbr_record +{ + uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */ + uint8_t start_head; /* unused by EFI, pt start in CHS */ + uint8_t start_sector; /* unused by EFI, pt start in CHS */ + uint8_t start_track; + uint8_t os_type; /* EFI and legacy non-EFI OS types */ + uint8_t end_head; /* unused by EFI, pt end in CHS */ + uint8_t end_sector; /* unused by EFI, pt end in CHS */ + uint8_t end_track; /* unused by EFI, pt end in CHS */ + uint32_t starting_lba; /* used by EFI - start addr of the on disk pt */ + uint32_t size_in_lba; /* used by EFI - size of pt in LBA */ +} gpt_mbr_record; + + +typedef struct _legacy_mbr +{ + uint8_t boot_code[440]; + uint32_t unique_mbr_signature; + uint16_t unknown; + gpt_mbr_record partition_record[4]; + uint16_t signature; +} legacy_mbr; +#pragma pack(pop) + +int check_gpt(struct rt_mmcsd_card *card); +int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex); +void gpt_free(void); +#endif /*__GPT_H*/ diff --git a/components/drivers/include/drivers/mmcsd_card.h b/components/drivers/include/drivers/mmcsd_card.h index 3ee5a204656b72a8d8bb26a50c0130c736fe40ad..ea2de15ca53a7e8a7a1be6ab6a2235c7200f5c97 100644 --- a/components/drivers/include/drivers/mmcsd_card.h +++ b/components/drivers/include/drivers/mmcsd_card.h @@ -141,6 +141,7 @@ struct rt_mmcsd_card { rt_uint32_t max_data_rate; /* max data transfer rate */ rt_uint32_t card_capacity; /* card capacity, unit:KB */ rt_uint32_t card_blksize; /* card block size */ + rt_uint32_t card_sec_cnt; /* card sector count*/ rt_uint32_t erase_size; /* erase size in sectors */ rt_uint16_t card_type; #define CARD_TYPE_MMC 0 /* MMC card */ diff --git a/components/drivers/include/drivers/mmcsd_core.h b/components/drivers/include/drivers/mmcsd_core.h index 05a5af6d79cc5d32214682022371beff1ba80edb..e78469007a97f2b048bc90b352592f9e40acdd3e 100644 --- a/components/drivers/include/drivers/mmcsd_core.h +++ b/components/drivers/include/drivers/mmcsd_core.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -235,6 +237,7 @@ void mmcsd_free_host(struct rt_mmcsd_host *host); int rt_mmcsd_core_init(void); int rt_mmcsd_blk_init(void); +rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count); rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card); void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card); diff --git a/components/drivers/sdio/SConscript b/components/drivers/sdio/SConscript index 95dcfa2578e019e47fb128876930d41da1fdb9e3..d5b6eb1cb9b957da2ce8c877ce06b71348313107 100644 --- a/components/drivers/sdio/SConscript +++ b/components/drivers/sdio/SConscript @@ -7,6 +7,7 @@ block_dev.c mmcsd_core.c sd.c sdio.c +gpt.c mmc.c """) diff --git a/components/drivers/sdio/block_dev.c b/components/drivers/sdio/block_dev.c index 1e12735cba0457d628ead6aeb465d37104ad5ab2..1c60ec0084ca4a0c20b30524387bec1be26e544e 100644 --- a/components/drivers/sdio/block_dev.c +++ b/components/drivers/sdio/block_dev.c @@ -12,6 +12,7 @@ #include #include +#include #define DBG_TAG "SDIO" #ifdef RT_SDIO_DEBUG @@ -38,6 +39,7 @@ struct mmcsd_blk_device #ifndef RT_MMCSD_MAX_PARTITION #define RT_MMCSD_MAX_PARTITION 16 #endif +#define RT_GPT_PARTITION_MAX 128 rt_int32_t mmcsd_num_wr_blocks(struct rt_mmcsd_card *card) { @@ -339,6 +341,19 @@ static rt_int32_t mmcsd_set_blksize(struct rt_mmcsd_card *card) return 0; } +rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count) +{ + rt_uint8_t status = 0; + + status = mmcsd_set_blksize(card); + if(status) + { + return status; + } + mmcsd_delay_ms(1); + status = rt_mmcsd_req_blk(card, lba, buffer, count, 0); + return status; +} #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops mmcsd_blk_ops = @@ -352,75 +367,147 @@ const static struct rt_device_ops mmcsd_blk_ops = }; #endif -rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card) +rt_int32_t gpt_device_probe(struct rt_mmcsd_card *card) { - rt_int32_t err = 0; + rt_int32_t err = RT_EOK; rt_uint8_t i, status; - rt_uint8_t *sector; char dname[10]; char sname[16]; struct mmcsd_blk_device *blk_dev = RT_NULL; - err = mmcsd_set_blksize(card); - if(err) + blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device)); + if (!blk_dev) { - return err; + LOG_E("mmcsd:malloc memory failed!"); + return -1; } - LOG_D("probe mmcsd block device!"); + blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs * + card->host->max_seg_size) >> 9, + (card->host->max_blk_count * + card->host->max_blk_size) >> 9); + blk_dev->part.offset = 0; + blk_dev->part.size = 0; + rt_snprintf(sname, sizeof(sname)-1, "sem_%s%d", card->host->name,0); + blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO); + /* register mmcsd device */ + blk_dev->dev.type = RT_Device_Class_Block; +#ifdef RT_USING_DEVICE_OPS + blk_dev->dev.ops = &mmcsd_blk_ops; +#else + blk_dev->dev.init = rt_mmcsd_init; + blk_dev->dev.open = rt_mmcsd_open; + blk_dev->dev.close = rt_mmcsd_close; + blk_dev->dev.read = rt_mmcsd_read; + blk_dev->dev.write = rt_mmcsd_write; + blk_dev->dev.control = rt_mmcsd_control; +#endif + blk_dev->card = card; - /* get the first sector to read partition table */ - sector = (rt_uint8_t *)rt_malloc(SECTOR_SIZE); - if (sector == RT_NULL) - { - LOG_E("allocate partition sector buffer failed!"); + blk_dev->geometry.bytes_per_sector = 1<<9; + blk_dev->geometry.block_size = card->card_blksize; + blk_dev->geometry.sector_count = + card->card_capacity * (1024 / 512); - return -RT_ENOMEM; - } + blk_dev->dev.user_data = blk_dev; - status = rt_mmcsd_req_blk(card, 0, sector, 1, 0); - if (status == RT_EOK) + rt_device_register(&(blk_dev->dev), card->host->name, + RT_DEVICE_FLAG_RDWR); + rt_list_insert_after(&blk_devices, &blk_dev->list); + + for (i = 0; i < RT_GPT_PARTITION_MAX; i++) { blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device)); if (!blk_dev) { LOG_E("mmcsd:malloc memory failed!"); - return -1; + break; } - blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs * - card->host->max_seg_size) >> 9, + card->host->max_seg_size) >> 9, (card->host->max_blk_count * - card->host->max_blk_size) >> 9); - blk_dev->part.offset = 0; - blk_dev->part.size = 0; - rt_snprintf(sname, sizeof(sname)-1, "sem_%s%d", card->host->name,0); - blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO); - /* register mmcsd device */ - blk_dev->dev.type = RT_Device_Class_Block; + card->host->max_blk_size) >> 9); + + /* get the first partition */ + status = gpt_get_partition_param(card, &blk_dev->part, i); + if (status == RT_EOK) + { + rt_snprintf(dname, sizeof(dname)-1, "%s%d", card->host->name,i); + rt_snprintf(sname, sizeof(sname)-1, "sem_%s%d", card->host->name,i+1); + blk_dev->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO); + + /* register mmcsd device */ + blk_dev->dev.type = RT_Device_Class_Block; #ifdef RT_USING_DEVICE_OPS - blk_dev->dev.ops = &mmcsd_blk_ops; + blk_dev->dev.ops = &mmcsd_blk_ops; #else - blk_dev->dev.init = rt_mmcsd_init; - blk_dev->dev.open = rt_mmcsd_open; - blk_dev->dev.close = rt_mmcsd_close; - blk_dev->dev.read = rt_mmcsd_read; - blk_dev->dev.write = rt_mmcsd_write; - blk_dev->dev.control = rt_mmcsd_control; + blk_dev->dev.init = rt_mmcsd_init; + blk_dev->dev.open = rt_mmcsd_open; + blk_dev->dev.close = rt_mmcsd_close; + blk_dev->dev.read = rt_mmcsd_read; + blk_dev->dev.write = rt_mmcsd_write; + blk_dev->dev.control = rt_mmcsd_control; +#endif + blk_dev->card = card; + + blk_dev->geometry.bytes_per_sector = 1<<9; + blk_dev->geometry.block_size = card->card_blksize; + blk_dev->geometry.sector_count = blk_dev->part.size; + + blk_dev->dev.user_data = blk_dev; + + rt_device_register(&(blk_dev->dev), dname, + RT_DEVICE_FLAG_RDWR); + rt_list_insert_after(&blk_devices, &blk_dev->list); + } + else + { + rt_free(blk_dev); + blk_dev = RT_NULL; + break; + } + +#ifdef RT_USING_DFS_MNTTABLE + if (blk_dev) + { + LOG_I("try to mount file system!"); + /* try to mount file system on this block device */ + dfs_mount_device(&(blk_dev->dev)); + } #endif - blk_dev->card = card; + } + gpt_free(); - blk_dev->geometry.bytes_per_sector = 1<<9; - blk_dev->geometry.block_size = card->card_blksize; - blk_dev->geometry.sector_count = - card->card_capacity * (1024 / 512); + return err; +} - blk_dev->dev.user_data = blk_dev; +rt_int32_t mbr_device_probe(struct rt_mmcsd_card *card) +{ + rt_int32_t err = 0; + rt_uint8_t i, status; + rt_uint8_t *sector; + char dname[10]; + char sname[16]; + struct mmcsd_blk_device *blk_dev = RT_NULL; + + err = mmcsd_set_blksize(card); + if(err) + { + return err; + } + mmcsd_delay_ms(1); + /* get the first sector to read partition table */ + sector = (rt_uint8_t *)rt_malloc(SECTOR_SIZE); + if (sector == RT_NULL) + { + LOG_E("allocate partition sector buffer failed!"); - rt_device_register(&(blk_dev->dev), card->host->name, - RT_DEVICE_FLAG_RDWR); - rt_list_insert_after(&blk_devices, &blk_dev->list); + return -RT_ENOMEM; + } + status = rt_mmcsd_req_blk(card, 0, sector, 1, 0); + if (status == RT_EOK) + { for (i = 0; i < RT_MMCSD_MAX_PARTITION; i++) { blk_dev = rt_calloc(1, sizeof(struct mmcsd_blk_device)); @@ -429,11 +516,10 @@ rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card) LOG_E("mmcsd:malloc memory failed!"); break; } - blk_dev->max_req_size = BLK_MIN((card->host->max_dma_segs * - card->host->max_seg_size) >> 9, + card->host->max_seg_size) >> 9, (card->host->max_blk_count * - card->host->max_blk_size) >> 9); + card->host->max_blk_size) >> 9); /* get the first partition */ status = dfs_filesystem_get_partition(&blk_dev->part, sector, i); @@ -445,16 +531,16 @@ rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card) /* register mmcsd device */ blk_dev->dev.type = RT_Device_Class_Block; -#ifdef RT_USING_DEVICE_OPS + #ifdef RT_USING_DEVICE_OPS blk_dev->dev.ops = &mmcsd_blk_ops; -#else + #else blk_dev->dev.init = rt_mmcsd_init; blk_dev->dev.open = rt_mmcsd_open; blk_dev->dev.close = rt_mmcsd_close; blk_dev->dev.read = rt_mmcsd_read; blk_dev->dev.write = rt_mmcsd_write; blk_dev->dev.control = rt_mmcsd_control; -#endif + #endif blk_dev->card = card; blk_dev->geometry.bytes_per_sector = 1<<9; @@ -474,26 +560,43 @@ rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card) break; } -#ifdef RT_USING_DFS_MNTTABLE + #ifdef RT_USING_DFS_MNTTABLE if (blk_dev) { LOG_I("try to mount file system!"); /* try to mount file system on this block device */ dfs_mount_device(&(blk_dev->dev)); } -#endif + #endif } } else { LOG_E("read mmcsd first sector failed"); - err = -RT_ERROR; + err = -RT_ERROR; } /* release sector buffer */ rt_free(sector); return err; + +} + +rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card) +{ + uint32_t err = 0; + + LOG_D("probe mmcsd block device!"); + if (check_gpt(card) != 0) + { + err = gpt_device_probe(card); + } + else + { + err = mbr_device_probe(card); + } + return err; } void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card) diff --git a/components/drivers/sdio/gpt.c b/components/drivers/sdio/gpt.c new file mode 100644 index 0000000000000000000000000000000000000000..9d1c11e1502322ecfa503980f68c00a657278337 --- /dev/null +++ b/components/drivers/sdio/gpt.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-05-05 linzhenxing first version + */ +#include +#include +#include +#include + +#define DBG_TAG "GPT" +#ifdef RT_SDIO_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_INFO +#endif /* RT_SDIO_DEBUG */ +#include + +#define min(a, b) a < b ? a : b +static int force_gpt = 0; +static gpt_header *_gpt; +static gpt_entry *_ptes; +#define GPT_TYPE 1 +#define MBR_TYPE 0 + +static inline int efi_guidcmp (gpt_guid_t left, gpt_guid_t right) +{ + return rt_memcmp(&left, &right, sizeof (gpt_guid_t)); +} + +static uint32_t last_lba(struct rt_mmcsd_card *card) +{ + RT_ASSERT(card != RT_NULL); + return (card->card_sec_cnt) - 1; +} + +static inline int pmbr_part_valid(gpt_mbr_record *part) +{ + if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT) + { + goto invalid; + } + + /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */ + if ((uint32_t)(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) + { + goto invalid; + } + + return GPT_MBR_PROTECTIVE; +invalid: + return 0; +} + +/* +* +* return ret +* ret = 0, invalid mbr +* ret = 1, protect mbr +* ret = 2, hybrid mbr +*/ +int is_pmbr_valid(legacy_mbr *mbr, uint64_t total_sectors) +{ + uint32_t sz = 0; + int i, part = 0, ret = 0; /* invalid by default */ + + if (!mbr || (uint16_t)(mbr->signature) != MSDOS_MBR_SIGNATURE) + { + goto done; + } + + for (i = 0; i < 4; i++) + { + ret = pmbr_part_valid(&mbr->partition_record[i]); + if (ret == GPT_MBR_PROTECTIVE) + { + part = i; + /* + * Ok, we at least know that there's a protective MBR, + * now check if there are other partition types for + * hybrid MBR. + */ + goto check_hybrid; + } + } + + if (ret != GPT_MBR_PROTECTIVE) + { + goto done; + } + +check_hybrid: + for (i = 0; i < 4; i++) + { + if ((mbr->partition_record[i].os_type != + EFI_PMBR_OSTYPE_EFI_GPT) && + (mbr->partition_record[i].os_type != 0x00)) + { + ret = GPT_MBR_HYBRID; + } + + } + + /* + * Protective MBRs take up the lesser of the whole disk + * or 2 TiB (32bit LBA), ignoring the rest of the disk. + * Some partitioning programs, nonetheless, choose to set + * the size to the maximum 32-bit limitation, disregarding + * the disk size. + * + * Hybrid MBRs do not necessarily comply with this. + * + * Consider a bad value here to be a warning to support dd'ing + * an image from a smaller disk to a larger disk. + */ + if (ret == GPT_MBR_PROTECTIVE) + { + sz = (uint32_t)(mbr->partition_record[part].size_in_lba); + if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF) + { + LOG_I("GPT: mbr size in lba (%u) different than whole disk (%u).\n", + sz, min(total_sectors - 1, 0xFFFFFFFF)); + } + } + +done: + return ret; + +} + +static gpt_entry *alloc_read_gpt_entries(struct rt_mmcsd_card *card, gpt_header *gpt) +{ + size_t count; + gpt_entry *pte; + + if (!gpt) + { + return RT_NULL; + } + + count = (size_t)(gpt->num_partition_entries) * (gpt->sizeof_partition_entry); + if (!count) + { + return RT_NULL; + } + + pte = rt_malloc(count); + if (!pte) + return RT_NULL; + + if (read_lba(card, (size_t)(gpt->partition_entry_lba),(uint8_t *)pte, count/512) != RT_EOK) + { + rt_free(pte); + return RT_NULL; + } + return pte; + +} + +static gpt_header *alloc_read_gpt_header(struct rt_mmcsd_card *card, size_t lba) +{ + gpt_header *gpt; + void *buf; + + buf = rt_malloc(512); + if (!buf) + { + return RT_NULL; + } + + if (read_lba(card, lba, (uint8_t *)buf, 1) != RT_EOK) + { + rt_free(buf); + return RT_NULL; + } + gpt = (gpt_header *)buf; + + return gpt; +} + +static int is_gpt_valid(struct rt_mmcsd_card *card, size_t lba, gpt_header **gpt, gpt_entry **ptes) +{ + size_t lastlba; + + if (!ptes) + { + return 0; + } + + if (!(*gpt = alloc_read_gpt_header(card, lba))) + { + return 0; + } + + /* Check the GUID Partition Table signature */ + if ((uint64_t)((*gpt)->signature) != GPT_HEADER_SIGNATURE) + { + LOG_E("GUID Partition Table Header signature is wrong:" + "%ld != %ld\n",(uint64_t)((*gpt)->signature),(uint64_t)GPT_HEADER_SIGNATURE); + goto fail; + } + + /* Check the GUID Partition Table header size is too small */ + if ((uint32_t)((*gpt)->header_size) < sizeof(gpt_header)) + { + LOG_E("GUID Partition Table Header size is too small: %u < %zu\n", + (uint32_t)((*gpt)->header_size),sizeof(gpt_header)); + goto fail; + } + + /* Check that the start_lba entry points to the LBA that contains + * the GUID Partition Table */ + if ((uint64_t)((*gpt)->start_lba) != lba) + { + LOG_E("GPT start_lba incorrect: %ld != %ld\n", + (uint64_t)((*gpt)->start_lba), + (uint64_t)lba); + goto fail; + } + + /* Check the first_usable_lba and last_usable_lba are + * within the disk. + */ + lastlba = last_lba(card); + if ((uint64_t)((*gpt)->first_usable_lba) > lastlba) + { + LOG_E("GPT: first_usable_lba incorrect: %ld > %ld\n", + ((uint64_t)((*gpt)->first_usable_lba)), + (size_t)lastlba); + goto fail; + } + + if ((uint64_t)((*gpt)->last_usable_lba) > lastlba) + { + LOG_E("GPT: last_usable_lba incorrect: %ld > %ld\n", + (uint64_t)((*gpt)->last_usable_lba), + (size_t)lastlba); + goto fail; + } + + if ((uint64_t)((*gpt)->last_usable_lba) < (uint64_t)((*gpt)->first_usable_lba)) + { + LOG_E("GPT: last_usable_lba incorrect: %ld > %ld\n", + (uint64_t)((*gpt)->last_usable_lba), + (uint64_t)((*gpt)->first_usable_lba)); + goto fail; + } + /* Check that sizeof_partition_entry has the correct value */ + if ((uint32_t)((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) { + LOG_E("GUID Partition Entry Size check failed.\n"); + goto fail; + } + + if (!(*ptes = alloc_read_gpt_entries(card, *gpt))) + { + goto fail; + } + + /* We're done, all's well */ + return 1; + + fail: + rt_free(*gpt); + *gpt = RT_NULL; + return 0; +} + +/** + * is_pte_valid() - tests one PTE for validity + * pte:pte to check + * lastlba: last lba of the disk + * + * Description: returns 1 if valid, 0 on error. + */ +static inline int is_pte_valid(const gpt_entry *pte, const size_t lastlba) +{ + if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || + (uint64_t)(pte->starting_lba) > lastlba || + (uint64_t)(pte->ending_lba) > lastlba) + { + return 0; + } + + return 1; +} + +/** + * compare_gpts() - Search disk for valid GPT headers and PTEs + * pgpt: primary GPT header + * agpt: alternate GPT header + * lastlba: last LBA number + * + * Description: Returns nothing. Sanity checks pgpt and agpt fields + * and prints warnings on discrepancies. + * + */ +static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, size_t lastlba) +{ + int error_found = 0; + if (!pgpt || !agpt) + { + return; + } + + if ((uint64_t)(pgpt->start_lba) != (uint64_t)(agpt->alternate_lba)) + { + LOG_I("GPT:Primary header LBA != Alt. header alternate_lba\n"); + LOG_I("GPT:%lld != %lld\n", + (uint64_t)(pgpt->start_lba), + (uint64_t)(agpt->alternate_lba)); + error_found++; + } + + if ((uint64_t)(pgpt->alternate_lba) != (uint64_t)(agpt->start_lba)) + { + LOG_I("GPT:Primary header alternate_lba != Alt. header start_lba\n"); + LOG_I("GPT:%lld != %lld\n", + (uint64_t)(pgpt->alternate_lba), + (uint64_t)(agpt->start_lba)); + error_found++; + } + + if ((uint64_t)(pgpt->first_usable_lba) != (uint64_t)(agpt->first_usable_lba)) + { + LOG_I("GPT:first_usable_lbas don't match.\n"); + LOG_I("GPT:%lld != %lld\n", + (uint64_t)(pgpt->first_usable_lba), + (uint64_t)(agpt->first_usable_lba)); + error_found++; + } + + if ((uint64_t)(pgpt->last_usable_lba) != (uint64_t)(agpt->last_usable_lba)) + { + LOG_I("GPT:last_usable_lbas don't match.\n"); + LOG_I("GPT:%lld != %lld\n", + (uint64_t)(pgpt->last_usable_lba), + (uint64_t)(agpt->last_usable_lba)); + error_found++; + } + + if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) + { + LOG_I("GPT:disk_guids don't match.\n"); + error_found++; + } + + if ((pgpt->num_partition_entries) != (agpt->num_partition_entries)) + { + LOG_I("GPT:num_partition_entries don't match: " + "0x%x != 0x%x\n", + (pgpt->num_partition_entries), + (agpt->num_partition_entries)); + error_found++; + } + + if ((pgpt->sizeof_partition_entry) != (agpt->sizeof_partition_entry)) + { + LOG_I("GPT:sizeof_partition_entry values don't match: " + "0x%x != 0x%x\n", + (pgpt->sizeof_partition_entry), + (agpt->sizeof_partition_entry)); + error_found++; + } + + if ((pgpt->partition_entry_array_crc32) != (agpt->partition_entry_array_crc32)) + { + LOG_I("GPT:partition_entry_array_crc32 values don't match: " + "0x%x != 0x%x\n", + (pgpt->partition_entry_array_crc32), + (agpt->partition_entry_array_crc32)); + error_found++; + } + + if ((pgpt->alternate_lba) != lastlba) + { + LOG_I("GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); + LOG_I("GPT:%lld != %lld\n", + (uint64_t)(pgpt->alternate_lba), + (size_t)lastlba); + error_found++; + } + + if ((agpt->start_lba) != lastlba) + { + LOG_I("GPT:Alternate GPT header not at the end of the disk.\n"); + LOG_I("GPT:%lld != %lld\n", + (uint64_t)(agpt->start_lba), + (size_t)lastlba); + error_found++; + } + + if (error_found) + { + LOG_I("GPT: Use GNU Parted to correct GPT errors.\n"); + } + return; +} + +/** + * find_valid_gpt() - Search disk for valid GPT headers and PTEs + * state: disk parsed partitions + * gpt: GPT header ptr, filled on return. + * ptes: PTEs ptr, filled on return. + * + * Description: Returns 1 if valid, 0 on error. + * If valid, returns pointers to newly allocated GPT header and PTEs. + * Validity depends on PMBR being valid (or being overridden by the + * 'gpt' kernel command line option) and finding either the Primary + * GPT header and PTEs valid, or the Alternate GPT header and PTEs + * valid. If the Primary GPT header is not valid, the Alternate GPT header + * is not checked unless the 'gpt' kernel command line option is passed. + * This protects against devices which misreport their size, and forces + * the user to decide to use the Alternate GPT. + */ +static int find_valid_gpt(struct rt_mmcsd_card *card, gpt_header **gpt, + gpt_entry **ptes) +{ + int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; + gpt_header *pgpt = RT_NULL, *agpt = RT_NULL; + gpt_entry *pptes = RT_NULL, *aptes = RT_NULL; + legacy_mbr *legacymbr; + size_t total_sectors = last_lba(card) + 1; + size_t lastlba; + int status = 0; + + if (!ptes) + { + return 0; + } + + lastlba = last_lba(card); + LOG_D("total_sectors:%d, lastlba:%d\n", total_sectors, lastlba); + if (!force_gpt) + { + /* This will be added to the EFI Spec. per Intel after v1.02. */ + legacymbr = rt_malloc(512); + if (!legacymbr) + { + goto fail; + } + + status = read_lba(card, 0, (uint8_t *)legacymbr, 1); + if (status) + { + LOG_I("status:%d\n", status); + goto fail; + } + + good_pmbr = is_pmbr_valid(legacymbr, total_sectors); + rt_free(legacymbr); + + if (!good_pmbr) + { + goto fail; + } + + LOG_D("Device has a %s MBR\n", + good_pmbr == GPT_MBR_PROTECTIVE ? + "protective" : "hybrid"); + } + + good_pgpt = is_gpt_valid(card, GPT_PRIMARY_PARTITION_TABLE_LBA, + &pgpt, &pptes); + if (good_pgpt) + { + good_agpt = is_gpt_valid(card, (pgpt->alternate_lba), &agpt, &aptes); + if (!good_agpt && force_gpt) + { + good_agpt = is_gpt_valid(card, lastlba, &agpt, &aptes); + } + + /* The obviously unsuccessful case */ + if (!good_pgpt && !good_agpt) + { + goto fail; + } + + compare_gpts(pgpt, agpt, lastlba); + + /* The good cases */ + if (good_pgpt) + { + *gpt = pgpt; + *ptes = pptes; + rt_free(agpt); + rt_free(aptes); + if (!good_agpt) + { + LOG_D("Alternate GPT is invalid, using primary GPT.\n"); + } + return 1; + } + else if (good_agpt) + { + *gpt = agpt; + *ptes = aptes; + rt_free(pgpt); + rt_free(pptes); + LOG_D("Primary GPT is invalid, using alternate GPT.\n"); + return 1; + } + } + + fail: + rt_free(pgpt); + rt_free(agpt); + rt_free(pptes); + rt_free(aptes); + *gpt = RT_NULL; + *ptes = RT_NULL; + return 0; +} + +int check_gpt(struct rt_mmcsd_card *card) +{ + if (!find_valid_gpt(card, &_gpt, &_ptes) || !_gpt || !_ptes) + { + rt_free(_gpt); + rt_free(_ptes); + return MBR_TYPE; + } + return GPT_TYPE; +} + +int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex) +{ + if (!is_pte_valid(&_ptes[pindex], last_lba(card))) + { + return -1; + } + + part->offset = (off_t)(_ptes[pindex].starting_lba); + part->size = (_ptes[pindex].ending_lba) - (_ptes[pindex].starting_lba) + 1ULL; + + rt_kprintf("found part[%d], begin(sector): %d, end(sector):%d size: ", + pindex, _ptes[pindex].starting_lba, _ptes[pindex].ending_lba); + + if ((part->size >> 11) == 0) + { + rt_kprintf("%d%s", part->size >> 1, "KB\n"); /* KB */ + } + else + { + unsigned int part_size; + part_size = part->size >> 11; /* MB */ + if ((part_size >> 10) == 0) + rt_kprintf("%d.%d%s", part_size, (part->size >> 1) & 0x3FF, "MB\n"); + else + rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n"); + } + return 0; +} + +void gpt_free(void) +{ + rt_free(_ptes); + rt_free(_gpt); +} diff --git a/components/drivers/sdio/mmc.c b/components/drivers/sdio/mmc.c index e3e09d8bccf58145f4a799c75766e1d235cc24d2..ff946d93d0b876bd34b7b39372448593c8596dca 100644 --- a/components/drivers/sdio/mmc.c +++ b/components/drivers/sdio/mmc.c @@ -193,10 +193,11 @@ static int mmc_parse_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd) card->hs_max_data_rate = 52000000; card_capacity = *((rt_uint32_t *)&ext_csd[EXT_CSD_SEC_CNT]); + card->card_sec_cnt = card_capacity; card_capacity *= card->card_blksize; card_capacity >>= 10; /* unit:KB */ card->card_capacity = card_capacity; - LOG_I("emmc card capacity %d KB.", card->card_capacity); + LOG_I("emmc card capacity %d KB, card sec count:%d.", card->card_capacity, card->card_sec_cnt); return 0; } @@ -322,7 +323,7 @@ static int mmc_select_bus_width(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd) * set by drivers. */ - if (!(((host->flags & MMCSD_BUSWIDTH_8) && + if (!(((host->flags & MMCSD_BUSWIDTH_8) && ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_8) || ((host->flags & MMCSD_BUSWIDTH_4) && ext_csd_bits[idx] == EXT_CSD_BUS_WIDTH_4) || diff --git a/components/drivers/sdio/sd.c b/components/drivers/sdio/sd.c index f7e4e46720e4a4daae0d98ffdf2633650a0570cf..0e6a14db830d9b891f2f8c7f89dd0e39dfb87f42 100644 --- a/components/drivers/sdio/sd.c +++ b/components/drivers/sdio/sd.c @@ -117,8 +117,9 @@ static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card) csd->wr_blk_partial = GET_BITS(resp, 21, 1); csd->csd_crc = GET_BITS(resp, 1, 7); - card->card_blksize = 512; + card->card_blksize = 512; card->card_capacity = (csd->c_size + 1) * 512; /* unit:KB */ + card->card_sec_cnt = card->card_capacity * 2; card->tacc_clks = 0; card->tacc_ns = 0; card->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3];