494 lines
12 KiB
C
Executable File
494 lines
12 KiB
C
Executable File
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2018-2020
|
|
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
|
* wangwei <wangwei@allwinnertech.com>
|
|
*
|
|
*/
|
|
#include <common.h>
|
|
#include <sys_partition.h>
|
|
#include <sunxi_flash.h>
|
|
#include <memalign.h>
|
|
#include <sunxi_mbr.h>
|
|
#include <sunxi_board.h>
|
|
#include <android_misc.h>
|
|
#include <android_ab.h>
|
|
|
|
#ifndef CONFIG_ENABLE_MTD_CMDLINE_PARTS_BY_ENV
|
|
static sunxi_mbr_t *mbr ;
|
|
#endif
|
|
|
|
extern struct bootloader_control ab_message;
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#if defined (CONFIG_ENABLE_MTD_CMDLINE_PARTS_BY_ENV)
|
|
typedef struct sunxi_env_partition_t
|
|
{
|
|
unsigned char name[16];
|
|
unsigned int addrlo;
|
|
unsigned int lenlo;
|
|
unsigned int ro;
|
|
}sunxi_env_partition;
|
|
|
|
typedef struct sunxi_env_mtd_t
|
|
{
|
|
unsigned char device_name[16];
|
|
unsigned int device_id;
|
|
unsigned int PartCount;
|
|
sunxi_env_partition array[SUNXI_MBR_MAX_PART_COUNT];
|
|
}sunxi_env_mtd;
|
|
|
|
static sunxi_env_mtd env_mtd;
|
|
|
|
int sunxi_partition_parse_get_info(int index, disk_partition_t *info)
|
|
{
|
|
int find_flag = 0;
|
|
char *src;
|
|
char *des;
|
|
char tmp[5];
|
|
int partcount;
|
|
int count;
|
|
int size;
|
|
char *cmdline = env_get("sunxi_mtdparts");
|
|
|
|
if(cmdline == NULL)
|
|
{
|
|
printf("error:can't find mtdparts in env.\n");
|
|
debug("get partition error\n");
|
|
return -1;
|
|
}
|
|
//name
|
|
src = cmdline;
|
|
des = strchr(src, '.');
|
|
count = (int)(des-src);
|
|
strncpy((char *)(env_mtd.device_name), src,count);
|
|
//printf("the device.name = %s\n",env_mtd.device_name);
|
|
src = des;
|
|
|
|
//id
|
|
memset(tmp, 0, 5);
|
|
des = strchr(src, ':');
|
|
count = (int)(des-src);
|
|
//printf("count %d\n",count);
|
|
strncpy(tmp, (src+1), (count-1));
|
|
env_mtd.device_id = (int)simple_strtoul(tmp, NULL, 10);
|
|
//printf("env_mtd.device_id = %d\n",env_mtd.device_id);
|
|
src = des;
|
|
|
|
//partition
|
|
for(partcount=0; *(des+1)!='\0'; partcount++)
|
|
{
|
|
//size
|
|
memset(tmp, 0, 5);
|
|
des = strchr(src, '(');
|
|
count = (int)(des-src);
|
|
//printf("count %d\n",count);
|
|
strncpy(tmp,src+1,count-2);
|
|
|
|
size = (int)simple_strtoul(tmp, NULL, 10);
|
|
//printf("size : %d\n",size);
|
|
if(*(des-1) == 'K')
|
|
env_mtd.array[partcount].lenlo = size *1024 / 512;
|
|
else if(*(des-1) == 'M')
|
|
env_mtd.array[partcount].lenlo = size *1024 * 1024 / 512;
|
|
if(partcount == 0)
|
|
env_mtd.array[partcount].addrlo = 0;
|
|
else
|
|
env_mtd.array[partcount].addrlo = env_mtd.array[partcount-1].addrlo
|
|
+ env_mtd.array[partcount-1].lenlo;
|
|
//partition_name
|
|
src = des;
|
|
des = strchr(src, ')');
|
|
count = (int)(des-src);
|
|
strncpy((char *)(env_mtd.array[partcount].name),src+1,count-1);
|
|
|
|
//only-read ?
|
|
src = des;
|
|
des = strchr(src, ',');
|
|
if(des == NULL)
|
|
{
|
|
env_mtd.array[partcount].ro = 0;
|
|
break;
|
|
}
|
|
count = (int)(des-src);
|
|
if(!(count-1) && !strncmp((src+1), "ro",2))
|
|
env_mtd.array[partcount].ro = 1;
|
|
else
|
|
env_mtd.array[partcount].ro = 0;
|
|
|
|
src = des;
|
|
if((index-1) == partcount)
|
|
{
|
|
find_flag = 1;
|
|
strncpy((char *)info->name, (const char *)env_mtd.array[partcount].name, PART_NAME_LEN);
|
|
info->start = env_mtd.array[partcount].addrlo;
|
|
info->size = env_mtd.array[partcount].lenlo;
|
|
//printf("name:%s, size:%d, offset:%x, ro:%d\n",env_mtd.array[partcount].name,env_mtd.array[partcount].lenlo,env_mtd.array[partcount].addrlo,env_mtd.array[partcount].ro);
|
|
break ; //dont check all
|
|
}
|
|
}
|
|
|
|
if(!find_flag) {
|
|
return -1;
|
|
}
|
|
/*
|
|
env_mtd.PartCount = partcount + 1;
|
|
printf("partition_count:%d\n",env_mtd.PartCount);
|
|
*/
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Parses a string into a number. The number stored at ptr is
|
|
* potentially suffixed with K (for kilobytes, or 1024 bytes),
|
|
* M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
|
|
* 1073741824). If the number is suffixed with K, M, or G, then
|
|
* the return value is the number multiplied by one kilobyte, one
|
|
* megabyte, or one gigabyte, respectively.
|
|
*
|
|
* @param ptr where parse begins
|
|
* @param retptr output pointer to next char after parse completes (output)
|
|
* @return resulting unsigned int
|
|
*/
|
|
static u64 size_parse(const char *const ptr, const char **retptr)
|
|
{
|
|
u64 ret = simple_strtoull(ptr, (char **)retptr, 0);
|
|
|
|
switch (**retptr) {
|
|
case 'G':
|
|
case 'g':
|
|
ret <<= 10;
|
|
case 'M':
|
|
case 'm':
|
|
ret <<= 10;
|
|
case 'K':
|
|
case 'k':
|
|
ret <<= 10;
|
|
(*retptr)++;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sunxi_partition_parse(const char *name, disk_partition_t *info)
|
|
{
|
|
const char *src, *des, *part_name;
|
|
const char *cmdline = env_get("mtdparts");
|
|
int name_len;
|
|
|
|
if (!cmdline) {
|
|
printf("error:can't find mtdparts in env.\n");
|
|
debug("get partition error\n");
|
|
return -1;
|
|
}
|
|
|
|
src = strchr(cmdline, ':');
|
|
if (!src) {
|
|
printf("Invalid mtdparts parameter\n");
|
|
return -1;
|
|
}
|
|
|
|
while (1) {
|
|
des = strchr(src, '(');
|
|
if (!des)
|
|
goto err;
|
|
|
|
part_name = ++des;
|
|
|
|
des = strchr(des, ')');
|
|
if (!des)
|
|
goto err;
|
|
|
|
name_len = des - part_name;
|
|
|
|
if (!strncmp(name, part_name, name_len))
|
|
break;
|
|
|
|
src = strchr(des, ',');
|
|
if (!src)
|
|
goto err;
|
|
}
|
|
|
|
src++;
|
|
if (*src == '-')
|
|
goto err;
|
|
|
|
strncpy((char *)info->name, part_name, name_len);
|
|
info->size = size_parse(src, &src);
|
|
|
|
if (*src == '@') {
|
|
src++;
|
|
info->start = size_parse(src, &src);
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
printf("%s not found in mtdparts\n", name);
|
|
return -1;
|
|
}
|
|
|
|
int sunxi_partition_init(void)
|
|
{
|
|
#ifndef CONFIG_ENABLE_MTD_CMDLINE_PARTS_BY_ENV
|
|
if (mbr == NULL) {
|
|
mbr = memalign(ARCH_DMA_MINALIGN, SUNXI_MBR_SIZE);
|
|
if (mbr == NULL) {
|
|
printf("unable to allocate TDs\n");
|
|
return -1;
|
|
}
|
|
|
|
if (sunxi_flash_read(0, SUNXI_MBR_SIZE / 512, (void *)mbr) <=
|
|
0) {
|
|
printf("line:%d:sunxi_flash_read fail\n", __LINE__);
|
|
return -1;
|
|
}
|
|
if (!strncmp((const char *)mbr->magic, SUNXI_MBR_MAGIC, 8)) {
|
|
int crc = 0;
|
|
crc = crc32(0, (const unsigned char *)&mbr->version,
|
|
SUNXI_MBR_SIZE - 4);
|
|
if (crc != mbr->crc32) {
|
|
return -1;
|
|
}
|
|
gd->lockflag = mbr->lockflag;
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int sunxi_probe_partition_map(void)
|
|
{
|
|
#ifndef CONFIG_ENABLE_MTD_CMDLINE_PARTS_BY_ENV
|
|
struct blk_desc *desc;
|
|
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
|
|
if (desc == NULL) {
|
|
pr_err("%s: get desc fail\n", __func__);
|
|
return -1;
|
|
}
|
|
if (part_init_info_map(desc) < 0)
|
|
return -1;
|
|
else
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
|
|
int sunxi_replace_android_ab_system(char *intput_part_name, char *output_part_name)
|
|
{
|
|
strncpy(output_part_name, intput_part_name, strlen(intput_part_name));
|
|
#ifdef CONFIG_ANDROID_AB
|
|
int i, ret;
|
|
static int part_cur_len;
|
|
static char ab_partition[16][16] = {"bootloader", "env", "boot", "vendor_boot", "init_boot", "dtbo", "vbmeta", "vbmeta_system", "vbmeta_vendor"};
|
|
char *ab_part_list = env_get("ab_partition_list");
|
|
if ((gd->env_has_init) && (ab_part_list != NULL) && (part_cur_len != strlen(ab_part_list))) {
|
|
memset(ab_partition, 0, sizeof(ab_partition));
|
|
sunxi_parsed_specific_string(ab_part_list, ab_partition, ',', ' ');
|
|
part_cur_len = strlen(ab_part_list);
|
|
}
|
|
ret = ab_select_slot_from_partname("misc");
|
|
/* tick_printf("output_part_name:%s\t intput_part_name:%s\n", output_part_name, intput_part_name); */
|
|
for (i = 0; i < sizeof(ab_partition)/sizeof(ab_partition[0]); i++) {
|
|
if (!strncmp(intput_part_name, ab_partition[i], max(strlen(intput_part_name), strlen(ab_partition[i])))) {
|
|
if (ret == 1) {
|
|
sprintf(output_part_name, "%s_b", intput_part_name);
|
|
} else {
|
|
sprintf(output_part_name, "%s_a", intput_part_name);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
/* tick_printf("output_part_name:%s\t intput_part_name:%s\n", output_part_name, intput_part_name); */
|
|
return 0;
|
|
}
|
|
|
|
int sunxi_partition_get_partno_byname(const char *part_name)
|
|
{
|
|
int i;
|
|
struct blk_desc *desc;
|
|
int ret;
|
|
disk_partition_t info;
|
|
char temp_part_name[16] = {0};
|
|
|
|
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
|
|
if (desc == NULL) {
|
|
printf("%s: get desc fail\n", __func__);
|
|
ret = -ENODEV;
|
|
}
|
|
sunxi_replace_android_ab_system((char *)part_name, temp_part_name);
|
|
|
|
for (i = 1;; i++) {
|
|
ret = part_get_info(desc, i, &info);
|
|
debug("%s: try part %d, ret = %d\n", __func__, i, ret);
|
|
if (ret < 0) {
|
|
printf("partno erro : can't find partition %s\n", part_name);
|
|
return ret;
|
|
}
|
|
if (!strncmp((const char *)info.name, temp_part_name, sizeof(info.name))) {
|
|
return i;
|
|
} else if (!strncmp((const char *)info.name, part_name, sizeof(info.name))) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int sunxi_partition_get_info_byname(const char *part_name, uint *part_offset,
|
|
uint *part_size)
|
|
{
|
|
disk_partition_t info = { 0 };
|
|
if (sunxi_partition_get_info(part_name, &info) == 0) {
|
|
*part_offset = info.start;
|
|
*part_size = info.size;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
uint sunxi_partition_get_offset_byname(const char *part_name)
|
|
{
|
|
disk_partition_t info = { 0 };
|
|
if (sunxi_partition_get_info(part_name, &info) == 0) {
|
|
return info.start;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* for blk read/write */
|
|
int sunxi_flash_try_partition(struct blk_desc *desc, const char *str,
|
|
disk_partition_t *info)
|
|
{
|
|
int i, ret;
|
|
char temp_part_name[16] = {0};
|
|
#if 0
|
|
char *gpt_signature[512] = {0};
|
|
printf("\n");
|
|
debug("line:%d:gpt_header_size %d\n", __LINE__, sizeof(gpt_header));
|
|
if (sunxi_flash_phyread(1, 1, (void *)gpt_signature) <= 0) {
|
|
printf("line:%d:sunxi_flash_read fail\n", __LINE__);
|
|
}
|
|
if (strncmp((const char *)(gpt_signature), GPT_SIGNATURE, sizeof(GPT_SIGNATURE))) {
|
|
debug("line:%d:get gpt partition fail\n", __LINE__);
|
|
debug("line:%d:try to mbr partition\n", __LINE__);
|
|
if (get_boot_storage_type() == STORAGE_SD) {
|
|
u32 start, size;
|
|
if (sunxi_partition_get_info_byname(str, &start, &size))
|
|
return -1;
|
|
strcpy((char *)info->name, str);
|
|
info->start = start;
|
|
info->size = size;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
printf("line:%d:get gpt partition success\n", __LINE__);
|
|
#endif
|
|
sunxi_replace_android_ab_system((char *)str, temp_part_name);
|
|
|
|
for (i = 1;; i++) {
|
|
#if defined (CONFIG_ENABLE_MTD_CMDLINE_PARTS_BY_ENV) /*Get partitiones by env*/
|
|
ret = sunxi_partition_parse_get_info(i, info);
|
|
#else /* Get partitiones by GPT */
|
|
ret = part_get_info(desc, i, info);
|
|
debug("%s: try part %d, ret = %d\n", __func__, i, ret);
|
|
|
|
#endif
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (!strncmp((const char *)info->name, temp_part_name, sizeof(info->name)))
|
|
break;
|
|
else if (!strncmp((const char *)info->name, (char *)str, sizeof(info->name)))
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* for sunxi_flash_read/write */
|
|
int sunxi_partition_get_info(const char *part_name, disk_partition_t *info)
|
|
{
|
|
struct blk_desc *desc;
|
|
int ret;
|
|
int storage_type;
|
|
int logic_offset;
|
|
|
|
storage_type = get_boot_storage_type();
|
|
if (get_boot_work_mode() == WORK_MODE_CARD_PRODUCT ||
|
|
storage_type == STORAGE_EMMC || storage_type == STORAGE_EMMC3
|
|
|| storage_type == STORAGE_SD || storage_type == STORAGE_EMMC0) {
|
|
logic_offset = sunxi_flashmap_logical_offset(FLASHMAP_SDMMC, LINUX_LOGIC_OFFSET);
|
|
} else {
|
|
logic_offset = 0;
|
|
}
|
|
|
|
desc = blk_get_devnum_by_typename("sunxi_flash", 0);
|
|
if (desc == NULL) {
|
|
debug("%s: get desc fail\n", __func__);
|
|
ret = -ENODEV;
|
|
goto __err;
|
|
}
|
|
ret = sunxi_flash_try_partition(desc, part_name, info);
|
|
if (ret < 0) {
|
|
debug("%s: get partition info fail\n", __func__);
|
|
ret = -ENODEV;
|
|
goto __err;
|
|
}
|
|
debug("name:%s start:0x%x, size: 0x%x\n", info->name, (u32)info->start,
|
|
(u32)info->size);
|
|
/* conver gpt info to sunxi_part */
|
|
/* gpt part use phy address */
|
|
/* sunxi part use logic address */
|
|
info->start -= logic_offset;
|
|
|
|
return 0;
|
|
__err:
|
|
return ret;
|
|
|
|
}
|
|
|
|
/* for card sprite mode*/
|
|
lbaint_t sunxi_partition_get_offset(int part_index)
|
|
{
|
|
|
|
if (get_boot_work_mode() != WORK_MODE_CARD_PRODUCT) {
|
|
printf("****not support*****\n");
|
|
return (lbaint_t)(-1);
|
|
}
|
|
|
|
#ifdef CONFIG_ENABLE_MTD_CMDLINE_PARTS_BY_ENV
|
|
disk_partition_t info;
|
|
int ret;
|
|
ret = sunxi_partition_parse_get_info(part_index, &info);
|
|
if (ret == 0) {
|
|
debug(" mbr->array[%d].name=%s\n", part_index,
|
|
info.name);
|
|
debug(" mbr->array[%d].lenlo=0x%x\n", part_index,
|
|
(u32)info.size);
|
|
debug("mbr->array[%d].addrlo=0x%x\n", part_index,
|
|
(u32)info.start);
|
|
return (lbaint_t)info.start;
|
|
}
|
|
#else
|
|
sunxi_partition_init();
|
|
if (mbr->PartCount && part_index <= mbr->PartCount) {
|
|
debug(" mbr->array[%d].name=%s\n", part_index,
|
|
mbr->array[part_index].name);
|
|
debug(" mbr->array[%d].lenlo=%d\n", part_index,
|
|
mbr->array[part_index].lenlo);
|
|
debug("mbr->array[%d].addrlo=%d\n", part_index,
|
|
mbr->array[part_index].addrlo);
|
|
return (lbaint_t)mbr->array[part_index].addrlo;
|
|
}
|
|
|
|
#endif
|
|
return (lbaint_t)(-1);
|
|
}
|