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 16 static struct efi_boot_services *boottime; 17 static const char *fdt; 18 19 /* This should be sufficent for */ 20 #define BUFFERSIZE 0x100000 21 22 static efi_guid_t fdt_guid = EFI_FDT_GUID; 23 24 /* 25 * Convert FDT value to host endianness. 26 * 27 * @val FDT value 28 * @return converted value 29 */ 30 static uint32_t f2h(fdt32_t val) 31 { 32 char *buf = (char *)&val; 33 char i; 34 35 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 36 /* Swap the bytes */ 37 i = buf[0]; buf[0] = buf[3]; buf[3] = i; 38 i = buf[1]; buf[1] = buf[2]; buf[2] = i; 39 #endif 40 return *(uint32_t *)buf; 41 } 42 43 /* 44 * Return the value of a property of the FDT root node. 45 * 46 * @name name of the property 47 * @return value of the property 48 */ 49 static char *get_property(const u16 *property) 50 { 51 struct fdt_header *header = (struct fdt_header *)fdt; 52 const fdt32_t *pos; 53 const char *strings; 54 55 if (!header) 56 return NULL; 57 58 if (f2h(header->magic) != FDT_MAGIC) { 59 printf("Wrong magic\n"); 60 return NULL; 61 } 62 63 pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct)); 64 strings = fdt + f2h(header->off_dt_strings); 65 66 for (;;) { 67 switch (f2h(pos[0])) { 68 case FDT_BEGIN_NODE: { 69 char *c = (char *)&pos[1]; 70 size_t i; 71 72 for (i = 0; c[i]; ++i) 73 ; 74 pos = &pos[2 + (i >> 2)]; 75 break; 76 } 77 case FDT_PROP: { 78 struct fdt_property *prop = (struct fdt_property *)pos; 79 const char *label = &strings[f2h(prop->nameoff)]; 80 efi_status_t ret; 81 82 /* Check if this is the property to be returned */ 83 if (!efi_st_strcmp_16_8(property, label)) { 84 char *str; 85 efi_uintn_t len = f2h(prop->len); 86 87 if (!len) 88 return NULL; 89 /* 90 * The string might not be 0 terminated. 91 * It is safer to make a copy. 92 */ 93 ret = boottime->allocate_pool( 94 EFI_LOADER_DATA, len + 1, 95 (void **)&str); 96 if (ret != EFI_SUCCESS) { 97 efi_st_printf("AllocatePool failed\n"); 98 return NULL; 99 } 100 boottime->copy_mem(str, &pos[3], len); 101 str[len] = 0; 102 103 return str; 104 } 105 106 pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)]; 107 break; 108 } 109 case FDT_NOP: 110 pos = &pos[1]; 111 break; 112 default: 113 return NULL; 114 } 115 } 116 } 117 118 /* 119 * Setup unit test. 120 * 121 * @handle: handle of the loaded image 122 * @systable: system table 123 * @return: EFI_ST_SUCCESS for success 124 */ 125 static int setup(const efi_handle_t img_handle, 126 const struct efi_system_table *systable) 127 { 128 efi_uintn_t i; 129 130 boottime = systable->boottime; 131 132 /* Find configuration tables */ 133 for (i = 0; i < systable->nr_tables; ++i) { 134 if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid, 135 sizeof(efi_guid_t))) 136 fdt = systable->tables[i].table; 137 } 138 if (!fdt) { 139 efi_st_error("Missing device tree\n"); 140 return EFI_ST_FAILURE; 141 } 142 143 return EFI_ST_SUCCESS; 144 } 145 146 /* 147 * Execute unit test. 148 * 149 * @return: EFI_ST_SUCCESS for success 150 */ 151 static int execute(void) 152 { 153 char *str; 154 efi_status_t ret; 155 156 str = get_property(L"compatible"); 157 if (str) { 158 efi_st_printf("compatible: %s\n", str); 159 ret = boottime->free_pool(str); 160 if (ret != EFI_SUCCESS) { 161 efi_st_error("FreePool failed\n"); 162 return EFI_ST_FAILURE; 163 } 164 } else { 165 efi_st_printf("Missing property 'compatible'\n"); 166 return EFI_ST_FAILURE; 167 } 168 str = get_property(L"serial-number"); 169 if (str) { 170 efi_st_printf("serial-number: %s\n", str); 171 ret = boottime->free_pool(str); 172 if (ret != EFI_SUCCESS) { 173 efi_st_error("FreePool failed\n"); 174 return EFI_ST_FAILURE; 175 } 176 } 177 178 return EFI_ST_SUCCESS; 179 } 180 181 EFI_UNIT_TEST(fdt) = { 182 .name = "device tree", 183 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 184 .setup = setup, 185 .execute = execute, 186 .on_request = true, 187 }; 188