| /* Copyright 2020 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * Code used by vboot_ui_legacy_clamshell for Wilco-specific features. |
| */ |
| |
| #include "2common.h" |
| #include "2nvstorage.h" |
| #include "2sysincludes.h" |
| #include "vboot_api.h" |
| #include "vboot_ui_legacy.h" |
| #include "vboot_ui_legacy_wilco.h" |
| |
| static inline int is_vowel(uint32_t key) |
| { |
| return key == 'A' || key == 'E' || key == 'I' || |
| key == 'O' || key == 'U'; |
| } |
| |
| static int vendor_data_length(char *data_value) |
| { |
| for (int len = 0; len <= VENDOR_DATA_LENGTH; len++) { |
| if (data_value[len] == '\0') |
| return len; |
| } |
| |
| return VENDOR_DATA_LENGTH; |
| } |
| |
| /* |
| * Prompt the user to enter the serial number |
| */ |
| static vb2_error_t vb2_enter_vendor_data_ui(struct vb2_context *ctx, |
| char *data_value) |
| { |
| int len = vendor_data_length(data_value); |
| int blinks = CURSOR_BLINK_MS / KEY_DELAY_MS; |
| int blink_count = 0; |
| VbScreenData data = { |
| .vendor_data = { |
| .input_text = data_value, |
| .flags = VB_VENDOR_DATA_SHOW_CURSOR, |
| .selected_index = 1, |
| } |
| }; |
| |
| VbDisplayScreen(ctx, VB_SCREEN_SET_VENDOR_DATA, 1, &data); |
| |
| /* We'll loop until the user decides what to do */ |
| do { |
| uint32_t key = VbExKeyboardRead(); |
| |
| if (vb2_want_shutdown(ctx, key)) { |
| VB2_DEBUG("Vendor Data UI - shutdown requested!\n"); |
| return VB2_REQUEST_SHUTDOWN; |
| } |
| switch (key) { |
| case 0: |
| /* Nothing pressed */ |
| break; |
| case VB_KEY_ESC: |
| /* Escape pressed - return to developer screen */ |
| VB2_DEBUG("Vendor Data UI - user pressed Esc: " |
| "exit to Developer screen\n"); |
| data_value[0] = '\0'; |
| return VB2_SUCCESS; |
| case 'a'...'z': |
| key = toupper(key); |
| VBOOT_FALLTHROUGH; |
| case '0'...'9': |
| case 'A'...'Z': |
| if ((len > 0 && is_vowel(key)) || |
| len >= VENDOR_DATA_LENGTH) { |
| vb2_error_beep(VB_BEEP_NOT_ALLOWED); |
| } else { |
| data_value[len++] = key; |
| data_value[len] = '\0'; |
| VbDisplayScreen(ctx, VB_SCREEN_SET_VENDOR_DATA, |
| 1, &data); |
| } |
| |
| VB2_DEBUG("Vendor Data UI - vendor_data: %s\n", |
| data_value); |
| break; |
| case VB_KEY_BACKSPACE: |
| if (len > 0) { |
| data_value[--len] = '\0'; |
| VbDisplayScreen(ctx, VB_SCREEN_SET_VENDOR_DATA, |
| 1, &data); |
| } |
| |
| VB2_DEBUG("Vendor Data UI - vendor_data: %s\n", |
| data_value); |
| break; |
| case VB_KEY_ENTER: |
| if (len == VENDOR_DATA_LENGTH) { |
| /* Enter pressed - confirm input */ |
| VB2_DEBUG("Vendor Data UI - user pressed " |
| "Enter: confirm vendor data\n"); |
| return VB2_SUCCESS; |
| } else { |
| vb2_error_beep(VB_BEEP_NOT_ALLOWED); |
| } |
| break; |
| default: |
| VB2_DEBUG("Vendor Data UI - pressed key %#x\n", key); |
| VbCheckDisplayKey(ctx, key, VB_SCREEN_SET_VENDOR_DATA, |
| &data); |
| break; |
| } |
| vb2ex_msleep(KEY_DELAY_MS); |
| |
| if (++blink_count == blinks) { |
| blink_count = 0; |
| data.vendor_data.flags ^= VB_VENDOR_DATA_SHOW_CURSOR; |
| data.vendor_data.flags |= |
| VB_VENDOR_DATA_ONLY_DRAW_CURSOR; |
| |
| VbDisplayScreen(ctx, VB_SCREEN_SET_VENDOR_DATA, |
| 1, &data); |
| |
| data.vendor_data.flags &= |
| ~(VB_VENDOR_DATA_ONLY_DRAW_CURSOR); |
| } |
| } while (1); |
| |
| return VB2_SUCCESS; |
| } |
| |
| /* |
| * Prompt the user to confirm the serial number and write to memory |
| */ |
| static vb2_error_t vb2_confirm_vendor_data_ui(struct vb2_context *ctx, |
| char* data_value, VbScreenData *data) |
| { |
| VbDisplayScreen(ctx, VB_SCREEN_CONFIRM_VENDOR_DATA, 1, data); |
| /* We'll loop until the user decides what to do */ |
| do { |
| uint32_t key_confirm = VbExKeyboardRead(); |
| |
| if (vb2_want_shutdown(ctx, key_confirm)) { |
| VB2_DEBUG("Confirm Vendor Data UI " |
| "- shutdown requested!\n"); |
| return VB2_REQUEST_SHUTDOWN; |
| } |
| switch (key_confirm) { |
| case 0: |
| /* Nothing pressed */ |
| break; |
| case VB_KEY_ESC: |
| /* Escape pressed - return to developer screen */ |
| VB2_DEBUG("Confirm Vendor Data UI - user " |
| "pressed Esc: exit to Developer screen\n"); |
| return VB2_SUCCESS; |
| case VB_KEY_RIGHT: |
| case VB_KEY_LEFT: |
| data->vendor_data.selected_index = |
| data->vendor_data.selected_index ^ 1; |
| VbDisplayScreen(ctx, VB_SCREEN_CONFIRM_VENDOR_DATA, |
| 1, data); |
| VB2_DEBUG("selected_index:%d\n", |
| data->vendor_data.selected_index); |
| break; |
| case VB_KEY_ENTER: |
| /* Enter pressed - write vendor data */ |
| if (data->vendor_data.selected_index == 0) { |
| VB2_DEBUG("Confirm Vendor Data UI - user " |
| "selected YES: " |
| "write vendor data (%s) to VPD\n", |
| data_value); |
| vb2_error_t ret = VbExSetVendorData(data_value); |
| |
| if (ret == VB2_SUCCESS) { |
| vb2_nv_set(ctx, |
| VB2_NV_DISABLE_DEV_REQUEST, |
| 1); |
| return VB2_REQUEST_REBOOT; |
| } else { |
| vb2_error_notify( |
| "ERROR: Vendor data was not " |
| "set.\n" |
| "System will now shutdown\n", |
| NULL, VB_BEEP_FAILED); |
| vb2ex_msleep(5 * VB2_MSEC_PER_SEC); |
| return VB2_REQUEST_SHUTDOWN; |
| } |
| } else { |
| VB2_DEBUG("Confirm Vendor Data UI - user " |
| "selected NO: " |
| "Returning to set screen\n"); |
| return VB2_SUCCESS; |
| } |
| default: |
| VB2_DEBUG("Confirm Vendor Data UI - pressed " |
| "key %#x\n", key_confirm); |
| VbCheckDisplayKey(ctx, key_confirm, |
| VB_SCREEN_CONFIRM_VENDOR_DATA, data); |
| break; |
| } |
| vb2ex_msleep(KEY_DELAY_MS); |
| } while (1); |
| return VB2_SUCCESS; |
| } |
| |
| vb2_error_t vb2_vendor_data_ui(struct vb2_context *ctx) |
| { |
| char data_value[VENDOR_DATA_LENGTH + 1]; |
| |
| VbScreenData data = {.vendor_data = {data_value, 0, 0}}; |
| VbDisplayScreen(ctx, VB_COMPLETE_VENDOR_DATA, 0, NULL); |
| |
| do { |
| uint32_t key_set = VbExKeyboardRead(); |
| |
| if (vb2_want_shutdown(ctx, key_set)) { |
| VB2_DEBUG("Vendor Data UI - shutdown requested!\n"); |
| return VB2_REQUEST_SHUTDOWN; |
| } |
| |
| switch (key_set) { |
| case 0: |
| /* Nothing pressed - do nothing. */ |
| break; |
| case VB_KEY_ESC: |
| /* ESC pressed - boot normally */ |
| VB2_DEBUG("Vendor Data UI - boot normally\n"); |
| return VB2_SUCCESS; |
| break; |
| case VB_KEY_ENTER: |
| data_value[0] = '\0'; |
| do { |
| /* ENTER pressed - |
| enter vendor data set screen */ |
| VB2_DEBUG("Vendor Data UI - Enter VD set " |
| "screen\n"); |
| vb2_error_t ret = vb2_enter_vendor_data_ui( |
| ctx, data_value); |
| |
| if (ret) |
| return ret; |
| |
| /* Vendor data was not entered just return */ |
| if (vendor_data_length(data_value) == 0) { |
| return VB2_SUCCESS; |
| } |
| |
| /* Reset confirmation answer to YES */ |
| data.vendor_data.selected_index = 0; |
| |
| ret = vb2_confirm_vendor_data_ui( |
| ctx, data_value, &data); |
| |
| if (ret) |
| return ret; |
| |
| /* Break if vendor data confirmed */ |
| if (data.vendor_data.selected_index == 0) |
| return VB2_SUCCESS; |
| } while (1); |
| break; |
| default: |
| break; |
| } |
| } while (1); |
| return VB2_SUCCESS; |
| } |
| |
| vb2_error_t vb2_check_diagnostic_key(struct vb2_context *ctx, uint32_t key) |
| { |
| if (DIAGNOSTIC_UI && (key == VB_KEY_CTRL('C') || key == VB_KEY_F(12))) { |
| VB2_DEBUG("Diagnostic mode requested, rebooting\n"); |
| vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1); |
| |
| return VB2_REQUEST_REBOOT; |
| } |
| |
| return VB2_SUCCESS; |
| } |
| |
| vb2_error_t vb2_diagnostics_ui(struct vb2_context *ctx) |
| { |
| int active = 1; |
| int button_released = 0; |
| int button_pressed = 0; |
| vb2_error_t result = VB2_REQUEST_REBOOT; |
| int action_confirmed = 0; |
| uint32_t start_time_ms; |
| |
| VbDisplayScreen(ctx, VB_SCREEN_CONFIRM_DIAG, 0, NULL); |
| |
| start_time_ms = vb2ex_mtime(); |
| |
| /* We'll loop until the user decides what to do */ |
| do { |
| uint32_t key = VbExKeyboardRead(); |
| /* Note that we need to check that the physical presence button |
| was pressed *and then* released. */ |
| if (vb2ex_physical_presence_pressed()) { |
| /* Wait for a release before registering a press. */ |
| if (button_released) |
| button_pressed = 1; |
| } else { |
| button_released = 1; |
| if (button_pressed) { |
| VB2_DEBUG("vb2_diagnostics_ui() - power released\n"); |
| action_confirmed = 1; |
| active = 0; |
| break; |
| } |
| } |
| |
| /* Check the lid and ignore the power button. */ |
| if (vb2_want_shutdown(ctx, 0) & ~VB_SHUTDOWN_REQUEST_POWER_BUTTON) { |
| VB2_DEBUG("vb2_diagnostics_ui() - shutdown request\n"); |
| result = VB2_REQUEST_SHUTDOWN; |
| active = 0; |
| break; |
| } |
| |
| switch (key) { |
| case 0: |
| /* Nothing pressed */ |
| break; |
| case VB_KEY_ESC: |
| /* Escape pressed - reboot */ |
| VB2_DEBUG("vb2_diagnostics_ui() - user pressed Esc\n"); |
| active = 0; |
| break; |
| default: |
| VB2_DEBUG("vb2_diagnostics_ui() - pressed key %#x\n", |
| key); |
| VbCheckDisplayKey(ctx, key, VB_SCREEN_CONFIRM_DIAG, |
| NULL); |
| break; |
| } |
| if (vb2ex_mtime() - start_time_ms >= 30 * VB2_MSEC_PER_SEC) { |
| VB2_DEBUG("vb2_diagnostics_ui() - timeout\n"); |
| break; |
| } |
| if (active) { |
| vb2ex_msleep(KEY_DELAY_MS); |
| } |
| } while (active); |
| |
| VbDisplayScreen(ctx, VB_SCREEN_BLANK, 0, NULL); |
| |
| if (action_confirmed) { |
| VB2_DEBUG("Diagnostic requested, running\n"); |
| |
| if (vb2ex_tpm_set_mode(VB2_TPM_MODE_DISABLED) != |
| VB2_SUCCESS) { |
| VB2_DEBUG("Failed to disable TPM\n"); |
| vb2api_fail(ctx, VB2_RECOVERY_TPM_DISABLE_FAILED, 0); |
| } else { |
| vb2_try_altfw(ctx, 1, VB_ALTFW_DIAGNOSTIC); |
| VB2_DEBUG("Diagnostic failed to run\n"); |
| /* |
| * Assuming failure was due to bad hash, though |
| * the rom could just be missing or invalid. |
| */ |
| vb2api_fail(ctx, VB2_RECOVERY_ALTFW_HASH_FAILED, 0); |
| } |
| } |
| |
| return result; |
| } |