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_access.h"
11#include "gbb_header.h"
12#include "load_firmware_fw.h"
13#include "rollback_index.h"
14#include "tpm_bootmode.h"
15#include "utility.h"
16#include "vboot_api.h"
17#include "vboot_common.h"
18#include "vboot_nvstorage.h"
19
20VbError_t VbSelectFirmware(VbCommonParams *cparams,
21                           VbSelectFirmwareParams *fparams)
22{
23	VbSharedDataHeader *shared =
24		(VbSharedDataHeader *)cparams->shared_data_blob;
25	VbNvContext vnc;
26	VbError_t retval = VBERROR_UNKNOWN; /* Default to error */
27	int is_rec = (shared->recovery_reason ? 1 : 0);
28	int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
29	uint32_t tpm_status = 0;
30
31	cparams->gbb = NULL;
32	cparams->bmp = NULL;
33
34	/* Start timer */
35	shared->timer_vb_select_firmware_enter = VbExGetTimer();
36
37	/* Load NV storage */
38	VbExNvStorageRead(vnc.raw);
39	VbNvSetup(&vnc);
40
41	if (is_rec) {
42		/*
43		 * Recovery is requested; go straight to recovery without
44		 * checking the RW firmware.
45		 */
46		VBDEBUG(("VbSelectFirmware() detected recovery request\n"));
47
48		/* Best effort to read the GBB */
49		cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
50		retval = VbGbbReadHeader_static(cparams, cparams->gbb);
51		if (VBERROR_SUCCESS != retval) {
52			VBDEBUG(("Can't read GBB. Continuing anyway...\n"));
53			VbExFree(cparams->gbb);
54			cparams->gbb = NULL;
55		}
56
57		/* Go directly to recovery mode */
58		fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
59	} else {
60		cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
61		retval = VbGbbReadHeader_static(cparams, cparams->gbb);
62		if (VBERROR_SUCCESS != retval)
63			goto VbSelectFirmware_exit;
64
65		/* Chain to LoadFirmware() */
66		retval = LoadFirmware(cparams, fparams, &vnc);
67
68		/* Exit if we failed to find an acceptable firmware */
69		if (VBERROR_SUCCESS != retval)
70			goto VbSelectFirmware_exit;
71
72		/* Translate the selected firmware path */
73		if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
74			/* Request the read-only normal/dev code path */
75			fparams->selected_firmware =
76				VB_SELECT_FIRMWARE_READONLY;
77		} else if (0 == shared->firmware_index)
78			fparams->selected_firmware = VB_SELECT_FIRMWARE_A;
79		else {
80			fparams->selected_firmware = VB_SELECT_FIRMWARE_B;
81		}
82
83		/* Update TPM if necessary */
84		if (shared->fw_version_tpm_start < shared->fw_version_tpm) {
85			tpm_status =
86				RollbackFirmwareWrite(shared->fw_version_tpm);
87			if (0 != tpm_status) {
88				VBDEBUG(("Can't write FW version to TPM.\n"));
89				VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
90					VBNV_RECOVERY_RO_TPM_W_ERROR);
91				retval = VBERROR_TPM_WRITE_FIRMWARE;
92				goto VbSelectFirmware_exit;
93			}
94		}
95
96		/* Lock firmware versions in TPM */
97		tpm_status = RollbackFirmwareLock();
98		if (0 != tpm_status) {
99			VBDEBUG(("Unable to lock firmware version in TPM.\n"));
100			VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
101				VBNV_RECOVERY_RO_TPM_L_ERROR);
102			retval = VBERROR_TPM_LOCK_FIRMWARE;
103			goto VbSelectFirmware_exit;
104		}
105	}
106
107	/*
108	 * At this point, we have a good idea of how we are going to
109	 * boot. Update the TPM with this state information.
110	 */
111	tpm_status = SetTPMBootModeState(is_dev, is_rec,
112					 shared->fw_keyblock_flags,
113					 cparams->gbb);
114	if (0 != tpm_status) {
115		VBDEBUG(("Can't update the TPM with boot mode information.\n"));
116		if (!is_rec) {
117			VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
118				VBNV_RECOVERY_RO_TPM_U_ERROR);
119			retval = VBERROR_TPM_SET_BOOT_MODE_STATE;
120			goto VbSelectFirmware_exit;
121		}
122	}
123
124	/* Success! */
125	retval = VBERROR_SUCCESS;
126
127 VbSelectFirmware_exit:
128
129	if (cparams->gbb) {
130		VbExFree(cparams->gbb);
131		cparams->gbb = NULL;
132	}
133
134	/* Save NV storage */
135	VbNvTeardown(&vnc);
136	if (vnc.raw_changed)
137		VbExNvStorageWrite(vnc.raw);
138
139	/* Stop timer */
140	shared->timer_vb_select_firmware_exit = VbExGetTimer();
141
142	/* Should always have a known error code */
143	VbAssert(VBERROR_UNKNOWN != retval);
144
145	return retval;
146}
147