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