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  * Tests for vboot_api_kernel, part 2
6  */
7 
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include "gbb_header.h"
13 #include "host_common.h"
14 #include "load_kernel_fw.h"
15 #include "rollback_index.h"
16 #include "test_common.h"
17 #include "vboot_audio.h"
18 #include "vboot_common.h"
19 #include "vboot_kernel.h"
20 #include "vboot_nvstorage.h"
21 #include "vboot_struct.h"
22 
23 /* Mock data */
24 static VbCommonParams cparams;
25 static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
26 static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
27 static GoogleBinaryBlockHeader gbb;
28 static LoadKernelParams lkp;
29 
30 static int shutdown_request_calls_left;
31 static int audio_looping_calls_left;
32 static uint32_t vbtlk_retval;
33 static int vbexlegacy_called;
34 static int trust_ec;
35 static int virtdev_set;
36 static uint32_t virtdev_retval;
37 static uint32_t mock_keypress[8];
38 static uint32_t mock_keyflags[8];
39 static uint32_t mock_keypress_count;
40 static uint32_t mock_switches[8];
41 static uint32_t mock_switches_count;
42 static int mock_switches_are_stuck;
43 static uint32_t screens_displayed[8];
44 static uint32_t screens_count = 0;
45 static uint32_t mock_num_disks[8];
46 static uint32_t mock_num_disks_count;
47 
48 extern enum VbEcBootMode_t VbGetMode(void);
49 
50 /* Reset mock data (for use before each test) */
ResetMocks(void)51 static void ResetMocks(void)
52 {
53 	Memset(&cparams, 0, sizeof(cparams));
54 	cparams.shared_data_size = sizeof(shared_data);
55 	cparams.shared_data_blob = shared_data;
56 	cparams.gbb_data = &gbb;
57 	cparams.gbb = &gbb;
58 
59 	Memset(&gbb, 0, sizeof(gbb));
60 	gbb.major_version = GBB_MAJOR_VER;
61 	gbb.minor_version = GBB_MINOR_VER;
62 	gbb.flags = 0;
63 
64 	/*
65 	 * Only the outermost vboot_api_kernel call sets vboot_api_kernel's
66 	 * vnc.  So clear it here too.
67 	 */
68 	Memset(VbApiKernelGetVnc(), 0, sizeof(VbNvContext));
69 	VbNvSetup(VbApiKernelGetVnc());
70 	VbNvTeardown(VbApiKernelGetVnc()); /* So CRC gets generated */
71 
72 	Memset(&shared_data, 0, sizeof(shared_data));
73 	VbSharedDataInit(shared, sizeof(shared_data));
74 
75 	Memset(&lkp, 0, sizeof(lkp));
76 
77 	shutdown_request_calls_left = -1;
78 	audio_looping_calls_left = 30;
79 	vbtlk_retval = 1000;
80 	vbexlegacy_called = 0;
81 	trust_ec = 0;
82 	virtdev_set = 0;
83 	virtdev_retval = 0;
84 
85 	Memset(screens_displayed, 0, sizeof(screens_displayed));
86 	screens_count = 0;
87 
88 	Memset(mock_keypress, 0, sizeof(mock_keypress));
89 	Memset(mock_keyflags, 0, sizeof(mock_keyflags));
90 	mock_keypress_count = 0;
91 
92 	Memset(mock_switches, 0, sizeof(mock_switches));
93 	mock_switches_count = 0;
94 	mock_switches_are_stuck = 0;
95 
96 	Memset(mock_num_disks, 0, sizeof(mock_num_disks));
97 	mock_num_disks_count = 0;
98 }
99 
100 /* Mock functions */
101 
VbExIsShutdownRequested(void)102 uint32_t VbExIsShutdownRequested(void)
103 {
104 	if (shutdown_request_calls_left == 0)
105 		return 1;
106 	else if (shutdown_request_calls_left > 0)
107 		shutdown_request_calls_left--;
108 
109 	return 0;
110 }
111 
VbExKeyboardRead(void)112 uint32_t VbExKeyboardRead(void)
113 {
114 	return VbExKeyboardReadWithFlags(NULL);
115 }
116 
VbExKeyboardReadWithFlags(uint32_t * key_flags)117 uint32_t VbExKeyboardReadWithFlags(uint32_t *key_flags)
118 {
119 	if (mock_keypress_count < ARRAY_SIZE(mock_keypress)) {
120 		if (key_flags != NULL)
121 			*key_flags = mock_keyflags[mock_keypress_count];
122 		return mock_keypress[mock_keypress_count++];
123 	} else
124 		return 0;
125 }
126 
VbExGetSwitches(uint32_t request_mask)127 uint32_t VbExGetSwitches(uint32_t request_mask)
128 {
129 	if (mock_switches_are_stuck)
130 		return mock_switches[0] & request_mask;
131 	if (mock_switches_count < ARRAY_SIZE(mock_switches))
132 		return mock_switches[mock_switches_count++] & request_mask;
133 	else
134 		return 0;
135 }
136 
VbExLegacy(void)137 int VbExLegacy(void)
138 {
139 	vbexlegacy_called++;
140 	return 0;
141 }
142 
VbExDiskGetInfo(VbDiskInfo ** infos_ptr,uint32_t * count,uint32_t disk_flags)143 VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count,
144                           uint32_t disk_flags)
145 {
146 	if (mock_num_disks_count < ARRAY_SIZE(mock_num_disks)) {
147 		if (mock_num_disks[mock_num_disks_count] == -1)
148 			return VBERROR_SIMULATED;
149 		else
150 			*count = mock_num_disks[mock_num_disks_count++];
151 	} else {
152 		*count = 0;
153 	}
154 	return VBERROR_SUCCESS;
155 }
156 
VbExDiskFreeInfo(VbDiskInfo * infos,VbExDiskHandle_t preserve_handle)157 VbError_t VbExDiskFreeInfo(VbDiskInfo *infos,
158                            VbExDiskHandle_t preserve_handle)
159 {
160 	return VBERROR_SUCCESS;
161 }
162 
VbExTrustEC(int devidx)163 int VbExTrustEC(int devidx)
164 {
165 	return trust_ec;
166 }
167 
VbAudioLooping(VbAudioContext * audio)168 int VbAudioLooping(VbAudioContext *audio)
169 {
170 	if (audio_looping_calls_left == 0)
171 		return 0;
172 	else if (audio_looping_calls_left > 0)
173 		audio_looping_calls_left--;
174 
175 	return 1;
176 }
177 
VbTryLoadKernel(VbCommonParams * cparams,LoadKernelParams * p,uint32_t get_info_flags)178 uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
179                          uint32_t get_info_flags)
180 {
181 	return vbtlk_retval + get_info_flags;
182 }
183 
VbDisplayScreen(VbCommonParams * cparams,uint32_t screen,int force,VbNvContext * vncptr)184 VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, int force,
185                           VbNvContext *vncptr)
186 {
187 	if (screens_count < ARRAY_SIZE(screens_displayed))
188 		screens_displayed[screens_count++] = screen;
189 
190 	return VBERROR_SUCCESS;
191 }
192 
SetVirtualDevMode(int val)193 uint32_t SetVirtualDevMode(int val)
194 {
195 	virtdev_set = val;
196 	return virtdev_retval;
197 }
198 
199 /* Tests */
200 
VbUserConfirmsTest(void)201 static void VbUserConfirmsTest(void)
202 {
203 	printf("Testing VbUserConfirms()...\n");
204 
205 	ResetMocks();
206 	shutdown_request_calls_left = 1;
207 	TEST_EQ(VbUserConfirms(&cparams, 0), -1, "Shutdown requested");
208 
209 	ResetMocks();
210 	mock_keypress[0] = '\r';
211 	TEST_EQ(VbUserConfirms(&cparams, 0), 1, "Enter");
212 
213 	ResetMocks();
214 	mock_keypress[0] = 0x1b;
215 	TEST_EQ(VbUserConfirms(&cparams, 0), 0, "Esc");
216 
217 	ResetMocks();
218 	mock_keypress[0] = ' ';
219 	shutdown_request_calls_left = 1;
220 	TEST_EQ(VbUserConfirms(&cparams, VB_CONFIRM_SPACE_MEANS_NO), 0,
221                 "Space means no");
222 
223 	ResetMocks();
224 	mock_keypress[0] = ' ';
225 	shutdown_request_calls_left = 1;
226 	TEST_EQ(VbUserConfirms(&cparams, 0), -1, "Space ignored");
227 
228 	ResetMocks();
229 	mock_keypress[0] = '\r';
230 	mock_keyflags[0] = VB_KEY_FLAG_TRUSTED_KEYBOARD;
231 	TEST_EQ(VbUserConfirms(&cparams, VB_CONFIRM_MUST_TRUST_KEYBOARD),
232 		1, "Enter with trusted keyboard");
233 
234 	ResetMocks();
235 	mock_keypress[0] = '\r';	/* untrusted */
236 	mock_keypress[1] = ' ';
237 	TEST_EQ(VbUserConfirms(&cparams,
238 			       VB_CONFIRM_SPACE_MEANS_NO |
239 			       VB_CONFIRM_MUST_TRUST_KEYBOARD),
240 		0, "Untrusted keyboard");
241 
242 	ResetMocks();
243 	mock_switches[0] = VB_INIT_FLAG_REC_BUTTON_PRESSED;
244 	TEST_EQ(VbUserConfirms(&cparams,
245 			       VB_CONFIRM_SPACE_MEANS_NO |
246 			       VB_CONFIRM_MUST_TRUST_KEYBOARD),
247 		1, "Recovery button");
248 
249 	ResetMocks();
250 	mock_keypress[0] = '\r';
251 	mock_keypress[1] = 'y';
252 	mock_keypress[2] = 'z';
253 	mock_keypress[3] = ' ';
254 	mock_switches[0] = VB_INIT_FLAG_REC_BUTTON_PRESSED;
255 	mock_switches_are_stuck = 1;
256 	TEST_EQ(VbUserConfirms(&cparams,
257 			       VB_CONFIRM_SPACE_MEANS_NO |
258 			       VB_CONFIRM_MUST_TRUST_KEYBOARD),
259 		0, "Recovery button stuck");
260 
261 	printf("...done.\n");
262 }
263 
VbBootTest(void)264 static void VbBootTest(void)
265 {
266 	ResetMocks();
267 	VbExEcEnteringMode(0, VB_EC_NORMAL);
268 	TEST_EQ(VbBootNormal(&cparams, &lkp), 1002, "VbBootNormal()");
269 	TEST_EQ(VbGetMode(), VB_EC_NORMAL, "vboot_mode normal");
270 }
271 
VbBootDevTest(void)272 static void VbBootDevTest(void)
273 {
274 	uint32_t u;
275 
276 	printf("Testing VbBootDeveloper()...\n");
277 
278 	/* Proceed after timeout */
279 	ResetMocks();
280 	VbExEcEnteringMode(0, VB_EC_DEVELOPER);
281 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Timeout");
282 	TEST_EQ(VbGetMode(), VB_EC_DEVELOPER, "vboot_mode developer");
283 	TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
284 		"  warning screen");
285 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
286 	TEST_EQ(u, 0, "  recovery reason");
287 	TEST_EQ(audio_looping_calls_left, 0, "  used up audio");
288 
289 	/* Proceed to legacy after timeout if GBB flag set */
290 	ResetMocks();
291 	gbb.flags |= GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY;
292 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Timeout");
293 	TEST_EQ(vbexlegacy_called, 1, "  try legacy");
294 
295 	/* Up arrow is uninteresting / passed to VbCheckDisplayKey() */
296 	ResetMocks();
297 	mock_keypress[0] = VB_KEY_UP;
298 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Up arrow");
299 
300 	/* Shutdown requested in loop */
301 	ResetMocks();
302 	shutdown_request_calls_left = 2;
303 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
304 		"Shutdown requested");
305 	TEST_NEQ(audio_looping_calls_left, 0, "  aborts audio");
306 
307 	/* Space goes straight to recovery if no virtual dev switch */
308 	ResetMocks();
309 	mock_keypress[0] = ' ';
310 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_LOAD_KERNEL_RECOVERY,
311 		"Space = recovery");
312 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
313 	TEST_EQ(u, VBNV_RECOVERY_RW_DEV_SCREEN, "  recovery reason");
314 
315 	/* Space asks to disable virtual dev switch */
316 	ResetMocks();
317 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
318 	mock_keypress[0] = ' ';
319 	mock_keypress[1] = '\r';
320 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_TPM_REBOOT_REQUIRED,
321 		"Space = tonorm");
322 	TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
323 		"  warning screen");
324 	TEST_EQ(screens_displayed[1], VB_SCREEN_DEVELOPER_TO_NORM,
325 		"  tonorm screen");
326 	TEST_EQ(screens_displayed[2], VB_SCREEN_TO_NORM_CONFIRMED,
327 		"  confirm screen");
328 	VbNvGet(VbApiKernelGetVnc(), VBNV_DISABLE_DEV_REQUEST, &u);
329 	TEST_EQ(u, 1, "  disable dev request");
330 
331 	/* Space-space doesn't disable it */
332 	ResetMocks();
333 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
334 	mock_keypress[0] = ' ';
335 	mock_keypress[1] = ' ';
336 	mock_keypress[2] = 0x1b;
337 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Space-space");
338 	TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
339 		"  warning screen");
340 	TEST_EQ(screens_displayed[1], VB_SCREEN_DEVELOPER_TO_NORM,
341 		"  tonorm screen");
342 	TEST_EQ(screens_displayed[2], VB_SCREEN_DEVELOPER_WARNING,
343 		"  warning screen");
344 
345 	/* Enter doesn't by default */
346 	ResetMocks();
347 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
348 	mock_keypress[0] = '\r';
349 	mock_keypress[1] = '\r';
350 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Enter ignored");
351 
352 	/* Enter does if GBB flag set */
353 	ResetMocks();
354 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
355 	gbb.flags |= GBB_FLAG_ENTER_TRIGGERS_TONORM;
356 	mock_keypress[0] = '\r';
357 	mock_keypress[1] = '\r';
358 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_TPM_REBOOT_REQUIRED,
359 		"Enter = tonorm");
360 
361 	/* Tonorm ignored if GBB forces dev switch on */
362 	ResetMocks();
363 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
364 	gbb.flags |= GBB_FLAG_FORCE_DEV_SWITCH_ON;
365 	mock_keypress[0] = ' ';
366 	mock_keypress[1] = '\r';
367 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Can't tonorm gbb-dev");
368 
369 	/* Shutdown requested at tonorm screen */
370 	ResetMocks();
371 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
372 	mock_keypress[0] = ' ';
373 	shutdown_request_calls_left = 2;
374 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
375 		"Shutdown requested at tonorm");
376 	TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
377 		"  warning screen");
378 	TEST_EQ(screens_displayed[1], VB_SCREEN_DEVELOPER_TO_NORM,
379 		"  tonorm screen");
380 
381 	/* Ctrl+D dismisses warning */
382 	ResetMocks();
383 	mock_keypress[0] = 0x04;
384 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+D");
385 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
386 	TEST_EQ(u, 0, "  recovery reason");
387 	TEST_NEQ(audio_looping_calls_left, 0, "  aborts audio");
388 	TEST_EQ(vbexlegacy_called, 0, "  not legacy");
389 
390 	/* Ctrl+D doesn't boot legacy even if GBB flag is set */
391 	ResetMocks();
392 	mock_keypress[0] = 0x04;
393 	gbb.flags |= GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY;
394 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+D");
395 	TEST_EQ(vbexlegacy_called, 0, "  not legacy");
396 
397 	/* Ctrl+L tries legacy boot mode only if enabled */
398 	ResetMocks();
399 	mock_keypress[0] = 0x0c;
400 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+L normal");
401 	TEST_EQ(vbexlegacy_called, 0, "  not legacy");
402 
403 	ResetMocks();
404 
405 	gbb.flags |= GBB_FLAG_FORCE_DEV_BOOT_LEGACY;
406 	mock_keypress[0] = 0x0c;
407 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+L force legacy");
408 	TEST_EQ(vbexlegacy_called, 1, "  try legacy");
409 
410 	ResetMocks();
411 	VbNvSet(VbApiKernelGetVnc(), VBNV_DEV_BOOT_LEGACY, 1);
412 	mock_keypress[0] = 0x0c;
413 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+L nv legacy");
414 	TEST_EQ(vbexlegacy_called, 1, "  try legacy");
415 
416 	/* Ctrl+U boots USB only if enabled */
417 	ResetMocks();
418 	mock_keypress[0] = 0x15;
419 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+U normal");
420 
421 	/* Ctrl+U enabled, with good USB boot */
422 	ResetMocks();
423 	VbNvSet(VbApiKernelGetVnc(), VBNV_DEV_BOOT_USB, 1);
424 	mock_keypress[0] = 0x15;
425 	vbtlk_retval = VBERROR_SUCCESS - VB_DISK_FLAG_REMOVABLE;
426 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 0, "Ctrl+U USB");
427 
428 	/* Ctrl+U enabled via GBB */
429 	ResetMocks();
430 	gbb.flags |= GBB_FLAG_FORCE_DEV_BOOT_USB;
431 	mock_keypress[0] = 0x15;
432 	vbtlk_retval = VBERROR_SUCCESS - VB_DISK_FLAG_REMOVABLE;
433 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 0, "Ctrl+U force USB");
434 
435 	/* If no USB, eventually times out and tries fixed disk */
436 	ResetMocks();
437 	VbNvSet(VbApiKernelGetVnc(), VBNV_DEV_BOOT_USB, 1);
438 	mock_keypress[0] = 0x15;
439 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+U enabled");
440 	TEST_EQ(vbexlegacy_called, 0, "  not legacy");
441 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
442 	TEST_EQ(u, 0, "  recovery reason");
443 	TEST_EQ(audio_looping_calls_left, 0, "  used up audio");
444 
445 	printf("...done.\n");
446 }
447 
VbBootRecTest(void)448 static void VbBootRecTest(void)
449 {
450 	uint32_t u;
451 
452 	printf("Testing VbBootRecovery()...\n");
453 
454 	/* Shutdown requested in loop */
455 	ResetMocks();
456 	shutdown_request_calls_left = 10;
457 	VbExEcEnteringMode(0, VB_EC_RECOVERY);
458 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
459 		"Shutdown requested");
460 	TEST_EQ(VbGetMode(), VB_EC_RECOVERY, "vboot_mode recovery");
461 
462 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
463 	TEST_EQ(u, 0, "  recovery reason");
464 	TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,
465 		"  blank screen");
466 	TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_NO_GOOD,
467 		"  no good screen");
468 
469 	/* Disk inserted after start */
470 	ResetMocks();
471 	vbtlk_retval = VBERROR_SUCCESS - VB_DISK_FLAG_REMOVABLE;
472 	TEST_EQ(VbBootRecovery(&cparams, &lkp), 0, "Good");
473 
474 	/* No disk inserted */
475 	ResetMocks();
476 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
477 	shutdown_request_calls_left = 10;
478 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
479 		"Bad disk");
480 	TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,
481 		"  blank screen");
482 	TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_INSERT,
483 		"  insert screen");
484 
485 	/* Remove disks */
486 	ResetMocks();
487 	shutdown_request_calls_left = 100;
488 	mock_num_disks[0] = 1;
489 	mock_num_disks[1] = 1;
490 	mock_num_disks[2] = 1;
491 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
492 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
493 		"Remove");
494 	TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_REMOVE,
495 		"  remove screen");
496 	TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_REMOVE,
497 		"  remove screen");
498 	TEST_EQ(screens_displayed[2], VB_SCREEN_BLANK,
499 		"  blank screen");
500 	TEST_EQ(screens_displayed[3], VB_SCREEN_RECOVERY_INSERT,
501 		"  insert screen");
502 
503 	/* No removal if dev switch is on */
504 	ResetMocks();
505 	shutdown_request_calls_left = 100;
506 	mock_num_disks[0] = 1;
507 	mock_num_disks[1] = 1;
508 	shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
509 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
510 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
511 		"No remove in dev");
512 	TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
513 		"  insert screen");
514 
515 	/* No removal if recovery button physically pressed */
516 	ResetMocks();
517 	shutdown_request_calls_left = 100;
518 	mock_num_disks[0] = 1;
519 	mock_num_disks[1] = 1;
520 	shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
521 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
522 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
523 		"No remove in rec");
524 	TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
525 		"  insert screen");
526 
527 	/* Removal if no disk initially found, but found on second attempt */
528 	ResetMocks();
529 	shutdown_request_calls_left = 100;
530 	mock_num_disks[0] = 0;
531 	mock_num_disks[1] = 1;
532 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
533 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
534 		"Remove");
535 	TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_REMOVE,
536 		"  remove screen");
537 	TEST_EQ(screens_displayed[1], VB_SCREEN_BLANK,
538 		"  blank screen");
539 	TEST_EQ(screens_displayed[2], VB_SCREEN_RECOVERY_INSERT,
540 		"  insert screen");
541 
542 	/* Bad disk count doesn't require removal */
543 	ResetMocks();
544 	mock_num_disks[0] = -1;
545 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
546 	shutdown_request_calls_left = 10;
547 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
548 		"Bad disk count");
549 	TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,
550 		"  blank screen");
551 	TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_INSERT,
552 		"  insert screen");
553 
554 	/* Ctrl+D ignored for many reasons... */
555 	ResetMocks();
556 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
557 	shutdown_request_calls_left = 100;
558 	mock_keypress[0] = 0x04;
559 	trust_ec = 0;
560 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
561 		"Ctrl+D ignored if EC not trusted");
562 	TEST_EQ(virtdev_set, 0, "  virtual dev mode off");
563 	TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
564 		 "  todev screen");
565 
566 	ResetMocks();
567 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON |
568 		VBSD_BOOT_DEV_SWITCH_ON;
569 	trust_ec = 1;
570 	shutdown_request_calls_left = 100;
571 	mock_keypress[0] = 0x04;
572 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
573 		"Ctrl+D ignored if already in dev mode");
574 	TEST_EQ(virtdev_set, 0, "  virtual dev mode off");
575 	TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
576 		 "  todev screen");
577 
578 	ResetMocks();
579 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH;
580 	trust_ec = 1;
581 	shutdown_request_calls_left = 100;
582 	mock_keypress[0] = 0x04;
583 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
584 		"Ctrl+D ignored if recovery not manually triggered");
585 	TEST_EQ(virtdev_set, 0, "  virtual dev mode off");
586 	TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
587 		 "  todev screen");
588 
589 	ResetMocks();
590 	shared->flags = VBSD_BOOT_REC_SWITCH_ON;
591 	trust_ec = 1;
592 	shutdown_request_calls_left = 100;
593 	mock_keypress[0] = 0x04;
594 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
595 		"Ctrl+D ignored if no virtual dev switch");
596 	TEST_EQ(virtdev_set, 0, "  virtual dev mode off");
597 	TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
598 		 "  todev screen");
599 
600 	/* Ctrl+D ignored because the physical recovery switch is still pressed
601 	 * and we don't like that.
602 	 */
603 	ResetMocks();
604 	shared->flags = VBSD_BOOT_REC_SWITCH_ON;
605 	trust_ec = 1;
606 	shutdown_request_calls_left = 100;
607 	mock_keypress[0] = 0x04;
608 	mock_switches[0] = VB_INIT_FLAG_REC_BUTTON_PRESSED;
609 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
610 		"Ctrl+D ignored if phys rec button is still pressed");
611 	TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
612 		 "  todev screen");
613 
614 	/* Ctrl+D then space means don't enable */
615 	ResetMocks();
616 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
617 	shutdown_request_calls_left = 100;
618 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
619 	trust_ec = 1;
620 	mock_keypress[0] = 0x04;
621 	mock_keypress[1] = ' ';
622 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
623 		"Ctrl+D todev abort");
624 	TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
625 		"  insert screen");
626 	TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
627 		"  todev screen");
628 	TEST_EQ(screens_displayed[2], VB_SCREEN_RECOVERY_INSERT,
629 		"  insert screen");
630 	TEST_EQ(virtdev_set, 0, "  virtual dev mode off");
631 
632 	/* Ctrl+D then enter means enable */
633 	ResetMocks();
634 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
635 	shutdown_request_calls_left = 100;
636 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
637 	trust_ec = 1;
638 	mock_keypress[0] = 0x04;
639 	mock_keypress[1] = '\r';
640 	mock_keyflags[1] = VB_KEY_FLAG_TRUSTED_KEYBOARD;
641 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_TPM_REBOOT_REQUIRED,
642 		"Ctrl+D todev confirm");
643 	TEST_EQ(virtdev_set, 1, "  virtual dev mode on");
644 
645 	/* Handle TPM error in enabling dev mode */
646 	ResetMocks();
647 	shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
648 	shutdown_request_calls_left = 100;
649 	vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
650 	trust_ec = 1;
651 	mock_keypress[0] = 0x04;
652 	mock_keypress[1] = '\r';
653 	mock_keyflags[1] = VB_KEY_FLAG_TRUSTED_KEYBOARD;
654 	virtdev_retval = VBERROR_SIMULATED;
655 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_TPM_SET_BOOT_MODE_STATE,
656 		"Ctrl+D todev failure");
657 
658 	printf("...done.\n");
659 }
660 
661 
main(void)662 int main(void)
663 {
664 	VbUserConfirmsTest();
665 	VbBootTest();
666 	VbBootDevTest();
667 	VbBootRecTest();
668 
669 	if (vboot_api_stub_check_memory())
670 		return 255;
671 
672 	return gTestSuccess ? 0 : 255;
673 }
674