/* 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 #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(); }