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