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