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