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 };
267