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>master
parent
bc4f9133ed
commit
06c3d5b989
@ -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, |
||||
}; |
Loading…
Reference in new issue