rv1126-uboot/arch/arm/mach-rockchip/resource_img.c

317 lines
8.2 KiB
C

/*
* (C) Copyright 2017 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <malloc.h>
#include <linux/list.h>
#include <asm/arch/resource_img.h>
#include <boot_rkimg.h>
#ifdef CONFIG_ANDROID_BOOT_IMAGE
#include <android_bootloader.h>
#include <android_image.h>
#endif
#define PART_RESOURCE "resource"
#define RESOURCE_MAGIC "RSCE"
#define RESOURCE_MAGIC_SIZE 4
#define RESOURCE_VERSION 0
#define CONTENT_VERSION 0
#define ENTRY_TAG "ENTR"
#define ENTRY_TAG_SIZE 4
#define MAX_FILE_NAME_LEN 256
/*
* resource image structure
* ----------------------------------------------
* | |
* | header (1 block) |
* | |
* ---------------------------------------------|
* | | |
* | entry0 (1 block) | |
* | | |
* ------------------------ |
* | | |
* | entry1 (1 block) | contents (n blocks) |
* | | |
* ------------------------ |
* | ...... | |
* ------------------------ |
* | | |
* | entryn (1 block) | |
* | | |
* ----------------------------------------------
* | |
* | file0 (x blocks) |
* | |
* ----------------------------------------------
* | |
* | file1 (y blocks) |
* | |
* ----------------------------------------------
* | ...... |
* |---------------------------------------------
* | |
* | filen (z blocks) |
* | |
* ----------------------------------------------
*/
/**
* struct resource_image_header
*
* @magic: should be "RSCE"
* @version: resource image version, current is 0
* @c_version: content version, current is 0
* @blks: the size of the header ( 1 block = 512 bytes)
* @c_offset: contents offset(by block) in the image
* @e_blks: the size(by block) of the entry in the contents
* @e_num: numbers of the entrys.
*/
struct resource_img_hdr {
char magic[4];
uint16_t version;
uint16_t c_version;
uint8_t blks;
uint8_t c_offset;
uint8_t e_blks;
uint32_t e_nums;
};
struct resource_entry {
char tag[4];
char name[MAX_FILE_NAME_LEN];
uint32_t f_offset;
uint32_t f_size;
};
struct resource_file {
char name[MAX_FILE_NAME_LEN];
uint32_t f_offset;
uint32_t f_size;
struct list_head link;
uint32_t rsce_base; /* Base addr of resource */
};
static LIST_HEAD(entrys_head);
static int resource_image_check_header(const struct resource_img_hdr *hdr)
{
int ret;
ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE);
if (ret) {
printf("bad resource image magic\n");
ret = -EINVAL;
}
debug("resource image header:\n");
debug("magic:%s\n", hdr->magic);
debug("version:%d\n", hdr->version);
debug("c_version:%d\n", hdr->c_version);
debug("blks:%d\n", hdr->blks);
debug("c_offset:%d\n", hdr->c_offset);
debug("e_blks:%d\n", hdr->e_blks);
debug("e_num:%d\n", hdr->e_nums);
return ret;
}
static int add_file_to_list(struct resource_entry *entry, int rsce_base)
{
struct resource_file *file;
if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) {
printf("invalid entry tag\n");
return -ENOENT;
}
file = malloc(sizeof(*file));
if (!file) {
printf("out of memory\n");
return -ENOMEM;
}
strcpy(file->name, entry->name);
file->rsce_base = rsce_base;
file->f_offset = entry->f_offset;
file->f_size = entry->f_size;
list_add_tail(&file->link, &entrys_head);
debug("entry:%p %s offset:%d size:%d\n",
entry, file->name, file->f_offset, file->f_size);
return 0;
}
static int init_resource_list(struct resource_img_hdr *hdr)
{
struct resource_entry *entry;
void *content;
int size;
int ret;
int e_num;
int offset = 0;
int mode = 0;
struct blk_desc *dev_desc;
disk_partition_t part_info;
#ifdef CONFIG_ANDROID_BOOT_IMAGE
struct andr_img_hdr *andr_hdr;
char *boot_partname = PART_BOOT;
#endif
if (hdr) {
content = (void *)((char *)hdr
+ (hdr->c_offset) * RK_BLK_SIZE);
for (e_num = 0; e_num < hdr->e_nums; e_num++) {
size = e_num * hdr->e_blks * RK_BLK_SIZE;
entry = (struct resource_entry *)(content + size);
add_file_to_list(entry, offset);
}
return 0;
}
dev_desc = rockchip_get_bootdev();
hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE);
if (!hdr) {
printf("%s out of memory!\n", __func__);
return -ENOMEM;
}
#ifdef CONFIG_ANDROID_BOOT_IMAGE
/* Get boot mode from misc */
mode = rockchip_get_boot_mode();
if (mode == BOOT_MODE_RECOVERY)
boot_partname = PART_RECOVERY;
/* Read boot/recovery and chenc if this is an AOSP img */
ret = part_get_info_by_name(dev_desc, boot_partname,
&part_info);
if (ret < 0) {
printf("fail to get %s part\n", boot_partname);
goto out;
}
andr_hdr = (void *)hdr;
ret = blk_dread(dev_desc, part_info.start, 1, andr_hdr);
if (ret != 1) {
printf("%s read fail\n", __func__);
goto out;
}
ret = android_image_check_header(andr_hdr);
if (!ret) {
debug("%s Load resource from %s senond pos\n",
__func__, part_info.name);
/* Read resource from second offset */
offset = part_info.start * RK_BLK_SIZE;
offset += andr_hdr->page_size;
offset += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size);
offset += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size);
offset = offset / RK_BLK_SIZE;
} else {
/* Set mode to 0 in for recovery is not valid AOSP img */
mode = 0;
}
#endif
if (!mode) {
/* Read resource from Rockchip Resource partition */
ret = part_get_info_by_name(dev_desc, PART_RESOURCE,
&part_info);
if (ret < 0) {
printf("fail to get %s part\n", PART_RESOURCE);
goto out;
}
offset = part_info.start;
debug("%s Load resource from %s\n", __func__, part_info.name);
}
ret = blk_dread(dev_desc, offset, 1, hdr);
if (ret != 1)
goto out;
ret = resource_image_check_header(hdr);
if (ret < 0)
goto out;
content = memalign(ARCH_DMA_MINALIGN,
hdr->e_blks * hdr->e_nums * RK_BLK_SIZE);
if (!content) {
printf("alloc memory for content failed\n");
goto out;
}
ret = blk_dread(dev_desc, offset + hdr->c_offset,
hdr->e_blks * hdr->e_nums, content);
if (ret != (hdr->e_blks * hdr->e_nums))
goto err;
for (e_num = 0; e_num < hdr->e_nums; e_num++) {
size = e_num * hdr->e_blks * RK_BLK_SIZE;
entry = (struct resource_entry *)(content + size);
add_file_to_list(entry, offset);
}
err:
free(content);
out:
free(hdr);
return 0;
}
static struct resource_file *get_file_info(struct resource_img_hdr *hdr,
const char *name)
{
struct resource_file *file;
struct list_head *node;
if (list_empty(&entrys_head))
init_resource_list(hdr);
list_for_each(node, &entrys_head) {
file = list_entry(node, struct resource_file, link);
if (!strcmp(file->name, name))
return file;
}
return NULL;
}
int rockchip_get_resource_file(void *buf, const char *name)
{
struct resource_file *file;
file = get_file_info(buf, name);
return file->f_offset;
}
/*
* read file from resource partition
* @buf: destination buf to store file data;
* @name: file name
* @offset: blocks offset in the file, 1 block = 512 bytes
* @len: the size(by bytes) of file to read.
*/
int rockchip_read_resource_file(void *buf, const char *name,
int offset, int len)
{
struct resource_file *file;
int ret = 0;
int blks;
struct blk_desc *dev_desc;
file = get_file_info(NULL, name);
if (!file) {
printf("Can't find file:%s\n", name);
return -ENOENT;
}
if (len <= 0 || len > file->f_size)
len = file->f_size;
blks = DIV_ROUND_UP(len, RK_BLK_SIZE);
dev_desc = rockchip_get_bootdev();
ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset,
blks, buf);
if (ret != blks)
ret = -EIO;
else
ret = len;
return ret;
}