uboot/lib/efi_selftest/efi_selftest_fdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * efi_selftest_pos
   4 *
   5 * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
   8 *
   9 * The following services are tested:
  10 * OutputString, TestString, SetAttribute.
  11 */
  12
  13#include <efi_selftest.h>
  14#include <linux/libfdt.h>
  15
  16static const struct efi_system_table *systemtab;
  17static const struct efi_boot_services *boottime;
  18static const char *fdt;
  19
  20/* This should be sufficient for */
  21#define BUFFERSIZE 0x100000
  22
  23static const efi_guid_t fdt_guid = EFI_FDT_GUID;
  24static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
  25
  26/*
  27 * Convert FDT value to host endianness.
  28 *
  29 * @val         FDT value
  30 * @return      converted value
  31 */
  32static uint32_t f2h(fdt32_t val)
  33{
  34        char *buf = (char *)&val;
  35        char i;
  36
  37#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
  38        /* Swap the bytes */
  39        i = buf[0]; buf[0] = buf[3]; buf[3] = i;
  40        i = buf[1]; buf[1] = buf[2]; buf[2] = i;
  41#endif
  42        return *(uint32_t *)buf;
  43}
  44
  45/*
  46 * Return the value of a property of the FDT root node.
  47 *
  48 * @name        name of the property
  49 * @return      value of the property
  50 */
  51static char *get_property(const u16 *property)
  52{
  53        struct fdt_header *header = (struct fdt_header *)fdt;
  54        const fdt32_t *pos;
  55        const char *strings;
  56
  57        if (!header)
  58                return NULL;
  59
  60        if (f2h(header->magic) != FDT_MAGIC) {
  61                printf("Wrong magic\n");
  62                return NULL;
  63        }
  64
  65        pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct));
  66        strings = fdt + f2h(header->off_dt_strings);
  67
  68        for (;;) {
  69                switch (f2h(pos[0])) {
  70                case FDT_BEGIN_NODE: {
  71                        char *c = (char *)&pos[1];
  72                        size_t i;
  73
  74                        for (i = 0; c[i]; ++i)
  75                                ;
  76                        pos = &pos[2 + (i >> 2)];
  77                        break;
  78                }
  79                case FDT_PROP: {
  80                        struct fdt_property *prop = (struct fdt_property *)pos;
  81                        const char *label = &strings[f2h(prop->nameoff)];
  82                        efi_status_t ret;
  83
  84                        /* Check if this is the property to be returned */
  85                        if (!efi_st_strcmp_16_8(property, label)) {
  86                                char *str;
  87                                efi_uintn_t len = f2h(prop->len);
  88
  89                                if (!len)
  90                                        return NULL;
  91                                /*
  92                                 * The string might not be 0 terminated.
  93                                 * It is safer to make a copy.
  94                                 */
  95                                ret = boottime->allocate_pool(
  96                                        EFI_LOADER_DATA, len + 1,
  97                                        (void **)&str);
  98                                if (ret != EFI_SUCCESS) {
  99                                        efi_st_printf("AllocatePool failed\n");
 100                                        return NULL;
 101                                }
 102                                boottime->copy_mem(str, &pos[3], len);
 103                                str[len] = 0;
 104
 105                                return str;
 106                        }
 107
 108                        pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)];
 109                        break;
 110                }
 111                case FDT_NOP:
 112                        pos = &pos[1];
 113                        break;
 114                default:
 115                        return NULL;
 116                }
 117        }
 118}
 119
 120/**
 121 * efi_st_get_config_table() - get configuration table
 122 *
 123 * @guid:       GUID of the configuration table
 124 * Return:      pointer to configuration table or NULL
 125 */
 126static void *efi_st_get_config_table(const efi_guid_t *guid)
 127{
 128        size_t i;
 129
 130        for (i = 0; i < systab.nr_tables; i++) {
 131                if (!guidcmp(guid, &systemtab->tables[i].guid))
 132                        return systemtab->tables[i].table;
 133        }
 134        return NULL;
 135}
 136
 137/*
 138 * Setup unit test.
 139 *
 140 * @handle:     handle of the loaded image
 141 * @systable:   system table
 142 * @return:     EFI_ST_SUCCESS for success
 143 */
 144static int setup(const efi_handle_t img_handle,
 145                 const struct efi_system_table *systable)
 146{
 147        void *acpi;
 148
 149        systemtab = systable;
 150        boottime = systable->boottime;
 151
 152        acpi = efi_st_get_config_table(&acpi_guid);
 153        fdt = efi_st_get_config_table(&fdt_guid);
 154
 155        if (!fdt) {
 156                efi_st_error("Missing device tree\n");
 157                return EFI_ST_FAILURE;
 158        }
 159        if (acpi) {
 160                efi_st_error("Found ACPI table and device tree\n");
 161                return EFI_ST_FAILURE;
 162        }
 163        return EFI_ST_SUCCESS;
 164}
 165
 166/*
 167 * Execute unit test.
 168 *
 169 * @return:     EFI_ST_SUCCESS for success
 170 */
 171static int execute(void)
 172{
 173        char *str;
 174        efi_status_t ret;
 175
 176        str = get_property(L"compatible");
 177        if (str) {
 178                efi_st_printf("compatible: %s\n", str);
 179                ret = boottime->free_pool(str);
 180                if (ret != EFI_SUCCESS) {
 181                        efi_st_error("FreePool failed\n");
 182                        return EFI_ST_FAILURE;
 183                }
 184        } else {
 185                efi_st_printf("Missing property 'compatible'\n");
 186                return EFI_ST_FAILURE;
 187        }
 188        str = get_property(L"serial-number");
 189        if (str) {
 190                efi_st_printf("serial-number: %s\n", str);
 191                ret = boottime->free_pool(str);
 192                if (ret != EFI_SUCCESS) {
 193                        efi_st_error("FreePool failed\n");
 194                        return EFI_ST_FAILURE;
 195                }
 196        }
 197
 198        return EFI_ST_SUCCESS;
 199}
 200
 201EFI_UNIT_TEST(fdt) = {
 202        .name = "device tree",
 203        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 204        .setup = setup,
 205        .execute = execute,
 206};
 207