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