int
boot_linux_from_mmc(
void
)
{
struct
boot_img_hdr *hdr = (
void
*) buf;
struct
boot_img_hdr *uhdr;
unsigned offset = 0;
int
rcode;
unsigned
long
long
ptn = 0;
int
index = INVALID_PTN;
unsigned
char
*image_addr = 0;
unsigned kernel_actual;
unsigned ramdisk_actual;
unsigned imagesize_actual;
unsigned second_actual = 0;
unsigned
int
dtb_size = 0;
unsigned
int
out_len = 0;
unsigned
int
out_avai_len = 0;
unsigned
char
*out_addr = NULL;
uint32_t dtb_offset = 0;
unsigned
char
*kernel_start_addr = NULL;
unsigned
int
kernel_size = 0;
int
rc;
#if DEVICE_TREE
struct
dt_table *table;
struct
dt_entry dt_entry;
unsigned dt_table_offset;
uint32_t dt_actual;
uint32_t dt_hdr_size;
unsigned
char
*best_match_dt_addr = NULL;
#endif
struct
kernel64_hdr *kptr = NULL;
if
(check_format_bit())
boot_into_recovery = 1;
if
(!boot_into_recovery) {
memset
(ffbm_mode_string,
'\0'
,
sizeof
(ffbm_mode_string));
rcode = get_ffbm(ffbm_mode_string,
sizeof
(ffbm_mode_string));
if
(rcode <= 0) {
boot_into_ffbm =
false
;
if
(rcode < 0)
dprintf(CRITICAL,
"failed to get ffbm cookie"
);
}
else
boot_into_ffbm =
true
;
}
else
boot_into_ffbm =
false
;
uhdr = (
struct
boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
if
(!
memcmp
(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
dprintf(INFO,
"Unified boot method!\n"
);
hdr = uhdr;
goto
unified_boot;
}
if
(!boot_into_recovery) {
index = partition_get_index(
"boot"
);
ptn = partition_get_offset(index);
if
(ptn == 0) {
dprintf(CRITICAL,
"ERROR: No boot partition found\n"
);
return
-1;
}
}
else
{
index = partition_get_index(
"recovery"
);
ptn = partition_get_offset(index);
if
(ptn == 0) {
dprintf(CRITICAL,
"ERROR: No recovery partition found\n"
);
return
-1;
}
}
mmc_set_lun(partition_get_lun(index));
if
(mmc_read(ptn + offset, (uint32_t *) buf, page_size)) {
dprintf(CRITICAL,
"ERROR: Cannot read boot image header\n"
);
return
-1;
}
if
(
memcmp
(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
dprintf(CRITICAL,
"ERROR: Invalid boot image header\n"
);
return
-1;
}
if
(hdr->page_size && (hdr->page_size != page_size)) {
if
(hdr->page_size > BOOT_IMG_MAX_PAGE_SIZE) {
dprintf(CRITICAL,
"ERROR: Invalid page size\n"
);
return
-1;
}
page_size = hdr->page_size;
page_mask = page_size - 1;
}
hdr->cmdline[BOOT_ARGS_SIZE-1] = 0;
kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
image_addr = (unsigned
char
*)target_get_scratch_address();
#if DEVICE_TREE
dt_actual = ROUND_TO_PAGE(hdr->dt_size, page_mask);
if
(UINT_MAX < ((uint64_t)kernel_actual + (uint64_t)ramdisk_actual+ (uint64_t)dt_actual + page_size)) {
dprintf(CRITICAL,
"Integer overflow detected in bootimage header fields at %u in %s\n"
,__LINE__,__FILE__);
return
-1;
}
imagesize_actual = (page_size + kernel_actual + ramdisk_actual + dt_actual);
#else
if
(UINT_MAX < ((uint64_t)kernel_actual + (uint64_t)ramdisk_actual + page_size)) {
dprintf(CRITICAL,
"Integer overflow detected in bootimage header fields at %u in %s\n"
,__LINE__,__FILE__);
return
-1;
}
imagesize_actual = (page_size + kernel_actual + ramdisk_actual);
#endif
#if VERIFIED_BOOT
boot_verifier_init();
#endif
if
(check_aboot_addr_range_overlap((
uintptr_t
) image_addr, imagesize_actual))
{
dprintf(CRITICAL,
"Boot image buffer address overlaps with aboot addresses.\n"
);
return
-1;
}
dprintf(INFO,
"Loading (%s) image (%d): start\n"
,
(!boot_into_recovery ?
"boot"
:
"recovery"
),imagesize_actual);
bs_set_timestamp(BS_KERNEL_LOAD_START);
if
((target_get_max_flash_size() - page_size) < imagesize_actual)
{
dprintf(CRITICAL,
"booimage size is greater than DDR can hold\n"
);
return
-1;
}
if
(mmc_read(ptn + offset, (
void
*)image_addr, imagesize_actual))
{
dprintf(CRITICAL,
"ERROR: Cannot read boot image\n"
);
return
-1;
}
dprintf(INFO,
"Loading (%s) image (%d): done\n"
,
(!boot_into_recovery ?
"boot"
:
"recovery"
),imagesize_actual);
bs_set_timestamp(BS_KERNEL_LOAD_DONE);
dprintf(INFO,
"use_signed_kernel=%d, is_unlocked=%d, is_tampered=%d.\n"
,
(
int
) target_use_signed_kernel(),
device.is_unlocked,
device.is_tampered);
if
((target_use_signed_kernel() && (!device.is_unlocked)) || is_test_mode_enabled())
{
offset = imagesize_actual;
if
(check_aboot_addr_range_overlap((
uintptr_t
)image_addr + offset, page_size))
{
dprintf(CRITICAL,
"Signature read buffer address overlaps with aboot addresses.\n"
);
return
-1;
}
if
(mmc_read(ptn + offset, (
void
*)(image_addr + offset), page_size))
{
dprintf(CRITICAL,
"ERROR: Cannot read boot image signature\n"
);
return
-1;
}
verify_signed_bootimg((uint32_t)image_addr, imagesize_actual);
if
(is_test_mode_enabled() && auth_kernel_img)
return
0;
}
else
{
second_actual = ROUND_TO_PAGE(hdr->second_size, page_mask);
#ifdef TZ_SAVE_KERNEL_HASH
aboot_save_boot_hash_mmc((uint32_t) image_addr, imagesize_actual);
#endif /* TZ_SAVE_KERNEL_HASH */
#ifdef MDTP_SUPPORT
{
mdtp_ext_partition_verification_t ext_partition;
ext_partition.partition = boot_into_recovery ? MDTP_PARTITION_RECOVERY : MDTP_PARTITION_BOOT;
ext_partition.integrity_state = MDTP_PARTITION_STATE_UNSET;
ext_partition.page_size = page_size;
ext_partition.image_addr = (uint32)image_addr;
ext_partition.image_size = imagesize_actual;
ext_partition.sig_avail = FALSE;
mdtp_fwlock_verify_lock(&ext_partition);
}
#endif /* MDTP_SUPPORT */
}
#if VERIFIED_BOOT
if
(boot_verify_get_state() == ORANGE)
{
#if FBCON_DISPLAY_MSG
display_bootverify_menu(DISPLAY_MENU_ORANGE);
wait_for_users_action();
#else
dprintf(CRITICAL,
"Your device has been unlocked and can't be trusted.\nWait for 5 seconds before proceeding\n"
);
#endif
}
#endif
#if VERIFIED_BOOT
#if !VBOOT_MOTA
if
(!send_rot_command((uint32_t)device.is_unlocked))
ASSERT(0);
#endif
#endif
if
(is_gzip_package((unsigned
char
*)(image_addr + page_size), hdr->kernel_size))
{
out_addr = (unsigned
char
*)(image_addr + imagesize_actual + page_size);
out_avai_len = target_get_max_flash_size() - imagesize_actual - page_size;
dprintf(INFO,
"decompressing kernel image: start\n"
);
rc = decompress((unsigned
char
*)(image_addr + page_size),
hdr->kernel_size, out_addr, out_avai_len,
&dtb_offset, &out_len);
if
(rc)
{
dprintf(CRITICAL,
"decompressing kernel image failed!!!\n"
);
ASSERT(0);
}
dprintf(INFO,
"decompressing kernel image: done\n"
);
kptr = (
struct
kernel64_hdr *)out_addr;
kernel_start_addr = out_addr;
kernel_size = out_len;
}
else
{
kptr = (
struct
kernel64_hdr *)(image_addr + page_size);
kernel_start_addr = (unsigned
char
*)(image_addr + page_size);
kernel_size = hdr->kernel_size;
}
update_ker_tags_rdisk_addr(hdr, IS_ARM64(kptr));
hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));
hdr->ramdisk_addr = VA((addr_t)(hdr->ramdisk_addr));
hdr->tags_addr = VA((addr_t)(hdr->tags_addr));
kernel_size = ROUND_TO_PAGE(kernel_size, page_mask);
if
(check_aboot_addr_range_overlap(hdr->kernel_addr, kernel_size) ||
check_aboot_addr_range_overlap(hdr->ramdisk_addr, ramdisk_actual))
{
dprintf(CRITICAL,
"kernel/ramdisk addresses overlap with aboot addresses.\n"
);
return
-1;
}
#ifndef DEVICE_TREE
if
(check_aboot_addr_range_overlap(hdr->tags_addr, MAX_TAGS_SIZE))
{
dprintf(CRITICAL,
"Tags addresses overlap with aboot addresses.\n"
);
return
-1;
}
#endif
memmove
((
void
*) hdr->kernel_addr, kernel_start_addr, kernel_size);
memmove
((
void
*) hdr->ramdisk_addr, (
char
*)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
#if DEVICE_TREE
if
(hdr->dt_size) {
dt_table_offset = ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual + second_actual);
table = (
struct
dt_table*) dt_table_offset;
if
(dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {
dprintf(CRITICAL,
"ERROR: Cannot validate Device Tree Table \n"
);
return
-1;
}
if
(dt_hdr_size > ROUND_TO_PAGE(hdr->dt_size,hdr->page_size)) {
dprintf(CRITICAL,
"ERROR: Invalid Device Tree size \n"
);
return
-1;
}
if
(dev_tree_get_entry_info(table, &dt_entry) != 0){
dprintf(CRITICAL,
"ERROR: Getting device tree address failed\n"
);
return
-1;
}
if
(dt_entry.offset > (UINT_MAX - dt_entry.size)) {
dprintf(CRITICAL,
"ERROR: Device tree contents are Invalid\n"
);
return
-1;
}
if
((dt_entry.offset + dt_entry.size) > hdr->dt_size) {
dprintf(CRITICAL,
"ERROR: Device tree contents are Invalid\n"
);
return
-1;
}
if
(is_gzip_package((unsigned
char
*)dt_table_offset + dt_entry.offset, dt_entry.size))
{
unsigned
int
compressed_size = 0;
out_addr += out_len;
out_avai_len -= out_len;
dprintf(INFO,
"decompressing dtb: start\n"
);
rc = decompress((unsigned
char
*)dt_table_offset + dt_entry.offset,
dt_entry.size, out_addr, out_avai_len,
&compressed_size, &dtb_size);
if
(rc)
{
dprintf(CRITICAL,
"decompressing dtb failed!!!\n"
);
ASSERT(0);
}
dprintf(INFO,
"decompressing dtb: done\n"
);
best_match_dt_addr = out_addr;
}
else
{
best_match_dt_addr = (unsigned
char
*)dt_table_offset + dt_entry.offset;
dtb_size = dt_entry.size;
}
if
(check_aboot_addr_range_overlap(hdr->tags_addr, dtb_size))
{
dprintf(CRITICAL,
"Device tree addresses overlap with aboot addresses.\n"
);
return
-1;
}
memmove
((
void
*)hdr->tags_addr, (
char
*)best_match_dt_addr, dtb_size);
}
else
{
if
(check_aboot_addr_range_overlap(hdr->tags_addr, kernel_actual))
{
dprintf(CRITICAL,
"Device tree addresses overlap with aboot addresses.\n"
);
return
-1;
}
void
*dtb;
dtb = dev_tree_appended((
void
*)(image_addr + page_size),
hdr->kernel_size, dtb_offset,
(
void
*)hdr->tags_addr);
if
(!dtb) {
dprintf(CRITICAL,
"ERROR: Appended Device Tree Blob not found\n"
);
return
-1;
}
}
#endif
if
(boot_into_recovery && !device.is_unlocked && !device.is_tampered)
target_load_ssd_keystore();
unified_boot:
boot_linux((
void
*)hdr->kernel_addr, (
void
*)hdr->tags_addr,
(
const
char
*)hdr->cmdline, board_machtype(),
(
void
*)hdr->ramdisk_addr, hdr->ramdisk_size);
return
0;
}