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
VbSelectFirmware(VbCommonParams * cparams,VbSelectFirmwareParams * fparams)20 VbError_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