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, &current) && 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