vboot_api_init.c revision 2596c657958477b06d1613902dfe4d47a2ad0ae0
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
20VbError_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
351VbInit_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