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 */
setup(const efi_handle_t img_handle,const struct efi_system_table * systable)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 */
create_single_node_device_path(unsigned int length,struct efi_device_path ** dp)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 */
execute(void)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 ret = boottime->free_pool(dp2);
260 if (ret != EFI_ST_SUCCESS) {
261 efi_st_error("FreePool failed\n");
262 return EFI_ST_FAILURE;
263 }
264
265 /* Clean up */
266 ret = boottime->free_pool(dp2);
267 if (ret != EFI_ST_SUCCESS) {
268 efi_st_error("FreePool failed\n");
269 return EFI_ST_FAILURE;
270 }
271 ret = boottime->free_pool(dp3);
272 if (ret != EFI_ST_SUCCESS) {
273 efi_st_error("FreePool failed\n");
274 return EFI_ST_FAILURE;
275 }
276
277 return EFI_ST_SUCCESS;
278 }
279
280 EFI_UNIT_TEST(dputil) = {
281 .name = "device path utilities protocol",
282 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
283 .setup = setup,
284 .execute = execute,
285 };
286