blob: 3860696e75658669aeca417afdb80a82c4250aa6 [file] [log] [blame]
#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);
}