efi_loader: validate load option
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_fdt.c
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 const struct efi_system_table *systemtab;
17 static const struct efi_boot_services *boottime;
18 static const char *fdt;
19
20 /* This should be sufficient for */
21 #define BUFFERSIZE 0x100000
22
23 static const efi_guid_t fdt_guid = EFI_FDT_GUID;
24 static 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  */
32 static 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  */
51 static 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  */
126 static 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  */
144 static 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  */
171 static 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
201 EFI_UNIT_TEST(fdt) = {
202         .name = "device tree",
203         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
204         .setup = setup,
205         .execute = execute,
206 };