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 
vb2_nv_regen_crc(struct vb2_context * ctx)15 static 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  */
vb2_nv_check_crc(const struct vb2_context * ctx)32 int 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 
vb2_nv_init(struct vb2_context * ctx)48 void 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 
vb2_nv_get(struct vb2_context * ctx,enum vb2_nv_param param)75 uint32_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 
vb2_nv_set(struct vb2_context * ctx,enum vb2_nv_param param,uint32_t value)167 void 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