efi_selftest: check installation of the device tree
The unit test checks if a device tree is installed. It requires that the 'compatible' property of the root node exists. If available it prints the 'serial-number' property. The serial-number property is derived from the environment variable 'serial#'. This can be used to check if the image_setup_libfdt() function is executed. A Python test is supplied. It sets a value for serial# and checks that the selftest shows this as serial-number. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
bc4f9133ed
commit
06c3d5b989
@ -19,6 +19,7 @@ efi_selftest_console.o \
|
||||
efi_selftest_devicepath.o \
|
||||
efi_selftest_events.o \
|
||||
efi_selftest_exitbootservices.o \
|
||||
efi_selftest_fdt.o \
|
||||
efi_selftest_gop.o \
|
||||
efi_selftest_manageprotocols.o \
|
||||
efi_selftest_snp.o \
|
||||
|
188
lib/efi_selftest/efi_selftest_fdt.c
Normal file
188
lib/efi_selftest/efi_selftest_fdt.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* efi_selftest_pos
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
|
||||
*
|
||||
* The following services are tested:
|
||||
* OutputString, TestString, SetAttribute.
|
||||
*/
|
||||
|
||||
#include <efi_selftest.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
static struct efi_boot_services *boottime;
|
||||
static const char *fdt;
|
||||
|
||||
/* This should be sufficent for */
|
||||
#define BUFFERSIZE 0x100000
|
||||
|
||||
static efi_guid_t fdt_guid = EFI_FDT_GUID;
|
||||
|
||||
/*
|
||||
* Convert FDT value to host endianness.
|
||||
*
|
||||
* @val FDT value
|
||||
* @return converted value
|
||||
*/
|
||||
static uint32_t f2h(fdt32_t val)
|
||||
{
|
||||
char *buf = (char *)&val;
|
||||
char i;
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
/* Swap the bytes */
|
||||
i = buf[0]; buf[0] = buf[3]; buf[3] = i;
|
||||
i = buf[1]; buf[1] = buf[2]; buf[2] = i;
|
||||
#endif
|
||||
return *(uint32_t *)buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the value of a property of the FDT root node.
|
||||
*
|
||||
* @name name of the property
|
||||
* @return value of the property
|
||||
*/
|
||||
static char *get_property(const u16 *property)
|
||||
{
|
||||
struct fdt_header *header = (struct fdt_header *)fdt;
|
||||
const fdt32_t *pos;
|
||||
const char *strings;
|
||||
|
||||
if (!header)
|
||||
return NULL;
|
||||
|
||||
if (f2h(header->magic) != FDT_MAGIC) {
|
||||
printf("Wrong magic\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct));
|
||||
strings = fdt + f2h(header->off_dt_strings);
|
||||
|
||||
for (;;) {
|
||||
switch (f2h(pos[0])) {
|
||||
case FDT_BEGIN_NODE: {
|
||||
char *c = (char *)&pos[1];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; c[i]; ++i)
|
||||
;
|
||||
pos = &pos[2 + (i >> 2)];
|
||||
break;
|
||||
}
|
||||
case FDT_PROP: {
|
||||
struct fdt_property *prop = (struct fdt_property *)pos;
|
||||
const char *label = &strings[f2h(prop->nameoff)];
|
||||
efi_status_t ret;
|
||||
|
||||
/* Check if this is the property to be returned */
|
||||
if (!efi_st_strcmp_16_8(property, label)) {
|
||||
char *str;
|
||||
efi_uintn_t len = f2h(prop->len);
|
||||
|
||||
if (!len)
|
||||
return NULL;
|
||||
/*
|
||||
* The string might not be 0 terminated.
|
||||
* It is safer to make a copy.
|
||||
*/
|
||||
ret = boottime->allocate_pool(
|
||||
EFI_LOADER_DATA, len + 1,
|
||||
(void **)&str);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_printf("AllocatePool failed\n");
|
||||
return NULL;
|
||||
}
|
||||
boottime->copy_mem(str, &pos[3], len);
|
||||
str[len] = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)];
|
||||
break;
|
||||
}
|
||||
case FDT_NOP:
|
||||
pos = &pos[1];
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup unit test.
|
||||
*
|
||||
* @handle: handle of the loaded image
|
||||
* @systable: system table
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int setup(const efi_handle_t img_handle,
|
||||
const struct efi_system_table *systable)
|
||||
{
|
||||
efi_uintn_t i;
|
||||
|
||||
boottime = systable->boottime;
|
||||
|
||||
/* Find configuration tables */
|
||||
for (i = 0; i < systable->nr_tables; ++i) {
|
||||
if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid,
|
||||
sizeof(efi_guid_t)))
|
||||
fdt = systable->tables[i].table;
|
||||
}
|
||||
if (!fdt) {
|
||||
efi_st_error("Missing device tree\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute unit test.
|
||||
*
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
char *str;
|
||||
efi_status_t ret;
|
||||
|
||||
str = get_property(L"compatible");
|
||||
if (str) {
|
||||
efi_st_printf("compatible: %s\n", str);
|
||||
ret = boottime->free_pool(str);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("FreePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
} else {
|
||||
efi_st_printf("Missing property 'compatible'\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
str = get_property(L"serial-number");
|
||||
if (str) {
|
||||
efi_st_printf("serial-number: %s\n", str);
|
||||
ret = boottime->free_pool(str);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("FreePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(fdt) = {
|
||||
.name = "device tree",
|
||||
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
.on_request = true,
|
||||
};
|
@ -24,6 +24,20 @@ def test_efi_selftest(u_boot_console):
|
||||
raise Exception('Reset failed during the EFI selftest')
|
||||
u_boot_console.restart_uboot();
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
|
||||
@pytest.mark.buildconfigspec('of_control')
|
||||
def test_efi_selftest_device_tree(u_boot_console):
|
||||
u_boot_console.run_command(cmd='setenv efi_selftest list')
|
||||
output = u_boot_console.run_command('bootefi selftest')
|
||||
assert '\'device tree\'' in output
|
||||
u_boot_console.run_command(cmd='setenv efi_selftest device tree')
|
||||
u_boot_console.run_command(cmd='setenv -f serial# Testing DT')
|
||||
u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['serial-number: Testing DT', 'U-Boot'])
|
||||
if m != 0:
|
||||
raise Exception('Reset failed in \'device tree\' test')
|
||||
u_boot_console.restart_uboot();
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
|
||||
def test_efi_selftest_watchdog_reboot(u_boot_console):
|
||||
u_boot_console.run_command(cmd='setenv efi_selftest list')
|
||||
|
Loading…
Reference in New Issue
Block a user