Files
banban/ql-config/soc_platform/preboot_boot2/sys/ptable/ptable.c
T

352 lines
9.6 KiB
C

#include <string.h>
#include <stdbool.h>
#include "ptable.h"
#include "heapmem.h"
#include "crc32.h"
#include "flash.h"
#ifdef USE_EMMC_FLASH
#include "emmc.h"
#endif
#include "log.h"
#define LOG_MODULE "PTable"
#define LOG_LEVEL LOG_LEVEL_MAIN
/*---------------------------------------------------------------------------*/
static struct ptable *ptable_info;
/*---------------------------------------------------------------------------*/
extern unsigned char __scratch2_start, __scratch2_end;
/*---------------------------------------------------------------------------*/
#ifdef USE_EMMC_FLASH
/*---------------------------------------------------------------------------*/
static void
adjust_emmc_area_size(struct ptentry *start, struct ptentry *end, int64_t adjustment)
{
struct ptentry *entry = end;
uint8_t depth = 0;
/* adjust the last sub-partition size */
while(--entry >= start) {
if(!depth || entry->depth == depth - 1) {
if(entry->size == entry->vsize) {
entry->size += adjustment;
entry->vsize = entry->size;
} else {
entry->size += adjustment;
}
depth = entry->depth;
}
}
/* adjust emmc flash size */
entry = ptable_find_flash_entry(start->name);
entry->size += adjustment;
entry->vsize = entry->size;
/* adjust all group flash size */
entry = &ptable_info->parts[0];
entry->size += adjustment;
entry->vsize = entry->size;
}
/*---------------------------------------------------------------------------*/
static void
adjust_emmc_ptable_size(void)
{
struct ptentry *entry = &ptable_info->parts[0];
struct ptentry *end = &ptable_info->parts[ptable_info->count];
struct ptentry *start = NULL;
uint8_t depth = 0;
int64_t adjustment = 0;
while(entry < end) {
if(!strcmp(entry->type, PTABLE_TYPE_AREA)) {
depth = entry->depth;
uint64_t area_size = 0;
if(!strcmp(entry->name, "user")) {
area_size = emmc_area_size(EMMC_AREA_USER);
} else if(!strcmp(entry->name, "boot1")) {
area_size = emmc_area_size(EMMC_AREA_BOOT1);
} else if(!strcmp(entry->name, "boot2")) {
area_size = emmc_area_size(EMMC_AREA_BOOT2);
}
if(start) {
/* adjust the area and sub-partition size */
adjust_emmc_area_size(start, entry, adjustment);
}
/* save for next loop use */
start = entry;
adjustment = area_size - entry->size;
} else if(entry->depth < depth) {
/*
* assert(start != NULL)
* process the last area and not the last partition
*/
adjust_emmc_area_size(start, entry, adjustment);
start = NULL; /* to inform no need more process */
break;
}
entry++;
}
if(start) {
/*
* process the last area and the last partition
*/
adjust_emmc_area_size(start, entry, adjustment);
}
}
#endif
/*---------------------------------------------------------------------------*/
int
ptable_init(const void *data, size_t size)
{
struct ptable *ptable = (struct ptable *)data;
size_t ptable_size;
if(ptable->magic == PTABLE_MAGIC_A) {
bool no_crc = false;
struct ptable_a *ptable = (struct ptable_a *)data;
ptable_size = sizeof(*ptable);
if(size < ptable_size) {
if(size < ptable_size - sizeof(ptable->crc)) {
LOG_ERR("[%s] error: ptable size too small = 0x%x\n",
__func__, size);
return -1;
} else {
no_crc = true;
}
}
if(!no_crc) {
unsigned crc = 0 ^ ~0;
crc = crc32(crc, ptable, ptable_size - sizeof(ptable->crc));
crc = crc ^ ~0;
if(ptable->crc != crc) {
LOG_ERR("[%s] error: ptable crc not match(%08lx, %08x)\n",
__func__, ptable->crc, crc);
return -1;
}
}
if(ptable->count > MAX_PTABLE_PARTS) {
LOG_ERR("[%s] ptable->count > MAX_PTABLE_PARTS\n", __func__);
return -1;
}
ptable_size = sizeof(struct ptable) + ptable->count * sizeof(struct ptentry);
} else if(ptable->magic == PTABLE_MAGIC) {
ptable_size = sizeof(struct ptable) + ptable->count * sizeof(struct ptentry);
if(size < ptable_size) {
LOG_ERR("[%s] error: ptable size too small = 0x%x\n", __func__, size);
return -1;
}
} else {
LOG_ERR("[%s] Invalid magic id = 0x%lx\n", __func__, ptable->magic);
return -1;
}
/* save a partition table copy */
if(ptable_info) {
heapmem_free(ptable_info);
}
ptable_info = (struct ptable *)heapmem_alloc(ptable_size);
if(!ptable_info) {
LOG_ERR("Out of memory\n");
return -1;
}
bool update_crc = false;
if(ptable->magic == PTABLE_MAGIC_A) {
struct ptable_a *ptable = (struct ptable_a *)data;
ptable_info->magic = PTABLE_MAGIC;
ptable_info->count = ptable->count;
for(uint32_t i = 0; i < ptable->count; i++) {
memcpy(ptable_info->parts[i].name, ptable->parts[i].name,
MAX_PTABLE_ENTRY_NAME);
memcpy(ptable_info->parts[i].type, ptable->parts[i].type,
MAX_PTABLE_ENTRY_TYPE);
ptable_info->parts[i].start = ptable->parts[i].start == (uint32_t)-1
? (uint64_t)-1 : ptable->parts[i].start;
ptable_info->parts[i].size = ptable->parts[i].size == (uint32_t)-1
? (uint64_t)-1 : ptable->parts[i].size;
ptable_info->parts[i].vstart = ptable->parts[i].vstart == (uint32_t)-1
? (uint64_t)-1 : ptable->parts[i].vstart;
ptable_info->parts[i].vsize = ptable->parts[i].vsize == (uint32_t)-1
? (uint64_t)-1 : ptable->parts[i].vsize;
ptable_info->parts[i].depth = ptable->parts[i].depth == (uint32_t)-1
? (uint64_t)-1 : ptable->parts[i].depth;
}
update_crc = true;
} else {
memcpy(ptable_info, data, ptable_size);
}
#ifdef USE_EMMC_FLASH
adjust_emmc_ptable_size();
update_crc = true;
#endif
if(update_crc) {
ptable_info->crc = 0;
unsigned crc = 0 ^ ~0;
crc = crc32(crc, ptable_info, ptable_size);
crc = crc ^ ~0;
ptable_info->crc = crc;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
ptable_dump(void)
{
struct ptentry *ptn;
unsigned i;
for(i = 0; i < ptable_info->count; ++i) {
ptn = &ptable_info->parts[i];
LOG_DBG("Ptn %d name='%s' start=%010llx size=%010llx vsize=%010llx type=%s depth=%d\n",
i, ptn->name, ptn->start, ptn->size, ptn->vsize, ptn->type, ptn->depth);
}
}
/*---------------------------------------------------------------------------*/
struct ptentry *
ptable_find_entry(const char *name)
{
struct ptentry *ptn;
unsigned i;
for(i = 0; i < ptable_info->count; ++i) {
ptn = &ptable_info->parts[i];
if(!strcmp(ptn->name, name)) {
return ptn;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
struct ptentry *
ptable_find_entry_with_type(const char *type)
{
struct ptentry *ptn;
unsigned i;
for(i = 0; i < ptable_info->count; ++i) {
ptn = &ptable_info->parts[i];
if(!strcmp(ptn->type, type)) {
return ptn;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
static struct ptentry *
_ptable_find_parent_entry_with_type(const char *name, const char *type)
{
struct ptentry *entry = NULL;
struct ptentry *ptn;
unsigned i;
for(i = 0; i < ptable_info->count; ++i) {
ptn = &ptable_info->parts[i];
if(!strcmp(ptn->type, type)) {
entry = ptn;
}
if(!strcmp(ptn->name, name)) {
return entry;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
struct ptentry *
ptable_find_flash_entry(const char *name)
{
return _ptable_find_parent_entry_with_type(name, PTABLE_TYPE_FLASH);
}
/*---------------------------------------------------------------------------*/
struct ptentry *
ptable_find_area_entry(const char *name)
{
return _ptable_find_parent_entry_with_type(name, PTABLE_TYPE_AREA);
}
/*---------------------------------------------------------------------------*/
/*
* char flash_type[16] is divided to two strings. [type string] + [flash id string]
* if flash0: "flash""0"
* if flash1: "flash""1"
*/
int
ptable_get_flash_id(const struct ptentry *ptn)
{
const char *ptr = ptn->type;
if(strncmp(ptr, PTABLE_TYPE_FLASH, sizeof(PTABLE_TYPE_FLASH))) {
return -1;
}
ptr += strlen(PTABLE_TYPE_FLASH) + 1;
if(strlen(ptr) > 0) {
return atoi(ptr);
}
/* for compatiable with old version */
if(!strcmp(ptn->name, PTABLE_FLASH_EXTERNAL)) {
return FLASH_ID_FIRST;
} else if(!strcmp(ptn->name, PTABLE_FLASH_INTERNAL)) {
return FLASH_ID_SECOND;
}
return -1;
}
/*---------------------------------------------------------------------------*/
void
ptable_exit(void)
{
if(ptable_info) {
heapmem_free(ptable_info);
}
ptable_info = NULL;
}
/*---------------------------------------------------------------------------*/
struct ptable *
ptable_get(void)
{
return ptable_info;
}
/*---------------------------------------------------------------------------*/
size_t
ptable_size(const struct ptable *ptable)
{
return sizeof(*ptable) + ptable->count * sizeof(struct ptentry);
}
/*---------------------------------------------------------------------------*/
int
ptable_backup(void *data, unsigned sz)
{
#if defined BOARD_SC2 || defined BOARD_JACANA || defined BOARD_JACANA_RISCV
(void)data;
(void)sz;
return 0;
#else
uint8_t *stash;
ssize_t stash_size;
int ret;
/*
* write ptable to __scratch2_start
*/
stash = &__scratch2_start;
stash_size = &__scratch2_end - &__scratch2_start;
if(sz > (unsigned)stash_size) {
ret = -1;
} else {
memcpy(stash, data, sz);
ret = 0;
}
return ret;
#endif
}
/*---------------------------------------------------------------------------*/