/** * @file partition_parse.h * * Copyright (c) 2021 Semidrive Semiconductor. * All rights reserved. * * Description: * * Revision History: * ----------------- */ #ifndef __PARTITION_PARSER_H #define __PARTITION_PARSER_H #include #define INVALID_PTN -1 #define PARTITION_TYPE_MBR 0 #define PARTITION_TYPE_GPT 1 #define PARTITION_TYPE_GPT_BACKUP 2 #define GPT_HEADER_SIZE 92 #define GPT_HEADER_BLOCKS 1 #define MBR_BLOCKS 1 #define GPT_LBA 1 #define PARTITION_ENTRY_SIZE 128 /* GPT Signature should be 0x5452415020494645 */ #define GPT_SIGNATURE_1 0x54524150 #define GPT_SIGNATURE_2 0x20494645 #define MMC_MBR_SIGNATURE_BYTE_0 0x55 #define MMC_MBR_SIGNATURE_BYTE_1 0xAA /* GPT Offsets */ #define PROTECTIVE_MBR_SIZE BLOCK_SIZE #define HEADER_SIZE_OFFSET 12 #define HEADER_CRC_OFFSET 16 #define PRIMARY_HEADER_OFFSET 24 #define BACKUP_HEADER_OFFSET 32 #define FIRST_USABLE_LBA_OFFSET 40 #define LAST_USABLE_LBA_OFFSET 48 #define PARTITION_ENTRIES_OFFSET 72 #define PARTITION_COUNT_OFFSET 80 #define PENTRY_SIZE_OFFSET 84 #define PARTITION_CRC_OFFSET 88 #define MIN_PARTITION_ARRAY_SIZE 0x4000 #define PARTITION_ENTRY_LAST_LBA 40 #define UNIQUE_GUID_OFFSET 16 #define FIRST_LBA_OFFSET 32 #define LAST_LBA_OFFSET 40 #define ATTRIBUTE_FLAG_OFFSET 48 #define PARTITION_NAME_OFFSET 56 #define MAX_GPT_NAME_SIZE 72 #define PARTITION_TYPE_GUID_SIZE 16 #define UNIQUE_PARTITION_GUID_SIZE 16 #define NUM_PARTITIONS 128 #define PART_ATT_READONLY_OFFSET 60 #define MAX_PRIORITY 4 #define MAX_RETRY_COUNT 4 #define PART_ATT_PRIORITY_BIT 48 #define PART_ATT_ACTIVE_BIT 50 #define PART_ATT_MAX_RETRY_CNT_BIT 51 #define PART_ATT_SUB_PARTITION_BIT 53 #define PART_ATT_SUCCESS_BIT 54 #define PART_ATT_UNBOOTABLE_BIT 55 #define PART_ATT_PRIORITY_VAL \ ((uint64_t)(MAX_PRIORITY - 1) << PART_ATT_PRIORITY_BIT) #define PART_ATT_ACTIVE_VAL ((uint64_t)0x1 << PART_ATT_ACTIVE_BIT) #define PART_ATT_MAX_RETRY_COUNT_VAL \ ((uint64_t)(MAX_RETRY_COUNT - 1) << PART_ATT_MAX_RETRY_CNT_BIT) #define PART_ATT_SUB_PARTITION_VAL ((uint64_t)0x1 << PART_ATT_SUB_PARTITION_BIT) #define PART_ATT_SUCCESSFUL_VAL ((uint64_t)0x1 << PART_ATT_SUCCESS_BIT) #define PART_ATT_UNBOOTABLE_VAL ((uint64_t)0x1 << PART_ATT_UNBOOTABLE_BIT) #define PART_ATT_READONLY_VAL ((uint64_t)0x1 << PART_ATT_READONLY_OFFSET) /* Some useful define used to access the MBR/EBR table */ #define BLOCK_SIZE 0x200 #define TABLE_ENTRY_0 0x1BE #define TABLE_ENTRY_1 0x1CE #define TABLE_ENTRY_2 0x1DE #define TABLE_ENTRY_3 0x1EE #define TABLE_SIGNATURE 0x1FE #define TABLE_ENTRY_SIZE 0x010 #define OFFSET_STATUS 0x00 #define OFFSET_TYPE 0x04 #define OFFSET_FIRST_SEC 0x08 #define OFFSET_SIZE 0x0C #define COPYBUFF_SIZE (1024 * 16) #define BINARY_IN_TABLE_SIZE (16 * 512) #define MAX_FILE_ENTRIES 20 #define MBR_EBR_TYPE 0x05 #define MBR_MODEM_TYPE 0x06 #define MBR_MODEM_TYPE2 0x0C #define MBR_SBL1_TYPE 0x4D #define MBR_SBL2_TYPE 0x51 #define MBR_SBL3_TYPE 0x45 #define MBR_RPM_TYPE 0x47 #define MBR_TZ_TYPE 0x46 #define MBR_MODEM_ST1_TYPE 0x4A #define MBR_MODEM_ST2_TYPE 0x4B #define MBR_EFS2_TYPE 0x4E #define MBR_ABOOT_TYPE 0x4C #define MBR_BOOT_TYPE 0x48 #define MBR_SYSTEM_TYPE 0x82 #define MBR_USERDATA_TYPE 0x83 #define MBR_RECOVERY_TYPE 0x60 #define MBR_MISC_TYPE 0x63 #define MBR_PROTECTED_TYPE 0xEE #define MBR_SSD_TYPE 0x5D #define GET_PRI_GPT_SIZE(block_size) \ ((GPT_HEADER_BLOCKS + 1) * block_size + \ NUM_PARTITIONS * PARTITION_ENTRY_SIZE) #define GET_SEC_GPT_SIZE(block_size) \ (GPT_HEADER_BLOCKS * block_size + NUM_PARTITIONS * PARTITION_ENTRY_SIZE) #define GET_LWORD_FROM_BYTE(x) \ ((unsigned)*(x) | ((unsigned)*(x + 1) << 8) | ((unsigned)*(x + 2) << 16) | \ ((unsigned)*(x + 3) << 24)) #define GET_LLWORD_FROM_BYTE(x) \ ((unsigned long long)*(x) | ((unsigned long long)*(x + 1) << 8) | \ ((unsigned long long)*(x + 2) << 16) | \ ((unsigned long long)*(x + 3) << 24) | \ ((unsigned long long)*(x + 4) << 32) | \ ((unsigned long long)*(x + 5) << 40) | \ ((unsigned long long)*(x + 6) << 48) | \ ((unsigned long long)*(x + 7) << 56)) #define GET_LONG(x) \ ((uint32_t) * (x) | ((uint32_t) * (x + 1) << 8) | \ ((uint32_t) * (x + 2) << 16) | ((uint32_t) * (x + 3) << 24)) #define PUT_LONG(x, y) \ *(x) = y & 0xff; \ *(x + 1) = (y >> 8) & 0xff; \ *(x + 2) = (y >> 16) & 0xff; \ *(x + 3) = (y >> 24) & 0xff; #define PUT_LONG_LONG(x, y) \ *(x) = (y)&0xff; \ *((x) + 1) = (((y) >> 8) & 0xff); \ *((x) + 2) = (((y) >> 16) & 0xff); \ *((x) + 3) = (((y) >> 24) & 0xff); \ *((x) + 4) = (((y) >> 32) & 0xff); \ *((x) + 5) = (((y) >> 40) & 0xff); \ *((x) + 6) = (((y) >> 48) & 0xff); \ *((x) + 7) = (((y) >> 56) & 0xff); #define PT_ALWAYS(format, args...) \ ssdk_printf(SSDK_CRIT, "[INFO]GPT: %s %d " format "", __func__, __LINE__, \ ##args); #define PT_ERROR(format, args...) \ ssdk_printf(SSDK_CRIT, "[ERROR]GPT: %s %d " format "", __func__, __LINE__, \ ##args); #define PT_DBG(format, args...) \ ssdk_printf(SSDK_INFO, "[DEBUG]GPT: %s %d " format "", __func__, __LINE__, \ ##args); #ifndef ROUNDUP #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) #endif #ifndef ROUNDDOWN #define ROUNDDOWN(a, b) ((a) & ~((b)-1)) #endif #ifndef MIN #define MIN(a, b) ((a) > (b) ? (b) : (a)) #endif struct partition_entry { unsigned char type_guid[PARTITION_TYPE_GUID_SIZE]; unsigned char unique_partition_guid[UNIQUE_PARTITION_GUID_SIZE]; unsigned long long first_lba; unsigned long long last_lba; unsigned long long attribute_flag; unsigned char name[MAX_GPT_NAME_SIZE]; // TMP no need unsigned dtype; unsigned long long size; }; /* Partition info requested by app layer */ struct partition_info { uint64_t offset; uint64_t size; }; typedef struct partition_device { struct disk_dev *diskdev; uint64_t gpt_offset; struct partition_entry *partition_entries; unsigned count; signed active_slot; /* to store current active slot */ bool attributes_updated; /* to store if we need to update partition table */ bool multislot_support; /* to store if multislot support is present */ bool gpt_partitions_exist; } partition_device_t; typedef struct { uint8_t sign[8]; uint8_t version[4]; uint32_t header_sz; uint32_t header_crc32; uint8_t reserve[4]; uint64_t current_lba; uint64_t backup_lba; uint64_t first_usable_lba; uint64_t last_usable_lba; uint8_t guid[16]; uint64_t partition_entry_lba; uint32_t partition_entry_count; uint32_t partition_entry_sz; uint32_t entry_array_crc32; struct partition_entry *partition_entries; uint32_t actual_entries_count; } GPT_header; typedef enum restore_direction { PRI2SEC = 0, SEC2PRI } restore_direction; /* * Name is for querying avaliable storage devices, which shall be implemented by * platform. gpt_start is for GPT table offset, some devices like OSPI, the GPT * head is not located at the second block. * * Return initialized partition_device */ partition_device_t *ptdev_setup(struct disk_dev *diskdev, uint64_t gpt_offset); /* * Release partition entries and ptdev */ unsigned int ptdev_destroy(partition_device_t *ptdev); /* * Query the index by partition name, the index is to indicate partition entries * array */ unsigned int ptdev_get_index(partition_device_t *part_dev, const char *name); /* * Get size of the partition * Return 0 if the name is invalid */ unsigned long long ptdev_get_size(partition_device_t *part_dev, const char *name); /* * Get offset of the partition * Return 0 if the name is invalid */ unsigned long long ptdev_get_offset(partition_device_t *part_dev, const char *name); /* * Read the storage device, fill the partition entries array, scan and find * active slot Invoke after ptdev_set_abslot_decider, or else take for no a/b * slot support */ int ptdev_read_table(partition_device_t *part_dev); /* * Overwrite the partition table, if name is NULL, overwrite the globe partition * table, or else overwrite the sub-partition table. */ int ptdev_write_table(partition_device_t *part_dev, const char *name, unsigned size, unsigned char *ptable, bool last_part_extend); /* Return the partition offset & size to app layer * Size and offset is zero if the name is invalid */ struct partition_info ptdev_get_info(partition_device_t *part_dev, const char *name); /* For Debugging * Print all parsed partitions */ void ptdev_dump(partition_device_t *part_dev); /* For Debugging * Print all parsed partitions attributes */ void ptdev_attr_dump(partition_device_t *ptdev); /* Read only attribute for partition */ bool partition_is_readonly(partition_device_t *part_dev, const char *name); /* Get Partition Count */ unsigned ptdev_get_partition_count(partition_device_t *part_dev); /* Read Partition entried list pointer, indicate the entry by index from * ptdev_get_index */ struct partition_entry * ptdev_get_partition_entries(partition_device_t *part_dev); /* check the attribute of part entry */ bool part_is_active(const struct partition_entry *entry); /* Parse a buffer, check if it has a primary or secondary parition table or * inside */ unsigned int parse_gpt_table_from_buffer(uint8_t *buf, uint32_t buf_len, GPT_header *gpt_header, uint32_t block_size, bool is_secondary_gpt); /* Get the partition index from header object */ int get_partition_index_from_header(const char *name, GPT_header *gpt_header); /* Get the partition size from header object buffer */ unsigned long long get_partition_size_from_header(int index, GPT_header *gpt_header, uint32_t block_size); /* Get the partition offset from header object buffer */ unsigned long long get_partition_offset_from_header(int index, GPT_header *gpt_header, uint32_t block_size); /* Get the partition size and offset from header object buffer */ struct partition_info get_partition_info_from_header(const char *name, GPT_header *gpt_header, uint32_t block_size); /* Making every parition is aligned to the sector size */ uint32_t gpt_partition_round(uint8_t *buffer, uint32_t buf_len, uint32_t block_size, uint32_t sector_sz, uint64_t cap); int pt_disk_read(struct disk_dev *dev, disk_addr_t addr, uint8_t *dst, disk_size_t size); int pt_disk_write(struct disk_dev *dev, disk_addr_t addr, uint8_t *src, disk_size_t size); int pt_disk_erase(struct disk_dev *dev, disk_addr_t addr, disk_size_t size); uint32_t pt_disk_get_blocksize(struct disk_dev *dev); uint32_t pt_disk_get_erasesize(struct disk_dev *dev); uint64_t pt_disk_get_capacity(struct disk_dev *dev); #endif