blob: 2903b9eb269fefe5203f24487b5e97a20afdbc4c [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Implementation of vboot display callbacks
*
* Copyright 2018 Google LLC
*/
#include <common.h>
#include <cros_ec.h>
#include <dm.h>
#include <log.h>
#include <tpm_api.h>
#include <cros/memory.h>
#include <cros/health_info.h>
#include <cros/storage_test.h>
#include <cros/ui.h>
#include <cros/vboot.h>
static struct ui_log_info log;
uint32_t vb2ex_prepare_log_screen(enum vb2_screen screen, uint32_t locale_id,
const char *str)
{
struct vboot_info *vboot = vboot_get();
const struct ui_locale *locale;
if (ui_get_locale_info(vboot, locale_id, &locale))
return 0;
if (ui_log_init(screen, locale->code, str, &log))
return 0;
return log.page_count;
}
uint32_t vb2ex_get_locale_count(void)
{
struct vboot_info *vboot = vboot_get();
return ui_get_locale_count(vboot);
}
#define DEBUG_INFO_EXTRA_LENGTH 256
const char *vb2ex_get_debug_info(struct vb2_context *ctx)
{
struct vboot_info *vboot = ctx_to_vboot(ctx);
static char *buf;
size_t buf_size;
char tpm_buf[80];
char *vboot_buf;
char *tpm_str = NULL;
char batt_pct_str[16];
/* Check if cache exists. */
if (buf)
return buf;
/* Debug info from the vboot context. */
vboot_buf = vb2api_get_debug_info(ctx);
buf_size = strlen(vboot_buf) + DEBUG_INFO_EXTRA_LENGTH + 1;
buf = malloc(buf_size);
if (buf == NULL) {
printf("%s: Failed to malloc string buffer\n", __func__);
free(vboot_buf);
return NULL;
}
/* States owned by firmware. */
if (!IS_ENABLED(CONFIG_TPM_V1) && !IS_ENABLED(CONFIG_TPM_V2))
tpm_str = "MOCK TPM";
else {
if (!tpm_report_state(tpm_buf, sizeof(tpm_buf)))
tpm_str = tpm_buf;
}
if (!tpm_str)
tpm_str = "(unsupported)";
if (!IS_ENABLED(CONFIG_CROSEC)) {
strncpy(batt_pct_str, "(unsupported)", sizeof(batt_pct_str));
} else {
struct udevice *cros_ec = board_get_cros_ec_dev();
uint batt_pct;
if (!cros_ec || cros_ec_read_batt_charge(cros_ec, &batt_pct))
strncpy(batt_pct_str, "(read failure)",
sizeof(batt_pct_str));
else
snprintf(batt_pct_str, sizeof(batt_pct_str),
"%u%%", batt_pct);
}
snprintf(buf, buf_size,
"%s\n" /* vboot output does not include newline. */
"read-only firmware id: %s\n"
"active firmware id: %s\n"
"battery level: %s\n"
"TPM state: %s",
vboot_buf,
vboot->readonly_firmware_id,
vboot->firmware_id,
batt_pct_str, tpm_str);
free(vboot_buf);
buf[buf_size - 1] = '\0';
printf("debug info: %s\n", buf);
return buf;
}
const char *vb2ex_get_firmware_log(int reset)
{
static char *buf;
if (!buf || reset) {
free(buf);
buf = cbmem_console_snapshot();
if (buf)
printf("Read cbmem console: size=%zu\n", strlen(buf));
else
printf("Failed to read cbmem console\n");
}
return buf;
}
#define DEFAULT_DIAGNOSTIC_OUTPUT_SIZE (64 * KiB)
vb2_error_t vb2ex_diag_get_storage_health(const char **out)
{
static char *buf;
if (!buf)
buf = malloc(DEFAULT_DIAGNOSTIC_OUTPUT_SIZE);
*out = buf;
if (!buf)
return VB2_ERROR_UI_MEMORY_ALLOC;
dump_all_health_info(buf, buf + DEFAULT_DIAGNOSTIC_OUTPUT_SIZE);
return VB2_SUCCESS;
}
vb2_error_t vb2ex_diag_get_storage_test_log(const char **out)
{
static char *buf;
if (!buf)
buf = malloc(DEFAULT_DIAGNOSTIC_OUTPUT_SIZE);
*out = buf;
if (!buf)
return VB2_ERROR_UI_MEMORY_ALLOC;
return diag_dump_storage_test_log(buf,
buf + DEFAULT_DIAGNOSTIC_OUTPUT_SIZE);
}
vb2_error_t vb2ex_diag_memory_quick_test(int reset, const char **out)
{
*out = NULL;
if (reset)
VB2_TRY(memory_test_init(MEMORY_TEST_MODE_QUICK));
return memory_test_run(out);
}
vb2_error_t vb2ex_diag_memory_full_test(int reset, const char **out)
{
*out = NULL;
if (reset)
VB2_TRY(memory_test_init(MEMORY_TEST_MODE_FULL));
return memory_test_run(out);
}
vb2_error_t vb2ex_display_ui(enum vb2_screen screen,
uint32_t locale_id,
uint32_t selected_item,
uint32_t disabled_item_mask,
uint32_t hidden_item_mask,
int timer_disabled,
uint32_t current_page,
enum vb2_ui_error error_code)
{
struct vboot_info *vboot = vboot_get();
vb2_error_t rv;
const struct ui_locale *locale = NULL;
const struct ui_screen_info *screen_info;
printf("%s: screen=%#x, locale=%u, selected_item=%u, "
"disabled_item_mask=%#x, hidden_item_mask=%#x, "
"timer_disabled=%d, current_page=%u, error=%#x\n",
__func__,
screen, locale_id, selected_item,
disabled_item_mask, hidden_item_mask,
timer_disabled, current_page, error_code);
rv = ui_get_locale_info(vboot, locale_id, &locale);
if (rv == VB2_ERROR_UI_INVALID_LOCALE) {
printf("Locale %u not found, falling back to locale 0",
locale_id);
rv = ui_get_locale_info(vboot, 0, &locale);
}
if (rv)
goto fail;
screen_info = ui_get_screen_info(screen);
if (!screen_info) {
printf("%s: Not a valid screen: %#x\n", __func__, screen);
rv = VB2_ERROR_UI_INVALID_SCREEN;
goto fail;
}
struct ui_state state = {
.screen = screen_info,
.locale = locale,
.selected_item = selected_item,
.disabled_item_mask = disabled_item_mask,
.hidden_item_mask = hidden_item_mask,
.timer_disabled = timer_disabled,
.log = &log,
.current_page = current_page,
.error_code = error_code,
};
static struct ui_state prev_state;
static int has_prev_state = 0;
rv = ui_display_screen(&state, has_prev_state ? &prev_state : NULL);
flush_graphics_buffer();
if (rv)
goto fail;
memcpy(&prev_state, &state, sizeof(struct ui_state));
has_prev_state = 1;
return VB2_SUCCESS;
fail:
has_prev_state = 0;
return rv;
}