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 */
24static VbCommonParams cparams;
25static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
26static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
27static GoogleBinaryBlockHeader gbb;
28static LoadKernelParams lkp;
29
30static int shutdown_request_calls_left;
31static int audio_looping_calls_left;
32static uint32_t vbtlk_retval;
33static int vbexlegacy_called;
34static int trust_ec;
35static int virtdev_set;
36static uint32_t virtdev_retval;
37static uint32_t mock_keypress[8];
38static uint32_t mock_keyflags[8];
39static uint32_t mock_keypress_count;
40static uint32_t mock_switches[8];
41static uint32_t mock_switches_count;
42static int mock_switches_are_stuck;
43static uint32_t screens_displayed[8];
44static uint32_t screens_count = 0;
45static uint32_t mock_num_disks[8];
46static uint32_t mock_num_disks_count;
47
48extern enum VbEcBootMode_t VbGetMode(void);
49
50/* Reset mock data (for use before each test) */
51static 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
102uint32_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
112uint32_t VbExKeyboardRead(void)
113{
114	return VbExKeyboardReadWithFlags(NULL);
115}
116
117uint32_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
127uint32_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
137int VbExLegacy(void)
138{
139	vbexlegacy_called++;
140	return 0;
141}
142
143VbError_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
157VbError_t VbExDiskFreeInfo(VbDiskInfo *infos,
158                           VbExDiskHandle_t preserve_handle)
159{
160	return VBERROR_SUCCESS;
161}
162
163int VbExTrustEC(int devidx)
164{
165	return trust_ec;
166}
167
168int 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
178uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
179                         uint32_t get_info_flags)
180{
181	return vbtlk_retval + get_info_flags;
182}
183
184VbError_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
193uint32_t SetVirtualDevMode(int val)
194{
195	virtdev_set = val;
196	return virtdev_retval;
197}
198
199/* Tests */
200
201static 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
264static 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
272static 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
448static 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
662int 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