| #include "io.h" |
| #include "string.h" |
| #include "debug.h" |
| #include "util.h" |
| |
| #include "flash_adaptor.h" |
| |
| #include "load_vt.h" |
| |
| #define CRC32_SIZE (4) |
| extern unsigned int crc32(unsigned int crc, unsigned char *buf, unsigned int len); |
| |
| /*version table*/ |
| #define MAX_VERSION_TABLE 32 |
| |
| #define CLEAR_VT_SIZE 2048 |
| |
| typedef struct { |
| int num; |
| ver_table_entry_t vt[MAX_VERSION_TABLE]; |
| unsigned int dev_ids[MAX_VERSION_TABLE]; |
| }ver_table_t; |
| static ver_table_t vts; |
| /*version table end*/ |
| |
| static void dump_version_entry(ver_table_entry_t * vte) |
| { |
| INFO("%s: part1(start=%d, blks=%d, version=%08u%04u), part2(start=%d, blks=%d, version=%08u%04u)\n", vte->name, |
| vte->part1_start_blkind, vte->part1_blks, vte->part1_version.major_version, vte->part1_version.minor_version, |
| #ifdef CONFIG_EMMC_WRITE_PROTECT |
| vte->part1_start_blkind, vte->part1_blks, vte->part1_version.major_version, vte->part1_version.minor_version); |
| #else |
| vte->part2_start_blkind, vte->part2_blks, vte->part2_version.major_version, vte->part2_version.minor_version); |
| #endif |
| } |
| |
| void dump_version_table(void) |
| { |
| int i = 0; |
| for(i = 0; i < vts.num; i++) { |
| INFO("[%02d,sd%02d] ", i, vts.dev_ids[i]); |
| dump_version_entry(&(vts.vt[i])); |
| } |
| } |
| |
| // because vt is encrypted, we need decrypt it then parse it |
| int parse_version_table(unsigned char* buff) |
| { |
| unsigned int i; |
| unsigned int dev_id = 0; |
| |
| unsigned vt_size = 0; |
| |
| ver_table_entry_t * vt_entry; |
| version_table_t *vt = (version_table_t *)(buff); |
| |
| vt_size = sizeof(version_table_t) + vt->num_entries * sizeof(ver_table_entry_t); |
| |
| /* check calculated version table size*/ |
| if(vt_size >= 2048) { |
| ERR("ERROR: vt_size is too big %d!!!\n", vt_size); |
| return FLASH_OP_ERR; |
| } |
| |
| if(vt->magic != MAGIC_NUMBER || 0xffffffff != crc32(0, (unsigned char *)buff, vt_size + CRC32_SIZE)) { |
| ERR("EMMC: MAGIC NUMBER or CRC error. %d\n", vt_size); |
| return FLASH_OP_ERR; |
| } |
| |
| dev_id = 0; |
| vts.num = 0; |
| for(i = 0;i < vt->num_entries;i++) { |
| vt_entry = &vt->table[i]; |
| |
| memcpy(&(vts.vt[i]), vt_entry, sizeof(ver_table_entry_t)); |
| vts.dev_ids[i] = dev_id; |
| vts.num ++; |
| |
| dev_id = flash_dev_id_inc(dev_id); |
| #ifdef CONFIG_EMMC_WRITE_PROTECT |
| |
| #else |
| if (vt_entry->part1_start_blkind != vt_entry->part2_start_blkind) { |
| /* double copy of the partition */ |
| dev_id = flash_dev_id_inc(dev_id); |
| } |
| #endif |
| } |
| return 0; |
| } |
| |
| inline static unsigned get_aligned(unsigned address, unsigned page_size) { |
| return (address + page_size - 1) / page_size * page_size; |
| } |
| |
| int get_partition_info(void * tbuff) |
| { |
| //clear pt is located at the last 1K of boot partition(block) |
| //encrypted pt is located at last 14K of boot partition(block) |
| |
| //we need a buff that is at least 64bytes aligned address because of the DMA of EMMC |
| unsigned char * buff = (unsigned char *)(uintmax_t)get_aligned((unsigned)(uintmax_t)tbuff, 64); |
| int num = 0, i = 0; |
| int ret = 0; |
| long long start = 0; |
| |
| num = get_boot_partition_number(); |
| for(i = 1; i <= num; i++) { |
| //read the clear pt only |
| start = get_block_size() - CLEAR_VT_SIZE; |
| if(read_flash_from_part(i, start, CLEAR_VT_SIZE, buff) != 0) { |
| ERR("read partiton info error\n"); |
| continue; |
| } |
| |
| ret = parse_version_table(buff); |
| |
| if(ret != 0) { |
| ERR("parse partiton info error\n"); |
| continue; |
| } |
| return 0; |
| } |
| |
| return FLASH_SWITCH_PART_NOEXIST; |
| } |
| |
| int find_partition(const void *name) |
| { |
| int i = 0; |
| for(i = 0; i < vts.num; i++) { |
| //FIXME: ugly condition |
| //avoid boot = bootloader, boot = bootlogo |
| if(strlen(name) != strlen(vts.vt[i].name)) |
| continue; |
| if(memcmp(name, vts.vt[i].name, strlen(name)) == 0) { |
| return i; |
| } |
| } |
| |
| return PARTITION_NOT_EXIST; |
| } |
| |
| int fetch_partition_info(int num, ver_table_entry_t *vt) |
| { |
| if((num >= 0) && (num < vts.num)) { |
| memcpy(vt, &(vts.vt[num]), sizeof(ver_table_entry_t)); |
| return (int)(vts.dev_ids[num]); |
| } |
| return PARTITION_NOT_EXIST; |
| } |
| |
| unsigned int get_version_table_entry_number() |
| { |
| return vts.num; |
| } |
| |
| long long read_image(ver_table_entry_t *vt,unsigned int image_size,unsigned char *image_buff) |
| { |
| return read_image_from_offset(vt, 0, image_size, image_buff); |
| } |
| |
| long long read_image_from_offset(ver_table_entry_t *vt, unsigned int pt_offset, unsigned int size, unsigned char *image_buf) |
| { |
| long long start = 0, end = 0; |
| |
| start = vt->part1_start_blkind; |
| start *= get_block_size(); |
| start += pt_offset; |
| end = vt->part1_start_blkind + vt->part1_blks; |
| end *= get_block_size(); |
| |
| //image_size must not exceed the current partition |
| if((start + size) > end) { |
| ERR("the image is exceed the partition(%x > %x). Possible hacker attack detected!\n", |
| (start + size), end); |
| return -1; |
| } |
| |
| //For EMMC:switch to user area |
| //For nand and nor: nothing |
| switch_flash_part(0); |
| |
| return read_flash(start, size, image_buf); |
| } |
| |
| //FIXME: how this function can be unified |
| #ifdef ENABLE_EMMC |
| void set_flash_ts_param(char *param_buf) |
| { |
| ver_table_entry_t vt_fts; |
| unsigned int fts_dev_id = 0; |
| int num = find_partition(FTS_NAME); |
| *param_buf = '\0'; |
| if(num >= 0) { |
| fts_dev_id = (unsigned int)fetch_partition_info(num, &vt_fts); |
| sprintf(param_buf, " emmc_ts.dev_id=%d emmc_ts.size=%d emmc_ts.erasesize=%d emmc_ts.writesize=%d", |
| fts_dev_id, vt_fts.part1_blks * get_block_size(), get_block_size(), 512); |
| } |
| } |
| #endif |
| |
| #ifdef ENABLE_NAND |
| void set_flash_ts_param(char *param_buf) |
| { |
| ver_table_entry_t vt_fts; |
| unsigned int fts_dev_id = 0; |
| int num = find_partition(FTS_NAME); |
| *param_buf = '\0'; |
| if(num >= 0) { |
| fts_dev_id = (unsigned int)fetch_partition_info(num, &vt_fts); |
| sprintf(param_buf, " flash_ts.dev_id=%d flash_ts.size=%d flash_ts.erasesize=%d flash_ts.writesize=%d", |
| fts_dev_id, vt_fts.part1_blks * get_block_size(), get_block_size(), get_page_size()); |
| } |
| } |
| #endif |