blob: 2b5384f21ba3f06f04ab11d1e988a0a7cadf55c4 [file] [log] [blame]
Heinrich Schuchardt5500d712018-04-16 07:59:10 +02001/*
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
13static struct efi_boot_services *boottime;
14
15static efi_guid_t guid_device_path_utilities_protocol =
16 EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
17
18struct 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 */
28static 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 */
55static 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 */
93static 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
281EFI_UNIT_TEST(dputil) = {
282 .name = "device path utilities protocol",
283 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
284 .setup = setup,
285 .execute = execute,
286};