1 /* Copyright (c) 2013 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 "sysincludes.h"
9
10 #include "crc8.h"
11 #include "utility.h"
12 #include "vboot_common.h"
13 #include "vboot_nvstorage.h"
14
15 /*
16 * Constants for NV storage. We use this rather than structs and bitfields so
17 * the data format is consistent across platforms and compilers.
18 *
19 * These constants must match the equivalent constants in 2lib/2nvstorage.c.
20 * (We currently don't share a common header file because we're tring to keep
21 * the two libs independent, and we hope to deprecate this one.)
22 */
23 #define HEADER_OFFSET 0
24 #define HEADER_MASK 0xC0
25 #define HEADER_SIGNATURE 0x40
26 #define HEADER_FIRMWARE_SETTINGS_RESET 0x20
27 #define HEADER_KERNEL_SETTINGS_RESET 0x10
28
29 #define BOOT_OFFSET 1
30 #define BOOT_DEBUG_RESET_MODE 0x80
31 #define BOOT_DISABLE_DEV_REQUEST 0x40
32 #define BOOT_OPROM_NEEDED 0x20
33 #define BOOT_BACKUP_NVRAM 0x10
34 #define BOOT_TRY_B_COUNT_MASK 0x0F
35
36 #define RECOVERY_OFFSET 2
37 #define LOCALIZATION_OFFSET 3
38
39 #define DEV_FLAGS_OFFSET 4
40 #define DEV_BOOT_USB_MASK 0x01
41 #define DEV_BOOT_SIGNED_ONLY_MASK 0x02
42 #define DEV_BOOT_LEGACY_MASK 0x04
43
44 #define TPM_FLAGS_OFFSET 5
45 #define TPM_CLEAR_OWNER_REQUEST 0x01
46 #define TPM_CLEAR_OWNER_DONE 0x02
47
48 #define RECOVERY_SUBCODE_OFFSET 6
49
50 #define BOOT2_OFFSET 7
51 #define BOOT2_RESULT_MASK 0x03
52 #define BOOT2_TRIED 0x04
53 #define BOOT2_TRY_NEXT 0x08
54 #define BOOT2_PREV_RESULT_MASK 0x30
55 #define BOOT2_PREV_RESULT_SHIFT 4 /* Number of bits to shift result */
56 #define BOOT2_PREV_TRIED 0x40
57
58 #define KERNEL_FIELD_OFFSET 11
59 #define CRC_OFFSET 15
60
VbNvSetup(VbNvContext * context)61 int VbNvSetup(VbNvContext *context)
62 {
63 uint8_t *raw = context->raw;
64
65 /* Nothing has changed yet. */
66 context->raw_changed = 0;
67 context->regenerate_crc = 0;
68
69 /* Check data for consistency */
70 if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK))
71 || (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) {
72 /* Data is inconsistent (bad CRC or header); reset defaults */
73 Memset(raw, 0, VBNV_BLOCK_SIZE);
74 raw[HEADER_OFFSET] = (HEADER_SIGNATURE |
75 HEADER_FIRMWARE_SETTINGS_RESET |
76 HEADER_KERNEL_SETTINGS_RESET);
77
78 /* Regenerate CRC on exit */
79 context->regenerate_crc = 1;
80 }
81
82 return 0;
83 }
84
VbNvTeardown(VbNvContext * context)85 int VbNvTeardown(VbNvContext *context)
86 {
87 if (context->regenerate_crc) {
88 context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET);
89 context->regenerate_crc = 0;
90 context->raw_changed = 1;
91 }
92
93 return 0;
94 }
95
VbNvGet(VbNvContext * context,VbNvParam param,uint32_t * dest)96 int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest)
97 {
98 const uint8_t *raw = context->raw;
99
100 switch (param) {
101 case VBNV_FIRMWARE_SETTINGS_RESET:
102 *dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ?
103 1 : 0);
104 return 0;
105
106 case VBNV_KERNEL_SETTINGS_RESET:
107 *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ?
108 1 : 0);
109 return 0;
110
111 case VBNV_DEBUG_RESET_MODE:
112 *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0);
113 return 0;
114
115 case VBNV_TRY_B_COUNT:
116 case VBNV_FW_TRY_COUNT:
117 *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK;
118 return 0;
119
120 case VBNV_RECOVERY_REQUEST:
121 *dest = raw[RECOVERY_OFFSET];
122 return 0;
123
124 case VBNV_RECOVERY_SUBCODE:
125 *dest = raw[RECOVERY_SUBCODE_OFFSET];
126 return 0;
127
128 case VBNV_LOCALIZATION_INDEX:
129 *dest = raw[LOCALIZATION_OFFSET];
130 return 0;
131
132 case VBNV_KERNEL_FIELD:
133 *dest = (raw[KERNEL_FIELD_OFFSET]
134 | (raw[KERNEL_FIELD_OFFSET + 1] << 8)
135 | (raw[KERNEL_FIELD_OFFSET + 2] << 16)
136 | (raw[KERNEL_FIELD_OFFSET + 3] << 24));
137 return 0;
138
139 case VBNV_DEV_BOOT_USB:
140 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0);
141 return 0;
142
143 case VBNV_DEV_BOOT_LEGACY:
144 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0);
145 return 0;
146
147 case VBNV_DEV_BOOT_SIGNED_ONLY:
148 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ?
149 1 : 0);
150 return 0;
151
152 case VBNV_DISABLE_DEV_REQUEST:
153 *dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0);
154 return 0;
155
156 case VBNV_OPROM_NEEDED:
157 *dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0);
158 return 0;
159
160 case VBNV_CLEAR_TPM_OWNER_REQUEST:
161 *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ?
162 1 : 0);
163 return 0;
164
165 case VBNV_CLEAR_TPM_OWNER_DONE:
166 *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0);
167 return 0;
168
169 case VBNV_BACKUP_NVRAM_REQUEST:
170 *dest = (raw[BOOT_OFFSET] & BOOT_BACKUP_NVRAM ? 1 : 0);
171 return 0;
172
173 case VBNV_FW_TRY_NEXT:
174 *dest = (raw[BOOT2_OFFSET] & BOOT2_TRY_NEXT ? 1 : 0);
175 return 0;
176
177 case VBNV_FW_TRIED:
178 *dest = (raw[BOOT2_OFFSET] & BOOT2_TRIED ? 1 : 0);
179 return 0;
180
181 case VBNV_FW_RESULT:
182 *dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK;
183 return 0;
184
185 case VBNV_FW_PREV_TRIED:
186 *dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_TRIED ? 1 : 0);
187 return 0;
188
189 case VBNV_FW_PREV_RESULT:
190 *dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_RESULT_MASK)
191 >> BOOT2_PREV_RESULT_SHIFT;
192 return 0;
193
194 default:
195 return 1;
196 }
197 }
198
VbNvSet(VbNvContext * context,VbNvParam param,uint32_t value)199 int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
200 {
201 uint8_t *raw = context->raw;
202 uint32_t current;
203
204 /* If not changing the value, don't regenerate the CRC. */
205 if (0 == VbNvGet(context, param, ¤t) && current == value)
206 return 0;
207
208 switch (param) {
209 case VBNV_FIRMWARE_SETTINGS_RESET:
210 if (value)
211 raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET;
212 else
213 raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET;
214 break;
215
216 case VBNV_KERNEL_SETTINGS_RESET:
217 if (value)
218 raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET;
219 else
220 raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET;
221 break;
222
223 case VBNV_DEBUG_RESET_MODE:
224 if (value)
225 raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE;
226 else
227 raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE;
228 break;
229
230 case VBNV_TRY_B_COUNT:
231 case VBNV_FW_TRY_COUNT:
232 /* Clip to valid range. */
233 if (value > BOOT_TRY_B_COUNT_MASK)
234 value = BOOT_TRY_B_COUNT_MASK;
235
236 raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK;
237 raw[BOOT_OFFSET] |= (uint8_t)value;
238 break;
239
240 case VBNV_RECOVERY_REQUEST:
241 /*
242 * Map values outside the valid range to the legacy reason,
243 * since we can't determine if we're called from kernel or user
244 * mode.
245 */
246 if (value > 0xFF)
247 value = VBNV_RECOVERY_LEGACY;
248 raw[RECOVERY_OFFSET] = (uint8_t)value;
249 break;
250
251 case VBNV_RECOVERY_SUBCODE:
252 raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value;
253 break;
254
255 case VBNV_LOCALIZATION_INDEX:
256 /* Map values outside the valid range to the default index. */
257 if (value > 0xFF)
258 value = 0;
259 raw[LOCALIZATION_OFFSET] = (uint8_t)value;
260 break;
261
262 case VBNV_KERNEL_FIELD:
263 raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value);
264 raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8);
265 raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16);
266 raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24);
267 break;
268
269 case VBNV_DEV_BOOT_USB:
270 if (value)
271 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK;
272 else
273 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK;
274 break;
275
276 case VBNV_DEV_BOOT_LEGACY:
277 if (value)
278 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK;
279 else
280 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK;
281 break;
282
283 case VBNV_DEV_BOOT_SIGNED_ONLY:
284 if (value)
285 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK;
286 else
287 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK;
288 break;
289
290 case VBNV_DISABLE_DEV_REQUEST:
291 if (value)
292 raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST;
293 else
294 raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST;
295 break;
296
297 case VBNV_OPROM_NEEDED:
298 if (value)
299 raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED;
300 else
301 raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED;
302 break;
303
304 case VBNV_CLEAR_TPM_OWNER_REQUEST:
305 if (value)
306 raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST;
307 else
308 raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST;
309 break;
310
311 case VBNV_CLEAR_TPM_OWNER_DONE:
312 if (value)
313 raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE;
314 else
315 raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE;
316 break;
317
318 case VBNV_BACKUP_NVRAM_REQUEST:
319 if (value)
320 raw[BOOT_OFFSET] |= BOOT_BACKUP_NVRAM;
321 else
322 raw[BOOT_OFFSET] &= ~BOOT_BACKUP_NVRAM;
323 break;
324
325 case VBNV_FW_TRY_NEXT:
326 if (value)
327 raw[BOOT2_OFFSET] |= BOOT2_TRY_NEXT;
328 else
329 raw[BOOT2_OFFSET] &= ~BOOT2_TRY_NEXT;
330 break;
331
332 case VBNV_FW_TRIED:
333 if (value)
334 raw[BOOT2_OFFSET] |= BOOT2_TRIED;
335 else
336 raw[BOOT2_OFFSET] &= ~BOOT2_TRIED;
337 break;
338
339 case VBNV_FW_RESULT:
340 /* Map out of range values to unknown */
341 if (value > BOOT2_RESULT_MASK)
342 value = VBNV_FW_RESULT_UNKNOWN;
343
344 raw[BOOT2_OFFSET] &= ~BOOT2_RESULT_MASK;
345 raw[BOOT2_OFFSET] |= (uint8_t)value;
346 break;
347
348 case VBNV_FW_PREV_TRIED:
349 if (value)
350 raw[BOOT2_OFFSET] |= BOOT2_PREV_TRIED;
351 else
352 raw[BOOT2_OFFSET] &= ~BOOT2_PREV_TRIED;
353 break;
354
355 case VBNV_FW_PREV_RESULT:
356 /* Map out of range values to unknown */
357 if (value > BOOT2_RESULT_MASK)
358 value = VBNV_FW_RESULT_UNKNOWN;
359
360 raw[BOOT2_OFFSET] &= ~BOOT2_PREV_RESULT_MASK;
361 raw[BOOT2_OFFSET] |= (uint8_t)value << BOOT2_PREV_RESULT_SHIFT;
362 break;
363
364 default:
365 return 1;
366 }
367
368 /* Need to regenerate CRC, since the value changed. */
369 context->regenerate_crc = 1;
370 return 0;
371 }
372