blob: c7dc25c6d0d94e1a97594d7a7644578e97fccee1 [file] [log] [blame]
/*
* Copyright (c) 2020 MediaTek Inc.
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <arch/ops.h>
#include <assert.h>
#include <errno.h>
#include <lib/android_bootimg.h>
#include <lib/bio.h>
#include <lib/boot_info.h>
#include <lib/decompress.h>
#include <lib/mempool.h>
#include <kernel/vm.h>
#include <string.h>
#include <trace.h>
#define LOCAL_TRACE 0
static int get_decompress_algo(unsigned char *src)
{
int ret = NO_DECOMPRESS;
uint16_t gzip_magic;
uint32_t lz4_magic;
/* lz4 magic stores to 32-bits little-endian */
lz4_magic = src[0];
lz4_magic |= (src[1] << 8);
lz4_magic |= (src[2] << 16);
lz4_magic |= (src[3] << 24);
/* gzip magic stores to 16-bits big-endian */
gzip_magic = (src[0] << 8);
gzip_magic |= src[1];
if (lz4_magic == LZ4_LEGACY_MAGIC)
ret = LZ4_DECOMPRESS;
else if (gzip_magic == GZIP_MAGIC)
ret = GZIP_DECOMPRESS;
return ret;
}
int android_get_image(const char *label, void **load_buf)
{
bdev_t *bdev;
struct bootimg_hdr bootimg;
size_t totalsize;
int hdr_len, ret = 0;
void *buf = NULL;
bdev = bio_open_by_label(label) ? : bio_open(label);
if (!bdev) {
LTRACEF_LEVEL(CRITICAL, "Partition [%s] is not exist.\n", label);
return -ENODEV;
}
hdr_len = sizeof(struct bootimg_hdr);
if (bio_read(bdev, &bootimg, 0, hdr_len) < hdr_len ) {
ret = -EIO;
goto closebdev;
}
ret = load_bootinfo_bootimg_hdr(&bootimg);
if (ret)
goto closebdev;
totalsize = get_page_sz() + get_ramdisk_sz() + get_dtb_size()
+ get_kernel_sz();
buf = mempool_alloc(totalsize, MEMPOOL_ANY);
if (!buf) {
ret = -ENOMEM;
goto closebdev;
}
if ((size_t)bio_read(bdev, buf, 0, totalsize) < totalsize) {
ret = -EIO;
goto closebdev;
}
*load_buf = buf;
closebdev:
bio_close(bdev);
if (ret && buf)
mempool_free(buf);
return ret;
}
int android_processing_data(const char *image_name, vaddr_t load_data,
addr_t target_addr, size_t size)
{
int ret;
int algo;
vaddr_t load_addr;
if (size == 0) {
LTRACEF_LEVEL(CRITICAL, "%s is NULL\n", image_name);
return -EINVAL;
}
#if WITH_KERNEL_VM
load_addr = (vaddr_t)paddr_to_kvaddr(target_addr);
#endif
algo = get_decompress_algo((unsigned char *)load_data);
switch(algo) {
case LZ4_DECOMPRESS:
ret = unlz4((void *)load_data, size - 4, (void *)load_addr);
if (ret != LZ4_OK) {
LTRACEF_LEVEL(ALWAYS, "[%s] lz4 decompress failure\n",
image_name);
return -LZ4_FAIL;
}
/* In lz4 kernel image, the last 4 bytes are the uncompressed
* kernel image size.
*/
size = *(uint32_t *)(load_data + size - 4);
break;
case GZIP_DECOMPRESS:
if (strcmp(image_name, "ramdisk")) {
LTRACEF_LEVEL(ALWAYS, "[%s] gzip is not suppport\n",
image_name);
return -EINVAL;
}
default:
memmove((void *)load_addr, (void *)load_data, size);
break;
}
#if WITH_KERNEL_VM
/* always flush cache to PoC */
arch_clean_cache_range(load_addr, size);
#endif
LTRACEF("[%s] load_addr = 0x%lx\n", image_name, load_addr);
LTRACEF("[%s] data = 0x%lx\n", image_name, load_data);
LTRACEF("[%s] size = %zu\n", image_name, size);
return 0;
}