1 /*
2  *  EFI device path interface
3  *
4  *  Copyright (c) 2017 Leif Lindholm
5  *
6  *  SPDX-License-Identifier:     GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <efi_loader.h>
11 
12 const efi_guid_t efi_guid_device_path_utilities_protocol =
13 		EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
14 
15 /*
16  * Get size of a device path.
17  *
18  * This function implements the GetDevicePathSize service of the device path
19  * utilities protocol. The device path length includes the end of path tag
20  * which may be an instance end.
21  *
22  * See the Unified Extensible Firmware Interface (UEFI) specification
23  * for details.
24  *
25  * @device_path		device path
26  * @return		size in bytes
27  */
28 static efi_uintn_t EFIAPI get_device_path_size(
29 	const struct efi_device_path *device_path)
30 {
31 	efi_uintn_t sz = 0;
32 
33 	EFI_ENTRY("%pD", device_path);
34 	/* size includes the END node: */
35 	if (device_path)
36 		sz = efi_dp_size(device_path) + sizeof(struct efi_device_path);
37 	return EFI_EXIT(sz);
38 }
39 
40 /*
41  * Duplicate a device path.
42  *
43  * This function implements the DuplicateDevicePath service of the device path
44  * utilities protocol.
45  *
46  * The UEFI spec does not indicate what happens to the end tag. We follow the
47  * EDK2 logic: In case the device path ends with an end of instance tag, the
48  * copy will also end with an end of instance tag.
49  *
50  * See the Unified Extensible Firmware Interface (UEFI) specification
51  * for details.
52  *
53  * @device_path		device path
54  * @return		copy of the device path
55  */
56 static struct efi_device_path * EFIAPI duplicate_device_path(
57 	const struct efi_device_path *device_path)
58 {
59 	EFI_ENTRY("%pD", device_path);
60 	return EFI_EXIT(efi_dp_dup(device_path));
61 }
62 
63 /*
64  * Append device path.
65  *
66  * This function implements the AppendDevicePath service of the device path
67  * utilities protocol.
68  *
69  * See the Unified Extensible Firmware Interface (UEFI) specification
70  * for details.
71  *
72  * @src1		1st device path
73  * @src2		2nd device path
74  * @return		concatenated device path
75  */
76 static struct efi_device_path * EFIAPI append_device_path(
77 	const struct efi_device_path *src1,
78 	const struct efi_device_path *src2)
79 {
80 	EFI_ENTRY("%pD, %pD", src1, src2);
81 	return EFI_EXIT(efi_dp_append(src1, src2));
82 }
83 
84 /*
85  * Append device path node.
86  *
87  * This function implements the AppendDeviceNode service of the device path
88  * utilities protocol.
89  *
90  * See the Unified Extensible Firmware Interface (UEFI) specification
91  * for details.
92  *
93  * @device_path		device path
94  * @device_node		device node
95  * @return		concatenated device path
96  */
97 static struct efi_device_path * EFIAPI append_device_node(
98 	const struct efi_device_path *device_path,
99 	const struct efi_device_path *device_node)
100 {
101 	EFI_ENTRY("%pD, %p", device_path, device_node);
102 	return EFI_EXIT(efi_dp_append_node(device_path, device_node));
103 }
104 
105 /*
106  * Append device path instance.
107  *
108  * This function implements the AppendDevicePathInstance service of the device
109  * path utilities protocol.
110  *
111  * See the Unified Extensible Firmware Interface (UEFI) specification
112  * for details.
113  *
114  * @device_path			1st device path
115  * @device_path_instance	2nd device path
116  * @return			concatenated device path
117  */
118 static struct efi_device_path * EFIAPI append_device_path_instance(
119 	const struct efi_device_path *device_path,
120 	const struct efi_device_path *device_path_instance)
121 {
122 	EFI_ENTRY("%pD, %pD", device_path, device_path_instance);
123 	return EFI_EXIT(efi_dp_append_instance(device_path,
124 					       device_path_instance));
125 }
126 
127 /*
128  * Get next device path instance.
129  *
130  * This function implements the GetNextDevicePathInstance service of the device
131  * path utilities protocol.
132  *
133  * See the Unified Extensible Firmware Interface (UEFI) specification
134  * for details.
135  *
136  * @device_path_instance	next device path instance
137  * @device_path_instance_size	size of the device path instance
138  * @return			concatenated device path
139  */
140 static struct efi_device_path * EFIAPI get_next_device_path_instance(
141 	struct efi_device_path **device_path_instance,
142 	efi_uintn_t *device_path_instance_size)
143 {
144 	EFI_ENTRY("%pD, %p", device_path_instance, device_path_instance_size);
145 	return EFI_EXIT(efi_dp_get_next_instance(device_path_instance,
146 						 device_path_instance_size));
147 }
148 
149 /*
150  * Check if a device path contains more than one instance.
151  *
152  * This function implements the AppendDeviceNode service of the device path
153  * utilities protocol.
154  *
155  * See the Unified Extensible Firmware Interface (UEFI) specification
156  * for details.
157  *
158  * @device_path		device path
159  * @device_node		device node
160  * @return		concatenated device path
161  */
162 static bool EFIAPI is_device_path_multi_instance(
163 	const struct efi_device_path *device_path)
164 {
165 	EFI_ENTRY("%pD", device_path);
166 	return EFI_EXIT(efi_dp_is_multi_instance(device_path));
167 }
168 
169 /*
170  * Create device node.
171  *
172  * This function implements the CreateDeviceNode service of the device path
173  * utilities protocol.
174  *
175  * See the Unified Extensible Firmware Interface (UEFI) specification
176  * for details.
177  *
178  * @node_type		node type
179  * @node_sub_type	node sub type
180  * @node_length		node length
181  * @return		device path node
182  */
183 static struct efi_device_path * EFIAPI create_device_node(
184 	uint8_t node_type, uint8_t node_sub_type, uint16_t node_length)
185 {
186 	EFI_ENTRY("%u, %u, %u", node_type, node_sub_type, node_length);
187 	return EFI_EXIT(efi_dp_create_device_node(node_type, node_sub_type,
188 			node_length));
189 }
190 
191 const struct efi_device_path_utilities_protocol efi_device_path_utilities = {
192 	.get_device_path_size = get_device_path_size,
193 	.duplicate_device_path = duplicate_device_path,
194 	.append_device_path = append_device_path,
195 	.append_device_node = append_device_node,
196 	.append_device_path_instance = append_device_path_instance,
197 	.get_next_device_path_instance = get_next_device_path_instance,
198 	.is_device_path_multi_instance = is_device_path_multi_instance,
199 	.create_device_node = create_device_node,
200 };
201