efi_loader: validate load option
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_devicepath_util.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_devicepath_util
4  *
5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This unit test checks the device path utilities protocol.
8  */
9
10 #include <efi_selftest.h>
11
12 static struct efi_boot_services *boottime;
13
14 static efi_guid_t guid_device_path_utilities_protocol =
15         EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
16
17 struct efi_device_path_utilities_protocol *dpu;
18
19 /*
20  * Setup unit test.
21  *
22  * Locate the device path utilities protocol.
23  *
24  * @handle:     handle of the loaded image
25  * @systable:   system table
26  */
27 static int setup(const efi_handle_t img_handle,
28                  const struct efi_system_table *systable)
29 {
30         int ret;
31
32         boottime = systable->boottime;
33
34         ret = boottime->locate_protocol(&guid_device_path_utilities_protocol,
35                                         NULL, (void **)&dpu);
36         if (ret != EFI_SUCCESS) {
37                 dpu = NULL;
38                 efi_st_error(
39                         "Device path to text protocol is not available.\n");
40                 return EFI_ST_FAILURE;
41         }
42
43         return EFI_ST_SUCCESS;
44 }
45
46 /*
47  * Create a device path consisting of a single media device node followed by an
48  * end node.
49  *
50  * @length:     length of the media device node
51  * @dp:         device path
52  * @return:     status code
53  */
54 static int create_single_node_device_path(unsigned int length,
55                                           struct efi_device_path **dp)
56 {
57         struct efi_device_path *node;
58         efi_uintn_t len;
59         int ret;
60
61         node = dpu->create_device_node(DEVICE_PATH_TYPE_MEDIA_DEVICE,
62                                        DEVICE_PATH_SUB_TYPE_FILE_PATH, length);
63         if (!node) {
64                 efi_st_error("CreateDeviceNode failed\n");
65                 return EFI_ST_FAILURE;
66         }
67         *dp = dpu->append_device_node(NULL, node);
68         if (!*dp) {
69                 efi_st_error("AppendDeviceNode failed\n");
70                 return EFI_ST_FAILURE;
71         }
72         ret = boottime->free_pool(node);
73         if (ret != EFI_ST_SUCCESS) {
74                 efi_st_error("FreePool failed\n");
75                 return EFI_ST_FAILURE;
76         }
77         len = dpu->get_device_path_size(*dp);
78         if (len != length + 4) {
79                 efi_st_error("Wrong device path length %u, expected %u\n",
80                              (unsigned int)len, length);
81                 return EFI_ST_FAILURE;
82         }
83         return EFI_ST_SUCCESS;
84 }
85
86 /*
87  * Execute unit test.
88  *
89  * In the test device paths are created, copied, and concatenated. The device
90  * path length is used as a measure of success.
91  */
92 static int execute(void)
93 {
94         struct efi_device_path *dp1;
95         struct efi_device_path *dp2;
96         struct efi_device_path *dp3;
97
98         efi_uintn_t len;
99         int ret;
100
101         /* IsDevicePathMultiInstance(NULL) */
102         if (dpu->is_device_path_multi_instance(NULL)) {
103                 efi_st_error("IsDevicePathMultiInstance(NULL) returned true\n");
104                 return EFI_ST_FAILURE;
105         }
106         /* GetDevicePathSize(NULL) */
107         len = dpu->get_device_path_size(NULL);
108         if (len) {
109                 efi_st_error("Wrong device path length %u, expected 0\n",
110                              (unsigned int)len);
111                 return EFI_ST_FAILURE;
112         }
113         /* DuplicateDevicePath(NULL) */
114         dp1 = dpu->duplicate_device_path(NULL);
115         if (dp1) {
116                 efi_st_error("DuplicateDevicePath(NULL) failed\n");
117                 return EFI_ST_FAILURE;
118         }
119         /* AppendDevicePath(NULL, NULL) */
120         dp1 = dpu->append_device_path(NULL, NULL);
121         if (!dp1) {
122                 efi_st_error("AppendDevicePath(NULL, NULL) failed\n");
123                 return EFI_ST_FAILURE;
124         }
125         len = dpu->get_device_path_size(dp1);
126         if (len != 4) {
127                 efi_st_error("Wrong device path length %u, expected 4\n",
128                              (unsigned int)len);
129                 return EFI_ST_FAILURE;
130         }
131         ret = boottime->free_pool(dp1);
132         if (ret != EFI_ST_SUCCESS) {
133                 efi_st_error("FreePool failed\n");
134                 return EFI_ST_FAILURE;
135         }
136         /* CreateDeviceNode */
137         ret = create_single_node_device_path(21, &dp1);
138         if (ret != EFI_ST_SUCCESS)
139                 return ret;
140         ret = create_single_node_device_path(17, &dp2);
141         if (ret != EFI_ST_SUCCESS)
142                 return ret;
143         /* AppendDevicePath */
144         dp3 = dpu->append_device_path(dp1, dp2);
145         if (!dp3) {
146                 efi_st_error("AppendDevicePath failed\n");
147                 return EFI_ST_FAILURE;
148         }
149         if (dp3 == dp1 || dp3 == dp2) {
150                 efi_st_error("AppendDevicePath reused buffer\n");
151                 return EFI_ST_FAILURE;
152         }
153         len = dpu->get_device_path_size(dp3);
154         /* 21 + 17 + 4 */
155         if (len != 42) {
156                 efi_st_error("Wrong device path length %u, expected 42\n",
157                              (unsigned int)len);
158                 return EFI_ST_FAILURE;
159         }
160         ret = boottime->free_pool(dp2);
161         if (ret != EFI_ST_SUCCESS) {
162                 efi_st_error("FreePool failed\n");
163                 return EFI_ST_FAILURE;
164         }
165         /* AppendDeviceNode */
166         dp2 = dpu->append_device_node(dp1, dp3);
167         if (!dp2) {
168                 efi_st_error("AppendDevicePath failed\n");
169                 return EFI_ST_FAILURE;
170         }
171         len = dpu->get_device_path_size(dp2);
172         /* 21 + 21 + 4 */
173         if (len != 46) {
174                 printf("%s(%d) %s\n", __FILE__, __LINE__, __func__);
175                 efi_st_error("Wrong device path length %u, expected 46\n",
176                              (unsigned int)len);
177                 return EFI_ST_FAILURE;
178         }
179         ret = boottime->free_pool(dp1);
180         if (ret != EFI_ST_SUCCESS) {
181                 efi_st_error("FreePool failed\n");
182                 return EFI_ST_FAILURE;
183         }
184         /* IsDevicePathMultiInstance */
185         if (dpu->is_device_path_multi_instance(dp2)) {
186                 printf("%s(%d) %s\n", __FILE__, __LINE__, __func__);
187                 efi_st_error("IsDevicePathMultiInstance returned true\n");
188                 return EFI_ST_FAILURE;
189         }
190         /* AppendDevicePathInstance */
191         dp1 = dpu->append_device_path_instance(dp2, dp3);
192         if (!dp1) {
193                 efi_st_error("AppendDevicePathInstance failed\n");
194                 return EFI_ST_FAILURE;
195         }
196         len = dpu->get_device_path_size(dp1);
197         /* 46 + 42 */
198         if (len != 88) {
199                 efi_st_error("Wrong device path length %u, expected 88\n",
200                              (unsigned int)len);
201                 return EFI_ST_FAILURE;
202         }
203         /* IsDevicePathMultiInstance */
204         if (!dpu->is_device_path_multi_instance(dp1)) {
205                 efi_st_error("IsDevicePathMultiInstance returned false\n");
206                 return EFI_ST_FAILURE;
207         }
208         ret = boottime->free_pool(dp2);
209         if (ret != EFI_ST_SUCCESS) {
210                 efi_st_error("FreePool failed\n");
211                 return EFI_ST_FAILURE;
212         }
213         ret = boottime->free_pool(dp3);
214         if (ret != EFI_ST_SUCCESS) {
215                 efi_st_error("FreePool failed\n");
216                 return EFI_ST_FAILURE;
217         }
218         /* GetNextDevicePathInstance */
219         dp3 = dp1;
220         dp2 = dpu->get_next_device_path_instance(&dp1, &len);
221         if (!dp2) {
222                 efi_st_error("GetNextDevicePathInstance failed\n");
223                 return EFI_ST_FAILURE;
224         }
225         if (!dp1) {
226                 efi_st_error("GetNextDevicePathInstance no 2nd instance\n");
227                 return EFI_ST_FAILURE;
228         }
229         if (len != 46) {
230                 efi_st_error("Wrong device path length %u, expected 46\n",
231                              (unsigned int)len);
232                 return EFI_ST_FAILURE;
233         }
234         len = dpu->get_device_path_size(dp1);
235         if (len != 42) {
236                 efi_st_error("Wrong device path length %u, expected 42\n",
237                              (unsigned int)len);
238                 return EFI_ST_FAILURE;
239         }
240         ret = boottime->free_pool(dp2);
241         if (ret != EFI_ST_SUCCESS) {
242                 efi_st_error("FreePool failed\n");
243                 return EFI_ST_FAILURE;
244         }
245         dp2 = dpu->get_next_device_path_instance(&dp1, &len);
246         if (!dp2) {
247                 efi_st_error("GetNextDevicePathInstance failed\n");
248                 return EFI_ST_FAILURE;
249         }
250         if (len != 42) {
251                 efi_st_error("Wrong device path length %u, expected 46\n",
252                              (unsigned int)len);
253                 return EFI_ST_FAILURE;
254         }
255         if (dp1) {
256                 efi_st_error("GetNextDevicePathInstance did not signal end\n");
257                 return EFI_ST_FAILURE;
258         }
259
260         /* Clean up */
261         ret = boottime->free_pool(dp2);
262         if (ret != EFI_ST_SUCCESS) {
263                 efi_st_error("FreePool failed\n");
264                 return EFI_ST_FAILURE;
265         }
266         ret = boottime->free_pool(dp3);
267         if (ret != EFI_ST_SUCCESS) {
268                 efi_st_error("FreePool failed\n");
269                 return EFI_ST_FAILURE;
270         }
271
272         return EFI_ST_SUCCESS;
273 }
274
275 EFI_UNIT_TEST(dputil) = {
276         .name = "device path utilities protocol",
277         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
278         .setup = setup,
279         .execute = execute,
280 };