efi_loader: validate load option
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_config_table.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_config_tables
4  *
5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This test checks the following service:
8  * InstallConfigurationTable.
9  */
10
11 #include <efi_selftest.h>
12 #include <u-boot/crc.h>
13
14 static const struct efi_system_table *sys_table;
15 static struct efi_boot_services *boottime;
16
17 static efi_guid_t table_guid =
18         EFI_GUID(0xff1c3f9e, 0x795b, 0x1529, 0xf1, 0x55,
19                  0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75);
20
21 /*
22  * Notification function, increments the notification count if parameter
23  * context is provided.
24  *
25  * @event       notified event
26  * @context     pointer to the notification count
27  */
28 static void EFIAPI notify(struct efi_event *event, void *context)
29 {
30         unsigned int *count = context;
31
32         if (count)
33                 ++*count;
34 }
35
36 /*
37  * Check CRC32 of a table.
38  */
39 static int check_table(const void *table)
40 {
41         efi_status_t ret;
42         u32 crc32, res;
43         /* Casting from constant to not constant */
44         struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
45
46         crc32 = hdr->crc32;
47         /*
48          * Setting the CRC32 of the 'const' table to zero is easier than
49          * copying
50          */
51         hdr->crc32 = 0;
52         ret = boottime->calculate_crc32(table, hdr->headersize, &res);
53         /* Reset table CRC32 so it stays constant */
54         hdr->crc32 = crc32;
55         if (ret != EFI_ST_SUCCESS) {
56                 efi_st_error("CalculateCrc32 failed\n");
57                 return EFI_ST_FAILURE;
58         }
59         if (res != crc32) {
60                 efi_st_error("Incorrect CRC32\n");
61                 return EFI_ST_FAILURE;
62         }
63         return EFI_ST_SUCCESS;
64 }
65
66 /*
67  * Setup unit test.
68  *
69  * @handle:     handle of the loaded image
70  * @systable:   system table
71  * @return:     EFI_ST_SUCCESS for success
72  */
73 static int setup(const efi_handle_t handle,
74                  const struct efi_system_table *systable)
75 {
76         sys_table = systable;
77         boottime = systable->boottime;
78
79         return EFI_ST_SUCCESS;
80 }
81
82 /*
83  * Execute unit test.
84  *
85  * A table is installed, updated, removed. The table entry and the
86  * triggering of events is checked.
87  *
88  * @return:     EFI_ST_SUCCESS for success
89  */
90 static int execute(void)
91 {
92         efi_status_t ret;
93         unsigned int counter = 0;
94         struct efi_event *event;
95         void *table;
96         const unsigned int tables[2];
97         efi_uintn_t i;
98         efi_uintn_t tabcnt;
99         efi_uintn_t table_count = sys_table->nr_tables;
100
101         ret = boottime->create_event_ex(0, TPL_NOTIFY,
102                                         notify, (void *)&counter,
103                                         &table_guid, &event);
104         if (ret != EFI_SUCCESS) {
105                 efi_st_error("Failed to create event\n");
106                 return EFI_ST_FAILURE;
107         }
108
109         /* Try to delete non-existent table */
110         ret = boottime->install_configuration_table(&table_guid, NULL);
111         if (ret != EFI_NOT_FOUND) {
112                 efi_st_error("Failed to detect missing table\n");
113                 return EFI_ST_FAILURE;
114         }
115         if (counter) {
116                 efi_st_error("Notification function was called.\n");
117                 return EFI_ST_FAILURE;
118         }
119         /* Check if the event was signaled  */
120         ret = boottime->check_event(event);
121         if (ret == EFI_SUCCESS) {
122                 efi_st_error("Event was signaled on EFI_NOT_FOUND\n");
123                 return EFI_ST_FAILURE;
124         }
125         if (counter != 1) {
126                 efi_st_error("Notification function was not called.\n");
127                 return EFI_ST_FAILURE;
128         }
129         if (table_count != sys_table->nr_tables) {
130                 efi_st_error("Incorrect table count %u, expected %u\n",
131                              (unsigned int)sys_table->nr_tables,
132                              (unsigned int)table_count);
133                 return EFI_ST_FAILURE;
134         }
135
136         /* Install table */
137         ret = boottime->install_configuration_table(&table_guid,
138                                                     (void *)&tables[0]);
139         if (ret != EFI_SUCCESS) {
140                 efi_st_error("Failed to install table\n");
141                 return EFI_ST_FAILURE;
142         }
143         /* Check signaled state */
144         ret = boottime->check_event(event);
145         if (ret != EFI_SUCCESS) {
146                 efi_st_error("Event was not signaled on insert\n");
147                 return EFI_ST_FAILURE;
148         }
149         if (++table_count != sys_table->nr_tables) {
150                 efi_st_error("Incorrect table count %u, expected %u\n",
151                              (unsigned int)sys_table->nr_tables,
152                              (unsigned int)table_count);
153                 return EFI_ST_FAILURE;
154         }
155         table = NULL;
156         for (i = 0; i < sys_table->nr_tables; ++i) {
157                 if (!memcmp(&sys_table->tables[i].guid, &table_guid,
158                             sizeof(efi_guid_t)))
159                         table = sys_table->tables[i].table;
160         }
161         if (!table) {
162                 efi_st_error("Installed table not found\n");
163                 return EFI_ST_FAILURE;
164         }
165         if (table != &tables[0]) {
166                 efi_st_error("Incorrect table address\n");
167                 return EFI_ST_FAILURE;
168         }
169         if (check_table(sys_table) != EFI_ST_SUCCESS) {
170                 efi_st_error("Checking system table\n");
171                 return EFI_ST_FAILURE;
172         }
173
174         /* Update table */
175         ret = boottime->install_configuration_table(&table_guid,
176                                                     (void *)&tables[1]);
177         if (ret != EFI_SUCCESS) {
178                 efi_st_error("Failed to update table\n");
179                 return EFI_ST_FAILURE;
180         }
181         /* Check signaled state */
182         ret = boottime->check_event(event);
183         if (ret != EFI_SUCCESS) {
184                 efi_st_error("Event was not signaled on update\n");
185                 return EFI_ST_FAILURE;
186         }
187         if (table_count != sys_table->nr_tables) {
188                 efi_st_error("Incorrect table count %u, expected %u\n",
189                              (unsigned int)sys_table->nr_tables,
190                              (unsigned int)table_count);
191                 return EFI_ST_FAILURE;
192         }
193         table = NULL;
194         tabcnt = 0;
195         for (i = 0; i < sys_table->nr_tables; ++i) {
196                 if (!memcmp(&sys_table->tables[i].guid, &table_guid,
197                             sizeof(efi_guid_t))) {
198                         table = sys_table->tables[i].table;
199                         ++tabcnt;
200                 }
201         }
202         if (!table) {
203                 efi_st_error("Installed table not found\n");
204                 return EFI_ST_FAILURE;
205         }
206         if (tabcnt > 1) {
207                 efi_st_error("Duplicate table GUID\n");
208                 return EFI_ST_FAILURE;
209         }
210         if (table != &tables[1]) {
211                 efi_st_error("Incorrect table address\n");
212                 return EFI_ST_FAILURE;
213         }
214         if (check_table(sys_table) != EFI_ST_SUCCESS) {
215                 efi_st_error("Checking system table\n");
216                 return EFI_ST_FAILURE;
217         }
218
219         /* Delete table */
220         ret = boottime->install_configuration_table(&table_guid, NULL);
221         if (ret != EFI_SUCCESS) {
222                 efi_st_error("Failed to delete table\n");
223                 return EFI_ST_FAILURE;
224         }
225         /* Check signaled state */
226         ret = boottime->check_event(event);
227         if (ret != EFI_SUCCESS) {
228                 efi_st_error("Event was not signaled on delete\n");
229                 return EFI_ST_FAILURE;
230         }
231         if (--table_count != sys_table->nr_tables) {
232                 efi_st_error("Incorrect table count %u, expected %u\n",
233                              (unsigned int)sys_table->nr_tables,
234                              (unsigned int)table_count);
235                 return EFI_ST_FAILURE;
236         }
237         table = NULL;
238         for (i = 0; i < sys_table->nr_tables; ++i) {
239                 if (!memcmp(&sys_table->tables[i].guid, &table_guid,
240                             sizeof(efi_guid_t))) {
241                         table = sys_table->tables[i].table;
242                 }
243         }
244         if (table) {
245                 efi_st_error("Wrong table deleted\n");
246                 return EFI_ST_FAILURE;
247         }
248
249         ret = boottime->close_event(event);
250         if (ret != EFI_SUCCESS) {
251                 efi_st_error("Failed to close event\n");
252                 return EFI_ST_FAILURE;
253         }
254         if (check_table(sys_table) != EFI_ST_SUCCESS) {
255                 efi_st_error("Checking system table\n");
256                 return EFI_ST_FAILURE;
257         }
258
259         return EFI_ST_SUCCESS;
260 }
261
262 EFI_UNIT_TEST(configtables) = {
263         .name = "configuration tables",
264         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
265         .setup = setup,
266         .execute = execute,
267 };