summaryrefslogtreecommitdiff
path: root/firmware/bdb/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/bdb/misc.c')
-rw-r--r--firmware/bdb/misc.c124
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();
+}