diff options
-rw-r--r-- | firmware/2lib/2stub.c | 13 | ||||
-rw-r--r-- | firmware/2lib/2ui_screens.c | 154 | ||||
-rw-r--r-- | firmware/2lib/include/2api.h | 28 | ||||
-rw-r--r-- | firmware/2lib/include/2ui.h | 2 | ||||
-rw-r--r-- | tests/vb2_ui_tests.c | 94 |
5 files changed, 260 insertions, 31 deletions
diff --git a/firmware/2lib/2stub.c b/firmware/2lib/2stub.c index f7b15ce5..7cec2e5d 100644 --- a/firmware/2lib/2stub.c +++ b/firmware/2lib/2stub.c @@ -194,6 +194,19 @@ vb2_error_t vb2ex_diag_get_storage_health(const char **out) } __attribute__((weak)) +vb2_error_t vb2ex_diag_get_storage_test_log(const char **out) +{ + *out = "mock"; + return VB2_SUCCESS; +} + +__attribute__((weak)) +vb2_error_t vb2ex_diag_storage_test_control(enum vb2_diag_storage_test ops) +{ + return VB2_SUCCESS; +} + +__attribute__((weak)) vb2_error_t vb2ex_diag_memory_quick_test(int reset, const char **out) { *out = "mock"; diff --git a/firmware/2lib/2ui_screens.c b/firmware/2lib/2ui_screens.c index ed13b9cb..1ac50edc 100644 --- a/firmware/2lib/2ui_screens.c +++ b/firmware/2lib/2ui_screens.c @@ -1026,12 +1026,38 @@ static const struct vb2_screen_info developer_select_bootloader_screen = { /******************************************************************************/ /* VB2_SCREEN_DIAGNOSTICS */ +#define DIAGNOSTICS_ITEM_STORAGE_HEALTH 1 +#define DIAGNOSTICS_ITEM_STORAGE_TEST_SHORT 2 +#define DIAGNOSTICS_ITEM_STORAGE_TEST_EXTENDED 3 + +static vb2_error_t diagnostics_init(struct vb2_ui_context *ui) +{ + const char *unused_log_string; + vb2_error_t rv = vb2ex_diag_get_storage_test_log(&unused_log_string); + if (rv == VB2_ERROR_EX_UNIMPLEMENTED) { + VB2_SET_BIT(ui->state->disabled_item_mask, + DIAGNOSTICS_ITEM_STORAGE_TEST_SHORT); + VB2_SET_BIT(ui->state->disabled_item_mask, + DIAGNOSTICS_ITEM_STORAGE_TEST_EXTENDED); + } + ui->state->selected_item = DIAGNOSTICS_ITEM_STORAGE_HEALTH; + return VB2_SUCCESS; +} + static const struct vb2_menu_item diagnostics_items[] = { LANGUAGE_SELECT_ITEM, - { + [DIAGNOSTICS_ITEM_STORAGE_HEALTH] = { .text = "Storage health info", .target = VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH, }, + [DIAGNOSTICS_ITEM_STORAGE_TEST_SHORT] = { + .text = "Storage self-test (short)", + .target = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT, + }, + [DIAGNOSTICS_ITEM_STORAGE_TEST_EXTENDED] = { + .text = "Storage self-test (Extended)", + .target = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED, + }, { .text = "Memory check (quick)", .target = VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK, @@ -1046,6 +1072,7 @@ static const struct vb2_menu_item diagnostics_items[] = { static const struct vb2_screen_info diagnostics_screen = { .id = VB2_SCREEN_DIAGNOSTICS, .name = "Diagnostic tools", + .init = diagnostics_init, .menu = MENU_ITEMS(diagnostics_items), }; @@ -1090,6 +1117,129 @@ static const struct vb2_screen_info diagnostics_storage_health_screen = { }; /******************************************************************************/ +/* VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST */ + +#define DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP 0 +#define DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN 1 +#define DIAGNOSTICS_STORAGE_TEST_ITEM_BACK 2 +#define DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL 3 + +static vb2_error_t diagnostics_storage_test_update_impl( + struct vb2_ui_context *ui) +{ + const char *log_string; + int is_test_running = 0; + + /* Early return if the test is done. */ + if (ui->state->test_finished) + return VB2_SUCCESS; + + vb2_error_t rv = vb2ex_diag_get_storage_test_log(&log_string); + switch (rv) { + case VB2_ERROR_EX_DIAG_TEST_RUNNING: + is_test_running = 1; + break; + case VB2_SUCCESS: + ui->state->test_finished = 1; + break; + default: + VB2_DEBUG("vb2ex_diag_get_storage_test_log returned %#x\n", rv); + return rv; + } + VB2_TRY(log_page_show_back_or_cancel(ui, is_test_running)); + return log_page_update(ui, log_string); +} + +static vb2_error_t diagnostics_storage_test_update(struct vb2_ui_context *ui) +{ + vb2_error_t rv = diagnostics_storage_test_update_impl(ui); + if (rv) { + ui->error_code = VB2_UI_ERROR_DIAGNOSTICS; + return vb2_ui_screen_back(ui); + } + return VB2_SUCCESS; +} + +static vb2_error_t diagnostics_storage_test_control( + struct vb2_ui_context *ui, enum vb2_diag_storage_test op) +{ + vb2_error_t rv = vb2ex_diag_storage_test_control(op); + if (rv) { + ui->error_code = VB2_UI_ERROR_DIAGNOSTICS; + return vb2_ui_screen_back(ui); + } + return VB2_SUCCESS; +} + +static vb2_error_t diagnostics_storage_test_init(struct vb2_ui_context *ui) +{ + VB2_TRY(diagnostics_storage_test_update(ui)); + return log_page_reset_to_top(ui); +} + +static vb2_error_t diagnostics_storage_test_short_init( + struct vb2_ui_context *ui) +{ + VB2_TRY(diagnostics_storage_test_control(ui, + VB2_DIAG_STORAGE_TEST_STOP)); + VB2_TRY(diagnostics_storage_test_control(ui, + VB2_DIAG_STORAGE_TEST_SHORT)); + return diagnostics_storage_test_init(ui); +} + +static vb2_error_t diagnostics_storage_test_extended_init( + struct vb2_ui_context *ui) +{ + VB2_TRY(diagnostics_storage_test_control(ui, + VB2_DIAG_STORAGE_TEST_STOP)); + VB2_TRY(diagnostics_storage_test_control( + ui, VB2_DIAG_STORAGE_TEST_EXTENDED)); + return diagnostics_storage_test_init(ui); +} + +static vb2_error_t diagnostics_storage_test_cancel(struct vb2_ui_context *ui) +{ + VB2_TRY(diagnostics_storage_test_control(ui, + VB2_DIAG_STORAGE_TEST_STOP)); + return vb2_ui_screen_back(ui); +} + +static const struct vb2_menu_item diagnostics_storage_test_items[] = { + [DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP] = PAGE_UP_ITEM, + [DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM, + [DIAGNOSTICS_STORAGE_TEST_ITEM_BACK] = BACK_ITEM, + [DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL] = { + .text = "Cancel", + .action = diagnostics_storage_test_cancel, + }, + POWER_OFF_ITEM, +}; + +static const struct vb2_screen_info diagnostics_storage_test_short_screen = { + .id = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT, + .name = "Storage self-test (short)", + .init = diagnostics_storage_test_short_init, + .action = diagnostics_storage_test_update, + .menu = MENU_ITEMS(diagnostics_storage_test_items), + .page_up_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP, + .page_down_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN, + .back_item = DIAGNOSTICS_STORAGE_TEST_ITEM_BACK, + .cancel_item = DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL, +}; + +static const struct vb2_screen_info diagnostics_storage_test_extended_screen = { + .id = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED, + .name = "Storage self-test (extended)", + .init = diagnostics_storage_test_extended_init, + .action = diagnostics_storage_test_update, + .menu = MENU_ITEMS(diagnostics_storage_test_items), + .page_up_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP, + .page_down_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN, + .back_item = DIAGNOSTICS_STORAGE_TEST_ITEM_BACK, + .cancel_item = DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL, +}; + +/******************************************************************************/ /* VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL */ @@ -1231,6 +1381,8 @@ static const struct vb2_screen_info *screens[] = { &developer_select_bootloader_screen, &diagnostics_screen, &diagnostics_storage_health_screen, + &diagnostics_storage_test_short_screen, + &diagnostics_storage_test_extended_screen, &diagnostics_memory_quick_screen, &diagnostics_memory_full_screen, }; diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 218a416c..f7acdc60 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -1343,6 +1343,8 @@ enum vb2_screen { VB2_SCREEN_DIAGNOSTICS = 0x400, /* Storage diagnostic screen */ VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH = 0x410, + VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT = 0x411, + VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED = 0x412, /* Memory diagnostic screens */ VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK = 0x420, VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL = 0x421, @@ -1524,6 +1526,21 @@ uint32_t vb2ex_prepare_log_screen(enum vb2_screen screen, uint32_t locale_id, vb2_error_t vb2ex_diag_get_storage_health(const char **out); /** + * Get the storage self-test log. + * + * @param out For returning a read-only pointer of full log string which is + * guaranteed to be null-terminated. The function will manage + * memory internally, so the returned pointer will only be valid + * until next call. + * @return The status of storage test. VB2_SUCCESS means the test is finished, + * regardless of passing or failing. VB2_ERROR_EX_DIAG_TEST_RUNNING means + * the test is still running. VB2_ERROR_EX_UNIMPLEMENTED means the storage + * self-test is not supported on this device. Other non-zero codes for internal + * errors. + */ +vb2_error_t vb2ex_diag_get_storage_test_log(const char **out); + +/** * Get the memory diagnostic status. When it is called, it will take over the * control for a short period of time running memory test, and then return the * result of current status. If `reset` is not zero, it will reset the memory @@ -1545,6 +1562,17 @@ vb2_error_t vb2ex_diag_memory_quick_test(int reset, const char **out); vb2_error_t vb2ex_diag_memory_full_test(int reset, const char **out); /*****************************************************************************/ +/* Functions for diagnostics control. */ + +enum vb2_diag_storage_test { + VB2_DIAG_STORAGE_TEST_STOP = 0, + VB2_DIAG_STORAGE_TEST_SHORT, + VB2_DIAG_STORAGE_TEST_EXTENDED, +}; + +vb2_error_t vb2ex_diag_storage_test_control(enum vb2_diag_storage_test ops); + +/*****************************************************************************/ /* Timer. */ /** diff --git a/firmware/2lib/include/2ui.h b/firmware/2lib/include/2ui.h index 017bd442..bfb2b8b7 100644 --- a/firmware/2lib/include/2ui.h +++ b/firmware/2lib/include/2ui.h @@ -79,7 +79,7 @@ struct vb2_screen_state { uint32_t page_count; uint32_t current_page; - /* For memory check screen. */ + /* For minidiag test screens. */ int test_finished; /* Do not update screen if the content is done */ struct vb2_screen_state *prev; diff --git a/tests/vb2_ui_tests.c b/tests/vb2_ui_tests.c index 607087e7..3eb0c9f9 100644 --- a/tests/vb2_ui_tests.c +++ b/tests/vb2_ui_tests.c @@ -100,6 +100,8 @@ static char mock_prepare_log[64][MOCK_PREPARE_LOG_SIZE]; static int mock_prepare_log_count; static uint32_t mock_log_page_count; +static vb2_error_t mock_diag_storage_test_rv; + static void add_mock_key(uint32_t press, int trusted) { if (mock_key_total >= ARRAY_SIZE(mock_key) || @@ -353,6 +355,8 @@ static void reset_common_data(enum reset_type t) else add_mock_vbtlk(VB2_ERROR_MOCK, 0); add_mock_pp_pressed(0); + + mock_diag_storage_test_rv = VB2_SUCCESS; } /* Mock functions */ @@ -571,6 +575,11 @@ uint32_t vb2ex_prepare_log_screen(enum vb2_screen screen, uint32_t locale_id, return mock_log_page_count; } +vb2_error_t vb2ex_diag_get_storage_test_log(const char **log) +{ + return mock_diag_storage_test_rv; +} + /* Tests */ static void developer_tests(void) { @@ -1794,8 +1803,8 @@ static void diagnostics_screen_tests(void) reset_common_data(FOR_DIAGNOSTICS); TEST_EQ(vb2_diagnostic_menu(ctx), VB2_REQUEST_SHUTDOWN, "diagnostic screen: no disabled or hidden item"); - DISPLAYED_EQ("diagnostic menu", VB2_SCREEN_DIAGNOSTICS, - MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE); + DISPLAYED_EQ("diagnostic menu", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, + MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE); /* Diagnostics screen */ reset_common_data(FOR_DIAGNOSTICS); @@ -1803,67 +1812,94 @@ static void diagnostics_screen_tests(void) /* #0: Language menu */ add_mock_keypress(VB_KEY_UP); add_mock_keypress(VB_KEY_ENTER); - /* #1: Storage screen */ add_mock_keypress(VB_KEY_ESC); + /* #1: Storage health screen */ + add_mock_keypress(VB_KEY_DOWN); + add_mock_keypress(VB_KEY_ENTER); + add_mock_keypress(VB_KEY_ESC); + /* #2: Short storage self-test screen */ + add_mock_keypress(VB_KEY_DOWN); + add_mock_keypress(VB_KEY_ENTER); + add_mock_keypress(VB_KEY_ESC); + /* #3: Extended storage self-test screen */ add_mock_keypress(VB_KEY_DOWN); add_mock_keypress(VB_KEY_ENTER); - /* #2: Quick memory test screen */ add_mock_keypress(VB_KEY_ESC); + /* #4: Quick memory test screen */ add_mock_keypress(VB_KEY_DOWN); add_mock_keypress(VB_KEY_ENTER); - /* #3: Full memory test screen */ add_mock_keypress(VB_KEY_ESC); + /* #5: Full memory test screen */ add_mock_keypress(VB_KEY_DOWN); add_mock_keypress(VB_KEY_ENTER); - /* #4: Power off (End of menu) */ add_mock_keypress(VB_KEY_ESC); + /* #6: Power off (End of menu) */ add_mock_keypress(VB_KEY_DOWN); add_mock_keypress(VB_KEY_ENTER); mock_calls_until_shutdown = -1; TEST_EQ(vb2_diagnostic_menu(ctx), VB2_REQUEST_SHUTDOWN, "diagnostic screen"); - DISPLAYED_EQ("default on first button of menu", - VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 1, MOCK_IGNORE, - MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_EQ("default on first button of menu", VB2_SCREEN_DIAGNOSTICS, + MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); /* #0: Language menu */ - DISPLAYED_EQ("language selection", - VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 0, MOCK_IGNORE, - MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_EQ("language selection", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, + 0, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); DISPLAYED_EQ("#0: language menu", VB2_SCREEN_LANGUAGE_SELECT, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); - /* #1: Storage screen */ DISPLAYED_PASS(); - DISPLAYED_EQ("storage button", - VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 1, MOCK_IGNORE, - MOCK_IGNORE, MOCK_IGNORE); + /* #1: Storage health screen */ + DISPLAYED_EQ("storage health button", VB2_SCREEN_DIAGNOSTICS, + MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); DISPLAYED_EQ("#1: storage screen", VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); - /* #2: Quick memory test screen */ DISPLAYED_PASS(); - DISPLAYED_EQ("quick memory test button", - VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 2, MOCK_IGNORE, - MOCK_IGNORE, MOCK_IGNORE); - DISPLAYED_EQ("#1: quick memory test screen", - VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK, MOCK_IGNORE, + /* #2: Short storage self-test screen */ + DISPLAYED_EQ("short storage self-test button", VB2_SCREEN_DIAGNOSTICS, + MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_EQ("#2: short storage self-test screen", + VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); - /* #3: Full memory test screen */ DISPLAYED_PASS(); - DISPLAYED_EQ("full memory test button", + /* #3: Extended storage self-test screen */ + DISPLAYED_EQ("extended storage self-test button", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); - DISPLAYED_EQ("#3: full memory test screen", + DISPLAYED_EQ("#3: extended storage self-test screen", + VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED, MOCK_IGNORE, + MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_PASS(); + /* #4: Quick memory test screen */ + DISPLAYED_EQ("quick memory test button", VB2_SCREEN_DIAGNOSTICS, + MOCK_IGNORE, 4, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_EQ("#4: quick memory test screen", + VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK, MOCK_IGNORE, + MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_PASS(); + /* #5: Full memory test screen */ + DISPLAYED_EQ("full memory test button", VB2_SCREEN_DIAGNOSTICS, + MOCK_IGNORE, 5, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); + DISPLAYED_EQ("#5: full memory test screen", VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); - /* #4: Power of (End of menu) */ DISPLAYED_PASS(); - DISPLAYED_EQ("power off", - VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 4, MOCK_IGNORE, - MOCK_IGNORE, MOCK_IGNORE); + /* #6: Power of (End of menu) */ + DISPLAYED_EQ("power off", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 6, + MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE); DISPLAYED_NO_EXTRA(); + /* Diagnostics screen: no nvme */ + reset_common_data(FOR_DIAGNOSTICS); + /* Non-nvme storage returns UNIMPLEMENTED. */ + mock_diag_storage_test_rv = VB2_ERROR_EX_UNIMPLEMENTED; + TEST_EQ(vb2_diagnostic_menu(ctx), VB2_REQUEST_SHUTDOWN, + "diagnostic screen: check disabled item"); + DISPLAYED_EQ("diagnostic menu: self-test disabled", + VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, MOCK_IGNORE, 0xc, 0x0, + MOCK_IGNORE); + VB2_DEBUG("...done.\n"); } |