blob: 55b46df626a82e926acd925fa456660a59e4018e [file] [log] [blame]
/*
* Copyright (c) 2020 The Fuchsia Authors
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common.h>
#include <asm/arch/io.h>
#include <asm/arch/secure_apb.h>
#include <command.h>
#include <environment.h>
#include <libabr/abr.h>
#include <libabr/data.h>
#include <libabr/util.h>
#include <zircon/zircon.h>
#include <zircon/zircon_abr_reg_util.h>
#include "override_reboot_mode.h"
// i.e. "_a", "_b" and "_r"
#define TPL_SLOT_NAME_LEN 2
const char *g_tpl_slot = NULL;
static int invalidate_abr_sticky_register(void)
{
abr_sticky_reg0_t reg0 = read_sticky_reg0();
reg0.fields.valid = 0;
write_sticky_reg0(reg0);
return 0;
}
static int get_abr_slot(void)
{
abr_sticky_reg1_t reg1 = read_sticky_reg1();
AbrSlotIndex slot = reg1.fields.current_slot;
g_tpl_slot = AbrGetSlotSuffix(slot);
if (!g_tpl_slot || g_tpl_slot[0] == '\0') {
fprintf(stderr, "failed to get tpl slot\n");
return -1;
}
printf("Active tpl slot is: %s\n", g_tpl_slot);
return 0;
}
static int sync_abr_reg_to_misc(void)
{
abr_sticky_reg0_t reg0 = read_sticky_reg0();
abr_sticky_reg1_t reg1 = read_sticky_reg1();
// Check if we need to override reboot reason
if (force_recovery_bit_set()) {
// Set force recovery mode flag to indicate that this boot is due to
// force recovery. The abr booting logic will skip cross-validating
// abr metdata for slot matching.
set_force_recovery_mode(true);
set_override_rebootmode_val(reg0.fields.rebootmode);
// Clear force recovery. If there is another watchdog reset due to
// other reasons. The watchdog reset reason shall be reported as
// it is.
set_force_recovery_bit(false);
}
if (!reg0.fields.valid) {
printf("sticky register does not contain abr metadata. "
"abr metadata in storage is up to date.\n");
return 0;
}
printf("flushing abr data in register to storage\n");
AbrData abr_data;
memset(&abr_data, 0, sizeof(abr_data));
memcpy(abr_data.magic, kAbrMagic, kAbrMagicLen);
abr_data.version_major = kAbrMajorVersion;
abr_data.version_minor = kAbrMinorVersion;
abr_data.slot_data[0].priority = reg0.fields.priority;
abr_data.slot_data[0].tries_remaining = reg0.fields.tries_remaining;
abr_data.slot_data[0].successful_boot = reg0.fields.successful;
abr_data.slot_data[1].priority = reg1.fields.priority;
abr_data.slot_data[1].tries_remaining = reg1.fields.tries_remaining;
abr_data.slot_data[1].successful_boot = reg1.fields.successful;
abr_data.crc32 = AbrHostToBigEndian(
AbrCrc32(&abr_data, sizeof(abr_data) - sizeof(uint32_t)));
const AbrOps *ops = zircon_abr_ops();
return ops->write_abr_metadata(NULL, (const uint8_t *)&abr_data,
sizeof(abr_data)) ?
0 :
-1;
}
int do_get_slot_and_sync_abr(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
if (get_abr_slot())
return -1;
if (sync_abr_reg_to_misc())
return -1;
if (invalidate_abr_sticky_register())
return -1;
return 0;
}
U_BOOT_CMD(get_slot_and_sync_abr, 1, 0, do_get_slot_and_sync_abr,
"get_slot_and_sync_abr",
"\nThis command retrieves slot decision and flushes abr metadata\n"
"to storage\n");
int do_process_force_recovery_request(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
if (strncmp(g_tpl_slot, "_r", 2)) {
printf("Force recovery enabled, but tpl slot is %s. "
"Setting force recovery bit and reset...\n",
g_tpl_slot);
set_force_recovery_bit(true);
set_abr_sticky_reg_rebootmode(get_rebootmode_value());
do_reset(NULL, 0, 0, NULL);
}
return 0;
}
U_BOOT_CMD(process_force_recovery_request, 1, 0,
do_process_force_recovery_request, "process_force_recovery_request",
"\nProcess a force recovery request.\n");