blob: 8023d04fc367ddb00fdacc56bc6532aad6de710a [file] [log] [blame] [edit]
/*
* Copyright 2016, Amlogic Inc
* yonghui.yu
*
* Based vaguely on the Linux code
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <command.h>
#include <errno.h>
#include <mmc.h>
#include <part.h>
#include <malloc.h>
#include <linux/list.h>
#include <div64.h>
#include "mmc_private.h"
#include <emmc_partitions.h>
#include <asm/cpu_id.h>
#include <part_efi.h>
/* using mbr*/
#define CONFIG_PTBL_MBR (0)
#if (CONFIG_PTBL_MBR)
/* cmpare partition name? */
#define CONFIG_CMP_PARTNAME (0)
/* cmpare partition mask */
#define CONFIG_CMP_PARTMASK (0)
#else
#define CONFIG_CMP_PARTNAME (1)
#define CONFIG_CMP_PARTMASK (1)
#endif
/* debug info*/
#define CONFIG_MPT_DEBUG (0)
#define CONFIG_CONSTRUCT_GPT (1)
#define apt_err(fmt, ...) printf( "%s()-%d: " fmt , \
__func__, __LINE__, ##__VA_ARGS__)
#define apt_wrn(fmt, ...) printf( "%s()-%d: " fmt , \
__func__, __LINE__, ##__VA_ARGS__)
#if (CONFIG_MPT_DEBUG)
/* for detail debug info */
#define apt_info(fmt, ...) printf( "%s()-%d: " fmt , \
__func__, __LINE__, ##__VA_ARGS__)
#else
#define apt_info(fmt, ...)
#endif
/* creat MBR for emmc */
#define MAX_PNAME_LEN (16)
#define MAX_PART_COUNT (32)
/*
Global offset of reserved partition is 36MBytes
since MMC_BOOT_PARTITION_RESERVED is 32MBytes and
MMC_BOOT_DEVICE_SIZE is 4MBytes.
MMC_RESERVED_SIZE is 64MBytes for now.
layout detail inside reserved partition.
0x000000 - 0x003fff: partition table
0x004000 - 0x03ffff: storage key area (16k offset & 256k size)
0x400000 - 0x47ffff: dtb area (4M offset & 512k size)
0x480000 - 64MBytes: resv for other usage.
...
*/
/*
#define RSV_DTB_OFFSET_GLB (SZ_1M*40)
#define RSV_DTB_SIZE (512*1024UL)
#define RSV_PTBL_OFFSET (SZ_1M*0)
#define RSV_PTBL_SIZE (16*1024UL)
#define RSV_SKEY_OFFSET (16*1024UL)
#define RSV_SKEY_SIZE (256*1024UL)
#define RSV_DTB_OFFSET (SZ_1M*4)
*/
/* virtual partitions which are in "reserved" */
#define MAX_MMC_VIRTUAL_PART_CNT (5)
/* BinaryLayout of partition table stored in rsv area */
struct ptbl_rsv {
char magic[4]; /* MPT */
unsigned char version[12]; /* binary version */
int count; /* partition count in using */
int checksum;
struct partitions partitions[MAX_MMC_PART_NUM];
};
/* partition table for innor usage*/
struct _iptbl {
struct partitions *partitions;
int count; /* partition count in use */
};
#ifdef CONFIG_AML_NAND
unsigned device_boot_flag = (unsigned)_AML_DEVICE_BOOT_FLAG_DEFAULT;
#else
/*unsigned device_boot_flag = (unsigned)_AML_DEVICE_BOOT_FLAG_DEFAULT;*/
unsigned device_boot_flag = (unsigned)EMMC_BOOT_FLAG;
#endif
bool is_partition_checked = false;
#ifndef CONFIG_AML_MMC_INHERENT_PART
/* fixme, name should be changed as aml_inherent_ptbl */
struct partitions emmc_partition_table[] = {
PARTITION_ELEMENT(MMC_BOOT_NAME, MMC_BOOT_DEVICE_SIZE, 0),
PARTITION_ELEMENT(MMC_RESERVED_NAME, MMC_RESERVED_SIZE, 0),
/* prior partitions, same partition name with dts*/
/* partition size will be overide by dts*/
/* PARTITION_ELEMENT(MMC_CACHE_NAME, 0, 0), */
PARTITION_ELEMENT(MMC_ENV_NAME, MMC_ENV_SIZE, 0),
};
struct virtual_partition virtual_partition_table[] = {
/* partition for name idx, off & size will not be used! */
#if (CONFIG_PTBL_MBR)
VIRTUAL_PARTITION_ELEMENT(MMC_MBR_NAME, MMC_MBR_OFFSET, MMC_MBR_SIZE),
#endif
VIRTUAL_PARTITION_ELEMENT(MMC_BOOT_NAME0, 0, 0),
VIRTUAL_PARTITION_ELEMENT(MMC_BOOT_NAME1, 0, 0),
/* virtual partition in reserved partition, take care off and size */
VIRTUAL_PARTITION_ELEMENT(MMC_TABLE_NAME, MMC_TABLE_OFFSET, MMC_TABLE_SIZE),
VIRTUAL_PARTITION_ELEMENT(MMC_KEY_NAME, EMMCKEY_RESERVE_OFFSET, MMC_KEY_SIZE),
VIRTUAL_PARTITION_ELEMENT(MMC_PATTERN_NAME, CALI_PATTERN_OFFSET, CALI_PATTERN_SIZE),
VIRTUAL_PARTITION_ELEMENT(MMC_DTB_NAME, DTB_OFFSET, DTB_SIZE),
VIRTUAL_PARTITION_ELEMENT(MMC_FASTBOOT_CONTEXT_NAME,
FASTBOOT_CONTEXT_OFFSET, FASTBOOT_CONTEXT_SIZE),
};
int get_emmc_partition_arraysize(void)
{
return ARRAY_SIZE(emmc_partition_table);
}
int get_emmc_virtual_partition_arraysize(void)
{
return ARRAY_SIZE(virtual_partition_table);
}
#endif
void __attribute__((unused)) _dump_part_tbl(struct partitions *p, int count)
{
int i = 0;
apt_info("count %d\n", count);
while (i < count) {
printf("%02d %10s %016llx %016llx\n", i, p[i].name, p[i].offset, p[i].size);
i++;
}
return;
}
static int _get_part_index_by_name(struct partitions *tbl,
int cnt, const char *name)
{
int i=0;
struct partitions *part = NULL;
while (i < cnt) {
part = &tbl[i];
if (!strcmp(name, part->name)) {
apt_info("find %s @ tbl[%d]\n", name, i);
break;
}
i++;
};
if (i == cnt) {
i = -1;
apt_wrn("do not find match in table %s\n", name);
}
return i;
}
static struct partitions *_find_partition_by_name(struct partitions *tbl,
int cnt, const char *name)
{
int i = 0;
struct partitions *part = NULL;
while (i < cnt) {
part = &tbl[i];
if (!strcmp(name, part->name)) {
apt_info("find %s @ tbl[%d]\n", name, i);
break;
}
i++;
};
if (i == cnt) {
part = NULL;
apt_wrn("do not find match in table %s\n", name);
}
return part;
}
/* fixme, must called after offset was calculated. */
static ulong _get_inherent_offset(const char *name)
{
struct partitions *part;
part = _find_partition_by_name(emmc_partition_table,
get_emmc_partition_arraysize(), name);
if (NULL == part)
return -1;
else
return part->offset;
}
/* partition table (Emmc Partition Table) */
struct _iptbl *p_iptbl_ept = NULL;
/* trans byte into lba manner for rsv area read/write */
static ulong _mmc_rsv_read(struct mmc *mmc, ulong offset, ulong size, void * buffer)
{
lbaint_t _blk, _cnt;
if (0 == size)
return 0;
_blk = offset / mmc->read_bl_len;
_cnt = size / mmc->read_bl_len;
_cnt = mmc->block_dev.block_read(mmc->block_dev.dev, _blk, _cnt, buffer);
return (ulong)(_cnt * mmc->read_bl_len);
}
static ulong _mmc_rsv_write(struct mmc *mmc, ulong offset, ulong size, void * buffer)
{
lbaint_t _blk, _cnt;
if (0 == size)
return 0;
_blk = offset / mmc->read_bl_len;
_cnt = size / mmc->read_bl_len;
_cnt = mmc->block_dev.block_write(mmc->block_dev.dev, _blk, _cnt, buffer);
return (ulong)(_cnt * mmc->read_bl_len);
}
static struct partitions * get_ptbl_from_dtb(struct mmc *mmc)
{
struct partitions * ptbl = NULL;
#ifndef DTB_BIND_KERNEL
unsigned char * buffer = NULL;
ulong ret, offset;
struct virtual_partition *vpart = aml_get_virtual_partition_by_name(MMC_DTB_NAME);
/* try get dtb table from ddr, which may exsit while usb burning */
if (NULL == get_partitions()) {
/* if failed, try rsv dtb area then. */
buffer = malloc(vpart->size * DTB_COPIES);
if (NULL == buffer) {
apt_err("Can not alloc enough buffer\n");
goto _err;
}
offset = _get_inherent_offset(MMC_RESERVED_NAME) + vpart->offset;
ret = _mmc_rsv_read(mmc, offset, (vpart->size * DTB_COPIES), buffer);
if (ret != (vpart->size * DTB_COPIES)) {
apt_err("Can not alloc enough buffer\n");
goto _err1;
}
/* parse it */
if (get_partition_from_dts(buffer)) {
apt_err("get partition table from dts faild\n");
goto _err1;
}
/* double check part_table(glb) */
if (NULL == get_partitions()) {
goto _err1;
}
apt_info("get partition table from dts successfully\n");
free(buffer);
buffer = NULL;
}
#endif
/* asign partition info to *ptbl */
ptbl = get_partitions();
return ptbl;
#ifndef DTB_BIND_KERNEL
_err1:
if (buffer)
free(buffer);
_err:
free (ptbl);
return NULL;
#endif
}
static struct partitions *is_prio_partition(struct _iptbl *list, struct partitions *part)
{
int i;
struct partitions *plist = NULL;
if (list->count == 0)
goto _out;
apt_info("count %d\n", list->count);
for (i=0; i<list->count; i++) {
plist = &list->partitions[i];
apt_info("%d: %s, %s\n", i, part->name, plist->name);
if (!strcmp(plist->name, part->name)) {
apt_info("%s is prio in list[%d]\n", part->name, i);
break;
}
}
if (i == list->count)
plist = NULL;
_out:
return plist;
}
/* calculate offset of each partitions.
bottom is a flag for considering
*/
static int _calculate_offset(struct mmc *mmc, struct _iptbl *itbl, u32 bottom)
{
int i;
struct partitions *part;
ulong gap = PARTITION_RESERVED;
int ret = 0;
if (itbl->count <= 0)
return -1;
part = itbl->partitions;
part->offset = 0;
#if (CONFIG_MPT_DEBUG)
_dump_part_tbl(part, itbl->count);
#endif
if (!strcmp(part->name, "bootloader")) {
gap = MMC_BOOT_PARTITION_RESERVED;
if (!is_mainstorage_emmc())
sprintf(part->name, "bootloadere");
}
for (i=1; i<itbl->count; i++) {
/**/
part[i].offset = part[i-1].offset + part[i-1].size + gap;
/* check capicity overflow ?*/
if (((part[i].offset + part[i].size) > mmc->capacity) ||
(part[i].size == -1)) {
part[i].size = mmc->capacity - part[i].offset;
/* reserv space @ the bottom */
if (bottom && (part[i].size > MMC_BOTTOM_RSV_SIZE)) {
apt_info("reserv %d bytes at bottom\n", MMC_BOTTOM_RSV_SIZE);
part[i].size -= MMC_BOTTOM_RSV_SIZE;
}
break;
}
gap = PARTITION_RESERVED;
}
if (i < (itbl->count - 1)) {
apt_err("too large partition table for current emmc, overflow!\n");
ret = -1;
}
#if (CONFIG_MPT_DEBUG)
_dump_part_tbl(part, itbl->count);
#endif
return ret;
}
static int _get_version(unsigned char * s)
{
int version = 0;
if (!strcmp((char *)s, MMC_MPT_VERSION_2))
version = 2;
else if (!strcmp((char *)s, MMC_MPT_VERSION_1))
version = 1;
else
version = -1;
return version;
}
/* calc checksum.
there's a bug on v1 which did not calculate all the partitios.
*/
static int _calc_iptbl_check_v2(struct partitions * part, int count)
{
int ret = 0, i;
int size = count * sizeof(struct partitions) >> 2;
int *buf = (int *)part;
for (i = 0; i < size; i++)
ret +=buf[i];
return ret;
}
static int _calc_iptbl_check_v1(struct partitions *part, int count)
{
int i, j;
u32 checksum = 0, *p;
for (i = 0; i < count; i++) {
p = (u32*)part;
/*BUG here, do not fix it!!*/
for (j = sizeof(struct partitions)/sizeof(checksum); j > 0; j--) {
checksum += *p;
p++;
}
}
return checksum;
}
static int _calc_iptbl_check(struct partitions * part, int count, int version)
{
if (1 == version)
return _calc_iptbl_check_v1(part, count);
else if (2 == version)
return _calc_iptbl_check_v2(part, count);
else
return -1;
}
/* ept is malloced out side */
static void compose_ept(struct _iptbl *dtb, struct _iptbl *inh,
struct _iptbl *ept)
{
int i;
struct partitions *partition = NULL;
struct partitions *dst, *src, *prio;
/* overide inh info by dts */
apt_info("dtb %p, inh %p, ept %p\n", dtb, inh, ept);
apt_info("ept->partitions %p\n", ept->partitions);
partition = ept->partitions;
apt_info("partition %p\n", partition);
for (i=0; i<MAX_PART_COUNT; i++) {
apt_info("i %d, ept->count %d\n", i, ept->count);
dst = &partition[ept->count];
src = (i < inh->count) ? &inh->partitions[i]:&dtb->partitions[i-inh->count];
prio = is_prio_partition(ept, src);
if (prio) {
/* overide prio partition by new */
apt_info("override %d: %s\n", ept->count, prio->name);
//*prio = *src;
dst = prio;
} else
ept->count ++;
*dst = *src;
if (-1 == src->size) {
apt_info("break! %s\n", src->name);
break;
}
}
return;
}
/* get ptbl from rsv area from emmc */
static int get_ptbl_rsv(struct mmc *mmc, struct _iptbl *rsv)
{
struct ptbl_rsv * ptbl_rsv = NULL;
uchar * buffer = NULL;
ulong size, offset;
int checksum, version, ret = 0;
struct virtual_partition *vpart = aml_get_virtual_partition_by_name(MMC_TABLE_NAME);
size = (sizeof(struct ptbl_rsv) + 511) / 512 * 512;
if (vpart->size < size) {
apt_err("too much partitons\n");
ret = -1;
goto _out;
}
buffer = malloc(size);
if (NULL == buffer) {
apt_err("no enough memory for ptbl rsv\n");
ret = -2;
goto _out;
}
/* read it from emmc. */
offset = _get_inherent_offset(MMC_RESERVED_NAME) + vpart->offset;
if (size != _mmc_rsv_read(mmc, offset, size, buffer)) {
apt_err("read ptbl from rsv failed\n");
ret = -3;
goto _out;
}
ptbl_rsv = (struct ptbl_rsv *) buffer;
apt_info("magic %3.3s, version %8.8s, checksum %x\n", ptbl_rsv->magic,
ptbl_rsv->version, ptbl_rsv->checksum);
/* fixme, check magic ?*/
if (strcmp(ptbl_rsv->magic, MMC_PARTITIONS_MAGIC)) {
apt_err("magic faild %s, %3.3s\n", MMC_PARTITIONS_MAGIC, ptbl_rsv->magic);
ret = -4;
goto _out;
}
/* check version*/
version = _get_version(ptbl_rsv->version);
if (version < 0) {
apt_err("version faild %s, %3.3s\n", MMC_PARTITIONS_MAGIC, ptbl_rsv->magic);
ret = -5;
goto _out;
}
/* check sum */
checksum = _calc_iptbl_check(ptbl_rsv->partitions, ptbl_rsv->count, version);
if (checksum != ptbl_rsv->checksum) {
apt_err("checksum faild 0x%x, 0x%x\n", ptbl_rsv->checksum, checksum);
ret = -6;
goto _out;
}
rsv->count = ptbl_rsv->count;
memcpy(rsv->partitions, ptbl_rsv->partitions, rsv->count * sizeof(struct partitions));
_out:
if (buffer)
free (buffer);
return ret;
}
/* update partition tables from src
if success, return 0;
else, return 1
*/
static int update_ptbl_rsv(struct mmc *mmc, struct _iptbl *src)
{
struct ptbl_rsv *ptbl_rsv = NULL;
uchar *buffer;
ulong size, offset;
int ret = 0, version;
struct virtual_partition *vpart = aml_get_virtual_partition_by_name(MMC_TABLE_NAME);
size = (sizeof(struct ptbl_rsv) + 511) / 512 * 512;
buffer = malloc(size);
if (NULL == buffer) {
apt_err("no enough memory for ptbl rsv\n");
return -1;
}
memset(buffer, 0 , size);
/* version, magic and checksum */
ptbl_rsv = (struct ptbl_rsv *) buffer;
strcpy((char *)ptbl_rsv->version, MMC_MPT_VERSION);
strcpy(ptbl_rsv->magic, MMC_PARTITIONS_MAGIC);
ptbl_rsv->count = src->count;
memcpy(ptbl_rsv->partitions, src->partitions,
sizeof(struct partitions)*src->count);
version = _get_version(ptbl_rsv->version);
ptbl_rsv->checksum = _calc_iptbl_check(src->partitions, src->count, version);
/* write it to emmc. */
apt_info("magic %3.3s, version %8.8s, checksum %x\n", ptbl_rsv->magic, ptbl_rsv->version, ptbl_rsv->checksum);
offset = _get_inherent_offset(MMC_RESERVED_NAME) + vpart->offset;
if (_mmc_rsv_write(mmc, offset, size, buffer) != size) {
apt_err("write ptbl to rsv failed\n");
ret = -1;
goto _err;
}
_err:
free (buffer);
return ret;
}
static int _cmp_partition(struct partitions *dst, struct partitions *src, int overide)
{
int ret = 0;
#if (CONFIG_CMP_PARTNAME)
if (strcmp(dst->name, src->name))
ret = -2;
#endif
if (dst->size != src->size)
ret = -3;
if (dst->offset != src->offset)
ret = -4;
#if (CONFIG_CMP_PARTMASK)
if (dst->mask_flags != src->mask_flags)
ret = -5;
#endif
if (ret && (!overide)) {
apt_err("name: %10.10s<->%10.10s\n", dst->name, src->name);
apt_err("size: %llx<->%llx\n", dst->size, src->size);
apt_err("offset: %llx<->%llx\n", dst->offset, src->offset);
apt_err("mask: %08x<->%08x\n", dst->mask_flags, src->mask_flags);
}
if (overide) {
*dst = *src;
ret = 0;
}
return ret;
}
/* compare partition tables
if same, do nothing then return 0;
else, print the diff ones and return -x
-1:count
-2:name
-3:size
-4:offset
*/
static int _cmp_iptbl(struct _iptbl * dst, struct _iptbl * src)
{
int ret = 0, i = 0;
struct partitions *dstp;
struct partitions *srcp;
if (dst->count != src->count) {
apt_err("partition count is not same %d:%d\n", dst->count, src->count);
ret = -1;
goto _out;
}
while (i < dst->count) {
dstp = &dst->partitions[i];
srcp = &src->partitions[i];
ret = _cmp_partition(dstp, srcp, 0);
if (ret) {
apt_err("partition %d has changed\n", i);
break;
}
i++;
}
_out:
return ret;
}
/* iptbl buffer opt. */
static int _zalloc_iptbl(struct _iptbl **_iptbl)
{
int ret = 0;
struct _iptbl *iptbl;
struct partitions *partition = NULL;
partition = malloc(sizeof(struct partitions)*MAX_PART_COUNT);
if (NULL == partition) {
ret = -1;
apt_err("no enough memory for partitions\n");
goto _out;
}
iptbl = malloc(sizeof(struct _iptbl));
if (NULL == iptbl) {
ret = -2;
apt_err("no enough memory for ept\n");
free(partition);
goto _out;
}
memset(partition, 0, sizeof(struct partitions)*MAX_PART_COUNT);
memset(iptbl, 0, sizeof(struct _iptbl));
iptbl->partitions = partition;
apt_info("iptbl %p, partition %p, iptbl->partitions %p\n",
iptbl, partition, iptbl->partitions);
*_iptbl = iptbl;
_out:
return ret;
}
static void _free_iptbl(struct _iptbl *iptbl)
{
if (iptbl && iptbl->partitions) {
free(iptbl->partitions);
iptbl->partitions = NULL;
}
if (iptbl) {
free(iptbl);
iptbl = NULL;
}
return;
}
/*
* fixme, need check space size later.
*/
static int _cpy_iptbl(struct _iptbl * dst, struct _iptbl * src)
{
int ret = 0;
if (!dst || !src) {
apt_err("invalid arg %s\n", !dst ? "dst" : "src");
ret = -1;
goto _out;
}
if (!dst->partitions || !src->partitions) {
apt_err("invalid arg %s->partitions\n", !dst ? "dst" : "src");
ret = -2;
goto _out;
}
dst->count = src->count;
memcpy(dst->partitions, src->partitions, sizeof(struct partitions) * src->count);
_out:
return ret;
}
static inline int le32_to_int(unsigned char *le32)
{
return ((le32[3] << 24) +
(le32[2] << 16) +
(le32[1] << 8) +
le32[0]
);
}
static int test_block_type(unsigned char *buffer)
{
int slot;
struct dos_partition *p;
if ((buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) ||
(buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) {
return (-1);
} /* no DOS Signature at all */
p = (struct dos_partition *)&buffer[DOS_PART_TBL_OFFSET];
for (slot = 0; slot < 3; slot++) {
if (p->boot_ind != 0 && p->boot_ind != 0x80) {
if (!slot &&
(strncmp((char *)&buffer[DOS_PBR_FSTYPE_OFFSET],
"FAT", 3) == 0 ||
strncmp((char *)&buffer[DOS_PBR32_FSTYPE_OFFSET],
"FAT32", 5) == 0)) {
return DOS_PBR; /* is PBR */
} else {
return -1;
}
}
}
return DOS_MBR; /* Is MBR */
}
//DOS_MBR OR DOS_PBR
/*
* re-constructe iptbl from mbr&ebr infos.
* memory for iptbl_mbr must be alloced outside.
*
*/
static void _construct_ptbl_by_mbr(struct mmc *mmc, struct _iptbl *iptbl_mbr)
{
int ret,i;
int flag = 0;
lbaint_t read_offset = 0;
int part_num = 0;
int primary_num = 0;
uint64_t logic_start = 0;
uint64_t externed_start = 0;
struct dos_partition *pt;
struct partitions *partitions = iptbl_mbr->partitions;
apt_info("aml MBR&EBR debug...\n");
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 512);
for (;;) {
apt_info("**%02d: read_offset %016llx\n", part_num, (uint64_t)read_offset<<9);
ret = mmc->block_dev.block_read(mmc->block_dev.dev, read_offset, 1, buffer);
if (read_offset == 0)
flag = 1;
else
flag = 0;
/* debug code */
// print_buffer(0,buffer,1,512,16);
if (ret != 1) {
apt_err("ret %d fail to read current ebr&mbr from emmc! \n", ret);
break;
}
ret = test_block_type(buffer);
if (ret != 0 && ret != 1) {
apt_err("invalid magic value: 0x%02x%02x\n",
buffer[DOS_PART_MAGIC_OFFSET], buffer[DOS_PART_MAGIC_OFFSET + 1]);
break;
}
pt = (dos_partition_t *)(&buffer[0] + DOS_PART_TBL_OFFSET);
for (i = 0; i < 4; i++, pt++) {
if ( (pt->boot_ind == 0x00 || pt->boot_ind == 0x80) && pt->sys_ind == 0x83 ) {
//emmc_partition[part_num]->name = NULL;
partitions[part_num].offset = ((uint64_t)(le32_to_int(pt->start4)+read_offset) << 9ULL);
partitions[part_num].size = (uint64_t)le32_to_int(pt->size4) << 9ULL;
partitions[part_num].mask_flags = pt->sys_ind;
apt_info("--partition[%d]: %016llx, %016llx, 0x%08x \n",
part_num, partitions[part_num].offset,
partitions[part_num].size,
le32_to_int(pt->size4));
part_num++;
if ( flag )
primary_num++;
}else{/* get the next externed partition info */
if ( pt->boot_ind == 0x00 && pt->sys_ind == 0x05) {
logic_start = (uint64_t)le32_to_int (pt->start4);
//logic_size = (uint64_t)le32_to_int (pt->size4);
}
}
}
/* mbr & ebr debug infos */
apt_info("******%02d: read_offset=%016llx, logic_start=%016llx\n",
part_num,(uint64_t)read_offset*512ULL,logic_start*512ULL);
if (part_num == primary_num) {
externed_start = logic_start;
read_offset = externed_start;
}else
read_offset = externed_start + logic_start;
if (logic_start == 0)
break;
logic_start = 0;
}
iptbl_mbr->count = part_num;
apt_info("iptbl_mbr->count = %d\n", iptbl_mbr->count);
return;
}
static int __attribute__((unused)) _check_ptbl_mbr(struct mmc *mmc, struct _iptbl *ept)
{
int ret = 0;
/* re-constructed by mbr */
struct _iptbl *iptbl_mbr = NULL;
struct partitions *partitions = NULL;
iptbl_mbr = malloc(sizeof(struct _iptbl));
if (NULL == iptbl_mbr) {
apt_err("no enough memory for iptbl_mbr\n");
return -1;
}
memset(iptbl_mbr , 0, sizeof(struct _iptbl));
partitions = (struct partitions *)malloc(sizeof(struct partitions) * DOS_PARTITION_COUNT);
if (NULL == partitions) {
apt_err("no enough memory for partitions\n");
free(iptbl_mbr);
return -1;
}
memset(partitions, 0, sizeof(struct partitions) * DOS_PARTITION_COUNT);
iptbl_mbr->partitions = partitions;
_construct_ptbl_by_mbr(mmc, iptbl_mbr);
ret = _cmp_iptbl(iptbl_mbr, ept);
if (partitions)
free(partitions);
if (iptbl_mbr)
free(iptbl_mbr);
apt_wrn("MBR is %s\n", ret?"Improper!":"OK!");
return ret;
}
/* construct a partition table entry of EBR */
static int _construct_ebr_1st_entry(struct _iptbl *p_iptbl,struct dos_partition *p_ebr, int part_num )
{
uint64_t start_offset = 0;
uint64_t logic_size = 0;
p_ebr->boot_ind = 0x00;
p_ebr->sys_ind = 0x83;
/* Starting = relative offset between this EBR sector and the first sector of the logical partition
* the gap between two partition is a fixed value of PARTITION_RESERVED ,otherwise the emmc partiton
* is different with reserved */
start_offset = PARTITION_RESERVED >> 9;
/* Number of sectors = total count of sectors for this logical partition */
// logic_size = (p_iptbl->partitions[part_num].size) >> 9ULL;
logic_size = lldiv(p_iptbl->partitions[part_num].size, 512);
apt_info("*** %02d: size 0x%016llx, logic_size 0x%016llx\n", part_num, p_iptbl->partitions[part_num].size, logic_size);
memcpy((unsigned char *)(p_ebr->start4), &start_offset, 4);
memcpy((unsigned char *)(p_ebr->size4), &logic_size, 4);
return 0;
}
static int _construct_ebr_2nd_entry(struct _iptbl *p_iptbl, struct dos_partition *p_ebr, int part_num)
{
uint64_t start_offset = 0;
uint64_t logic_size = 0;
if ((part_num+2) > p_iptbl->count)
return 0;
p_ebr->boot_ind = 0x00;
p_ebr->sys_ind = 0x05;
/* Starting sector = LBA address of next EBR minus LBA address of extended partition's first EBR */
start_offset = (p_iptbl->partitions[part_num+1].offset - PARTITION_RESERVED -
(p_iptbl->partitions[3].offset - PARTITION_RESERVED)) >> 9;
/* total count of sectors for next logical partition, but count starts from the next EBR sector */
logic_size = (p_iptbl->partitions[part_num+1].size + PARTITION_RESERVED) >> 9;
memcpy((unsigned char *)(p_ebr->start4), &start_offset, 4);
memcpy((unsigned char *)(p_ebr->size4), &logic_size, 4);
return 0;
}
/* construct a partition table entry of MBR OR EBR */
static int _construct_mbr_entry(struct _iptbl *p_iptbl, struct dos_partition *p_entry, int part_num)
{
uint64_t start_offset = 0;
uint64_t primary_size = 0;
uint64_t externed_size = 0;
int i;
/* the entry is active or not */
if (part_num == 0 )
p_entry->boot_ind = 0x00;
else
p_entry->boot_ind = 0x00;
if (part_num == 3) {/* the logic partion entry */
/* the entry type */
p_entry->sys_ind = 0x05;
start_offset = (p_iptbl->partitions[3].offset - PARTITION_RESERVED) >> 9;
for ( i = 3;i< p_iptbl->count;i++)
externed_size = p_iptbl->partitions[i].size >> 9;
memcpy((unsigned char *)p_entry->start4, &start_offset, 4);
memcpy((unsigned char *)p_entry->size4, &externed_size, 4);
}else{/* the primary partion entry */
/* the entry type */
p_entry->sys_ind = 0x83;
start_offset = (p_iptbl->partitions[part_num].offset) >> 9;
primary_size = (p_iptbl->partitions[part_num].size)>>9;
memcpy((unsigned char *)p_entry->start4, &start_offset, 4);
memcpy((unsigned char *)p_entry->size4, &primary_size, 4);
}
return 0;
}
static int _construct_mbr_or_ebr(struct _iptbl *p_iptbl, struct dos_mbr_or_ebr *p_br,
int part_num, int type)
{
int i;
if (DOS_MBR == type) {
/* constuct a integral MBR */
for (i = 0; i<4 ; i++)
_construct_mbr_entry(p_iptbl, &p_br->part_entry[i], i);
}else{
/* constuct a integral EBR */
p_br->bootstart[DOS_PBR32_FSTYPE_OFFSET] = 'F';
p_br->bootstart[DOS_PBR32_FSTYPE_OFFSET + 1] = 'A';
p_br->bootstart[DOS_PBR32_FSTYPE_OFFSET + 2] = 'T';
p_br->bootstart[DOS_PBR32_FSTYPE_OFFSET + 3] = '3';
p_br->bootstart[DOS_PBR32_FSTYPE_OFFSET + 4] = '2';
_construct_ebr_1st_entry(p_iptbl, &p_br->part_entry[0], part_num);
_construct_ebr_2nd_entry(p_iptbl, &p_br->part_entry[1], part_num);
}
p_br->magic[0] = 0x55 ;
p_br->magic[1] = 0xAA ;
return 0;
}
static __attribute__((unused)) int _update_ptbl_mbr(struct mmc *mmc, struct _iptbl *p_iptbl)
{
int ret = 0, start_blk = 0, blk_cnt = 1;
unsigned char *src;
int i;
struct dos_mbr_or_ebr *mbr;
struct _iptbl *ptb ;
ptb = p_iptbl;
mbr = malloc(sizeof(struct dos_mbr_or_ebr));
for (i=0;i<ptb->count;i++) {
apt_info("-update MBR-: partition[%02d]: %016llx - %016llx\n",i,
ptb->partitions[i].offset, ptb->partitions[i].size);
}
for (i = 0;i < ptb->count;) {
memset(mbr ,0 ,sizeof(struct dos_mbr_or_ebr));
if (i == 0) {
_construct_mbr_or_ebr(ptb, mbr, i, 0);
i = i+2;
} else
_construct_mbr_or_ebr(ptb, mbr, i, 2);
src = (unsigned char *)mbr;
apt_info("--%s(): %02d(%02d), off %x\n", __func__, i, ptb->count, start_blk);
ret = mmc->block_dev.block_write(mmc->block_dev.dev, start_blk, blk_cnt, src);
i++;
if (ret != blk_cnt) {
apt_err("write current MBR failed! ret: %d != cnt: %d\n",ret,blk_cnt);
break;
}
start_blk = (ptb->partitions[i].offset - PARTITION_RESERVED) >> 9;
}
free(mbr);
ret = !ret;
if (ret)
apt_err("write MBR failed!\n");
return ret;
}
#if (CONFIG_CONSTRUCT_GPT)
static inline u32 efi_crc32(const void *buf, u32 len)
{
return crc32(0, buf, len);
}
static int set_protective_mbr(block_dev_desc_t *dev_desc)
{
/* Setup the Protective MBR */
ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, p_mbr, 1);
memset(p_mbr, 0, sizeof(*p_mbr));
if (!p_mbr) {
printf("%s: calloc failed!\n", __func__);
return -1;
}
/* Append signature */
p_mbr->signature = MSDOS_MBR_SIGNATURE;
p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
p_mbr->partition_record[0].start_sect = 1;
p_mbr->partition_record[0].nr_sects = (u32)dev_desc->lba - 1;
/* Write MBR sector to the MMC device */
if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) {
printf("** Can't write to device %d **\n",
dev_desc->dev);
return -1;
}
return 0;
}
void set_partition_type_guid(gpt_entry *gpt_e, char *partition_name)
{
if (!strcmp(partition_name, "bootloader"))
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_ANDROID_BOOTLOADER_GUID, 16);
else if (!strcmp(partition_name, "recovery"))
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_ANDROID_RECOVERY_GUID, 16);
else if (!strcmp(partition_name, "misc"))
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_ANDROID_MISC_GUID, 16);
else if (!strcmp(partition_name, "system"))
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_ANDROID_SYSTEM_GUID, 16);
else if (!strcmp(partition_name, "cache"))
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_ANDROID_CACHE_GUID, 16);
else if (!strcmp(partition_name, "data"))
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_ANDROID_DATA_GUID, 16);
else
memcpy(gpt_e->partition_type_guid.b,
&PARTITION_LINUX_DEFAULT_GUID, 16);
}
static uint64_t fill_gpt_entry(gpt_entry *gpt_e, struct _iptbl *p_iptbl_ept)
{
u64 next_usable_lba;
u64 last_usable_lba = 0;
int i, k;
size_t efiname_len, dosname_len;
struct _iptbl *ept = p_iptbl_ept;
struct partitions *partitions = ept->partitions;
int parts_num = ept->count;
for (i = 0; i < parts_num; i++) {
gpt_e[i].starting_lba = cpu_to_le64(partitions[i].offset >>
9ULL);
next_usable_lba = (partitions[i].offset +
partitions[i].size) >> 9ULL;
gpt_e[i].ending_lba = cpu_to_le64(next_usable_lba - 1);
if (i == parts_num - 1)
last_usable_lba = gpt_e[i].ending_lba;
/* partition type GUID */
set_partition_type_guid(&gpt_e[i], partitions[i].name);
/* partition attributes */
memset(&gpt_e[i].attributes, 0,
sizeof(gpt_entry_attributes));
/* partition name */
efiname_len = sizeof(gpt_e[i].partition_name)
/ sizeof(efi_char16_t);
dosname_len = sizeof(partitions[i].name);
memset(gpt_e[i].partition_name, 0,
sizeof(gpt_e[i].partition_name));
for (k = 0; k < min(dosname_len, efiname_len); k++)
gpt_e[i].partition_name[k] =
(efi_char16_t)(partitions[i].name[k]);
}
return last_usable_lba;
}
static int fill_gpt_header(lbaint_t last_usable_lba, gpt_header *gpt_h)
{
gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
gpt_h->my_lba = cpu_to_le64(1);
gpt_h->first_usable_lba = cpu_to_le64(34);
gpt_h->last_usable_lba = cpu_to_le64(last_usable_lba);
gpt_h->partition_entry_lba = cpu_to_le64(2);
gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS);
gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
gpt_h->header_crc32 = 0;
gpt_h->partition_entry_array_crc32 = 0;
return 0;
}
static int write_gpt(
block_dev_desc_t *dev_desc, gpt_header *gpt_h, gpt_entry *gpt_e)
{
const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries *
sizeof(gpt_entry)), dev_desc);
u32 calc_crc32;
debug("max lba: %x\n", (u32)dev_desc->lba);
/* Setup the Protective MBR */
if (set_protective_mbr(dev_desc) < 0)
goto err;
/* Generate CRC for the Primary GPT Header */
calc_crc32 = efi_crc32(
(const unsigned char *)gpt_e,
le32_to_cpu(gpt_h->num_partition_entries) *
le32_to_cpu(gpt_h->sizeof_partition_entry));
gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);
calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
le32_to_cpu(gpt_h->header_size));
gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
/* Write the First GPT to the block right after the Legacy MBR */
if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1)
goto err;
if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_cnt, gpt_e)
!= pte_blk_cnt)
goto err;
debug("GPT successfully written to block device!\n");
return 0;
err:
printf("** Can't write to device %d **\n", dev_desc->dev);
return -1;
}
static int _cmp_gpt_e(struct _iptbl *iptbl_mbr, struct _gpt_entry *gpt_ent)
{
int ret = 0, i = 0;
struct partitions *mbrp;
u64 size;
u64 offset;
while (i < iptbl_mbr->count) {
mbrp = &iptbl_mbr->partitions[i];
size = (le64_to_cpu(gpt_ent[i].ending_lba) -
le64_to_cpu(gpt_ent[i].starting_lba) + 1) << 9ULL;
if (mbrp->size != size) {
apt_err("Error: partition size is different\n");
ret = -3;
goto _out;
}
offset = le64_to_cpu(gpt_ent[i].starting_lba) << 9ULL;
if (mbrp->offset != offset) {
apt_err("Error: partition offset is different\n");
ret = -4;
goto _out;
}
i++;
}
_out:
return ret;
}
static int __attribute__((unused)) check_gpt_mbr(
struct mmc *mmc, struct _gpt_entry *gpt_e)
{
int ret = 0;
/* re-constructed by mbr */
struct _iptbl *iptbl_mbr = NULL;
struct partitions *partitions = NULL;
iptbl_mbr = malloc(sizeof(struct _iptbl));
if (!iptbl_mbr) {
apt_err("no enough memory for iptbl_mbr\n");
return -1;
}
memset(iptbl_mbr, 0, sizeof(struct _iptbl));
partitions = (struct partitions *)malloc(sizeof(struct partitions) *
DOS_PARTITION_COUNT);
if (!partitions) {
apt_err("no enough memory for partitions\n");
free(iptbl_mbr);
return -1;
}
memset(partitions, 0, sizeof(struct partitions) * DOS_PARTITION_COUNT);
iptbl_mbr->partitions = partitions;
_construct_ptbl_by_mbr(mmc, iptbl_mbr);
ret = _cmp_gpt_e(iptbl_mbr, gpt_e);
if (partitions)
free(partitions);
if (iptbl_mbr)
free(iptbl_mbr);
apt_wrn("gpt is %s\n", ret ? "Improper!" : "OK!");
return ret;
}
static int gpt_restore_by_ept(
struct mmc *mmc, struct _iptbl *p_iptbl_ept)
{
int ret = 0;
u64 last_usable_lba = 0;
block_dev_desc_t *dev_desc = &mmc->block_dev;
gpt_header *gpt_h = calloc(1, PAD_TO_BLOCKSIZE(sizeof(gpt_header),
dev_desc));
gpt_entry *gpt_e;
if (!gpt_h) {
printf("%s: calloc failed!\n", __func__);
return -1;
}
gpt_e = calloc(1, PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS
* sizeof(gpt_entry),
dev_desc));
if (!gpt_e) {
printf("%s: calloc failed!\n", __func__);
free(gpt_h);
return -1;
}
/* Generate partition entries */
last_usable_lba = fill_gpt_entry(gpt_e, p_iptbl_ept);
if (!last_usable_lba)
goto err;
/* Generate Primary GPT header (LBA1) */
fill_gpt_header(last_usable_lba, gpt_h);
/* Write GPT partition table */
ret = write_gpt(dev_desc, gpt_h, gpt_e);
if (ret) {
printf("write gpt failed\n");
goto err;
}
/* Check gpt */
ret = check_gpt_mbr(mmc, gpt_e);
if (ret) {
printf("gpt and mbr improper\n");
goto err;
}
err:
free(gpt_e);
free(gpt_h);
return ret;
}
#endif
/***************************************************
* init partition table for emmc device.
* returns 0 means ok.
* other means failure.
***************************************************
* work flows:
* source of logic partition table(LPT) is from dts
* no matter MACRO is on/off
* 1. try to get LPT from dtb
* 1.1 if dtb exist, compose ept by LPT&inh
* 1.2 if not, go ahead
* 2. try to get ept from emmc rsv partition
* 2.1 if not:
* 2.1.1 when dtb exists
* 2.1.1.1 check ept with dtb
* 2.1.1.2 update rsv if needed
* 2.1.1 without dtb, exit
* 2.2 if got:
* 2.2.1 try to reconstruct ept by MBR
* 2.2.2 check it with ept
* 2.2.3 update MBR if needed
***************************************************
* when normal boot:
* without dtb, with rsv, with MBR
* when blank emmc:
* without dtb, without rsv, without MBR
* when burning MBR on a blank emmc:
* with dtb, without rsv, without MBR
* when burning MBR on a emmc with rsv:
* with dtb, with rsv, without MBR
* when burning MBR on a emmc with rsv&MBR:
* with dtb, with rsv, with MBR
***************************************************/
int mmc_device_init (struct mmc *mmc)
{
int ret = 1;
#if (CONFIG_PTBL_MBR)
cpu_id_t cpu_id = get_cpu_id();
#endif
/* partition table from dtb/code/emmc rsv */
struct _iptbl iptbl_dtb, iptbl_inh;
struct _iptbl *p_iptbl_rsv = NULL;
int update = 1;
/* calculate inherent offset */
iptbl_inh.count = get_emmc_partition_arraysize();
if (iptbl_inh.count) {
iptbl_inh.partitions = emmc_partition_table;
_calculate_offset(mmc, &iptbl_inh, 0);
}
apt_info("inh count %d\n", iptbl_inh.count);
#if (CONFIG_MPT_DEBUG)
apt_info("inherent partition table\n");
_dump_part_tbl(iptbl_inh.partitions, iptbl_inh.count);
#endif
/* For re-entry */
if (NULL == p_iptbl_ept) {
ret = _zalloc_iptbl(&p_iptbl_ept);
if (ret)
goto _out;
} else {
p_iptbl_ept->count = 0;
memset(p_iptbl_ept->partitions, 0,
sizeof(struct partitions)*MAX_PART_COUNT);
}
/* try to get partition table from dtb(ddr or emmc) */
iptbl_dtb.partitions = get_ptbl_from_dtb(mmc);
/* construct ept by dtb if exist */
if (iptbl_dtb.partitions) {
iptbl_dtb.count = get_partition_count();
apt_info("dtb %p, count %d\n", iptbl_dtb.partitions, iptbl_dtb.count);
/* reserved partition must exist! */
if (iptbl_inh.count) {
compose_ept(&iptbl_dtb, &iptbl_inh, p_iptbl_ept);
if (0 == p_iptbl_ept->count) {
apt_err("compose partition table failed!\n");
goto _out;
}
/* calculate offset infos. considering GAPs */
if (_calculate_offset(mmc, p_iptbl_ept, 1)) {
goto _out;
}
#if (CONFIG_MPT_DEBUG)
apt_info("ept partition table\n");
_dump_part_tbl(p_iptbl_ept->partitions, p_iptbl_ept->count);
#endif
} else {
/* report fail, because there is no reserved partitions */
apt_err("compose partition table failed!\n");
ret = -1;
goto _out;
}
} else
apt_wrn("get partition table from dtb failed\n");
/* try to get partiton table from rsv */
ret = _zalloc_iptbl(&p_iptbl_rsv);
if (ret)
goto _out;
ret = get_ptbl_rsv(mmc, p_iptbl_rsv);
if (p_iptbl_rsv->count) {
/* dtb exist, p_iptbl_ept already inited */
if (iptbl_dtb.partitions) {
ret = _cmp_iptbl(p_iptbl_ept, p_iptbl_rsv);
if (!ret) {
update = 0;
}
} else {
/* without dtb, update ept with rsv */
#if 0
p_iptbl_ept->count = p_iptbl_rsv->count;
memcpy(p_iptbl_ept->partitions, p_iptbl_rsv->partitions,
p_iptbl_ept->count * sizeof(struct partitions));
#endif
_cpy_iptbl(p_iptbl_ept, p_iptbl_rsv);
update = 0;
}
} else {
/* without dtb& rsv */
if (!iptbl_dtb.partitions) {
apt_err("dtb&rsv are not exist, no LPT source\n");
ret = -9;
goto _out;
}
}
if (update && iptbl_dtb.partitions) {
apt_wrn("update rsv with dtb!\n");
ret = update_ptbl_rsv(mmc, p_iptbl_ept);
}
//apt_wrn("ept source is %s\n", (ept_source == p_iptbl_ept)?"ept":"rsv");
#if (CONFIG_PTBL_MBR)
/* 1st sector was reserved by romboot after gxl */
if (cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXL) {
if (_check_ptbl_mbr(mmc, p_iptbl_ept)) {
/*fixme, comaptible for mbr&ebr */
ret |= _update_ptbl_mbr(mmc, p_iptbl_ept);
apt_wrn("MBR Updated!\n");
}
}
#endif
#if (CONFIG_CONSTRUCT_GPT)
ret = gpt_restore_by_ept(mmc, p_iptbl_ept);
apt_wrn("GPT IS RESTORED %s\n", ret ? "Failed!" : "OK!");
#endif
/* init part again */
init_part(&mmc->block_dev);
_out:
if (p_iptbl_rsv)
_free_iptbl(p_iptbl_rsv);
return ret;
}
struct partitions *find_mmc_partition_by_name (char *name)
{
struct partitions *partition = NULL;
if (NULL == p_iptbl_ept)
goto _out;
partition = p_iptbl_ept->partitions;
partition = _find_partition_by_name(partition,
p_iptbl_ept->count, name);
_out:
return partition;
}
/*
find virtual partition in inherent table.
*/
int find_virtual_partition_by_name (char *name, struct partitions *partition)
{
int ret = 0;
ulong offset;
struct virtual_partition *vpart = aml_get_virtual_partition_by_name(MMC_DTB_NAME);
if (NULL == partition)
return -1;
offset = _get_inherent_offset(MMC_RESERVED_NAME);
if (-1 == offset) {
apt_err("can't find %s in inherent\n", MMC_RESERVED_NAME);
return -1;
}
if (!strcmp(name, "dtb")) {
strcpy(partition->name, name);
partition->offset = offset + vpart->offset;
partition->size = (vpart->size * DTB_COPIES);
}
return ret;
}
int find_dev_num_by_partition_name (char *name)
{
int dev = -1;
/* card */
if (!strcmp(name, MMC_CARD_PARTITION_NAME)) {
dev = 0;
} else { /* eMMC OR TSD */
/* partition name is valid */
if (find_mmc_partition_by_name(name)) {
dev = 1;
}
}
return dev;
}
static inline uint64_t get_part_size(struct partitions *part, int num)
{
return part[num].size;
}
static inline uint64_t get_part_offset(struct partitions *part, int num)
{
return part[num].offset;
}
static inline char * get_part_name(struct partitions *part, int num)
{
return (char *)part[num].name;
}
int get_part_info_from_tbl(block_dev_desc_t *dev_desc,
int num, disk_partition_t *info)
{
int ret = 0;
struct partitions *part;
if (NULL == p_iptbl_ept)
return -1;
if (num > (p_iptbl_ept->count-1))
return -1;
part = p_iptbl_ept->partitions;
/*get partition info by index! */
info->start = (lbaint_t)(get_part_offset(part, num)/dev_desc->blksz);
info->size = (lbaint_t)(get_part_size(part, num)/dev_desc->blksz);
info->blksz = dev_desc->blksz;
strcpy((char *)info->name, get_part_name(part, num));
return ret;
}
#if (CONFIG_MPT_DEBUG)
void show_partition_info(disk_partition_t *info)
{
printf("----------%s----------\n", __func__);
printf("name %10s\n", info->name);
printf("blksz " LBAFU "\n", info->blksz);
printf("sart %ld\n", info->start);
printf("size %ld\n", info->size);
printf("----------end----------\n");
}
#endif
int mmc_boot_size(char *name, uint64_t* size)
{
return get_boot_size(name, size);
}
struct partitions *aml_get_partition_by_name(const char *name)
{
struct partitions *partition = NULL;
partition = _find_partition_by_name(emmc_partition_table,
get_emmc_partition_arraysize(), name);
if (partition == NULL)
apt_wrn("do not find match in inherent table %s\n", name);
return partition;
}
struct virtual_partition *aml_get_virtual_partition_by_name(const char *name)
{
int i = 0, cnt;
struct virtual_partition *part = NULL;
cnt = get_emmc_virtual_partition_arraysize();
while (i < cnt) {
part = &virtual_partition_table[i];
if (!strcmp(name, part->name)) {
apt_info("find %10s @ tbl[%d]\n", name, i);
break;
}
i++;
};
if (i == cnt) {
part = NULL;
apt_wrn("do not find match in table %10s\n", name);
}
return part;
}
int get_part_info_by_name(block_dev_desc_t *dev_desc,
const char *name, disk_partition_t *info)
{
struct partitions *partition = NULL;
struct partitions virtual;
int ret = 0;
cpu_id_t cpu_id = get_cpu_id();
partition = find_mmc_partition_by_name((char *)name);
if (partition) {
info->start = (lbaint_t)(partition->offset/dev_desc->blksz);
info->size = (lbaint_t)(partition->size/dev_desc->blksz);
info->blksz = dev_desc->blksz;
strcpy((char *)info->name, partition->name);
} else if (!find_virtual_partition_by_name((char *)name, &virtual)) {
/* try virtual partitions */
apt_wrn("Got %s in virtual table\n", name);
info->start = (lbaint_t)(virtual.offset/dev_desc->blksz);
info->size = (lbaint_t)(virtual.size/dev_desc->blksz);
info->blksz = dev_desc->blksz;
strcpy((char *)info->name, virtual.name);
} else {
/* all partitions were tried, fail */
ret = -1;
goto _out;
}
/* for bootloader */
if ((0 == info->start) && (cpu_id.family_id >= MESON_CPU_MAJOR_ID_GXL)) {
info->start = 1;
info->size -= 1;
}
#if (CONFIG_MPT_DEBUG)
show_partition_info(info);
#endif
_out:
return ret;
}
/*
* get the partition number by name
* return value
* < 0 means no partition found
* >= 0 means valid partition
*/
__weak int get_partition_num_by_name(char *name)
{
int ret = -1;
struct partitions *partition = NULL;
if (NULL == p_iptbl_ept)
goto _out;
partition = p_iptbl_ept->partitions;
ret = _get_part_index_by_name(partition,
p_iptbl_ept->count, name);
_out:
return ret;
}