blob: ec1e7fa9689c0315c37d6ec74819ac2be5647760 [file] [log] [blame]
Randall Spangler391b3102011-09-02 11:28:24 -07001/* Copyright (c) 2011 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 * Tests for vboot_api_init
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10
Bill Richardsonc8e4ff72011-11-10 13:31:39 -080011#include "gbb_header.h"
Randall Spangler391b3102011-09-02 11:28:24 -070012#include "host_common.h"
13#include "rollback_index.h"
14#include "test_common.h"
15#include "vboot_common.h"
16#include "vboot_nvstorage.h"
17#include "vboot_struct.h"
18
19/* Mock data */
20static VbCommonParams cparams;
21static VbInitParams iparams;
22static VbNvContext vnc;
23static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
24static VbSharedDataHeader* shared = (VbSharedDataHeader*)shared_data;
25static uint64_t mock_timer;
26static int rollback_s3_retval;
27static int nv_write_called;
Bill Richardsonc8e4ff72011-11-10 13:31:39 -080028static GoogleBinaryBlockHeader gbb;
Bill Richardsonec8df162012-06-07 04:21:14 -070029static int mock_virt_dev_sw;
Bill Richardsonb75d8ad2012-05-17 13:26:05 -070030static uint32_t mock_tpm_version;
31static uint32_t mock_rfs_retval;
Randall Spangler391b3102011-09-02 11:28:24 -070032
33/* Reset mock data (for use before each test) */
34static void ResetMocks(void) {
35 Memset(&cparams, 0, sizeof(cparams));
36 cparams.shared_data_size = sizeof(shared_data);
37 cparams.shared_data_blob = shared_data;
Bill Richardsonc8e4ff72011-11-10 13:31:39 -080038 cparams.gbb_data = &gbb;
39
40 Memset(&gbb, 0, sizeof(gbb));
41 gbb.major_version = GBB_MAJOR_VER;
42 gbb.minor_version = GBB_MINOR_VER;
43 gbb.flags = 0;
Randall Spangler391b3102011-09-02 11:28:24 -070044
45 Memset(&iparams, 0, sizeof(iparams));
46
47 Memset(&vnc, 0, sizeof(vnc));
48 VbNvSetup(&vnc);
Bill Richardsonb75d8ad2012-05-17 13:26:05 -070049 VbNvTeardown(&vnc); /* So CRC gets generated */
Randall Spangler391b3102011-09-02 11:28:24 -070050
51 Memset(&shared_data, 0, sizeof(shared_data));
52 VbSharedDataInit(shared, sizeof(shared_data));
53
54 mock_timer = 10;
55 rollback_s3_retval = TPM_SUCCESS;
56 nv_write_called = 0;
Bill Richardsonb75d8ad2012-05-17 13:26:05 -070057
Bill Richardsonec8df162012-06-07 04:21:14 -070058 mock_virt_dev_sw = 0;
Bill Richardsonb75d8ad2012-05-17 13:26:05 -070059 mock_tpm_version = 0x10001;
60 mock_rfs_retval = 0;
Randall Spangler391b3102011-09-02 11:28:24 -070061}
62
63/****************************************************************************/
64/* Mocked verification functions */
65
66VbError_t VbExNvStorageRead(uint8_t* buf) {
67 Memcpy(buf, vnc.raw, sizeof(vnc.raw));
68 return VBERROR_SUCCESS;
69}
70
71VbError_t VbExNvStorageWrite(const uint8_t* buf) {
72 nv_write_called = 1;
73 Memcpy(vnc.raw, buf, sizeof(vnc.raw));
74 return VBERROR_SUCCESS;
75}
76
77uint64_t VbExGetTimer(void) {
78 /* Exponential-ish rather than linear time, so that subtracting any
79 * two mock values will yield a unique result. */
80 uint64_t new_timer = mock_timer * 2 + 1;
81 VbAssert(new_timer > mock_timer); /* Make sure we don't overflow */
82 mock_timer = new_timer;
83 return mock_timer;
84}
85
86uint32_t RollbackS3Resume(void) {
87 return rollback_s3_retval;
88}
89
Bill Richardsonec8df162012-06-07 04:21:14 -070090uint32_t RollbackFirmwareSetup(int recovery_mode, int is_hw_dev,
91 int disable_dev_request,
92 /* two outputs on success */
93 int *is_virt_dev, uint32_t *version) {
94 *is_virt_dev = mock_virt_dev_sw;
Bill Richardsonb75d8ad2012-05-17 13:26:05 -070095 *version = mock_tpm_version;
96 return mock_rfs_retval;
97}
98
Randall Spangler391b3102011-09-02 11:28:24 -070099/****************************************************************************/
100/* Test VbInit() and check expected return value and recovery reason */
101static void TestVbInit(VbError_t expected_retval,
102 uint8_t expected_recovery, const char* desc) {
103 uint32_t rr = 256;
104
105 TEST_EQ(VbInit(&cparams, &iparams), expected_retval, desc);
106 VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &rr);
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700107 TEST_EQ(rr, expected_recovery, " (recovery request)");
Randall Spangler391b3102011-09-02 11:28:24 -0700108}
109
110/****************************************************************************/
111
112static void VbInitTest(void) {
113 uint32_t u;
114
115 /* Test passing in too small a shared data area */
116 ResetMocks();
117 cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE - 1;
118 TestVbInit(VBERROR_INIT_SHARED_DATA, 0, "Shared data too small");
119
120 /* Normal call; dev=0 rec=0 */
121 ResetMocks();
122 TestVbInit(0, 0, "Normal call");
123 TEST_EQ(shared->timer_vb_init_enter, 21, " time enter");
124 TEST_EQ(shared->timer_vb_init_exit, 43, " time exit");
125 TEST_EQ(shared->flags, 0, " shared flags");
126 TEST_EQ(iparams.out_flags, 0, " out flags");
127 TEST_EQ(nv_write_called, 0, " NV write not called since nothing changed");
128
129 /* If NV data is trashed, we initialize it */
130 ResetMocks();
131 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
132 /* Note that we're not doing a VbNvTeardown(), so the CRC hasn't
133 * been regenerated yet. So VbInit() should ignore the corrupted
134 * recovery value and boot normally. */
135 TestVbInit(0, 0, "NV data trashed");
136 TEST_EQ(nv_write_called, 1, " NV write called");
137
138 /* Test boot switch flags which are just passed through to shared
139 * flags, and don't have an effect on VbInit(). */
140 ResetMocks();
141 iparams.flags = VB_INIT_FLAG_WP_ENABLED;
142 TestVbInit(0, 0, "Flags test WP");
143 TEST_EQ(shared->flags, VBSD_BOOT_FIRMWARE_WP_ENABLED, " shared flags WP");
144
145 ResetMocks();
146 iparams.flags = VB_INIT_FLAG_RO_NORMAL_SUPPORT;
147 TestVbInit(0, 0, " flags test RO normal");
148 TEST_EQ(shared->flags, VBSD_BOOT_RO_NORMAL_SUPPORT,
149 " shared flags RO normal");
150
151 /* S3 resume */
152 ResetMocks();
153 iparams.flags = VB_INIT_FLAG_S3_RESUME;
154 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
155 VbNvTeardown(&vnc);
156 /* S3 resume doesn't clear the recovery request (or act on it) */
157 TestVbInit(0, 123, "S3 resume");
158 TEST_EQ(shared->flags, VBSD_BOOT_S3_RESUME, " shared flags S3");
159 TEST_EQ(iparams.out_flags, 0, " out flags");
160 TEST_EQ(shared->recovery_reason, 0, " S3 doesn't look at recovery request");
161
162 /* S3 resume with TPM resume error */
163 ResetMocks();
164 iparams.flags = VB_INIT_FLAG_S3_RESUME;
165 rollback_s3_retval = 1;
166 /* S3 resume doesn't clear the recovery request (or act on it) */
167 TestVbInit(VBERROR_TPM_S3_RESUME, 0, "S3 resume rollback error");
168
169 /* Normal boot doesn't care about TPM resume error because it
170 * doesn't call RollbackS3Resume() */
171 ResetMocks();
172 rollback_s3_retval = 1;
173 TestVbInit(0, 0, "Normal doesn't S3 resume");
174
175 /* S3 resume with debug reset */
176 ResetMocks();
177 iparams.flags = VB_INIT_FLAG_S3_RESUME;
178 VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
179 VbNvTeardown(&vnc);
180 TestVbInit(0, 0, "S3 debug reset");
181 TEST_EQ(iparams.out_flags, VB_INIT_OUT_S3_DEBUG_BOOT, " out flags");
182 VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &u);
183 TEST_EQ(u, 0, " S3 clears nv debug reset mode");
184
185 /* Normal boot clears S3 debug reset mode, but doesn't set output flag */
186 ResetMocks();
187 VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
188 VbNvTeardown(&vnc);
189 TestVbInit(0, 0, "Normal with debug reset mode");
190 TEST_EQ(iparams.out_flags, 0, " out flags");
191 VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &u);
192 TEST_EQ(u, 0, " normal clears nv debug reset mode");
193
194 /* S3 resume with debug reset is a normal boot, so doesn't resume the TPM */
195 ResetMocks();
196 iparams.flags = VB_INIT_FLAG_S3_RESUME;
197 rollback_s3_retval = 1;
198 VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 1);
199 VbNvTeardown(&vnc);
200 TestVbInit(0, 0, "S3 debug reset rollback error");
201
202 /* Developer mode */
203 ResetMocks();
204 iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
205 TestVbInit(0, 0, "Dev mode on");
206 TEST_EQ(shared->recovery_reason, 0, " recovery reason");
207 TEST_EQ(iparams.out_flags,
208 VB_INIT_OUT_CLEAR_RAM |
209 VB_INIT_OUT_ENABLE_DISPLAY |
Bill Richardson7272a692011-11-17 10:48:59 -0800210 VB_INIT_OUT_ENABLE_USB_STORAGE |
211 VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
Randall Spangler391b3102011-09-02 11:28:24 -0700212 TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
213
214 /* Recovery mode from NV storage */
215 ResetMocks();
216 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
217 VbNvTeardown(&vnc);
218 TestVbInit(0, 0, "Recovery mode - from nv");
219 TEST_EQ(shared->recovery_reason, 123, " recovery reason");
220 TEST_EQ(iparams.out_flags,
221 VB_INIT_OUT_ENABLE_RECOVERY |
222 VB_INIT_OUT_CLEAR_RAM |
223 VB_INIT_OUT_ENABLE_DISPLAY |
224 VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
225 TEST_EQ(shared->flags, 0, " shared flags");
226
227 /* Recovery mode from recovery button */
228 ResetMocks();
229 iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
230 TestVbInit(0, 0, "Recovery mode - button");
231 TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
232 " recovery reason");
233 TEST_EQ(iparams.out_flags,
234 VB_INIT_OUT_ENABLE_RECOVERY |
235 VB_INIT_OUT_CLEAR_RAM |
236 VB_INIT_OUT_ENABLE_DISPLAY |
237 VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
238 TEST_EQ(shared->flags, VBSD_BOOT_REC_SWITCH_ON, " shared flags");
239
240 /* Recovery button reason supersedes NV reason */
241 ResetMocks();
242 iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
243 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
244 VbNvTeardown(&vnc);
245 TestVbInit(0, 0, "Recovery mode - button AND nv");
246 TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
247 " recovery reason");
248
249 /* Recovery mode from previous boot fail */
250 ResetMocks();
251 iparams.flags = VB_INIT_FLAG_PREVIOUS_BOOT_FAIL;
252 TestVbInit(0, 0, "Recovery mode - previous boot fail");
253 TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_FIRMWARE,
254 " recovery reason");
255 TEST_EQ(iparams.out_flags,
256 VB_INIT_OUT_ENABLE_RECOVERY |
257 VB_INIT_OUT_CLEAR_RAM |
258 VB_INIT_OUT_ENABLE_DISPLAY |
259 VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
260 TEST_EQ(shared->flags, 0, " shared flags");
261
262 /* Recovery mode from NV supersedes previous boot fail */
263 ResetMocks();
264 iparams.flags = VB_INIT_FLAG_PREVIOUS_BOOT_FAIL;
265 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
266 VbNvTeardown(&vnc);
267 TestVbInit(0, 0, "Recovery mode - previous boot fail AND nv");
268 TEST_EQ(shared->recovery_reason, 123, " recovery reason");
269
270 /* Dev + recovery = recovery */
271 ResetMocks();
272 iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED | VB_INIT_FLAG_DEV_SWITCH_ON;
273 TestVbInit(0, 0, "Recovery mode - button");
274 TEST_EQ(shared->recovery_reason, VBNV_RECOVERY_RO_MANUAL,
275 " recovery reason");
276 TEST_EQ(iparams.out_flags,
277 VB_INIT_OUT_ENABLE_RECOVERY |
278 VB_INIT_OUT_CLEAR_RAM |
279 VB_INIT_OUT_ENABLE_DISPLAY |
280 VB_INIT_OUT_ENABLE_USB_STORAGE, " out flags");
281 TEST_EQ(shared->flags,
282 VBSD_BOOT_REC_SWITCH_ON | VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
283}
284
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700285static void VbInitTestTPM(void) {
286
287 /* Rollback setup needs to reboot */
288 ResetMocks();
289 mock_rfs_retval = TPM_E_MUST_REBOOT;
290 TestVbInit(VBERROR_TPM_REBOOT_REQUIRED, 0, "Rollback TPM reboot (rec=0)");
291 ResetMocks();
292 mock_rfs_retval = TPM_E_MUST_REBOOT;
293 iparams.flags = VB_INIT_FLAG_REC_BUTTON_PRESSED;
294 TestVbInit(VBERROR_TPM_REBOOT_REQUIRED, VBNV_RECOVERY_RO_TPM_REBOOT,
295 "Rollback TPM reboot, in recovery, first time");
296 /* Ignore if we already tried rebooting */
297 ResetMocks();
298 mock_rfs_retval = TPM_E_MUST_REBOOT;
299 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_REBOOT);
300 VbNvTeardown(&vnc);
301 TestVbInit(0, 0, "Rollback TPM reboot, in recovery, already retried");
302 TEST_EQ(shared->fw_version_tpm, 0x10001, " shared fw_version_tpm");
303
304 /* Other rollback setup errors */
305 ResetMocks();
306 mock_rfs_retval = TPM_E_IOERROR;
307 mock_tpm_version = 0x20002;
308 TestVbInit(VBERROR_TPM_FIRMWARE_SETUP, VBNV_RECOVERY_RO_TPM_ERROR,
309 "Rollback TPM setup error - not in recovery");
310 TEST_EQ(shared->fw_version_tpm, 0, " shared fw_version_tpm not set");
311 ResetMocks();
312 mock_rfs_retval = TPM_E_IOERROR;
313 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_US_TEST);
314 VbNvTeardown(&vnc);
315 TestVbInit(0, 0, "Rollback TPM setup error ignored in recovery");
316 TEST_EQ(shared->fw_version_tpm, 0x10001, " shared fw_version_tpm");
317
318 /* Virtual developer switch, but not enabled. */
319 ResetMocks();
Bill Richardsonec8df162012-06-07 04:21:14 -0700320 iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700321 TestVbInit(0, 0, "TPM Dev mode off");
322 TEST_EQ(shared->recovery_reason, 0, " recovery reason");
323 TEST_EQ(iparams.out_flags, 0, " out flags");
Bill Richardsonec8df162012-06-07 04:21:14 -0700324 TEST_EQ(shared->flags, VBSD_HONOR_VIRT_DEV_SWITCH, " shared flags");
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700325
326 /* Virtual developer switch, enabled. */
327 ResetMocks();
328 iparams.flags = VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
Bill Richardsonec8df162012-06-07 04:21:14 -0700329 mock_virt_dev_sw = 1;
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700330 TestVbInit(0, 0, "TPM Dev mode on");
331 TEST_EQ(shared->recovery_reason, 0, " recovery reason");
332 TEST_EQ(iparams.out_flags,
333 VB_INIT_OUT_CLEAR_RAM |
334 VB_INIT_OUT_ENABLE_DISPLAY |
335 VB_INIT_OUT_ENABLE_USB_STORAGE |
336 VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
Bill Richardsonec8df162012-06-07 04:21:14 -0700337 TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON | VBSD_HONOR_VIRT_DEV_SWITCH,
338 " shared flags");
339
340 /* Ignore virtual developer switch, even though enabled. */
341 ResetMocks();
342 mock_virt_dev_sw = 1;
343 TestVbInit(0, 0, "TPM Dev mode on but ignored");
344 TEST_EQ(shared->recovery_reason, 0, " recovery reason");
345 TEST_EQ(iparams.out_flags, 0, " out flags");
346 TEST_EQ(shared->flags, 0, " shared flags");
347
348 /* HW dev switch on, no virtual developer switch */
349 ResetMocks();
350 iparams.flags = VB_INIT_FLAG_DEV_SWITCH_ON;
351 TestVbInit(0, 0, "HW Dev mode on");
352 TEST_EQ(shared->recovery_reason, 0, " recovery reason");
353 TEST_EQ(iparams.out_flags,
354 VB_INIT_OUT_CLEAR_RAM |
355 VB_INIT_OUT_ENABLE_DISPLAY |
356 VB_INIT_OUT_ENABLE_USB_STORAGE |
357 VB_INIT_OUT_ENABLE_ALTERNATE_OS, " out flags");
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700358 TEST_EQ(shared->flags, VBSD_BOOT_DEV_SWITCH_ON, " shared flags");
359}
360
Randall Spangler391b3102011-09-02 11:28:24 -0700361
362/* disable MSVC warnings on unused arguments */
363__pragma(warning (disable: 4100))
364
365int main(int argc, char* argv[]) {
366 int error_code = 0;
367
368 VbInitTest();
Bill Richardsonb75d8ad2012-05-17 13:26:05 -0700369 VbInitTestTPM();
Randall Spangler391b3102011-09-02 11:28:24 -0700370
371 if (!gTestSuccess)
372 error_code = 255;
373
374 return error_code;
375}