u-boot/lib/efi_loader/dbginfodump.c
Vincent Stehlé ac59ac1b7c efi_loader: dbginfodump: use guid definition
Use the Debug Image Info Table GUID definition from efi_api.h instead or
redefining it locally.

Signed-off-by: Vincent Stehlé <vincent.stehle@arm.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Tom Rini <trini@konsulko.com>
Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
2025-10-18 11:59:53 +02:00

355 lines
7.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2025, Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* dbginfodump.efi prints out the content of the EFI_DEBUG_IMAGE_INFO_TABLE.
*/
#include <efi_api.h>
/**
* BUFFER_SIZE - size of the command line input buffer
*/
#define BUFFER_SIZE 64
static struct efi_simple_text_output_protocol *cerr;
static struct efi_simple_text_output_protocol *cout;
static struct efi_simple_text_input_protocol *cin;
static efi_handle_t handle;
static struct efi_system_table *systable;
static struct efi_boot_services *bs;
static efi_guid_t guid_device_path_to_text_protocol =
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
static struct efi_device_path_to_text_protocol *device_path_to_text;
static const efi_guid_t dbg_info_guid =
EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
/* EFI_DEBUG_IMAGE_INFO_NORMAL */
struct dbg_info {
u32 type;
struct efi_loaded_image *info;
efi_handle_t handle;
};
/* FI_DEBUG_IMAGE_INFO_TABLE_HEADER */
struct dbg_info_header {
u32 status;
u32 size;
struct dbg_info **info;
};
/**
* print() - print string
*
* @string: text
*/
static void print(u16 *string)
{
cout->output_string(cout, string);
}
/**
* error() - print error string
*
* @string: error text
*/
static void error(u16 *string)
{
cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
print(string);
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
}
/**
* printu() - print unsigned
*
* @val: value to print
*/
static void printu(u32 val)
{
u16 str[19] = u"0x";
u16 *ptr = &str[2];
u16 ch;
for (ssize_t i = 8 * sizeof(u32) - 4; i >= 0; i -= 4) {
ch = (val >> i & 0xf) + '0';
if (ch > '9')
ch += 'a' - '9' - 1;
*ptr++ = ch;
}
*ptr = 0;
print(str);
}
/**
* printp() - print pointer
*
* @p: pointer
*/
static void printp(void *p)
{
u16 str[19] = u"0x";
u16 *ptr = &str[2];
u16 ch;
for (ssize_t i = 8 * sizeof(void *) - 4; i >= 0; i -= 4) {
ch = ((uintptr_t)p >> i & 0xf) + '0';
if (ch > '9')
ch += 'a' - '9' - 1;
*ptr++ = ch;
}
*ptr = 0;
print(str);
}
/**
* efi_input() - read string from console
*
* @buffer: input buffer
* @buffer_size: buffer size
* Return: status code
*/
static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
{
struct efi_input_key key = {0};
efi_uintn_t index;
efi_uintn_t pos = 0;
u16 outbuf[2] = u" ";
efi_status_t ret;
/* Drain the console input */
ret = cin->reset(cin, true);
*buffer = 0;
for (;;) {
ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
if (ret != EFI_SUCCESS)
continue;
ret = cin->read_key_stroke(cin, &key);
if (ret != EFI_SUCCESS)
continue;
switch (key.scan_code) {
case 0x17: /* Escape */
print(u"\r\nAborted\r\n");
return EFI_ABORTED;
default:
break;
}
switch (key.unicode_char) {
case 0x08: /* Backspace */
if (pos) {
buffer[pos--] = 0;
print(u"\b \b");
}
break;
case 0x0a: /* Linefeed */
case 0x0d: /* Carriage return */
print(u"\r\n");
return EFI_SUCCESS;
default:
break;
}
/* Ignore surrogate codes */
if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
continue;
if (key.unicode_char >= 0x20 &&
pos < buffer_size - 1) {
*outbuf = key.unicode_char;
buffer[pos++] = key.unicode_char;
buffer[pos] = 0;
print(outbuf);
}
}
}
/**
* skip_whitespace() - skip over leading whitespace
*
* @pos: UTF-16 string
* Return: pointer to first non-whitespace
*/
static u16 *skip_whitespace(u16 *pos)
{
for (; *pos && *pos <= 0x20; ++pos)
;
return pos;
}
/**
* starts_with() - check if @string starts with @keyword
*
* @string: string to search for keyword
* @keyword: keyword to be searched
* Return: true fi @string starts with the keyword
*/
static bool starts_with(u16 *string, u16 *keyword)
{
for (; *keyword; ++string, ++keyword) {
if (*string != *keyword)
return false;
}
return true;
}
/**
* do_help() - print help
*/
static void do_help(void)
{
error(u"dump - print debug info table\r\n");
error(u"exit - exit the shell\r\n");
}
/**
* get_dbg_info_table() - get debug info table
*
* Return: debug info table or NULL
*/
static void *get_dbg_info(void)
{
void *dbg = NULL;
efi_uintn_t i;
for (i = 0; i < systable->nr_tables; ++i) {
if (!memcmp(&systable->tables[i].guid, &dbg_info_guid,
sizeof(efi_guid_t))) {
dbg = systable->tables[i].table;
break;
}
}
return dbg;
}
/**
* print_info() - print loaded image protocol
*/
static void print_info(struct efi_loaded_image *info)
{
print(u" Address: [");
printp(info->image_base);
print(u", ");
printp(info->image_base + info->image_size - 1);
print(u"]\r\n");
if (device_path_to_text && info->file_path) {
u16 *string;
string = device_path_to_text->convert_device_path_to_text(
info->file_path, true, false);
if (!string) {
error(u"ConvertDevicePathToText failed");
} else {
print(u" File: ");
print(string);
}
print(u"\r\n");
}
}
/**
* do_dump() - print debug info table
*/
static efi_status_t do_dump(void)
{
struct dbg_info_header *dbg;
u32 count;
dbg = get_dbg_info();
if (!dbg) {
error(u"Debug info table not found\r\n");
return EFI_NOT_FOUND;
}
if (dbg->status & 0x01) {
error(u"Update in progress\r\n");
return EFI_LOAD_ERROR;
}
if (dbg->status & 0x02)
print(u"Modified\r\n");
print(u"Number of entries: ");
printu(dbg->size);
print(u"\r\n");
count = dbg->size;
for (u32 i = 0; count; ++i) {
struct dbg_info *info = dbg->info[i];
/*
* The EDK II implementation decreases the size field and
* writes a NULL value when deleting an entry which is not
* backed by the UEFI specification.
*/
if (!info) {
print(u"Deleted entry\r\n");
continue;
}
--count;
print(u"Info type ");
printu(info->type);
print(u"\r\n");
if (info->type != 1)
continue;
print_info(info->info);
print(u" Handle: ");
printp(info->handle);
print(u"\r\n");
}
return EFI_SUCCESS;
}
/**
* efi_main() - entry point of the EFI application.
*
* @handle: handle of the loaded image
* @systab: system table
* Return: status code
*/
efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
struct efi_system_table *systab)
{
efi_status_t ret;
handle = image_handle;
systable = systab;
cerr = systable->std_err;
cout = systable->con_out;
cin = systable->con_in;
bs = systable->boottime;
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
cout->clear_screen(cout);
cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
print(u"Debug Info Table Dump\r\n=====================\r\n\r\n");
cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
ret = bs->locate_protocol(&guid_device_path_to_text_protocol,
NULL, (void **)&device_path_to_text);
if (ret != EFI_SUCCESS) {
error(u"No device path to text protocol\r\n");
device_path_to_text = NULL;
}
for (;;) {
u16 command[BUFFER_SIZE];
u16 *pos;
efi_uintn_t ret;
print(u"=> ");
ret = efi_input(command, sizeof(command));
if (ret == EFI_ABORTED)
break;
pos = skip_whitespace(command);
if (starts_with(pos, u"exit"))
break;
else if (starts_with(pos, u"dump"))
do_dump();
else
do_help();
}
cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
cout->clear_screen(cout);
return EFI_SUCCESS;
}