Home | History | Annotate | Download | only in tests
      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) */
     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 
    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 
    112 uint32_t VbExKeyboardRead(void)
    113 {
    114 	return VbExKeyboardReadWithFlags(NULL);
    115 }
    116 
    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 
    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 
    137 int VbExLegacy(void)
    138 {
    139 	vbexlegacy_called++;
    140 	return 0;
    141 }
    142 
    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 
    157 VbError_t VbExDiskFreeInfo(VbDiskInfo *infos,
    158                            VbExDiskHandle_t preserve_handle)
    159 {
    160 	return VBERROR_SUCCESS;
    161 }
    162 
    163 int VbExTrustEC(int devidx)
    164 {
    165 	return trust_ec;
    166 }
    167 
    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 
    178 uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
    179                          uint32_t get_info_flags)
    180 {
    181 	return vbtlk_retval + get_info_flags;
    182 }
    183 
    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 
    193 uint32_t SetVirtualDevMode(int val)
    194 {
    195 	virtdev_set = val;
    196 	return virtdev_retval;
    197 }
    198 
    199 /* Tests */
    200 
    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 
    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 
    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 
    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 
    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