1/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6/* Non-volatile storage routines */
7
8#include "2sysincludes.h"
9#include "2common.h"
10#include "2crc8.h"
11#include "2misc.h"
12#include "2nvstorage.h"
13#include "2nvstorage_fields.h"
14
15static void vb2_nv_regen_crc(struct vb2_context *ctx)
16{
17	ctx->nvdata[VB2_NV_OFFS_CRC] = vb2_crc8(ctx->nvdata, VB2_NV_OFFS_CRC);
18	ctx->flags |= VB2_CONTEXT_NVDATA_CHANGED;
19}
20
21/**
22 * Check the CRC of the non-volatile storage context.
23 *
24 * Use this if reading from non-volatile storage may be flaky, and you want to
25 * retry reading it several times.
26 *
27 * This may be called before vb2_context_init().
28 *
29 * @param ctx		Context pointer
30 * @return VB2_SUCCESS, or non-zero error code if error.
31 */
32int vb2_nv_check_crc(const struct vb2_context *ctx)
33{
34	const uint8_t *p = ctx->nvdata;
35
36	/* Check header */
37	if (VB2_NV_HEADER_SIGNATURE !=
38	    (p[VB2_NV_OFFS_HEADER] & VB2_NV_HEADER_MASK))
39		return VB2_ERROR_NV_HEADER;
40
41	/* Check CRC */
42	if (vb2_crc8(p, VB2_NV_OFFS_CRC) != p[VB2_NV_OFFS_CRC])
43		return VB2_ERROR_NV_CRC;
44
45	return VB2_SUCCESS;
46}
47
48void vb2_nv_init(struct vb2_context *ctx)
49{
50	struct vb2_shared_data *sd = vb2_get_sd(ctx);
51	uint8_t *p = ctx->nvdata;
52
53	/* Check data for consistency */
54	if (vb2_nv_check_crc(ctx) != VB2_SUCCESS) {
55		/* Data is inconsistent (bad CRC or header); reset defaults */
56		memset(p, 0, VB2_NVDATA_SIZE);
57		p[VB2_NV_OFFS_HEADER] = (VB2_NV_HEADER_SIGNATURE |
58					 VB2_NV_HEADER_FW_SETTINGS_RESET |
59					 VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
60
61		/* Regenerate CRC */
62		vb2_nv_regen_crc(ctx);
63
64		/* Set status flag */
65		sd->status |= VB2_SD_STATUS_NV_REINIT;
66		// TODO: unit test for status flag being set
67	}
68
69	sd->status |= VB2_SD_STATUS_NV_INIT;
70}
71
72/* Macro for vb2_nv_get() single-bit settings to reduce duplicate code. */
73#define GETBIT(offs, mask) (p[offs] & mask ? 1 : 0)
74
75uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param)
76{
77	const uint8_t *p = ctx->nvdata;
78
79	/*
80	 * TODO: We could reduce the binary size for this code by #ifdef'ing
81	 * out the params not used by firmware verification.
82	 */
83	switch (param) {
84	case VB2_NV_FIRMWARE_SETTINGS_RESET:
85		return GETBIT(VB2_NV_OFFS_HEADER,
86			      VB2_NV_HEADER_FW_SETTINGS_RESET);
87
88	case VB2_NV_KERNEL_SETTINGS_RESET:
89		return GETBIT(VB2_NV_OFFS_HEADER,
90			      VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
91
92	case VB2_NV_DEBUG_RESET_MODE:
93		return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET);
94
95	case VB2_NV_TRY_NEXT:
96		return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRY_NEXT);
97
98	case VB2_NV_TRY_COUNT:
99		return p[VB2_NV_OFFS_BOOT] & VB2_NV_BOOT_TRY_COUNT_MASK;
100
101	case VB2_NV_FW_TRIED:
102		return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED);
103
104	case VB2_NV_FW_RESULT:
105		return p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_RESULT_MASK;
106
107	case VB2_NV_FW_PREV_TRIED:
108		return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_PREV_TRIED);
109
110	case VB2_NV_FW_PREV_RESULT:
111		return (p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_PREV_RESULT_MASK)
112			>> VB2_NV_BOOT2_PREV_RESULT_SHIFT;
113
114	case VB2_NV_RECOVERY_REQUEST:
115		return p[VB2_NV_OFFS_RECOVERY];
116
117	case VB2_NV_RECOVERY_SUBCODE:
118		return p[VB2_NV_OFFS_RECOVERY_SUBCODE];
119
120	case VB2_NV_LOCALIZATION_INDEX:
121		return p[VB2_NV_OFFS_LOCALIZATION];
122
123	case VB2_NV_KERNEL_FIELD:
124		return (p[VB2_NV_OFFS_KERNEL]
125			| (p[VB2_NV_OFFS_KERNEL + 1] << 8)
126			| (p[VB2_NV_OFFS_KERNEL + 2] << 16)
127			| (p[VB2_NV_OFFS_KERNEL + 3] << 24));
128
129	case VB2_NV_DEV_BOOT_USB:
130		return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB);
131
132	case VB2_NV_DEV_BOOT_LEGACY:
133		return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
134
135	case VB2_NV_DEV_BOOT_SIGNED_ONLY:
136		return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY);
137
138	case VB2_NV_DISABLE_DEV_REQUEST:
139		return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV);
140
141	case VB2_NV_OPROM_NEEDED:
142		return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED);
143
144	case VB2_NV_BACKUP_NVRAM_REQUEST:
145		return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_BACKUP_NVRAM);
146
147	case VB2_NV_CLEAR_TPM_OWNER_REQUEST:
148		return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST);
149
150	case VB2_NV_CLEAR_TPM_OWNER_DONE:
151		return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
152	}
153
154	/*
155	 * Put default return outside the switch() instead of in default:, so
156	 * that adding a new param will cause a compiler warning.
157	 */
158	return 0;
159}
160
161#undef GETBIT
162
163/* Macro for vb2_nv_set() single-bit settings to reduce duplicate code. */
164#define SETBIT(offs, mask)					\
165	{ if (value) p[offs] |= mask; else p[offs] &= ~mask; }
166
167void vb2_nv_set(struct vb2_context *ctx,
168		enum vb2_nv_param param,
169		uint32_t value)
170{
171	uint8_t *p = ctx->nvdata;
172
173	/* If not changing the value, don't regenerate the CRC. */
174	if (vb2_nv_get(ctx, param) == value)
175		return;
176
177	/*
178	 * TODO: We could reduce the binary size for this code by #ifdef'ing
179	 * out the params not used by firmware verification.
180	 */
181	switch (param) {
182	case VB2_NV_FIRMWARE_SETTINGS_RESET:
183		SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_FW_SETTINGS_RESET);
184		break;
185
186	case VB2_NV_KERNEL_SETTINGS_RESET:
187		SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
188		break;
189
190	case VB2_NV_DEBUG_RESET_MODE:
191		SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET);
192		break;
193
194	case VB2_NV_TRY_NEXT:
195		SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRY_NEXT);
196		break;
197
198	case VB2_NV_TRY_COUNT:
199		/* Clip to valid range. */
200		if (value > VB2_NV_BOOT_TRY_COUNT_MASK)
201			value = VB2_NV_BOOT_TRY_COUNT_MASK;
202
203		p[VB2_NV_OFFS_BOOT] &= ~VB2_NV_BOOT_TRY_COUNT_MASK;
204		p[VB2_NV_OFFS_BOOT] |= (uint8_t)value;
205		break;
206
207	case VB2_NV_FW_TRIED:
208		SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED);
209		break;
210
211	case VB2_NV_FW_RESULT:
212		/* Map out of range values to unknown */
213		if (value > VB2_NV_BOOT2_RESULT_MASK)
214			value = VB2_FW_RESULT_UNKNOWN;
215
216		p[VB2_NV_OFFS_BOOT2] &= ~VB2_NV_BOOT2_RESULT_MASK;
217		p[VB2_NV_OFFS_BOOT2] |= (uint8_t)value;
218		break;
219
220	case VB2_NV_FW_PREV_TRIED:
221		SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_PREV_TRIED);
222		break;
223
224	case VB2_NV_FW_PREV_RESULT:
225		/* Map out of range values to unknown */
226		if (value > VB2_NV_BOOT2_RESULT_MASK)
227			value = VB2_FW_RESULT_UNKNOWN;
228
229		p[VB2_NV_OFFS_BOOT2] &= ~VB2_NV_BOOT2_PREV_RESULT_MASK;
230		p[VB2_NV_OFFS_BOOT2] |=
231			(uint8_t)(value << VB2_NV_BOOT2_PREV_RESULT_SHIFT);
232		break;
233
234	case VB2_NV_RECOVERY_REQUEST:
235		/*
236		 * Map values outside the valid range to the legacy reason,
237		 * since we can't determine if we're called from kernel or user
238		 * mode.
239		 */
240		if (value > 0xff)
241			value = VB2_RECOVERY_LEGACY;
242		p[VB2_NV_OFFS_RECOVERY] = (uint8_t)value;
243		break;
244
245	case VB2_NV_RECOVERY_SUBCODE:
246		p[VB2_NV_OFFS_RECOVERY_SUBCODE] = (uint8_t)value;
247		break;
248
249	case VB2_NV_LOCALIZATION_INDEX:
250		/* Map values outside the valid range to the default index. */
251		if (value > 0xFF)
252			value = 0;
253		p[VB2_NV_OFFS_LOCALIZATION] = (uint8_t)value;
254		break;
255
256	case VB2_NV_KERNEL_FIELD:
257		p[VB2_NV_OFFS_KERNEL] = (uint8_t)(value);
258		p[VB2_NV_OFFS_KERNEL + 1] = (uint8_t)(value >> 8);
259		p[VB2_NV_OFFS_KERNEL + 2] = (uint8_t)(value >> 16);
260		p[VB2_NV_OFFS_KERNEL + 3] = (uint8_t)(value >> 24);
261		break;
262
263	case VB2_NV_DEV_BOOT_USB:
264		SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB);
265		break;
266
267	case VB2_NV_DEV_BOOT_LEGACY:
268		SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
269		break;
270
271	case VB2_NV_DEV_BOOT_SIGNED_ONLY:
272		SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY);
273		break;
274
275	case VB2_NV_DISABLE_DEV_REQUEST:
276		SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV);
277		break;
278
279	case VB2_NV_OPROM_NEEDED:
280		SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED);
281		break;
282
283	case VB2_NV_BACKUP_NVRAM_REQUEST:
284		SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_BACKUP_NVRAM);
285		break;
286
287	case VB2_NV_CLEAR_TPM_OWNER_REQUEST:
288		SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST);
289		break;
290
291	case VB2_NV_CLEAR_TPM_OWNER_DONE:
292		SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
293		break;
294	}
295
296	/*
297	 * Note there is no default case.  This causes a compiler warning if
298	 * a new param is added to the enum without adding support here.
299	 */
300
301	/* Need to regenerate CRC, since the value changed. */
302	vb2_nv_regen_crc(ctx);
303}
304
305#undef SETBIT
306