diff options
-rw-r--r-- | firmware/include/vboot_api.h | 2 | ||||
-rw-r--r-- | firmware/lib/include/vboot_kernel.h | 5 | ||||
-rw-r--r-- | firmware/lib/vboot_ui.c | 55 | ||||
-rw-r--r-- | tests/vboot_api_kernel2_tests.c | 423 |
4 files changed, 372 insertions, 113 deletions
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index 682e7fc5..c5b382ac 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -204,8 +204,6 @@ typedef struct VbCommonParams { } VbCommonParams; /* Flags for VbExGetSwitches() */ -/* Recovery button was pressed at boot time. */ -#define VB_SWITCH_FLAG_REC_BUTTON_PRESSED 0x00000002 /* Report if user is currently present (typically via power button) */ #define VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED 0x00000004 /* Allow USB boot on transition to dev */ diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h index 7a8087e4..fe8d7023 100644 --- a/firmware/lib/include/vboot_kernel.h +++ b/firmware/lib/include/vboot_kernel.h @@ -93,4 +93,9 @@ uint32_t vb2_get_fwmp_flags(void); */ void vb2_nv_commit(struct vb2_context *ctx); +/** + * Reinitialize global state. This should only need to be called by init tests. + */ +void vb2_init_ui(void); + #endif /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */ diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c index 6009d90d..60afadc9 100644 --- a/firmware/lib/vboot_ui.c +++ b/firmware/lib/vboot_ui.c @@ -28,11 +28,15 @@ #include "vboot_ui_common.h" /* Global variables */ -static int power_button_released; +enum { + POWER_BUTTON_HELD_SINCE_BOOT = 0, + POWER_BUTTON_RELEASED, + POWER_BUTTON_PRESSED, /* must have been previously released */ +} power_button_state; -static void vb2_init_ui(void) +void vb2_init_ui(void) { - power_button_released = 0; + power_button_state = POWER_BUTTON_HELD_SINCE_BOOT; } static void VbAllowUsbBoot(struct vb2_context *ctx) @@ -58,13 +62,17 @@ static int VbWantShutdown(struct vb2_context *ctx, uint32_t key) /* * Ignore power button push until after we have seen it released. * This avoids shutting down immediately if the power button is still - * being held on startup. + * being held on startup. After we've recognized a valid power button + * push then don't report the event until after the button is released. */ if (shutdown_request & VB_SHUTDOWN_REQUEST_POWER_BUTTON) { - if (!power_button_released) - shutdown_request &= ~VB_SHUTDOWN_REQUEST_POWER_BUTTON; + shutdown_request &= ~VB_SHUTDOWN_REQUEST_POWER_BUTTON; + if (power_button_state == POWER_BUTTON_RELEASED) + power_button_state = POWER_BUTTON_PRESSED; } else { - power_button_released = 1; + if (power_button_state == POWER_BUTTON_PRESSED) + shutdown_request |= VB_SHUTDOWN_REQUEST_POWER_BUTTON; + power_button_state = POWER_BUTTON_RELEASED; } if (key == VB_BUTTON_POWER_SHORT_PRESS) @@ -107,15 +115,15 @@ int VbUserConfirms(struct vb2_context *ctx, uint32_t confirm_flags) uint32_t key; uint32_t key_flags; uint32_t btn; - int rec_button_was_pressed = 0; + int phys_presence_button_was_pressed = 0; + int shutdown_requested = 0; VB2_DEBUG("Entering(%x)\n", confirm_flags); /* Await further instructions */ - while (1) { + do { key = VbExKeyboardReadWithFlags(&key_flags); - if (VbWantShutdown(ctx, key)) - return -1; + shutdown_requested = VbWantShutdown(ctx, key); switch (key) { case VB_KEY_ENTER: /* If we require a trusted keyboard for confirmation, @@ -145,26 +153,28 @@ int VbUserConfirms(struct vb2_context *ctx, uint32_t confirm_flags) return 0; break; default: - /* If the recovery button is physical, and is pressed, - * this is also a YES, but must wait for release. + /* If the physical presence button is physical, and is + * pressed, this is also a YES, but must wait for + * release. */ btn = VbExGetSwitches( - VB_SWITCH_FLAG_REC_BUTTON_PRESSED); + VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED); if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL)) { if (btn) { - VB2_DEBUG("Rec button pressed\n"); - rec_button_was_pressed = 1; - } else if (rec_button_was_pressed) { - VB2_DEBUG("Rec button (1)\n"); + VB2_DEBUG("Presence button pressed, " + "awaiting release\n"); + phys_presence_button_was_pressed = 1; + } else if (phys_presence_button_was_pressed) { + VB2_DEBUG("Presence button released " + "(1)\n"); return 1; } } VbCheckDisplayKey(ctx, key, NULL); } VbExSleepMs(CONFIRM_KEY_DELAY); - } + } while (!shutdown_requested); - /* Not reached, but compiler will complain without it */ return -1; } @@ -888,9 +898,9 @@ static VbError_t recovery_ui(struct vb2_context *ctx) if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL) && VbExGetSwitches( - VB_SWITCH_FLAG_REC_BUTTON_PRESSED)) { + VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED)) { /* - * Is the recovery button stuck? In + * Is the presence button stuck? In * any case we don't like this. Beep * and ignore. */ @@ -949,7 +959,6 @@ static VbError_t recovery_ui(struct vb2_context *ctx) VbError_t VbBootRecovery(struct vb2_context *ctx) { - vb2_init_ui(); VbError_t retval = recovery_ui(ctx); VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL); return retval; diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c index a3cbd487..cb2471f4 100644 --- a/tests/vboot_api_kernel2_tests.c +++ b/tests/vboot_api_kernel2_tests.c @@ -33,9 +33,6 @@ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]; static struct vb2_context ctx; static struct vb2_shared_data *sd; -static int shutdown_request_calls_left; -static int shutdown_request_power_held; -static int shutdown_via_lid_close; static int audio_looping_calls_left; static uint32_t vbtlk_retval; static int vbexlegacy_called; @@ -47,9 +44,17 @@ static uint32_t virtdev_retval; static uint32_t mock_keypress[16]; static uint32_t mock_keyflags[8]; static uint32_t mock_keypress_count; -static uint32_t mock_switches[8]; -static uint32_t mock_switches_count; -static int mock_switches_are_stuck; + +#define GPIO_SHUTDOWN 1 +#define GPIO_PRESENCE 2 +#define GPIO_LID_CLOSED 4 +typedef struct GpioState { + uint32_t gpio_flags; + uint32_t count; +} GpioState; +struct GpioState mock_gpio[8]; +static uint32_t mock_gpio_count; + static uint32_t screens_displayed[8]; static uint32_t screens_count = 0; static uint32_t mock_num_disks[8]; @@ -60,9 +65,24 @@ static enum vb2_tpm_mode tpm_mode; static char set_vendor_data[32]; static int set_vendor_data_called; +/* + * Mocks the assertion of 1 or more gpios in |gpio_flags| for 100 ticks after + * an optional |ticks| delay. + */ +static void MockGpioAfter(uint32_t ticks, uint32_t gpio_flags) +{ + uint32_t index = 0; + if (ticks > 0) + mock_gpio[index++].count = ticks - 1; + + mock_gpio[index].gpio_flags = gpio_flags; + mock_gpio[index].count = 100; +} + /* Reset mock data (for use before each test) */ static void ResetMocks(void) { + vb2_init_ui(); memset(VbApiKernelGetFwmp(), 0, sizeof(struct RollbackSpaceFwmp)); memset(&shared_data, 0, sizeof(shared_data)); @@ -79,9 +99,6 @@ static void ResetMocks(void) sd = vb2_get_sd(&ctx); sd->vbsd = shared; - shutdown_request_calls_left = -1; - shutdown_request_power_held = -1; - shutdown_via_lid_close = 0; audio_looping_calls_left = 30; vbtlk_retval = 1000; vbexlegacy_called = 0; @@ -98,11 +115,8 @@ static void ResetMocks(void) memset(mock_keypress, 0, sizeof(mock_keypress)); memset(mock_keyflags, 0, sizeof(mock_keyflags)); mock_keypress_count = 0; - - memset(mock_switches, 0, sizeof(mock_switches)); - mock_switches_count = 0; - mock_switches_are_stuck = 0; - + memset(mock_gpio, 0, sizeof(mock_gpio)); + mock_gpio_count = 0; memset(mock_num_disks, 0, sizeof(mock_num_disks)); mock_num_disks_count = 0; @@ -114,23 +128,19 @@ static void ResetMocks(void) uint32_t VbExIsShutdownRequested(void) { - if (shutdown_request_calls_left == 0) - return shutdown_via_lid_close ? - VB_SHUTDOWN_REQUEST_LID_CLOSED : - VB_SHUTDOWN_REQUEST_POWER_BUTTON; - else if (shutdown_request_calls_left > 0) - shutdown_request_calls_left--; - - if (shutdown_request_power_held >= 0) { - /* Hold power button for 10 calls, then release for 10. */ - if (shutdown_request_calls_left % 10 == 0) - shutdown_request_power_held - = !shutdown_request_power_held; - if (shutdown_request_power_held) - return VB_SHUTDOWN_REQUEST_POWER_BUTTON; + uint32_t result = 0; + if (mock_gpio_count >= ARRAY_SIZE(mock_gpio)) + return 0; + if (mock_gpio[mock_gpio_count].gpio_flags & GPIO_SHUTDOWN) + result |= VB_SHUTDOWN_REQUEST_POWER_BUTTON; + if (mock_gpio[mock_gpio_count].gpio_flags & GPIO_LID_CLOSED) + result |= VB_SHUTDOWN_REQUEST_LID_CLOSED; + if (mock_gpio[mock_gpio_count].count > 0) { + --mock_gpio[mock_gpio_count].count; + } else { + ++mock_gpio_count; } - - return 0; + return result; } uint32_t VbExKeyboardRead(void) @@ -150,12 +160,18 @@ uint32_t VbExKeyboardReadWithFlags(uint32_t *key_flags) uint32_t VbExGetSwitches(uint32_t request_mask) { - if (mock_switches_are_stuck) - return mock_switches[0] & request_mask; - if (mock_switches_count < ARRAY_SIZE(mock_switches)) - return mock_switches[mock_switches_count++] & request_mask; - else + uint32_t result = 0; + if (mock_gpio_count >= ARRAY_SIZE(mock_gpio)) return 0; + if ((request_mask & VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED) && + (mock_gpio[mock_gpio_count].gpio_flags & GPIO_PRESENCE)) + result |= VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED; + if (mock_gpio[mock_gpio_count].count > 0) { + --mock_gpio[mock_gpio_count].count; + } else { + ++mock_gpio_count; + } + return result; } int VbExLegacy(enum VbAltFwIndex_t _altfw_num) @@ -259,12 +275,49 @@ int vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val) /* Tests */ +/* + * Helper function to test VbUserConfirms against a sequence of gpio events. + * caller specifies a sequence of gpio events and the expected confirm vs. + * reboot result. + * + * Non-asserted gpios are used for 5 events, then 'first' for 5 events, + * 'second' for 5 events, and 'third' for 5 events. + * Typically most tests want 5 events of each type (so they'll specify 0 for + * 'first' and use 'second' through 'fourth'), but a few tests want the + * shutdown event to be seen once. + */ +static void VbUserConfirmsTestGpio(uint32_t first, uint32_t second, + uint32_t third, uint32_t confirm, + const char *msg) +{ + ResetMocks(); + mock_gpio[0].gpio_flags = 0; + mock_gpio[0].count = 4; + mock_gpio[1].gpio_flags = first; + mock_gpio[1].count = 4; + mock_gpio[2].gpio_flags = second; + mock_gpio[2].count = 4; + mock_gpio[3].gpio_flags = third; + mock_gpio[3].count = 4; + if (confirm) { + TEST_EQ(VbUserConfirms(&ctx, + VB_CONFIRM_SPACE_MEANS_NO | + VB_CONFIRM_MUST_TRUST_KEYBOARD), + 1, msg); + } else { + TEST_EQ(VbUserConfirms(&ctx, + VB_CONFIRM_SPACE_MEANS_NO | + VB_CONFIRM_MUST_TRUST_KEYBOARD), + -1, msg); + } +} + static void VbUserConfirmsTest(void) { printf("Testing VbUserConfirms()...\n"); ResetMocks(); - shutdown_request_calls_left = 1; + MockGpioAfter(1, GPIO_SHUTDOWN); TEST_EQ(VbUserConfirms(&ctx, 0), -1, "Shutdown requested"); ResetMocks(); @@ -281,13 +334,13 @@ static void VbUserConfirmsTest(void) ResetMocks(); mock_keypress[0] = ' '; - shutdown_request_calls_left = 1; + MockGpioAfter(1, GPIO_SHUTDOWN); TEST_EQ(VbUserConfirms(&ctx, VB_CONFIRM_SPACE_MEANS_NO), 0, "Space means no"); ResetMocks(); mock_keypress[0] = ' '; - shutdown_request_calls_left = 1; + MockGpioAfter(1, GPIO_SHUTDOWN); TEST_EQ(VbUserConfirms(&ctx, 0), -1, "Space ignored"); ResetMocks(); @@ -305,24 +358,99 @@ static void VbUserConfirmsTest(void) 0, "Untrusted keyboard"); ResetMocks(); - mock_switches[0] = VB_SWITCH_FLAG_REC_BUTTON_PRESSED; + MockGpioAfter(0, GPIO_PRESENCE); TEST_EQ(VbUserConfirms(&ctx, VB_CONFIRM_SPACE_MEANS_NO | VB_CONFIRM_MUST_TRUST_KEYBOARD), - 1, "Recovery button"); + 1, "Presence button"); + + /* + * List of possiblities for shutdown and physical presence events that + * occur over time. Time advanced from left to right (where each + * represents the gpio[s] that are seen during a given iteration of + * the loop). The meaning of the characters: + * + * _ means no gpio + * s means shutdown gpio + * p means presence gpio + * B means both shutdown and presence gpio + * + * 1: ______ppp______ -> confirm + * 2: ______sss______ -> shutdown + * 3: ___pppsss______ -> confirm + * 4: ___sssppp______ -> shutdown + * 5: ___pppBBB______ -> confirm + * 6: ___pppBBBppp___ -> shutdown + * 7: ___pppBBBsss___ -> confirm + * 8: ___sssBBB______ -> confirm + * 9: ___sssBBBppp___ -> shutdown + * 10: ___sssBBBsss___ -> confirm + * 11: ______BBB______ -> confirm + * 12: ______BBBsss___ -> confirm + * 13: ______BBBppp___ -> shutdown + */ + + /* 1: presence means confirm */ + VbUserConfirmsTestGpio(GPIO_PRESENCE, 0, 0, 1, "presence"); + + /* 2: shutdown means shutdown */ + VbUserConfirmsTestGpio(GPIO_SHUTDOWN, 0, 0, 0, "shutdown"); + + /* 3: presence then shutdown means confirm */ + VbUserConfirmsTestGpio(GPIO_PRESENCE, GPIO_SHUTDOWN, 0, 1, + "presence then shutdown"); + + /* 4: shutdown then presence means shutdown */ + VbUserConfirmsTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE, 0, 0, + "shutdown then presence"); + + /* 5: presence then shutdown+presence then none mean confirm */ + VbUserConfirmsTestGpio(GPIO_PRESENCE, GPIO_PRESENCE | GPIO_SHUTDOWN, + 0, 1, "presence, both, none"); + + /* 6: presence then shutdown+presence then presence means shutdown */ + VbUserConfirmsTestGpio(GPIO_PRESENCE, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_PRESENCE, 0, "presence, both, presence"); + + /* 7: presence then shutdown+presence then shutdown means confirm */ + VbUserConfirmsTestGpio(GPIO_PRESENCE, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_SHUTDOWN, 1, "presence, both, shutdown"); + + /* 8: shutdown then shutdown+presence then none means confirm */ + VbUserConfirmsTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE | GPIO_SHUTDOWN, + 0, 1, "shutdown, both, none"); + + /* 9: shutdown then shutdown+presence then presence means shutdown */ + VbUserConfirmsTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_PRESENCE, 0, "shutdown, both, presence"); + + /* 10: shutdown then shutdown+presence then shutdown means confirm */ + VbUserConfirmsTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_SHUTDOWN, 1, "shutdown, both, shutdown"); + + /* 11: shutdown+presence then none means confirm */ + VbUserConfirmsTestGpio(GPIO_PRESENCE | GPIO_SHUTDOWN, 0, 0, 1, + "both"); + + /* 12: shutdown+presence then shutdown means confirm */ + VbUserConfirmsTestGpio(GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_SHUTDOWN, 0, 1, "both, shutdown"); + + /* 13: shutdown+presence then presence means shutdown */ + VbUserConfirmsTestGpio(GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_PRESENCE, 0, 0, "both, presence"); ResetMocks(); mock_keypress[0] = VB_KEY_ENTER; mock_keypress[1] = 'y'; mock_keypress[2] = 'z'; mock_keypress[3] = ' '; - mock_switches[0] = VB_SWITCH_FLAG_REC_BUTTON_PRESSED; - mock_switches_are_stuck = 1; + mock_gpio[0].gpio_flags = GPIO_PRESENCE; + mock_gpio[0].count = ~0; TEST_EQ(VbUserConfirms(&ctx, VB_CONFIRM_SPACE_MEANS_NO | VB_CONFIRM_MUST_TRUST_KEYBOARD), 0, "Recovery button stuck"); - printf("...done.\n"); } @@ -414,7 +542,9 @@ static void VbBootDevTest(void) /* Shutdown requested in loop */ ResetMocks(); - shutdown_request_calls_left = 2; + mock_gpio[0].gpio_flags = 0; + mock_gpio[0].count = 2; + mock_gpio[1].gpio_flags = GPIO_SHUTDOWN; TEST_EQ(VbBootDeveloper(&ctx), VBERROR_SHUTDOWN_REQUESTED, "Shutdown requested"); @@ -495,7 +625,7 @@ static void VbBootDevTest(void) ResetMocks(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; mock_keypress[0] = ' '; - shutdown_request_calls_left = 2; + MockGpioAfter(3, GPIO_SHUTDOWN); TEST_EQ(VbBootDeveloper(&ctx), VBERROR_SHUTDOWN_REQUESTED, "Shutdown requested at tonorm"); @@ -536,7 +666,7 @@ static void VbBootDevTest(void) /* Enter altfw menu and time out */ ResetMocks(); - shutdown_request_calls_left = 1000; + MockGpioAfter(1000, GPIO_SHUTDOWN); sd->gbb_flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY; mock_keypress[0] = VB_KEY_CTRL('L'); TEST_EQ(VbBootDeveloper(&ctx), VBERROR_SHUTDOWN_REQUESTED, @@ -858,7 +988,7 @@ static void VbBootDevTest(void) ResetMocks(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; VbApiKernelGetFwmp()->flags |= FWMP_DEV_DISABLE_BOOT; - shutdown_request_calls_left = 1; + MockGpioAfter(1, GPIO_SHUTDOWN); TEST_EQ(VbBootDeveloper(&ctx), VBERROR_SHUTDOWN_REQUESTED, "Shutdown requested when dev disabled"); @@ -877,13 +1007,48 @@ static void VbBootDevTest(void) printf("...done.\n"); } +/* + * Helper function to test VbBootRecovery against a sequence of gpio events. + * caller specifies a sequence of gpio events and the expected confirm vs. + * reboot result. + * + * Non-asserted gpios are used for 5 events, then 'first' for 5 events, + * 'second' for 5 events, and 'third' for 5 events. + */ +static void VbBootRecTestGpio(uint32_t first, uint32_t second, uint32_t third, + uint32_t confirm, const char *msg) +{ + ResetMocks(); + shared->flags = VBSD_BOOT_REC_SWITCH_ON; + vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; + trust_ec = 1; + mock_keypress[0] = VB_KEY_CTRL('D'); + mock_gpio[0].gpio_flags = 0; + mock_gpio[0].count = 4; + mock_gpio[1].gpio_flags = first; + mock_gpio[1].count = 4; + mock_gpio[2].gpio_flags = second; + mock_gpio[2].count = 4; + mock_gpio[3].gpio_flags = third; + mock_gpio[3].count = 4; + + if (confirm) { + TEST_EQ(VbBootRecovery(&ctx), VBERROR_EC_REBOOT_TO_RO_REQUIRED, + msg); + TEST_EQ(virtdev_set, 1, " virtual dev mode on"); + } else { + TEST_EQ(VbBootRecovery(&ctx), VBERROR_SHUTDOWN_REQUESTED, msg); + TEST_EQ(virtdev_set, 0, " virtual dev mode off"); + } +} + static void VbBootRecTest(void) { printf("Testing VbBootRecovery()...\n"); /* Shutdown requested in loop */ ResetMocks(); - shutdown_request_calls_left = 10; + MockGpioAfter(10, GPIO_SHUTDOWN); VbExEcEnteringMode(0, VB_EC_RECOVERY); TEST_EQ(VbBootRecovery(&ctx), VBERROR_SHUTDOWN_REQUESTED, @@ -905,8 +1070,14 @@ static void VbBootRecTest(void) /* Ignore power button held on boot */ ResetMocks(); - shutdown_request_calls_left = 100; - shutdown_request_power_held = 1; + mock_gpio[0].gpio_flags = GPIO_SHUTDOWN; + mock_gpio[0].count = 10; + mock_gpio[1].gpio_flags = 0; + mock_gpio[1].count = 10; + mock_gpio[2].gpio_flags = GPIO_SHUTDOWN; + mock_gpio[2].count = 10; + mock_gpio[3].gpio_flags = 0; + mock_gpio[3].count = 100; shared->flags = VBSD_BOOT_REC_SWITCH_ON; trust_ec = 1; vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; @@ -915,17 +1086,12 @@ static void VbBootRecTest(void) "Ignore power button held on boot"); TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT, " insert screen"); - /* - * shutdown_request_power_held holds power button for 10 calls, then - * releases for 10, then holds again, so expect shutdown after 20: - * 100 - 20 = 80. - */ - TEST_EQ(shutdown_request_calls_left, 80, - " ignore held button"); + /* Shutdown should happen while we're sending the 2nd block of events */ + TEST_EQ(mock_gpio_count, 3, " ignore held button"); /* Broken screen */ ResetMocks(); - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_num_disks[0] = 1; mock_num_disks[1] = 1; mock_num_disks[2] = 1; @@ -938,7 +1104,7 @@ static void VbBootRecTest(void) /* Broken screen even if dev switch is on */ ResetMocks(); - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_num_disks[0] = 1; mock_num_disks[1] = 1; shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; @@ -951,7 +1117,7 @@ static void VbBootRecTest(void) /* Force insert screen with GBB flag */ ResetMocks(); - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); sd->gbb_flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY; vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; TEST_EQ(VbBootRecovery(&ctx), @@ -962,7 +1128,7 @@ static void VbBootRecTest(void) /* No removal if recovery button physically pressed */ ResetMocks(); - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_num_disks[0] = 1; mock_num_disks[1] = 1; shared->flags |= VBSD_BOOT_REC_SWITCH_ON; @@ -975,7 +1141,7 @@ static void VbBootRecTest(void) /* Removal if no disk initially found, but found on second attempt */ ResetMocks(); - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_num_disks[0] = 0; mock_num_disks[1] = 1; vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; @@ -987,10 +1153,9 @@ static void VbBootRecTest(void) /* Bad disk count doesn't require removal */ ResetMocks(); - shutdown_request_calls_left = 100; + MockGpioAfter(10, GPIO_SHUTDOWN); mock_num_disks[0] = -1; vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; - shutdown_request_calls_left = 10; TEST_EQ(VbBootRecovery(&ctx), VBERROR_SHUTDOWN_REQUESTED, "Bad disk count"); @@ -1000,7 +1165,7 @@ static void VbBootRecTest(void) /* Ctrl+D ignored for many reasons... */ ResetMocks(); shared->flags = VBSD_BOOT_REC_SWITCH_ON; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_keypress[0] = VB_KEY_CTRL('D'); trust_ec = 0; TEST_EQ(VbBootRecovery(&ctx), @@ -1013,7 +1178,7 @@ static void VbBootRecTest(void) ResetMocks(); shared->flags = VBSD_BOOT_REC_SWITCH_ON | VBSD_BOOT_DEV_SWITCH_ON; trust_ec = 1; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_keypress[0] = VB_KEY_CTRL('D'); TEST_EQ(VbBootRecovery(&ctx), VBERROR_SHUTDOWN_REQUESTED, @@ -1024,7 +1189,7 @@ static void VbBootRecTest(void) ResetMocks(); trust_ec = 1; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_keypress[0] = VB_KEY_CTRL('D'); TEST_EQ(VbBootRecovery(&ctx), VBERROR_SHUTDOWN_REQUESTED, @@ -1033,25 +1198,27 @@ static void VbBootRecTest(void) TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV, " todev screen"); - /* Ctrl+D ignored because the physical recovery switch is still pressed + /* Ctrl+D ignored because the physical presence switch is still pressed * and we don't like that. */ ResetMocks(); shared->flags = VBSD_BOOT_REC_SWITCH_ON; trust_ec = 1; - shutdown_request_calls_left = 100; mock_keypress[0] = VB_KEY_CTRL('D'); - mock_switches[0] = VB_SWITCH_FLAG_REC_BUTTON_PRESSED; + mock_gpio[0].gpio_flags = GPIO_PRESENCE; + mock_gpio[0].count = 100; + mock_gpio[1].gpio_flags = GPIO_PRESENCE | GPIO_SHUTDOWN; + mock_gpio[1].count = 100; TEST_EQ(VbBootRecovery(&ctx), VBERROR_SHUTDOWN_REQUESTED, - "Ctrl+D ignored if phys rec button is still pressed"); + "Ctrl+D ignored if phys pres button is still pressed"); TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV, " todev screen"); /* Ctrl+D then space means don't enable */ ResetMocks(); shared->flags = VBSD_BOOT_REC_SWITCH_ON; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; trust_ec = 1; mock_keypress[0] = VB_KEY_CTRL('D'); @@ -1070,20 +1237,102 @@ static void VbBootRecTest(void) /* Ctrl+D then enter means enable */ ResetMocks(); shared->flags = VBSD_BOOT_REC_SWITCH_ON; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; trust_ec = 1; mock_keypress[0] = VB_KEY_CTRL('D'); mock_keypress[1] = VB_KEY_ENTER; mock_keyflags[1] = VB_KEY_FLAG_TRUSTED_KEYBOARD; TEST_EQ(VbBootRecovery(&ctx), VBERROR_EC_REBOOT_TO_RO_REQUIRED, - "Ctrl+D todev confirm"); + "Ctrl+D todev confirm via enter"); TEST_EQ(virtdev_set, 1, " virtual dev mode on"); + /* + * List of possiblities for shutdown and physical presence events that + * occur over time. Time advanced from left to right (where each + * represents the gpio[s] that are seen during a given iteration of + * the loop). The meaning of the characters: + * + * _ means no gpio + * s means shutdown gpio + * p means presence gpio + * B means both shutdown and presence gpio + * + * 1: ______ppp______ -> confirm + * 2: ______sss______ -> shutdown + * 3: ___pppsss______ -> confirm + * 4: ___sssppp______ -> shutdown + * 5: ___pppBBB______ -> confirm + * 6: ___pppBBBppp___ -> shutdown + * 7: ___pppBBBsss___ -> confirm + * 8: ___sssBBB______ -> confirm + * 9: ___sssBBBppp___ -> shutdown + * 10: ___sssBBBsss___ -> confirm + * 11: ______BBB______ -> confirm + * 12: ______BBBsss___ -> confirm + * 13: ______BBBppp___ -> shutdown + */ + + /* 1: Ctrl+D then presence means enable */ + VbBootRecTestGpio(GPIO_PRESENCE, 0, 0, 1, + "Ctrl+D todev confirm via presence"); + + /* 2: Ctrl+D then shutdown means shutdown */ + VbBootRecTestGpio(GPIO_SHUTDOWN, 0, 0, 0, + "Ctrl+D todev then shutdown"); + + /* 3: Ctrl+D then presence then shutdown means confirm */ + VbBootRecTestGpio(GPIO_PRESENCE, GPIO_SHUTDOWN, 0, 1, + "Ctrl+D todev confirm via presence then shutdown"); + + /* 4: Ctrl+D then 2+ instance shutdown then presence means shutdown */ + VbBootRecTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE, 0, 0, + "Ctrl+D todev then 2+ shutdown then presence"); + + /* 5: Ctrl+D then presence then shutdown+presence then none */ + VbBootRecTestGpio(GPIO_PRESENCE, GPIO_PRESENCE | GPIO_SHUTDOWN, 0, 1, + "Ctrl+D todev confirm via presence, both, none"); + + /* 6: Ctrl+D then presence then shutdown+presence then presence */ + VbBootRecTestGpio(GPIO_PRESENCE, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_PRESENCE, 0, + "Ctrl+D todev confirm via presence, both, presence"); + + /* 7: Ctrl+D then presence then shutdown+presence then shutdown */ + VbBootRecTestGpio(GPIO_PRESENCE, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_SHUTDOWN, 1, + "Ctrl+D todev confirm via presence, both, shutdown"); + + /* 8: Ctrl+D then shutdown then shutdown+presence then none */ + VbBootRecTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE | GPIO_SHUTDOWN, 0, 1, + "Ctrl+D todev then 2+ shutdown, both, none"); + + /* 9: Ctrl+D then shutdown then shutdown+presence then presence */ + VbBootRecTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_PRESENCE, 0, + "Ctrl+D todev then 2+ shutdown, both, presence"); + + /* 10: Ctrl+D then shutdown then shutdown+presence then shutdown */ + VbBootRecTestGpio(GPIO_SHUTDOWN, GPIO_PRESENCE | GPIO_SHUTDOWN, + GPIO_SHUTDOWN, 1, + "Ctrl+D todev then 2+ shutdown, both, shutdown"); + + /* 11: Ctrl+D then shutdown+presence then none */ + VbBootRecTestGpio(GPIO_PRESENCE | GPIO_SHUTDOWN, 0, 0, 1, + "Ctrl+D todev confirm via both then none"); + + /* 12: Ctrl+D then shutdown+presence then shutdown */ + VbBootRecTestGpio(GPIO_PRESENCE | GPIO_SHUTDOWN, GPIO_SHUTDOWN, 0, 1, + "Ctrl+D todev confirm via both then shutdown"); + + /* 13: Ctrl+D then shutdown+presence then presence */ + VbBootRecTestGpio(GPIO_PRESENCE | GPIO_SHUTDOWN, GPIO_PRESENCE, 0, 0, + "Ctrl+D todev confirm via both then presence"); + /* Handle TPM error in enabling dev mode */ ResetMocks(); shared->flags = VBSD_BOOT_REC_SWITCH_ON; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; trust_ec = 1; mock_keypress[0] = VB_KEY_CTRL('D'); @@ -1099,7 +1348,7 @@ static void VbBootRecTest(void) shared->flags = VBSD_BOOT_REC_SWITCH_ON; trust_ec = 1; vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_keypress[0] = VB_KEY_CTRL('C'); TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DIAG_REQUEST), 0, "todiag is zero"); @@ -1124,7 +1373,7 @@ static void VbBootRecTest(void) shared->flags = VBSD_BOOT_REC_SWITCH_ON | VBSD_OPROM_MATTERS; trust_ec = 1; vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_keypress[0] = VB_KEY_F(12); TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DIAG_REQUEST), 0, "todiag is zero"); @@ -1146,7 +1395,7 @@ static void VbBootRecTest(void) /* Test Diagnostic Mode via Ctrl-C OS broken */ ResetMocks(); shared->flags = 0; - shutdown_request_calls_left = 100; + MockGpioAfter(100, GPIO_SHUTDOWN); mock_keypress[0] = VB_KEY_CTRL('C'); TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DIAG_REQUEST), 0, "todiag is zero"); @@ -1198,8 +1447,7 @@ static void VbBootDiagTest(void) /* Shutdown requested via lid close */ ResetMocks(); - shutdown_via_lid_close = 1; - shutdown_request_calls_left = 10; + MockGpioAfter(10, GPIO_LID_CLOSED); TEST_EQ(VbBootDiagnostic(&ctx), VBERROR_SHUTDOWN_REQUESTED, "Shutdown"); TEST_EQ(screens_displayed[0], VB_SCREEN_CONFIRM_DIAG, " confirm screen"); @@ -1211,8 +1459,8 @@ static void VbBootDiagTest(void) /* Power button pressed but not released. */ ResetMocks(); - mock_switches_are_stuck = 1; - mock_switches[0] = VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED; + mock_gpio[0].gpio_flags = GPIO_PRESENCE; + mock_gpio[0].count = ~0; TEST_EQ(VbBootDiagnostic(&ctx), VBERROR_REBOOT_REQUIRED, "Power held"); TEST_EQ(screens_displayed[0], VB_SCREEN_CONFIRM_DIAG, " confirm screen"); @@ -1223,9 +1471,7 @@ static void VbBootDiagTest(void) /* Power button is pressed and released. */ ResetMocks(); - mock_switches[0] = 0; - mock_switches[1] = VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED; - mock_switches[2] = 0; + MockGpioAfter(3, GPIO_PRESENCE); TEST_EQ(VbBootDiagnostic(&ctx), VBERROR_REBOOT_REQUIRED, "Confirm"); TEST_EQ(screens_displayed[0], VB_SCREEN_CONFIRM_DIAG, " confirm screen"); @@ -1246,9 +1492,10 @@ static void VbBootDiagTest(void) /* Power button confirm, but now with a tpm failure. */ ResetMocks(); tpm_mode = VB2_TPM_MODE_DISABLED; - mock_switches[0] = 0; - mock_switches[1] = VB_SWITCH_FLAG_PHYS_PRESENCE_PRESSED; - mock_switches[2] = 0; + mock_gpio[0].gpio_flags = 0; + mock_gpio[0].count = 2; + mock_gpio[1].gpio_flags = GPIO_PRESENCE; + mock_gpio[1].count = 2; TEST_EQ(VbBootDiagnostic(&ctx), VBERROR_REBOOT_REQUIRED, "Confirm but tpm fail"); TEST_EQ(screens_displayed[0], VB_SCREEN_CONFIRM_DIAG, |