354 lines
12 KiB
C
354 lines
12 KiB
C
/**
|
|
* @file partition_parse.h
|
|
*
|
|
* Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*
|
|
* Description:
|
|
*
|
|
* Revision History:
|
|
* -----------------
|
|
*/
|
|
|
|
#ifndef __PARTITION_PARSER_H
|
|
#define __PARTITION_PARSER_H
|
|
|
|
#include <disk.h>
|
|
|
|
#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
|