blob: e5a8d6a6ae59098ac52577c471d6cc14d8e2554d [file] [log] [blame]
Heinrich Schuchardt43d27992018-03-03 15:29:04 +01001/*
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>
Heinrich Schuchardt0a9b9e52018-03-12 19:52:25 +010015#include <linux/libfdt.h>
Heinrich Schuchardt43d27992018-03-03 15:29:04 +010016
17static struct efi_boot_services *boottime;
18static const char *fdt;
19
20/* This should be sufficent for */
21#define BUFFERSIZE 0x100000
22
23static 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 */
31static 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 */
50static 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 */
126static 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 */
152static 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
182EFI_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};