summaryrefslogtreecommitdiff
path: root/firmware/bdb/misc.c
blob: fd3e0c9b64211d04381111f67f9e0db01406cc7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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();
}