306 lines
8.8 KiB
C
306 lines
8.8 KiB
C
/*
|
|
* (C) Copyright 2023 Rockchip Electronics Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <android_image.h>
|
|
#include <crypto.h>
|
|
#include <image.h>
|
|
#include <mp_boot.h>
|
|
#include <part.h>
|
|
#include <spl.h>
|
|
#include <asm/io.h>
|
|
|
|
#define BLK_CNT(_num_bytes, _block_size) \
|
|
((_num_bytes + _block_size - 1) / _block_size)
|
|
|
|
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|
|
static int android_check_header(const struct andr_img_hdr *hdr)
|
|
{
|
|
return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
|
|
}
|
|
|
|
static void print_hash(const char *label, u8 *hash, int len)
|
|
{
|
|
int i;
|
|
|
|
printf("%s:\n 0x", label ? : "Hash");
|
|
for (i = 0; i < len; i++)
|
|
printf("%02x", hash[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
#if 0
|
|
static void spl_android_print_contents(const struct andr_img_hdr *hdr)
|
|
{
|
|
const char * const p = IMAGE_INDENT_STRING;
|
|
/* os_version = ver << 11 | lvl */
|
|
u32 os_ver = hdr->os_version >> 11;
|
|
u32 os_lvl = hdr->os_version & ((1U << 11) - 1);
|
|
u32 header_version = hdr->header_version;
|
|
|
|
printf("%skernel size: %x\n", p, hdr->kernel_size);
|
|
printf("%skernel address: %x\n", p, hdr->kernel_addr);
|
|
printf("%sramdisk size: %x\n", p, hdr->ramdisk_size);
|
|
printf("%sramdisk address: %x\n", p, hdr->ramdisk_addr);
|
|
printf("%ssecond size: %x\n", p, hdr->second_size);
|
|
printf("%ssecond address: %x\n", p, hdr->second_addr);
|
|
printf("%stags address: %x\n", p, hdr->tags_addr);
|
|
printf("%spage size: %x\n", p, hdr->page_size);
|
|
printf("%sheader_version: %x\n", p, header_version);
|
|
/* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
|
|
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) */
|
|
printf("%sos_version: %x (ver: %u.%u.%u, level: %u.%u)\n",
|
|
p, hdr->os_version,
|
|
(os_ver >> 7) & 0x7F, (os_ver >> 14) & 0x7F, os_ver & 0x7F,
|
|
(os_lvl >> 4) + 2000, os_lvl & 0x0F);
|
|
printf("%sname: %s\n", p, hdr->name);
|
|
printf("%scmdline: %s\n", p, hdr->cmdline);
|
|
|
|
if (header_version == 1 || header_version == 2) {
|
|
printf("%srecovery dtbo size: %x\n", p, hdr->recovery_dtbo_size);
|
|
printf("%srecovery dtbo offset: %llx\n", p, hdr->recovery_dtbo_offset);
|
|
printf("%sheader size: %x\n", p, hdr->header_size);
|
|
}
|
|
|
|
if (header_version == 2 || header_version == 3) {
|
|
printf("%sdtb size: %x\n", p, hdr->dtb_size);
|
|
printf("%sdtb addr: %llx\n", p, hdr->dtb_addr);
|
|
}
|
|
|
|
if (header_version >= 3) {
|
|
printf("%scmdline: %s\n", p, hdr->total_cmdline);
|
|
printf("%svendor ramdisk size: %x\n", p, hdr->vendor_ramdisk_size);
|
|
printf("%svendor page size: %x\n", p, hdr->vendor_page_size);
|
|
printf("%svendor header version: %d\n", p, hdr->vendor_header_version);
|
|
printf("%svendor header size: %x\n", p, hdr->vendor_header_size);
|
|
}
|
|
|
|
if (header_version >= 4) {
|
|
printf("%svendor ramdisk table size: %x\n",
|
|
p, hdr->vendor_ramdisk_table_size);
|
|
printf("%svendor ramdisk table entry num: %x\n",
|
|
p, hdr->vendor_ramdisk_table_entry_num);
|
|
printf("%svendor ramdisk table entry size: %x\n",
|
|
p, hdr->vendor_ramdisk_table_entry_size);
|
|
printf("%svendor bootconfig size: %d\n",
|
|
p, hdr->vendor_bootconfig_size);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static ulong android_size(struct andr_img_hdr *hdr)
|
|
{
|
|
ulong len;
|
|
|
|
len = hdr->page_size +
|
|
ALIGN(hdr->kernel_size, hdr->page_size) +
|
|
ALIGN(hdr->ramdisk_size, hdr->page_size) +
|
|
ALIGN(hdr->second_size, hdr->page_size);
|
|
if (hdr->header_version > 0)
|
|
len += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
|
|
if (hdr->header_version > 1)
|
|
len += ALIGN(hdr->dtb_size, hdr->page_size);
|
|
#if 0
|
|
spl_android_print_contents(hdr);
|
|
#endif
|
|
|
|
return len;
|
|
}
|
|
|
|
int spl_load_android(struct task_data *data)
|
|
{
|
|
struct spl_load_info *info = &data->info;
|
|
void *buf = (void *)CONFIG_SPL_BOOT_IMAGE_BUF;
|
|
disk_partition_t part;
|
|
ulong blkcnt;
|
|
|
|
debug("== Android: load start\n");
|
|
|
|
if (part_get_info_by_name(info->dev, "boot", &part) < 0) {
|
|
printf("No boot partition\n");
|
|
return -ENOENT;
|
|
}
|
|
|
|
blkcnt = BLK_CNT(sizeof(struct andr_img_hdr), info->bl_len);
|
|
if (info->read(info, part.start, blkcnt, buf) != blkcnt)
|
|
return -EIO;
|
|
|
|
if (android_check_header(buf))
|
|
return -EINVAL;
|
|
|
|
blkcnt = BLK_CNT(android_size(buf), info->bl_len);
|
|
if (info->read(info, part.start, blkcnt, buf) != blkcnt)
|
|
return -EIO;
|
|
|
|
data->boot_addr = (void *)CONFIG_SPL_BOOT_IMAGE_BUF;
|
|
data->boot_size = blkcnt * info->bl_len;
|
|
|
|
flush_dcache_range((ulong)data, (ulong)data + sizeof(*data));
|
|
flush_dcache_range((ulong)buf, (ulong)buf + blkcnt);
|
|
|
|
debug("== Android: load 0x%08lx size OK\n", blkcnt * info->bl_len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_ARMV8_CE_SHA1
|
|
int spl_hash_android(struct task_data *data)
|
|
{
|
|
struct andr_img_hdr *hdr = (void *)CONFIG_SPL_BOOT_IMAGE_BUF;
|
|
sha1_context ctx;
|
|
uchar hash[32];
|
|
void *buf;
|
|
|
|
printf("== Android: hash start\n");
|
|
|
|
if (hdr->header_version >= 3)
|
|
return -EINVAL;
|
|
|
|
sha1_starts(&ctx);
|
|
|
|
buf = (void *)hdr + hdr->page_size;
|
|
sha1_update(&ctx, (const uchar *)buf, hdr->kernel_size);
|
|
sha1_update(&ctx, (const uchar *)&hdr->kernel_size, sizeof(hdr->kernel_size));
|
|
|
|
buf += ALIGN(hdr->kernel_size, hdr->page_size);
|
|
sha1_update(&ctx, (const uchar *)buf, hdr->ramdisk_size);
|
|
sha1_update(&ctx, (const uchar *)&hdr->ramdisk_size, sizeof(hdr->ramdisk_size));
|
|
|
|
buf += ALIGN(hdr->ramdisk_size, hdr->page_size);
|
|
sha1_update(&ctx, (const uchar *)buf, hdr->second_size);
|
|
sha1_update(&ctx, (const uchar *)&hdr->second_size, sizeof(hdr->second_size));
|
|
|
|
if (hdr->header_version > 0) {
|
|
buf += ALIGN(hdr->second_size, hdr->page_size);
|
|
sha1_update(&ctx, (const uchar *)buf, hdr->recovery_dtbo_size);
|
|
sha1_update(&ctx, (const uchar *)&hdr->recovery_dtbo_size, sizeof(hdr->recovery_dtbo_size));
|
|
}
|
|
if (hdr->header_version > 1) {
|
|
buf += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
|
|
sha1_update(&ctx, (const uchar *)buf, hdr->dtb_size);
|
|
sha1_update(&ctx, (const uchar *)&hdr->dtb_size, sizeof(hdr->dtb_size));
|
|
}
|
|
|
|
sha1_finish(&ctx, hash);
|
|
|
|
if (memcmp(hash, hdr->id, 20)) {
|
|
print_hash("Hash from header", (u8 *)hdr->id, 20);
|
|
print_hash("Hash real", (u8 *)hash, 20);
|
|
return -EBADFD;
|
|
}
|
|
|
|
printf("== Android: hash OK, 0x%08lx\n", (ulong)data->boot_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
int spl_hash_android(struct task_data *data)
|
|
{
|
|
struct andr_img_hdr *hdr = (void *)CONFIG_SPL_BOOT_IMAGE_BUF;
|
|
struct udevice *dev;
|
|
sha_context ctx;
|
|
uchar hash[32];
|
|
void *buf;
|
|
|
|
debug("== Android: hash start\n");
|
|
|
|
if (hdr->header_version >= 3)
|
|
return -EINVAL;
|
|
|
|
ctx.algo = CRYPTO_SHA1;
|
|
dev = crypto_get_device(ctx.algo);
|
|
if (!dev) {
|
|
printf("No crypto device for sha1\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
ctx.length = hdr->kernel_size + sizeof(hdr->kernel_size) +
|
|
hdr->ramdisk_size + sizeof(hdr->ramdisk_size) +
|
|
hdr->second_size + sizeof(hdr->second_size);
|
|
if (hdr->header_version > 0)
|
|
ctx.length += hdr->recovery_dtbo_size + sizeof(hdr->recovery_dtbo_size);
|
|
if (hdr->header_version > 1)
|
|
ctx.length += hdr->dtb_size + sizeof(hdr->dtb_size);
|
|
|
|
crypto_sha_init(dev, &ctx);
|
|
|
|
buf = (void *)hdr + hdr->page_size;
|
|
crypto_sha_update(dev, buf, hdr->kernel_size);
|
|
crypto_sha_update(dev, &hdr->kernel_size, sizeof(hdr->kernel_size));
|
|
|
|
buf += ALIGN(hdr->kernel_size, hdr->page_size);
|
|
crypto_sha_update(dev, buf, hdr->ramdisk_size);
|
|
crypto_sha_update(dev, &hdr->ramdisk_size, sizeof(hdr->ramdisk_size));
|
|
|
|
buf += ALIGN(hdr->ramdisk_size, hdr->page_size);
|
|
crypto_sha_update(dev, buf, hdr->second_size);
|
|
crypto_sha_update(dev, &hdr->second_size, sizeof(hdr->second_size));
|
|
|
|
if (hdr->header_version > 0) {
|
|
buf += ALIGN(hdr->second_size, hdr->page_size);
|
|
crypto_sha_update(dev, buf, hdr->recovery_dtbo_size);
|
|
crypto_sha_update(dev, &hdr->recovery_dtbo_size, sizeof(hdr->recovery_dtbo_size));
|
|
}
|
|
if (hdr->header_version > 1) {
|
|
buf += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
|
|
crypto_sha_update(dev, buf, hdr->dtb_size);
|
|
crypto_sha_update(dev, &hdr->dtb_size, sizeof(hdr->dtb_size));
|
|
}
|
|
|
|
crypto_sha_final(dev, &ctx, hash);
|
|
|
|
if (memcmp(hash, hdr->id, 20)) {
|
|
print_hash("Hash from header", (u8 *)hdr->id, 20);
|
|
print_hash("Hash real", (u8 *)hash, 20);
|
|
return -EBADFD;
|
|
}
|
|
|
|
debug("== Android: hash OK, 0x%08lx\n", (ulong)data->boot_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CONFIG_ROCKCHIP_FIT_IMAGE
|
|
int spl_load_fit(struct task_data *data)
|
|
{
|
|
struct spl_load_info *info = &data->info;
|
|
void *buf = (void *)CONFIG_SPL_BOOT_IMAGE_BUF;
|
|
disk_partition_t part;
|
|
ulong blkcnt;
|
|
int size;
|
|
|
|
debug("== FIT: load start\n");
|
|
|
|
if (part_get_info_by_name(info->dev, "boot", &part) < 0) {
|
|
printf("No boot partition\n");
|
|
return -ENOENT;
|
|
}
|
|
|
|
blkcnt = BLK_CNT(sizeof(struct fdt_header), info->bl_len);
|
|
if (info->read(info, part.start, blkcnt, buf) != blkcnt)
|
|
return -EIO;
|
|
|
|
if (fdt_check_header(buf))
|
|
return -EINVAL;
|
|
|
|
size = fit_get_totalsize(buf, &size);
|
|
blkcnt = BLK_CNT(size, info->bl_len);
|
|
if (info->read(info, part.start, blkcnt, buf) != blkcnt)
|
|
return -EIO;
|
|
|
|
flush_dcache_range((ulong)buf, (ulong)buf + blkcnt);
|
|
|
|
debug("== FIT: load 0x%08x size OK\n", size);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|