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