blob: 5b154ef526bd8c17b346fc3c0c43ca28b0c3a280 [file] [log] [blame]
/*
* Copyright (c) 2018 MediaTek Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <app.h>
#include <assert.h>
#include <boot_mode.h>
#include <err.h>
#include <errno.h>
#include <fit.h>
#include <kernel/event.h>
#include <kernel/thread.h>
#include <kernel/vm.h>
#include <libfdt.h>
#include <lib/dl_commands.h> /* [TODO] separate rpmb define from fastboot */
#include <lib/mempool.h>
#include <platform.h>
#include <rpmb/include/rpmb_mac.h> /* [TODO] #include <lib/rpmb_mac.h> */
#include <trace.h>
#include "blx_common.h"
#include "blxboot_ab.h"
#include "blxboot_plat.h"
#include "dto.h"
#include "imageinfo.h"
#define LOCAL_TRACE 0
extern void ext_boot(void);
extern struct imageinfo_t imagelist[];
static int load_all_images(struct blxboot *obj)
{
int rc;
int load_idx;
struct imageinfo_t *img;
const char *part_name[3];
uint32_t *boot_mode = &(obj->bootcfg.boot_mode);
img = &imagelist[0];
while (img->type != IMGTYPE_NONE) {
LTRACEF("image load: %s\n", img->imgdata->part_name);
ASSERT((img->load != NULL) && (img->imgdata != NULL));
/* setup the load retry sequence: fastboot -> normal -> recovery */
if (*boot_mode == NORMAL_BOOT)
load_idx = 1;
else if (*boot_mode == RECOVERY_BOOT)
load_idx = 0;
else /* FASTBOOT_BOOT */
load_idx = 2;
part_name[2] = img->imgdata->membdev_name;
part_name[1] = img->imgdata->part_name;
part_name[0] = img->imgdata->recovery_part_name;
/* for non recovery boot partition, no need to try recovery partition
* if its name is the same with normal boot partition */
if (*boot_mode != RECOVERY_BOOT) {
if ((part_name[0] != NULL) && (part_name[1] != NULL) &&
(!strcmp(part_name[0], part_name[1])))
part_name[0] = NULL;
}
rc = -ENODEV;
while (load_idx >= 0) {
if (part_name[load_idx] != NULL) {
rc = img->load(part_name[load_idx], img);
if (rc == 0)
break;
}
load_idx--;
}
if (rc == 0) {
if (obj->ops.notify)
obj->ops.notify(obj, img);
} else {
LTRACEF("load part: %s, type=%d failed\n",
img->imgdata->part_name, img->type);
if ((img->type != IMGTYPE_DTBO) && (img->type != IMGTYPE_VPD))
return -1;
/* dtbo/vpd image: allow partition not exist or no valid data.
* Other cases, boot fail */
if ((rc != -ENODEV) && (rc != -ENOTSUP))
return -1;
}
img++;
}
return 0;
}
static void append_suffix(const char **name, const char *suffix, int suffix_len)
{
char *new_name;
int len;
len = strlen(*name) + suffix_len + 1;
new_name = mempool_alloc(len, MEMPOOL_ANY);
ASSERT(new_name != NULL);
sprintf(new_name, "%s%s", *name, suffix);
*name = new_name;
}
static void update_image_partition_name(const char *suffix)
{
struct imageinfo_t *img;
struct image_load_data *imgdata;
int suffix_len;
suffix_len = strlen(suffix);
for (img = &imagelist[0]; img->type != IMGTYPE_NONE; img++) {
ASSERT((img != NULL) && (img->imgdata != NULL));
imgdata = img->imgdata;
if (!imgdata->has_slot)
continue;
append_suffix(&imgdata->part_name, suffix, suffix_len);
if (imgdata->recovery_part_name)
append_suffix(&imgdata->recovery_part_name, suffix, suffix_len);
}
}
static void blxboot_task(const struct app_descriptor *app, void *args)
{
struct blxboot *blxobj;
struct boot_param bprm;
bool fastboot_on_fail;
uint32_t *boot_mode;
void *fdt_dtb, *dtbo, *vpd;
int rc;
#if (defined AVB_ENABLE_ANTIROLLBACK) || (defined AVB_ENABLE_DEVICE_STATE_CHANGE)
rpmb_init();
#endif
if (plat_fixup_init() != NO_ERROR)
return;
blxobj = blxboot_create();
if (!blxobj)
return;
boot_mode = &(blxobj->bootcfg.boot_mode);
*boot_mode = get_boot_mode();
assert(*boot_mode <= FASTBOOT_BOOT);
if (blxobj->ops.init) {
rc = blxobj->ops.init();
/*
* if init fails, and boot mode is
* - fastboot mode: enter fastboot mode
* - non fastboot mode:
* . AB OTA updater enabled: reboot,
* . non AB OTA updater: enter fastboot mode
*/
if (rc && (*boot_mode != FASTBOOT_BOOT)) {
if (is_enabled_ab_ota_updater())
platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
else
*boot_mode = FASTBOOT_BOOT;
}
}
blxobj->bootcfg.ab_suffix = get_suffix();
if (blxobj->bootcfg.ab_suffix != NULL)
update_image_partition_name(blxobj->bootcfg.ab_suffix);
if (is_enabled_ab_ota_updater())
fastboot_on_fail = false;
else
fastboot_on_fail = true; /* enter fastboot mode if load fail */
do {
if (*boot_mode == FASTBOOT_BOOT) {
ext_boot();
fastboot_on_fail = false;
}
if ((rc = load_all_images(blxobj)) == 0)
break;
if (fastboot_on_fail)
*boot_mode = FASTBOOT_BOOT;
} while (fastboot_on_fail);
if (rc != 0) {
if (is_enabled_ab_ota_updater())
platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
return;
}
/* dtbo may contains kernel bootargs, do overlay_fdt before fixup_image */
blxobj->ops.get_overlay_image(blxobj, &fdt_dtb, &dtbo, &vpd);
if (fdt_dtb && (dtbo || vpd)) {
rc = overlay_fdt(fdt_dtb, dtbo, vpd);
if (rc) {
LTRACEF_LEVEL(CRITICAL, "dtbo overlay failed\n");
return;
}
}
if (blxobj->ops.fixup_image)
blxobj->ops.fixup_image(blxobj, fdt_dtb);
plat_fixup_hook(*boot_mode, blxobj->bootcfg.ab_suffix,
fdt_dtb, MAX_DTB_SIZE);
if (blxobj->ops.setup_boot_param) {
blxobj->ops.setup_boot_param(blxobj, &bprm);
}
dprintf(ALWAYS, "LK run time: %lld (us)\n", current_time_hires());
dprintf(ALWAYS, "jump to next ep %p, arg (0x%lx)\n",
(void *)bprm.arg1, bprm.arg2);
arch_chain_load((void *)blxobj->ops.exit,
bprm.arg0, bprm.arg1, bprm.arg2, bprm.arg3);
}
APP_START(blxboot)
.entry = blxboot_task,
.flags = 0,
APP_END