| #include "io.h" |
| #include "string.h" |
| #include "debug.h" |
| #include "util.h" |
| |
| #include "flash_adaptor.h" |
| |
| #include "uuid.h" |
| #include "gpt.h" |
| |
| #include "load_gpt.h" |
| |
| #define SDIO_BLK_SIZE 512 |
| |
| #define CRC32_SIZE (4) |
| extern unsigned int crc32(unsigned int crc, unsigned char *buf, unsigned int len); |
| |
| /*version table*/ |
| #define MAX_GPT_ENTRY 128 |
| |
| typedef struct { |
| int num; |
| struct gpt_ent entry[MAX_GPT_ENTRY]; |
| }gpt_table_t; |
| static gpt_table_t gptes; |
| /*version table end*/ |
| |
| static void dump_gpt_entry(struct gpt_ent * gpte) |
| { |
| INFO("%s: start=%d, end=%d\n", gpte->ent_name, gpte->ent_lba_start, gpte->ent_lba_end); |
| } |
| |
| void dump_gpt_table(void) |
| { |
| int i = 0; |
| for(i = 0; i < gptes.num; i++) { |
| INFO("[%02d,sd%02d] ", i, i); |
| dump_gpt_entry(&(gptes.entry[i])); |
| } |
| } |
| |
| int parse_gpt_table(struct gpt_hdr * hdr, struct gpt_ent * entry) |
| { |
| unsigned int i; |
| |
| gptes.num = 0; |
| for(i = 0;i < hdr->hdr_entries; i++) { |
| |
| memcpy(&(gptes.entry[i]), &entry[i], sizeof(struct gpt_ent)); |
| gptes.num ++; |
| } |
| return 0; |
| } |
| |
| static unsigned get_aligned(unsigned address, unsigned page_size) { |
| return (address + page_size - 1) / page_size * page_size; |
| } |
| |
| #define START_ADDR_GPT 0x0 //start from MBR |
| #define GPT_PRI_READ_SIZE 0x6800 //26k (MBR 512B; GPT HEADER 512B; GPT TABLE 16K; RESERVE 1K; SIGN 8K) |
| #define GPT_ALT_READ_SIZE 0x4200 // 16.5K |
| |
| int get_gpt(void * tbuff) |
| { |
| //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 ret = 0; |
| long long start = START_ADDR_GPT; |
| struct gpt_hdr * hdr = NULL; |
| struct gpt_ent * entry = NULL; |
| //unsigned char * signature = NULL; |
| |
| //primary_gpt: |
| //emmc only now |
| if(read_flash_from_part(0, start, GPT_PRI_READ_SIZE, buff) != 0) { |
| ERR("read primary gpt error\n"); |
| goto alt_gpt; |
| } |
| hdr = (struct gpt_hdr *)(buff + 512); |
| entry = (struct gpt_ent *)(buff + 1024); |
| |
| //crc verification |
| |
| //signature = buff + 0x4800; |
| //FIXME: verify will be implemented later |
| |
| goto gpt_load_done; |
| alt_gpt: |
| start = get_flash_capacity() - GPT_ALT_READ_SIZE;//at the last 16.5K of emmc user area |
| |
| if(read_flash_from_part(0, start, GPT_ALT_READ_SIZE, buff) != 0) { |
| ERR("read alt gpt error\n"); |
| goto gpt_err; |
| } |
| hdr = (struct gpt_hdr *)(buff + 0x4000); |
| entry = (struct gpt_ent *)(buff); |
| //crc verification |
| |
| //FIXME: read signature(offset 1MB - 8KB) |
| /* |
| start = 0x100000 - 0x2000; |
| if(read_flash_from_part(0, start, 0x2000, (buff + 0x4800)) != 0) { |
| ERR("read alt gpt error\n"); |
| goto gpt_err; |
| } |
| */ |
| |
| //FIXME: verify will be implemented later |
| |
| gpt_load_done: |
| ret = parse_gpt_table(hdr, entry); |
| |
| if(ret != 0) { |
| ERR("parse partiton info error\n"); |
| } |
| return 0; |
| |
| gpt_err: |
| ERR("both primary and alt gpt are wrong!\n"); |
| return FLASH_OP_ERR; |
| } |
| |
| static void gpt_convert_efi_name_to_char(char *s, const uint16_t *ent_name, int n) |
| { |
| const char *ent_name_tmp = (const char *)ent_name; |
| unsigned char index = 0x00; |
| |
| memset((void *)s, 0x00, n); |
| |
| for(index = 0; (index<<1) < n; index++) { |
| s[index] = ent_name_tmp[index<<1]; |
| |
| if(!s[index]) |
| break; |
| } |
| |
| return; |
| } |
| |
| int get_partition_info(void * tbuff) |
| { |
| int ret; |
| |
| ret = get_gpt(tbuff); |
| if(ret != 0) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int find_partition(const char * name) |
| { |
| int i = 0; |
| char ent_name_char[72] = {0}; |
| |
| for(i = 0; i < gptes.num; i++) { |
| //avoid boot = bootloader, boot = bootlogo |
| gpt_convert_efi_name_to_char(ent_name_char, gptes.entry[i].ent_name, sizeof(gptes.entry[i].ent_name)); |
| if(strlen(name) != strlen(ent_name_char)) |
| continue; |
| if(memcmp(name, ent_name_char, strlen(name)) == 0) { |
| return i; |
| } |
| } |
| |
| return PARTITION_NOT_EXIST; |
| } |
| |
| |
| int fetch_partition_info(int num, struct gpt_ent *gpte) |
| { |
| if((num >= 0) && (num < gptes.num)) { |
| memcpy(gpte, &(gptes.entry[num]), sizeof(struct gpt_ent)); |
| return num; |
| } |
| return PARTITION_NOT_EXIST; |
| } |
| |
| unsigned int get_gpt_entry_number() |
| { |
| return gptes.num; |
| } |
| |
| long long read_image(struct gpt_ent *gpte, unsigned int image_size, unsigned char *image_buff) |
| { |
| return read_image_from_offset(gpte, 0, image_size, image_buff); |
| } |
| |
| long long read_image_by_ptname(const char *module_name, unsigned int image_size, unsigned char *image_buff) |
| { |
| struct gpt_ent gpte; |
| int ret = find_partition(module_name); |
| if(ret < 0) { |
| return ret; |
| } |
| fetch_partition_info(ret, &gpte); |
| |
| return read_image(&gpte, image_size, image_buff); |
| } |
| |
| long long read_image_from_offset(struct gpt_ent *gpte, unsigned int pt_offset, unsigned int size, unsigned char *image_buf) |
| { |
| long long start = 0, end = 0; |
| |
| start = gpte->ent_lba_start; |
| start *= SDIO_BLK_SIZE; |
| start += pt_offset; |
| end = gpte->ent_lba_end; |
| end *= SDIO_BLK_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); |
| } |