]>
Commit | Line | Data |
---|---|---|
9b30232b HS |
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> | |
3db71108 | 12 | #include <u-boot/crc.h> |
9b30232b HS |
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 | /* | |
d8b2216c | 22 | * Notification function, increments the notification count if parameter |
9b30232b HS |
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 | ||
74fc0445 | 36 | /* |
d8b2216c | 37 | * Check CRC32 of a table. |
74fc0445 HS |
38 | */ |
39 | static int check_table(const void *table) | |
40 | { | |
41 | efi_status_t ret; | |
42 | u32 crc32, res; | |
d8b2216c | 43 | /* Casting from constant to not constant */ |
74fc0445 HS |
44 | struct efi_table_hdr *hdr = (struct efi_table_hdr *)table; |
45 | ||
46 | crc32 = hdr->crc32; | |
47 | /* | |
d8b2216c | 48 | * Setting the CRC32 of the 'const' table to zero is easier than |
74fc0445 HS |
49 | * copying |
50 | */ | |
51 | hdr->crc32 = 0; | |
52 | ret = boottime->calculate_crc32(table, hdr->headersize, &res); | |
d8b2216c | 53 | /* Reset table CRC32 so it stays constant */ |
74fc0445 HS |
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 | ||
9b30232b HS |
66 | /* |
67 | * Setup unit test. | |
68 | * | |
69 | * @handle: handle of the loaded image | |
70 | * @systable: system table | |
3dd719d4 | 71 | * Return: EFI_ST_SUCCESS for success |
9b30232b HS |
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 | * | |
3dd719d4 | 88 | * Return: EFI_ST_SUCCESS for success |
9b30232b HS |
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) { | |
8101dd3d HS |
157 | if (!memcmp(&sys_table->tables[i].guid, &table_guid, |
158 | sizeof(efi_guid_t))) | |
9b30232b HS |
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 | } | |
74fc0445 HS |
169 | if (check_table(sys_table) != EFI_ST_SUCCESS) { |
170 | efi_st_error("Checking system table\n"); | |
171 | return EFI_ST_FAILURE; | |
172 | } | |
173 | ||
9b30232b HS |
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) { | |
8101dd3d HS |
196 | if (!memcmp(&sys_table->tables[i].guid, &table_guid, |
197 | sizeof(efi_guid_t))) { | |
9b30232b HS |
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) { | |
d8b2216c | 207 | efi_st_error("Duplicate table GUID\n"); |
9b30232b HS |
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 | } | |
74fc0445 HS |
214 | if (check_table(sys_table) != EFI_ST_SUCCESS) { |
215 | efi_st_error("Checking system table\n"); | |
216 | return EFI_ST_FAILURE; | |
217 | } | |
9b30232b HS |
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) { | |
8101dd3d HS |
239 | if (!memcmp(&sys_table->tables[i].guid, &table_guid, |
240 | sizeof(efi_guid_t))) { | |
9b30232b HS |
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 | } | |
74fc0445 HS |
254 | if (check_table(sys_table) != EFI_ST_SUCCESS) { |
255 | efi_st_error("Checking system table\n"); | |
256 | return EFI_ST_FAILURE; | |
257 | } | |
9b30232b HS |
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 | }; |