• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * High-level firmware wrapper API - entry points for init, firmware selection
6  */
7 
8 #include "sysincludes.h"
9 
10 #include "region.h"
11 #include "gbb_access.h"
12 #include "gbb_header.h"
13 #include "load_firmware_fw.h"
14 #include "rollback_index.h"
15 #include "utility.h"
16 #include "vboot_api.h"
17 #include "vboot_common.h"
18 #include "vboot_nvstorage.h"
19 
VbInit(VbCommonParams * cparams,VbInitParams * iparams)20 VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams)
21 {
22 	VbSharedDataHeader *shared =
23 		(VbSharedDataHeader *)cparams->shared_data_blob;
24 	GoogleBinaryBlockHeader gbb;
25 	VbNvContext vnc;
26 	VbError_t retval = VBERROR_SUCCESS;
27 	uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
28 	int is_s3_resume = 0;
29 	uint32_t s3_debug_boot = 0;
30 	uint32_t require_official_os = 0;
31 	uint32_t tpm_version = 0;
32 	uint32_t tpm_status = 0;
33 	int has_virt_dev_switch = 0;
34 	int is_hw_dev = 0;
35 	int is_virt_dev = 0;
36 	uint32_t disable_dev_request = 0;
37 	uint32_t clear_tpm_owner_request = 0;
38 	int is_dev = 0;
39 	uint32_t backup_requested = 0;
40 	uint32_t backup_for_safety = 0;
41 	int lost_nvram;
42 
43 	/* Initialize output flags */
44 	iparams->out_flags = 0;
45 
46 	retval = VbGbbReadHeader_static(cparams, &gbb);
47 	if (retval)
48 		return retval;
49 
50 	VBDEBUG(("VbInit() input flags 0x%x gbb flags 0x%x\n", iparams->flags,
51 		 gbb.flags));
52 
53 	/* Set up NV storage */
54 	VbExNvStorageRead(vnc.raw);
55 	VbNvSetup(&vnc);
56 	lost_nvram = vnc.regenerate_crc;
57 
58 	/* Initialize shared data structure */
59 	if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) {
60 		VBDEBUG(("Shared data init error\n"));
61 		return VBERROR_INIT_SHARED_DATA;
62 	}
63 
64 	shared->timer_vb_init_enter = VbExGetTimer();
65 
66 	/* Copy some boot switch flags */
67 	/* TODO: in next refactor, just save in/out flags in VbSharedData */
68 	shared->flags = 0;
69 	if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
70 		shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
71 	if (iparams->flags & VB_INIT_FLAG_WP_ENABLED)
72 		shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
73 	if (iparams->flags & VB_INIT_FLAG_SW_WP_ENABLED)
74 		shared->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED;
75 	if (iparams->flags & VB_INIT_FLAG_S3_RESUME)
76 		shared->flags |= VBSD_BOOT_S3_RESUME;
77 	if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT)
78 		shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT;
79 	if (iparams->flags & VB_INIT_FLAG_EC_SOFTWARE_SYNC)
80 		shared->flags |= VBSD_EC_SOFTWARE_SYNC;
81 	if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE)
82 		shared->flags |= VBSD_EC_SLOW_UPDATE;
83 	if (iparams->flags & VB_INIT_FLAG_VIRTUAL_REC_SWITCH)
84 		shared->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL;
85 	if (iparams->flags & VB_INIT_FLAG_OPROM_MATTERS)
86 		shared->flags |= VBSD_OPROM_MATTERS;
87 	if (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)
88 		shared->flags |= VBSD_OPROM_LOADED;
89 
90 	is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);
91 
92 	/* Check if the OS is requesting a debug S3 reset */
93 	VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot);
94 	if (s3_debug_boot) {
95 		if (is_s3_resume) {
96 			VBDEBUG(("VbInit() requesting S3 debug boot\n"));
97 			iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT;
98 			is_s3_resume = 0;  /* Proceed as if normal boot */
99 		}
100 
101 		/*
102 		 * Clear the request even if this is a normal boot, since we
103 		 * don't want the NEXT S3 resume to be a debug reset unless the
104 		 * OS asserts the request again.
105 		 */
106 		VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0);
107 	}
108 
109 	/*
110 	 * If this isn't a S3 resume, read the current recovery request, then
111 	 * clear it so we don't get stuck in recovery mode.
112 	 */
113 	if (!is_s3_resume) {
114 		VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery);
115 		VBDEBUG(("VbInit sees recovery request = %d\n", recovery));
116 		if (VBNV_RECOVERY_NOT_REQUESTED != recovery)
117 			VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
118 				VBNV_RECOVERY_NOT_REQUESTED);
119 	}
120 
121 	/*
122 	 * If the previous boot failed in the firmware somewhere outside of
123 	 * verified boot, and recovery is not requested for our own reasons,
124 	 * request recovery mode.  This gives the calling firmware a way to
125 	 * request recovery if it finds something terribly wrong.
126 	 */
127 	if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
128 	    iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
129 		recovery = VBNV_RECOVERY_RO_FIRMWARE;
130 	}
131 
132 	/*
133 	 * If recovery button is pressed, override recovery reason.  Note that
134 	 * we do this in the S3 resume path also.
135 	 */
136 	if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
137 		recovery = VBNV_RECOVERY_RO_MANUAL;
138 
139 	/*
140 	 * Copy current recovery reason to shared data. If we fail later on, it
141 	 * won't matter, since we'll just reboot.
142 	 */
143 	shared->recovery_reason = (uint8_t)recovery;
144 	VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));
145 
146 	/*
147 	 * If this is a S3 resume, resume the TPM.
148 	 *
149 	 * FIXME: I think U-Boot won't ever ask us to do this. Can we remove
150 	 * it?
151 	 */
152 	if (is_s3_resume) {
153 		if (TPM_SUCCESS != RollbackS3Resume()) {
154 			/*
155 			 * If we can't resume, just do a full reboot.  No need
156 			 * to go to recovery mode here, since if the TPM is
157 			 * really broken we'll catch it on the next boot.
158 			 */
159 			retval = VBERROR_TPM_S3_RESUME;
160 		}
161 	} else {
162 		/* Should we pay attention to the TPM's virtual dev-switch? */
163 		if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) {
164 			shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
165 			has_virt_dev_switch = 1;
166 		}
167 
168 		/*
169 		 * We always believe the HW dev-switch, since there's one
170 		 * attached to servo which may be active even on systems
171 		 * without a physical switch. The EC may also implement a fake
172 		 * dev-switch for testing.
173 		 */
174 		if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
175 			is_hw_dev = 1;
176 
177 		/* We may be asked to clear the virtual dev-switch at boot. */
178 		VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);
179 
180 		/* Allow GBB flag to override dev switch */
181 		if (gbb.flags & GBB_FLAG_FORCE_DEV_SWITCH_ON)
182 			is_hw_dev = 1;
183 
184 		/* Have we been explicitly asked to clear the TPM owner? */
185 		VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST,
186 			&clear_tpm_owner_request);
187 
188 		/*
189 		 * Initialize the TPM. If the developer mode state has changed
190 		 * since the last boot, we need to clear TPM ownership. If the
191 		 * TPM space is initialized by this call, the virtual
192 		 * dev-switch will be disabled by default)
193 		 */
194 		VBDEBUG(("TPM: Call RollbackFirmwareSetup(r%d, d%d)\n",
195 			 recovery, is_hw_dev));
196 		tpm_status = RollbackFirmwareSetup(is_hw_dev,
197 						   disable_dev_request,
198 						   clear_tpm_owner_request,
199 						   /* two outputs on success */
200 						   &is_virt_dev, &tpm_version);
201 
202 		if (0 != tpm_status) {
203 			VBDEBUG(("Unable to setup TPM and read "
204 				 "firmware version (0x%x)\n", tpm_status));
205 
206 			if (TPM_E_MUST_REBOOT == tpm_status) {
207 				/*
208 				 * TPM wants to reboot into the same mode we're
209 				 * in now
210 				 */
211 				VBDEBUG(("TPM requires a reboot.\n"));
212 				if (!recovery) {
213 					/*
214 					 * Not recovery mode.  Just reboot (not
215 					 * into recovery).
216 					 */
217 					retval = VBERROR_TPM_REBOOT_REQUIRED;
218 					goto VbInit_exit;
219 				} else if (VBNV_RECOVERY_RO_TPM_REBOOT !=
220 					   shared->recovery_reason) {
221 					/*
222 					 * In recovery mode now, and we haven't
223 					 * requested a TPM reboot yet, so
224 					 * request one.
225 					 */
226 					VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
227 						VBNV_RECOVERY_RO_TPM_REBOOT);
228 					retval = VBERROR_TPM_REBOOT_REQUIRED;
229 					goto VbInit_exit;
230 				}
231 			}
232 
233 			if (!recovery) {
234 				VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
235 					VBNV_RECOVERY_RO_TPM_S_ERROR);
236 				VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE,
237 					tpm_status);
238 				retval = VBERROR_TPM_FIRMWARE_SETUP;
239 				goto VbInit_exit;
240 			}
241 		}
242 
243 		/* TPM setup succeeded, or we're in recovery mode and ignoring
244 		 * errors. What did we learn? */
245 		shared->fw_version_tpm_start = tpm_version;
246 		shared->fw_version_tpm = tpm_version;
247 		if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) {
248 			is_dev = 1;
249 			shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
250 		}
251 		if (disable_dev_request && !is_virt_dev)
252 			VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0);
253 		if (clear_tpm_owner_request) {
254 			VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0);
255 			VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1);
256 		}
257 	}
258 
259 	/*
260 	 * If the nvram state was lost, try to restore the bits we care about
261 	 * from the backup in the TPM. It's okay if we can't, though.
262 	 * Note: None of the bits that we back up should have been referenced
263 	 * before this point. Otherwise, they'll just be overwritten here.
264 	 * All the other bits will be unchanged from whatever has happened to
265 	 * them since VbNvSetup() reinitialized the VbNvContext.
266 	 */
267 	if (lost_nvram)
268 		RestoreNvFromBackup(&vnc);
269 
270 	/* Allow BIOS to load arbitrary option ROMs? */
271 	if (gbb.flags & GBB_FLAG_LOAD_OPTION_ROMS)
272 		iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM;
273 
274 	/* Factory may need to boot custom OSes when the dev-switch is on */
275 	if (is_dev && (gbb.flags & GBB_FLAG_ENABLE_ALTERNATE_OS))
276 		iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
277 
278 	/* Set output flags */
279 	if (VBNV_RECOVERY_NOT_REQUESTED != recovery) {
280 		/* Requesting recovery mode */
281 		iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY |
282 				       VB_INIT_OUT_CLEAR_RAM |
283 				       VB_INIT_OUT_ENABLE_DISPLAY |
284 				       VB_INIT_OUT_ENABLE_USB_STORAGE);
285 	} else if (is_dev) {
286 		/* Developer switch is on, so need to support dev mode */
287 		iparams->out_flags |= (VB_INIT_OUT_ENABLE_DEVELOPER |
288 				       VB_INIT_OUT_CLEAR_RAM |
289 				       VB_INIT_OUT_ENABLE_DISPLAY |
290 				       VB_INIT_OUT_ENABLE_USB_STORAGE);
291 		/* ... which may or may not include custom OSes */
292 		VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
293 		if (!require_official_os)
294 			iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
295 
296 		/*
297 		 * Dev-mode needs the VGA option ROM to be loaded so it can
298 		 * display the scary boot screen. If we don't have it, we need
299 		 * to request it and reboot so it can be loaded.
300 		 */
301 		if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
302 		    !(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
303 			VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
304 			/*
305 			 * If VbInit() is run before Option ROMs are run it
306 			 * can still respond to the VbNv flag and does not
307 			 * need to reboot here.
308 			 */
309 			if (!(iparams->flags & VB_INIT_FLAG_BEFORE_OPROM_LOAD))
310 				retval = VBERROR_VGA_OPROM_MISMATCH;
311 			VBDEBUG(("VbInit() needs oprom, doesn't have it\n"));
312 		}
313 
314 	} else {
315 		/*
316 		 * Normal mode, so disable dev_boot_* flags.  This ensures they
317 		 * will be initially disabled if the user later transitions
318 		 * back into developer mode.
319 		 */
320 		VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
321 		VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0);
322 		VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0);
323 		/*
324 		 * Back up any changes now, so these values can't be forgotten
325 		 * by draining the battery. We really only care about these
326 		 * three fields, but it's uncommon for any others to change so
327 		 * this is an easier test than checking each one.
328 		 */
329 		if (vnc.regenerate_crc)
330 			backup_for_safety = 1;
331 
332 		/*
333 		 * If we don't need the VGA option ROM but got it anyway, stop
334 		 * asking for it and reboot in case there's some vulnerability
335 		 * in using it.
336 		 */
337 		if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
338 		    (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
339 			VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
340 			/*
341 			 * If VbInit() is run before Option ROMs are run it
342 			 * can still respond to the VbNv flag and does not
343 			 * need to reboot here.
344 			 */
345 			if (!(iparams->flags & VB_INIT_FLAG_BEFORE_OPROM_LOAD))
346 				retval = VBERROR_VGA_OPROM_MISMATCH;
347 			VBDEBUG(("VbInit() has oprom, doesn't need it\n"));
348 		}
349 	}
350 
351 VbInit_exit:
352 	/*
353 	 * If we successfully backup the NV storage, it will clear the
354 	 * VBNV_BACKUP_NVRAM_REQUEST field, so we want to do it before
355 	 * calling VbNvTeardown(). It's okay if we can't backup, though.
356 	 */
357 	VbNvGet(&vnc, VBNV_BACKUP_NVRAM_REQUEST, &backup_requested);
358 	if (backup_requested || backup_for_safety)
359 		SaveNvToBackup(&vnc);
360 
361 	/* Tear down NV storage */
362 	VbNvTeardown(&vnc);
363 	if (vnc.raw_changed)
364 		VbExNvStorageWrite(vnc.raw);
365 
366 	VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
367 
368 	shared->timer_vb_init_exit = VbExGetTimer();
369 
370 	VBDEBUG(("VbInit() returning 0x%x\n", retval));
371 
372 	return retval;
373 }
374