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