blob: fd3e0c9b64211d04381111f67f9e0db01406cc7f [file] [log] [blame]
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdint.h>
#include "bdb.h"
#include "bdb_api.h"
#include "vboot_register.h"
static int did_current_slot_fail(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
return val & VBOOT_REGISTER_FAILED_RW_SECONDARY;
else
return val & VBOOT_REGISTER_FAILED_RW_PRIMARY;
}
static int did_other_slot_fail(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
return val & VBOOT_REGISTER_FAILED_RW_PRIMARY;
else
return val & VBOOT_REGISTER_FAILED_RW_SECONDARY;
}
static void set_try_other_slot(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
val &= ~VBOOT_REGISTER_TRY_SECONDARY_BDB;
else
val |= VBOOT_REGISTER_TRY_SECONDARY_BDB;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
static void set_recovery_request(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
val |= VBOOT_REGISTER_RECOVERY_REQUEST;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
static void get_current_slot(struct vba_context *ctx)
{
/* Assume SP-RO selects slot this way */
ctx->slot = (vbe_get_vboot_register(VBOOT_REGISTER_PERSIST)
& VBOOT_REGISTER_TRY_SECONDARY_BDB) ? 1 : 0;
}
static void set_current_slot_failed(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
val |= VBOOT_REGISTER_FAILED_RW_SECONDARY;
else
val |= VBOOT_REGISTER_FAILED_RW_PRIMARY;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
static void unset_current_slot_failed(struct vba_context *ctx)
{
uint32_t val = vbe_get_vboot_register(VBOOT_REGISTER_PERSIST);
if (ctx->slot)
val &= ~VBOOT_REGISTER_FAILED_RW_SECONDARY;
else
val &= ~VBOOT_REGISTER_FAILED_RW_PRIMARY;
vbe_set_vboot_register(VBOOT_REGISTER_PERSIST, val);
}
int vba_bdb_init(struct vba_context *ctx)
{
/* Get current slot */
get_current_slot(ctx);
/* Check current slot failed or not at the last boot */
if (!did_current_slot_fail(ctx)) {
/* If not, we try this slot. Prepare for any accidents */
set_current_slot_failed(ctx);
return BDB_SUCCESS;
}
/* Check other slot failed or not at the previous boot */
if (!did_other_slot_fail(ctx)) {
/* If not, we try the other slot after reboot. */
set_try_other_slot(ctx);
return BDB_ERROR_TRY_OTHER_SLOT;
} else {
/* Otherwise, both slots are bad. Reboot to recovery */
set_recovery_request(ctx);
return BDB_ERROR_RECOVERY_REQUEST;
}
}
int vba_bdb_finalize(struct vba_context *ctx)
{
/* Mark the current slot good */
unset_current_slot_failed(ctx);
/* Disable NVM bus */
return BDB_SUCCESS;
}
void vba_bdb_fail(struct vba_context *ctx)
{
/* We can do some logging here if we want */
/* Unconditionally reboot. FailedRW flag is already set.
* At the next boot, bdb_init will decide what to do. */
vbe_reset();
}