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 * get_property() - return value of a property of an FDT node
  47 *
  48 * A property of the root node or one of its direct children can be
  49 * retrieved.
  50 *
  51 * @property    name of the property
  52 * @node        name of the node or NULL for root node
  53 * @return      value of the property
  54 */
  55static char *get_property(const u16 *property, const u16 *node)
  56{
  57        struct fdt_header *header = (struct fdt_header *)fdt;
  58        const fdt32_t *end;
  59        const fdt32_t *pos;
  60        const char *strings;
  61        size_t level = 0;
  62        const char *nodelabel = NULL;
  63
  64        if (!header) {
  65                efi_st_error("Missing device tree\n");
  66                return NULL;
  67        }
  68
  69        if (f2h(header->magic) != FDT_MAGIC) {
  70                efi_st_error("Wrong device tree magic\n");
  71                return NULL;
  72        }
  73
  74        pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct));
  75        end = &pos[f2h(header->totalsize) >> 2];
  76        strings = fdt + f2h(header->off_dt_strings);
  77
  78        for (; pos < end;) {
  79                switch (f2h(pos[0])) {
  80                case FDT_BEGIN_NODE: {
  81                        const char *c = (char *)&pos[1];
  82                        size_t i;
  83
  84                        if (level == 1)
  85                                nodelabel = c;
  86                        ++level;
  87                        for (i = 0; c[i]; ++i)
  88                                ;
  89                        pos = &pos[2 + (i >> 2)];
  90                        break;
  91                }
  92                case FDT_PROP: {
  93                        struct fdt_property *prop = (struct fdt_property *)pos;
  94                        const char *label = &strings[f2h(prop->nameoff)];
  95                        efi_status_t ret;
  96
  97                        /* Check if this is the property to be returned */
  98                        if (!efi_st_strcmp_16_8(property, label) &&
  99                            ((level == 1 && !node) ||
 100                             (level == 2 && node &&
 101                              !efi_st_strcmp_16_8(node, nodelabel)))) {
 102                                char *str;
 103                                efi_uintn_t len = f2h(prop->len);
 104
 105                                if (!len)
 106                                        return NULL;
 107                                /*
 108                                 * The string might not be 0 terminated.
 109                                 * It is safer to make a copy.
 110                                 */
 111                                ret = boottime->allocate_pool(
 112                                        EFI_LOADER_DATA, len + 1,
 113                                        (void **)&str);
 114                                if (ret != EFI_SUCCESS) {
 115                                        efi_st_error("AllocatePool failed\n");
 116                                        return NULL;
 117                                }
 118                                boottime->copy_mem(str, &pos[3], len);
 119                                str[len] = 0;
 120
 121                                return str;
 122                        }
 123
 124                        pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)];
 125                        break;
 126                }
 127                case FDT_NOP:
 128                        ++pos;
 129                        break;
 130                case FDT_END_NODE:
 131                        --level;
 132                        ++pos;
 133                        break;
 134                case FDT_END:
 135                        return NULL;
 136                default:
 137                        efi_st_error("Invalid device tree token\n");
 138                        return NULL;
 139                }
 140        }
 141        efi_st_error("Missing FDT_END token\n");
 142        return NULL;
 143}
 144
 145/**
 146 * efi_st_get_config_table() - get configuration table
 147 *
 148 * @guid:       GUID of the configuration table
 149 * Return:      pointer to configuration table or NULL
 150 */
 151static void *efi_st_get_config_table(const efi_guid_t *guid)
 152{
 153        size_t i;
 154
 155        for (i = 0; i < systab.nr_tables; i++) {
 156                if (!guidcmp(guid, &systemtab->tables[i].guid))
 157                        return systemtab->tables[i].table;
 158        }
 159        return NULL;
 160}
 161
 162/*
 163 * Setup unit test.
 164 *
 165 * @handle:     handle of the loaded image
 166 * @systable:   system table
 167 * @return:     EFI_ST_SUCCESS for success
 168 */
 169static int setup(const efi_handle_t img_handle,
 170                 const struct efi_system_table *systable)
 171{
 172        void *acpi;
 173
 174        systemtab = systable;
 175        boottime = systable->boottime;
 176
 177        acpi = efi_st_get_config_table(&acpi_guid);
 178        fdt = efi_st_get_config_table(&fdt_guid);
 179
 180        if (!fdt) {
 181                efi_st_error("Missing device tree\n");
 182                return EFI_ST_FAILURE;
 183        }
 184        if (acpi) {
 185                efi_st_error("Found ACPI table and device tree\n");
 186                return EFI_ST_FAILURE;
 187        }
 188        return EFI_ST_SUCCESS;
 189}
 190
 191/*
 192 * Execute unit test.
 193 *
 194 * @return:     EFI_ST_SUCCESS for success
 195 */
 196static int execute(void)
 197{
 198        char *str;
 199        efi_status_t ret;
 200
 201        str = get_property(L"compatible", NULL);
 202        if (str) {
 203                efi_st_printf("compatible: %s\n", str);
 204                ret = boottime->free_pool(str);
 205                if (ret != EFI_SUCCESS) {
 206                        efi_st_error("FreePool failed\n");
 207                        return EFI_ST_FAILURE;
 208                }
 209        } else {
 210                efi_st_error("Missing property 'compatible'\n");
 211                return EFI_ST_FAILURE;
 212        }
 213        str = get_property(L"serial-number", NULL);
 214        if (str) {
 215                efi_st_printf("serial-number: %s\n", str);
 216                ret = boottime->free_pool(str);
 217                if (ret != EFI_SUCCESS) {
 218                        efi_st_error("FreePool failed\n");
 219                        return EFI_ST_FAILURE;
 220                }
 221        }
 222        str = get_property(L"boot-hartid", L"chosen");
 223        if (IS_ENABLED(CONFIG_RISCV)) {
 224                if (str) {
 225                        efi_st_printf("boot-hartid: %u\n",
 226                                      f2h(*(fdt32_t *)str));
 227                        ret = boottime->free_pool(str);
 228                        if (ret != EFI_SUCCESS) {
 229                                efi_st_error("FreePool failed\n");
 230                                return EFI_ST_FAILURE;
 231                        }
 232                } else {
 233                        efi_st_error("boot-hartid not found\n");
 234                        return EFI_ST_FAILURE;
 235                }
 236        }
 237
 238        return EFI_ST_SUCCESS;
 239}
 240
 241EFI_UNIT_TEST(fdt) = {
 242        .name = "device tree",
 243        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 244        .setup = setup,
 245        .execute = execute,
 246};
 247