blob: 02904741735612c0f016a287d3464ad92a1429c8 [file] [log] [blame]
Randall Spangler3333e572014-05-14 11:37:52 -07001/* 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
14/*
15 * Constants for NV storage. We use this rather than structs and bitfields so
16 * the data format is consistent across platforms and compilers. Total NV
17 * storage size is VB2_NVDATA_SIZE = 16 bytes.
Randall Spangler9e1da782014-06-24 15:31:04 -070018 *
19 * These constants must match the equivalent constants in
20 * lib/vboot_nvstorage.c. (We currently don't share a common header file
21 * because we're tring to keep the two libs independent, and we hope to
22 * deprecate that one.)
Randall Spangler3333e572014-05-14 11:37:52 -070023 */
24
25enum vb2_nv_offset {
26 VB2_NV_OFFS_HEADER = 0,
27 VB2_NV_OFFS_BOOT = 1,
28 VB2_NV_OFFS_RECOVERY = 2,
29 VB2_NV_OFFS_LOCALIZATION = 3,
30 VB2_NV_OFFS_DEV = 4,
31 VB2_NV_OFFS_TPM = 5,
32 VB2_NV_OFFS_RECOVERY_SUBCODE = 6,
33 VB2_NV_OFFS_BOOT2 = 7,
34 /* Offsets 7-10 are currently unused */
35 VB2_NV_OFFS_KERNEL = 11, /* 11-14; field is 32 bits */
36 /* CRC must be last field */
37 VB2_NV_OFFS_CRC = 15
38};
39
40/* Fields in VB2_NV_OFFS_HEADER (unused = 0x0f) */
41#define VB2_NV_HEADER_KERNEL_SETTINGS_RESET 0x10
42#define VB2_NV_HEADER_FW_SETTINGS_RESET 0x20
43#define VB2_NV_HEADER_SIGNATURE 0x40
44#define VB2_NV_HEADER_MASK 0xc0
45
46/* Fields in VB2_NV_OFFS_BOOT */
47#define VB2_NV_BOOT_TRY_COUNT_MASK 0x0f
Randall Spangler8de992c2014-06-24 13:11:02 -070048#define VB2_NV_BOOT_BACKUP_NVRAM 0x10
Randall Spangler3333e572014-05-14 11:37:52 -070049#define VB2_NV_BOOT_OPROM_NEEDED 0x20
50#define VB2_NV_BOOT_DISABLE_DEV 0x40
51#define VB2_NV_BOOT_DEBUG_RESET 0x80
52
Randall Spangler8de992c2014-06-24 13:11:02 -070053/* Fields in VB2_NV_OFFS_BOOT2 (unused = 0xf0) */
Randall Spangler3333e572014-05-14 11:37:52 -070054#define VB2_NV_BOOT2_RESULT_MASK 0x03
55#define VB2_NV_BOOT2_TRIED 0x04
Randall Spangler8de992c2014-06-24 13:11:02 -070056#define VB2_NV_BOOT2_TRY_NEXT 0x08
Randall Spangler3333e572014-05-14 11:37:52 -070057
58/* Fields in VB2_NV_OFFS_DEV (unused = 0xf8) */
59#define VB2_NV_DEV_FLAG_USB 0x01
60#define VB2_NV_DEV_FLAG_SIGNED_ONLY 0x02
61#define VB2_NV_DEV_FLAG_LEGACY 0x04
62
63/* Fields in VB2_NV_OFFS_TPM (unused = 0xfc) */
64#define VB2_NV_TPM_CLEAR_OWNER_REQUEST 0x01
65#define VB2_NV_TPM_CLEAR_OWNER_DONE 0x02
66
67static void vb2_nv_regen_crc(struct vb2_context *ctx)
68{
69 ctx->nvdata[VB2_NV_OFFS_CRC] = vb2_crc8(ctx->nvdata, VB2_NV_OFFS_CRC);
70 ctx->flags |= VB2_CONTEXT_NVDATA_CHANGED;
71}
72
73/**
74 * Check the CRC of the non-volatile storage context.
75 *
76 * Use this if reading from non-volatile storage may be flaky, and you want to
77 * retry reading it several times.
78 *
79 * This may be called before vb2_context_init().
80 *
81 * @param ctx Context pointer
82 * @return VB2_SUCCESS, or non-zero error code if error.
83 */
84int vb2_nv_check_crc(const struct vb2_context *ctx)
85{
86 const uint8_t *p = ctx->nvdata;
87
88 /* Check header */
89 if (VB2_NV_HEADER_SIGNATURE !=
90 (p[VB2_NV_OFFS_HEADER] & VB2_NV_HEADER_MASK))
Randall Spanglerb9be5362014-06-05 13:32:11 -070091 return VB2_ERROR_NV_HEADER;
Randall Spangler3333e572014-05-14 11:37:52 -070092
93 /* Check CRC */
94 if (vb2_crc8(p, VB2_NV_OFFS_CRC) != p[VB2_NV_OFFS_CRC])
Randall Spanglerb9be5362014-06-05 13:32:11 -070095 return VB2_ERROR_NV_CRC;
Randall Spangler3333e572014-05-14 11:37:52 -070096
97 return VB2_SUCCESS;
98}
99
100void vb2_nv_init(struct vb2_context *ctx)
101{
102 struct vb2_shared_data *sd = vb2_get_sd(ctx);
103 uint8_t *p = ctx->nvdata;
104
105 /* Check data for consistency */
106 if (vb2_nv_check_crc(ctx) != VB2_SUCCESS) {
107 /* Data is inconsistent (bad CRC or header); reset defaults */
108 memset(p, 0, VB2_NVDATA_SIZE);
109 p[VB2_NV_OFFS_HEADER] = (VB2_NV_HEADER_SIGNATURE |
110 VB2_NV_HEADER_FW_SETTINGS_RESET |
111 VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
112
113 /* Regenerate CRC */
114 vb2_nv_regen_crc(ctx);
115
116 /* Set status flag */
117 sd->status |= VB2_SD_STATUS_NV_REINIT;
118 // TODO: unit test for status flag being set
119 }
120
121 sd->status |= VB2_SD_STATUS_NV_INIT;
122}
123
124/* Macro for vb2_nv_get() single-bit settings to reduce duplicate code. */
125#define GETBIT(offs, mask) (p[offs] & mask ? 1 : 0)
126
127uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param)
128{
129 const uint8_t *p = ctx->nvdata;
130
131 /*
132 * TODO: We could reduce the binary size for this code by #ifdef'ing
133 * out the params not used by firmware verification.
134 */
135 switch (param) {
136 case VB2_NV_FIRMWARE_SETTINGS_RESET:
137 return GETBIT(VB2_NV_OFFS_HEADER,
138 VB2_NV_HEADER_FW_SETTINGS_RESET);
139
140 case VB2_NV_KERNEL_SETTINGS_RESET:
141 return GETBIT(VB2_NV_OFFS_HEADER,
142 VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
143
144 case VB2_NV_DEBUG_RESET_MODE:
145 return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET);
146
147 case VB2_NV_TRY_NEXT:
Randall Spangler8de992c2014-06-24 13:11:02 -0700148 return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRY_NEXT);
Randall Spangler3333e572014-05-14 11:37:52 -0700149
150 case VB2_NV_TRY_COUNT:
151 return p[VB2_NV_OFFS_BOOT] & VB2_NV_BOOT_TRY_COUNT_MASK;
152
153 case VB2_NV_FW_TRIED:
154 return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED);
155
156 case VB2_NV_FW_RESULT:
157 return p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_RESULT_MASK;
158
159 case VB2_NV_RECOVERY_REQUEST:
160 return p[VB2_NV_OFFS_RECOVERY];
161
162 case VB2_NV_RECOVERY_SUBCODE:
163 return p[VB2_NV_OFFS_RECOVERY_SUBCODE];
164
165 case VB2_NV_LOCALIZATION_INDEX:
166 return p[VB2_NV_OFFS_LOCALIZATION];
167
168 case VB2_NV_KERNEL_FIELD:
169 return (p[VB2_NV_OFFS_KERNEL]
170 | (p[VB2_NV_OFFS_KERNEL + 1] << 8)
171 | (p[VB2_NV_OFFS_KERNEL + 2] << 16)
172 | (p[VB2_NV_OFFS_KERNEL + 3] << 24));
173
174 case VB2_NV_DEV_BOOT_USB:
175 return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB);
176
177 case VB2_NV_DEV_BOOT_LEGACY:
178 return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
179
180 case VB2_NV_DEV_BOOT_SIGNED_ONLY:
181 return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY);
182
183 case VB2_NV_DISABLE_DEV_REQUEST:
184 return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV);
185
186 case VB2_NV_OPROM_NEEDED:
187 return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED);
188
Randall Spangler8de992c2014-06-24 13:11:02 -0700189 case VB2_NV_BACKUP_NVRAM_REQUEST:
190 return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_BACKUP_NVRAM);
191
Randall Spangler3333e572014-05-14 11:37:52 -0700192 case VB2_NV_CLEAR_TPM_OWNER_REQUEST:
193 return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST);
194
195 case VB2_NV_CLEAR_TPM_OWNER_DONE:
196 return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
197 }
198
199 /*
200 * Put default return outside the switch() instead of in default:, so
201 * that adding a new param will cause a compiler warning.
202 */
203 return 0;
204}
205
206#undef GETBIT
207
208/* Macro for vb2_nv_set() single-bit settings to reduce duplicate code. */
209#define SETBIT(offs, mask) \
210 { if (value) p[offs] |= mask; else p[offs] &= ~mask; }
211
212void vb2_nv_set(struct vb2_context *ctx,
213 enum vb2_nv_param param,
214 uint32_t value)
215{
216 uint8_t *p = ctx->nvdata;
217
218 /* If not changing the value, don't regenerate the CRC. */
219 if (vb2_nv_get(ctx, param) == value)
220 return;
221
222 /*
223 * TODO: We could reduce the binary size for this code by #ifdef'ing
224 * out the params not used by firmware verification.
225 */
226 switch (param) {
227 case VB2_NV_FIRMWARE_SETTINGS_RESET:
228 SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_FW_SETTINGS_RESET);
229 break;
230
231 case VB2_NV_KERNEL_SETTINGS_RESET:
232 SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
233 break;
234
235 case VB2_NV_DEBUG_RESET_MODE:
236 SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET);
237 break;
238
239 case VB2_NV_TRY_NEXT:
Randall Spangler8de992c2014-06-24 13:11:02 -0700240 SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRY_NEXT);
Randall Spangler3333e572014-05-14 11:37:52 -0700241 break;
242
243 case VB2_NV_TRY_COUNT:
244 /* Clip to valid range. */
245 if (value > VB2_NV_BOOT_TRY_COUNT_MASK)
246 value = VB2_NV_BOOT_TRY_COUNT_MASK;
247
248 p[VB2_NV_OFFS_BOOT] &= ~VB2_NV_BOOT_TRY_COUNT_MASK;
249 p[VB2_NV_OFFS_BOOT] |= (uint8_t)value;
250 break;
251
252 case VB2_NV_FW_TRIED:
253 SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED);
254 break;
255
256 case VB2_NV_FW_RESULT:
257 /* Map out of range values to unknown */
258 if (value > VB2_NV_BOOT2_RESULT_MASK)
259 value = VB2_FW_RESULT_UNKNOWN;
260
261 p[VB2_NV_OFFS_BOOT2] &= ~VB2_NV_BOOT2_RESULT_MASK;
262 p[VB2_NV_OFFS_BOOT2] |= (uint8_t)value;
263 break;
264
265 case VB2_NV_RECOVERY_REQUEST:
266 /*
267 * Map values outside the valid range to the legacy reason,
268 * since we can't determine if we're called from kernel or user
269 * mode.
270 */
271 if (value > 0xff)
272 value = VB2_RECOVERY_LEGACY;
273 p[VB2_NV_OFFS_RECOVERY] = (uint8_t)value;
274 break;
275
276 case VB2_NV_RECOVERY_SUBCODE:
277 p[VB2_NV_OFFS_RECOVERY_SUBCODE] = (uint8_t)value;
278 break;
279
280 case VB2_NV_LOCALIZATION_INDEX:
281 /* Map values outside the valid range to the default index. */
282 if (value > 0xFF)
283 value = 0;
284 p[VB2_NV_OFFS_LOCALIZATION] = (uint8_t)value;
285 break;
286
287 case VB2_NV_KERNEL_FIELD:
288 p[VB2_NV_OFFS_KERNEL] = (uint8_t)(value);
289 p[VB2_NV_OFFS_KERNEL + 1] = (uint8_t)(value >> 8);
290 p[VB2_NV_OFFS_KERNEL + 2] = (uint8_t)(value >> 16);
291 p[VB2_NV_OFFS_KERNEL + 3] = (uint8_t)(value >> 24);
292 break;
293
294 case VB2_NV_DEV_BOOT_USB:
295 SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB);
296 break;
297
298 case VB2_NV_DEV_BOOT_LEGACY:
299 SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
300 break;
301
302 case VB2_NV_DEV_BOOT_SIGNED_ONLY:
303 SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY);
304 break;
305
306 case VB2_NV_DISABLE_DEV_REQUEST:
307 SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV);
308 break;
309
310 case VB2_NV_OPROM_NEEDED:
311 SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED);
312 break;
313
Randall Spangler8de992c2014-06-24 13:11:02 -0700314 case VB2_NV_BACKUP_NVRAM_REQUEST:
315 SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_BACKUP_NVRAM);
316 break;
317
Randall Spangler3333e572014-05-14 11:37:52 -0700318 case VB2_NV_CLEAR_TPM_OWNER_REQUEST:
319 SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST);
320 break;
321
322 case VB2_NV_CLEAR_TPM_OWNER_DONE:
323 SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
324 break;
325 }
326
327 /*
328 * Note there is no default case. This causes a compiler warning if
329 * a new param is added to the enum without adding support here.
330 */
331
332 /* Need to regenerate CRC, since the value changed. */
333 vb2_nv_regen_crc(ctx);
334}
335
336#undef SETBIT