Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | /* |
| 3 | * EFI device path functions |
| 4 | * |
| 5 | * (C) Copyright 2017 Rob Clark |
| 6 | */ |
| 7 | |
| 8 | #ifndef EFI_DEVICE_PATH_H |
| 9 | #define EFI_DEVICE_PATH_H |
| 10 | |
| 11 | #include <efi.h> |
| 12 | |
| 13 | struct blk_desc; |
| 14 | struct efi_load_option; |
| 15 | struct udevice; |
| 16 | |
| 17 | /* |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 18 | * EFI_DP_END - Template end node for EFI device paths. |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 19 | * |
| 20 | * Represents the terminating node of an EFI device path. |
| 21 | * It has a type of DEVICE_PATH_TYPE_END and sub_type DEVICE_PATH_SUB_TYPE_END |
| 22 | */ |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 23 | extern const struct efi_device_path EFI_DP_END; |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 24 | |
| 25 | /** |
| 26 | * efi_dp_next() - Iterate to next block in device-path |
| 27 | * |
| 28 | * Advance to the next node in an EFI device path. |
| 29 | * |
| 30 | * @dp: Pointer to the current device path node. |
| 31 | * Return: Pointer to the next device path node, or NULL if at the end |
| 32 | * or if input is NULL. |
| 33 | */ |
| 34 | struct efi_device_path *efi_dp_next(const struct efi_device_path *dp); |
| 35 | |
| 36 | /** |
| 37 | * efi_dp_match() - Compare two device-paths |
| 38 | * |
| 39 | * Compare two device paths node by node. The comparison stops when an End |
| 40 | * node is reached in the shorter of the two paths. This is useful, for example, |
| 41 | * to compare a device-path representing a device with one representing a file |
| 42 | * on that device, or a device with a parent device. |
| 43 | * |
| 44 | * @a: Pointer to the first device path. |
| 45 | * @b: Pointer to the second device path. |
| 46 | * Return: An integer less than, equal to, or greater than zero if the first |
| 47 | * differing node in 'a' is found, respectively, to be less than, |
| 48 | * to match, or be greater than the corresponding node in 'b'. Returns 0 |
| 49 | * if they match up to the end of the shorter path. Compares length first, |
| 50 | * then content. |
| 51 | */ |
| 52 | int efi_dp_match(const struct efi_device_path *a, |
| 53 | const struct efi_device_path *b); |
| 54 | |
| 55 | /** |
| 56 | * efi_dp_shorten() - shorten device-path |
| 57 | * |
| 58 | * When creating a short-boot option we want to use a device-path that is |
| 59 | * independent of the location where the block device is plugged in. |
| 60 | * |
| 61 | * UsbWwi() nodes contain a serial number, hard drive paths a partition |
| 62 | * UUID. Both should be unique. |
| 63 | * |
| 64 | * See UEFI spec, section 3.1.2 for "short-form device path". |
| 65 | * |
| 66 | * @dp: original device-path |
| 67 | * Return: shortened device-path or NULL |
| 68 | */ |
| 69 | struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp); |
| 70 | |
| 71 | /** |
| 72 | * efi_dp_find_obj() - find handle by device path |
| 73 | * |
| 74 | * If @rem is provided, the handle with the longest partial match is returned. |
| 75 | * |
| 76 | * @dp: device path to search |
| 77 | * @guid: GUID of protocol that must be installed on path or NULL |
| 78 | * @rem: pointer to receive remaining device path |
| 79 | * Return: matching handle |
| 80 | */ |
| 81 | efi_handle_t efi_dp_find_obj(struct efi_device_path *dp, const efi_guid_t *guid, |
| 82 | struct efi_device_path **rem); |
| 83 | |
| 84 | /** |
| 85 | * efi_dp_last_node() - Determine the last device path node before the end node |
| 86 | * |
| 87 | * Iterate through the device path to find the very last node before |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 88 | * the terminating EFI_DP_END node. |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 89 | * |
| 90 | * @dp: Pointer to the device path. |
| 91 | * Return: Pointer to the last actual data node before the end node if it exists |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 92 | * otherwise NULL (e.g., if dp is NULL or only an EFI_DP_END node). |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 93 | */ |
| 94 | const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp); |
| 95 | |
| 96 | /** |
| 97 | * efi_dp_instance_size() - Get size of the first device path instance |
| 98 | * |
| 99 | * Calculate the total length of all nodes in the first instance of a |
| 100 | * (potentially multi-instance) device path. The size of the instance-specific |
| 101 | * end node (if any) or the final device path. The end node is not included. |
| 102 | * |
| 103 | * @dp: Pointer to the device path. |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 104 | * Return: Size in bytes of the first instance, or 0 if dp is NULL or an |
| 105 | * EFI_DP_END node |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 106 | */ |
| 107 | efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp); |
| 108 | |
| 109 | /** |
| 110 | * efi_dp_size() - Get size of multi-instance device path excluding end node |
| 111 | * |
| 112 | * Calculate the total size of the entire device path structure, traversing |
| 113 | * through all instances, up to but not including the final |
| 114 | * END_ENTIRE_DEVICE_PATH node. |
| 115 | * |
| 116 | * @dp: Pointer to the device path. |
| 117 | * Return: Total size in bytes of all nodes in the device path (excluding the |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 118 | * final EFI_DP_END node), or 0 if dp is NULL. |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 119 | */ |
| 120 | efi_uintn_t efi_dp_size(const struct efi_device_path *dp); |
| 121 | |
| 122 | /** |
| 123 | * efi_dp_dup() - Copy multi-instance device path |
| 124 | * |
| 125 | * Duplicate the given device path, including its end node(s). |
| 126 | * The caller is responsible for freeing the allocated memory (e.g., |
| 127 | * using efi_free()). |
| 128 | * |
| 129 | * @dp: Pointer to the device path to duplicate. |
| 130 | * Return: Pointer to the newly allocated and copied device path, or NULL on |
| 131 | * allocation failure or if dp is NULL. |
| 132 | */ |
| 133 | struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp); |
| 134 | |
| 135 | /** |
| 136 | * efi_dp_concat() - Concatenate two device paths and terminate the result |
| 137 | * |
| 138 | * @dp1: First device path |
| 139 | * @dp2: Second device path |
| 140 | * @split_end_node: |
| 141 | * - 0 to concatenate (dp1 is assumed not to have an end node or it's ignored, |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 142 | * dp2 is appended, then one EFI_DP_END node) |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 143 | * - 1 to concatenate with end node added as separator (dp1, END_THIS_INSTANCE, |
| 144 | * dp2, END_ENTIRE) |
| 145 | * |
| 146 | * Size of dp1 excluding last end node to concatenate with end node as |
| 147 | * separator in case dp1 contains an end node (dp1 (partial), END_THIS_INSTANCE, |
| 148 | * dp2, END_ENTIRE) |
| 149 | * |
| 150 | * Return: |
| 151 | * concatenated device path or NULL. Caller must free the returned value. |
| 152 | */ |
| 153 | struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, |
| 154 | const struct efi_device_path *dp2, |
| 155 | size_t split_end_node); |
| 156 | |
| 157 | /** |
| 158 | * efi_dp_append_node() - Append a single node to a device path |
| 159 | * |
| 160 | * Create a new device path by appending a given node to an existing |
| 161 | * device path. |
| 162 | * If the original device path @dp is NULL, a new path is created |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 163 | * with the given @node followed by an EFI_DP_END node. |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 164 | * If the @node is NULL and @dp is not NULL, the original path @dp is |
| 165 | * duplicated. |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 166 | * If both @dp and @node are NULL, a path with only an EFI_DP_END node is |
| 167 | * returned. |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 168 | * The caller must free the returned path (e.g., using efi_free()). |
| 169 | * |
| 170 | * @dp: Original device path (can be NULL). |
| 171 | * @node: Node to append (can be NULL). |
| 172 | * Return: New device path with the node appended, or NULL on allocation |
| 173 | * failure. |
| 174 | */ |
| 175 | struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp, |
| 176 | const struct efi_device_path *node); |
| 177 | |
| 178 | /** |
| 179 | * efi_dp_create_device_node() - Create a new device path node |
| 180 | * |
| 181 | * Allocate and initialise the header of a new EFI device path node with the |
| 182 | * given type, sub-type, and length. The content of the node beyond the basic |
| 183 | * efi_device_path header is zeroed by efi_alloc. |
| 184 | * |
| 185 | * @type: Device path type. |
| 186 | * @sub_type: Device path sub-type. |
| 187 | * @length: Length of the node (must be >= sizeof(struct efi_device_path)). |
| 188 | * Return: Pointer to the new device path node, or NULL on allocation failure |
| 189 | * or if length is invalid. |
| 190 | */ |
| 191 | struct efi_device_path *efi_dp_create_device_node(const u8 type, |
| 192 | const u8 sub_type, |
| 193 | const u16 length); |
| 194 | |
| 195 | /** |
| 196 | * efi_dp_append_instance() - Append a device path instance to another |
| 197 | * |
| 198 | * Concatenate two device paths, treating the second path (@dpi) as a new |
| 199 | * instance appended to the first path (@dp). An END_THIS_INSTANCE node is |
| 200 | * inserted between @dp and @dpi if @dp is not NULL. |
| 201 | * If @dp is NULL, @dpi is duplicated (and terminated appropriately). |
| 202 | * @dpi must not be NULL. |
| 203 | * The caller is responsible for freeing the returned path (e.g., using |
| 204 | * efi_free()). |
| 205 | * |
| 206 | * @dp: The base device path. If NULL, @dpi is duplicated. |
| 207 | * @dpi: The device path instance to append. Must not be NULL. |
| 208 | * Return: A new device path with @dpi appended as a new instance, or NULL on |
| 209 | * error (e.g. allocation failure, @dpi is NULL). |
| 210 | */ |
| 211 | struct efi_device_path * |
| 212 | efi_dp_append_instance(const struct efi_device_path *dp, |
| 213 | const struct efi_device_path *dpi); |
| 214 | |
| 215 | /** |
| 216 | * efi_dp_get_next_instance() - Extract the next dp instance |
| 217 | * |
| 218 | * Given a pointer to a pointer to a device path (@dp), this function extracts |
| 219 | * the first instance from the path. It allocates a new path for this extracted |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 220 | * instance (including its instance-specific EFI_DP_END node). The input pointer |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 221 | * (*@dp) is then updated to point to the start of the next instance in the |
| 222 | * original path, or set to NULL if no more instances remain. |
| 223 | * The caller is responsible for freeing the returned instance path (e.g., |
| 224 | * using efi_free()). |
| 225 | * |
| 226 | * @dp: On input, a pointer to a pointer to the multi-instance device path. |
| 227 | * On output, *@dp is updated to point to the start of the next instance, |
| 228 | * or NULL if no more instances. |
| 229 | * @size: Optional pointer to an efi_uintn_t variable that will receive the size |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 230 | * of the extracted instance path (including its EFI_DP_END node). |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 231 | * Return: Pointer to a newly allocated device path for the extracted instance, |
| 232 | * or NULL if no instance could be extracted or an error occurred (e.g., |
| 233 | * allocation failure). |
| 234 | */ |
| 235 | struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp, |
| 236 | efi_uintn_t *size); |
| 237 | |
| 238 | /** |
| 239 | * efi_dp_is_multi_instance() - Check if a device path is multi-instance |
| 240 | * |
| 241 | * Traverse the device path to its end. It is considered multi-instance if an |
| 242 | * END_THIS_INSTANCE_DEVICE_PATH node (type DEVICE_PATH_TYPE_END, sub-type |
| 243 | * DEVICE_PATH_SUB_TYPE_INSTANCE_END) is encountered before the final |
| 244 | * END_ENTIRE_DEVICE_PATH node. |
| 245 | * |
| 246 | * @dp: The device path to check. |
| 247 | * Return: True if the device path contains multiple instances, false otherwise |
| 248 | * (including if @dp is NULL). |
| 249 | */ |
| 250 | bool efi_dp_is_multi_instance(const struct efi_device_path *dp); |
| 251 | |
| 252 | /** |
| 253 | * efi_dp_from_part() - Construct a dp from a partition on a block device |
| 254 | * |
| 255 | * Create a full device path for a specified partition on a given block device. |
| 256 | * If the partition number @part is 0, the path is for the block device itself. |
| 257 | * The caller is responsible for freeing the allocated memory (e.g., using |
| 258 | * efi_free()). |
| 259 | * |
| 260 | * @desc: Pointer to the block device descriptor. |
| 261 | * @part: Partition number (0 for the whole device, >0 for a specific |
| 262 | * partition). |
| 263 | * Return: Pointer to the newly created device path, or NULL on allocation |
| 264 | * failure or if the device/partition is not found or invalid. |
| 265 | */ |
| 266 | struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part); |
| 267 | |
| 268 | /** |
| 269 | * efi_dp_part_node() - Create a device node for a block device partition |
| 270 | * |
| 271 | * Creates a single device path node representing a specific partition |
| 272 | * (e.g., HardDrivePath or CDROMPath, depending on desc->part_type). |
| 273 | * It does not create the full path from the root, only the partition-specific |
| 274 | * node. The caller is responsible for freeing the allocated memory (e.g., |
| 275 | * using efi_free()). |
| 276 | * |
| 277 | * @desc: Pointer to the block device descriptor. |
| 278 | * @part: Partition number (must be > 0 and correspond to a valid partition on |
| 279 | * the device). |
| 280 | * Return: Pointer to the new device path node for the partition, or NULL on |
| 281 | * allocation * failure or error in getting partition information. |
| 282 | */ |
| 283 | struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part); |
| 284 | |
| 285 | /** |
| 286 | * efi_dp_from_file() - append file path node to device path. |
| 287 | * |
| 288 | * @dp: device path or NULL |
| 289 | * @path: file path or NULL |
| 290 | * Return: device path or NULL in case of an error |
| 291 | */ |
| 292 | struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp, |
| 293 | const char *path); |
| 294 | |
| 295 | /** |
| 296 | * efi_dp_from_uart() - Create a device path for a UART device. |
| 297 | * |
| 298 | * Construct a device path representing the system's default UART, |
| 299 | * typically based on the U-Boot device model root and a UART messaging node. |
| 300 | * The caller is responsible for freeing the allocated memory (e.g., using |
| 301 | * efi_free()). |
| 302 | * |
| 303 | * Return: Pointer to the new UART device path, or NULL on allocation failure. |
| 304 | */ |
| 305 | struct efi_device_path *efi_dp_from_uart(void); |
| 306 | |
| 307 | /** |
| 308 | * efi_dp_from_eth() - Create a device path for an Ethernet device |
| 309 | * |
| 310 | * Construct a device path representing the given device. The caller is |
| 311 | * responsible for freeing the allocated memory (e.g. using efi_free()) |
| 312 | * |
| 313 | * @dev: UCLASS_ETH device to process |
| 314 | * |
| 315 | * Return: Pointer to the new Ethernet device path, or NULL on allocation |
| 316 | * failure |
| 317 | */ |
| 318 | struct efi_device_path *efi_dp_from_eth(struct udevice *dev); |
| 319 | |
| 320 | /** |
| 321 | * efi_dp_from_mem() - Construct a device-path for a memory-mapped region |
| 322 | * |
| 323 | * Create an EFI device path representing a specific memory region, defined |
| 324 | * by its type, start address, and size. |
| 325 | * The caller is responsible for freeing the allocated memory (e.g., |
| 326 | * using efi_free()). |
| 327 | * |
| 328 | * @memory_type: EFI memory type (e.g., EFI_RESERVED_MEMORY_TYPE). |
| 329 | * @start_address: Starting address of the memory region. |
| 330 | * @size: Size of the memory region in bytes. |
| 331 | * Return: Pointer to the new memory device path, or NULL on allocation failure |
| 332 | */ |
| 333 | struct efi_device_path *efi_dp_from_mem(u32 memory_type, u64 start_address, |
| 334 | size_t size); |
| 335 | |
| 336 | /** |
| 337 | * efi_dp_split_file_path() - split of relative file path from device path |
| 338 | * |
| 339 | * Given a device path indicating a file on a device, separate the device |
| 340 | * path in two: the device path of the actual device and the file path |
| 341 | * relative to this device. |
| 342 | * |
| 343 | * @full_path: device path including device and file path |
| 344 | * @device_path: path of the device |
| 345 | * @file_path: relative path of the file or NULL if there is none |
| 346 | * Return: status code |
| 347 | */ |
| 348 | efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path, |
| 349 | struct efi_device_path **device_path, |
| 350 | struct efi_device_path **file_path); |
| 351 | |
| 352 | /** |
| 353 | * efi_dp_from_name() - convert U-Boot device and file path to device path |
| 354 | * |
| 355 | * @dev: U-Boot device, e.g. 'mmc' |
| 356 | * @devnr: U-Boot device number, e.g. 1 for 'mmc:1' |
| 357 | * @path: file path relative to U-Boot device, may be NULL |
| 358 | * @device: pointer to receive device path of the device |
| 359 | * @file: pointer to receive device path for the file |
| 360 | * Return: status code |
| 361 | */ |
| 362 | efi_status_t efi_dp_from_name(const char *dev, const char *devnr, |
| 363 | const char *path, struct efi_device_path **device, |
| 364 | struct efi_device_path **file); |
| 365 | |
| 366 | /** |
| 367 | * efi_dp_check_length() - check length of a device path |
| 368 | * |
| 369 | * @dp: pointer to device path |
| 370 | * @maxlen: maximum length of the device path |
| 371 | * Return: |
| 372 | * * length of the device path if it is less or equal @maxlen |
| 373 | * * -1 if the device path is longer then @maxlen |
| 374 | * * -1 if a device path node has a length of less than 4 |
| 375 | * * -EINVAL if maxlen exceeds SSIZE_MAX |
| 376 | */ |
| 377 | ssize_t efi_dp_check_length(const struct efi_device_path *dp, |
| 378 | const size_t maxlen); |
| 379 | |
| 380 | /** |
| 381 | * efi_dp_from_lo() - get device-path from load option |
| 382 | * |
| 383 | * The load options in U-Boot may contain multiple concatenated device-paths. |
| 384 | * The first device-path indicates the EFI binary to execute. Subsequent |
| 385 | * device-paths start with a VenMedia node where the GUID identifies the |
| 386 | * function (initrd or fdt). |
| 387 | * |
| 388 | * @lo: EFI load option containing a valid device path |
| 389 | * @guid: GUID identifying device-path or NULL for the EFI binary |
| 390 | * |
| 391 | * Return: |
| 392 | * device path excluding the matched VenMedia node or NULL. |
| 393 | * Caller must free the returned value. |
| 394 | */ |
| 395 | struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, |
| 396 | const efi_guid_t *guid); |
| 397 | |
| 398 | /** |
| 399 | * search_gpt_dp_node() - search gpt device path node |
| 400 | * |
| 401 | * @device_path: device path |
| 402 | * |
| 403 | * Return: pointer to the gpt device path node |
| 404 | */ |
| 405 | struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path); |
| 406 | |
| 407 | /** |
| 408 | * efi_dp_from_http() - set device path from http |
| 409 | * |
| 410 | * Set the device path to an IPv4 path as provided by efi_dp_from_ipv4 |
| 411 | * concatenated with a device path of subtype DEVICE_PATH_SUB_TYPE_MSG_URI, |
Simon Glass | c88552c | 2025-05-24 11:28:23 -0600 | [diff] [blame^] | 412 | * and an EFI_DP_END node. |
Simon Glass | 37972f4 | 2025-05-24 11:28:21 -0600 | [diff] [blame] | 413 | * |
| 414 | * @server: URI of remote server |
| 415 | * @dev: net udevice |
| 416 | * Return: pointer to HTTP device path, NULL on error |
| 417 | */ |
| 418 | struct efi_device_path *efi_dp_from_http(const char *server, |
| 419 | struct udevice *dev); |
| 420 | |
| 421 | #endif /* EFI_DEVICE_PATH_H */ |