diff options
Diffstat (limited to 'firmware/bdb/misc.c')
-rw-r--r-- | firmware/bdb/misc.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/firmware/bdb/misc.c b/firmware/bdb/misc.c new file mode 100644 index 00000000..fd3e0c9b --- /dev/null +++ b/firmware/bdb/misc.c @@ -0,0 +1,124 @@ +/* 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(); +} |