]>
Commit | Line | Data |
---|---|---|
562d2849 | 1 | /*++ |
2 | ||
3 | Copyright (c) 2006, Intel Corporation | |
4 | All rights reserved. This program and the accompanying materials | |
5 | are licensed and made available under the terms and conditions of the BSD License | |
6 | which accompanies this distribution. The full text of the license may be found at | |
7 | http://opensource.org/licenses/bsd-license.php | |
8 | ||
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
11 | ||
12 | Module Name: | |
13 | ||
14 | DevicePathUtilities.c | |
15 | ||
16 | Abstract: | |
17 | ||
18 | Implementation file for Device Path Utilities Protocol | |
19 | ||
20 | --*/ | |
21 | ||
22 | #include <protocol/DevicePathUtilities.h> | |
23 | #include <protocol/DevicePath.h> | |
24 | #include "DevicePath.h" | |
25 | ||
26 | UINTN | |
27 | GetDevicePathSize ( | |
28 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
29 | ) | |
30 | /*++ | |
31 | ||
32 | Routine Description: | |
33 | Returns the size of the device path, in bytes. | |
34 | ||
35 | Arguments: | |
36 | DevicePath - Points to the start of the EFI device path. | |
37 | ||
38 | Returns: | |
39 | Size - Size of the specified device path, in bytes, including the end-of-path tag. | |
40 | ||
41 | --*/ | |
42 | { | |
43 | CONST EFI_DEVICE_PATH_PROTOCOL *Start; | |
44 | ||
45 | if (DevicePath == NULL) { | |
46 | return 0; | |
47 | } | |
48 | ||
49 | // | |
50 | // Search for the end of the device path structure | |
51 | // | |
52 | Start = (EFI_DEVICE_PATH_PROTOCOL *) DevicePath; | |
53 | while (!IsDevicePathEnd (DevicePath)) { | |
54 | DevicePath = NextDevicePathNode (DevicePath); | |
55 | } | |
56 | ||
57 | // | |
58 | // Compute the size and add back in the size of the end device path structure | |
59 | // | |
60 | return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
61 | } | |
62 | ||
63 | EFI_DEVICE_PATH_PROTOCOL * | |
64 | DuplicateDevicePath ( | |
65 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
66 | ) | |
67 | /*++ | |
68 | ||
69 | Routine Description: | |
70 | Create a duplicate of the specified path. | |
71 | ||
72 | Arguments: | |
73 | DevicePath - Points to the source EFI device path. | |
74 | ||
75 | Returns: | |
76 | Pointer - A pointer to the duplicate device path. | |
77 | NULL - Insufficient memory. | |
78 | ||
79 | --*/ | |
80 | { | |
81 | EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
82 | UINTN Size; | |
83 | ||
84 | if (DevicePath == NULL) { | |
85 | return NULL; | |
86 | } | |
87 | ||
88 | // | |
89 | // Compute the size | |
90 | // | |
91 | Size = GetDevicePathSize (DevicePath); | |
92 | if (Size == 0) { | |
93 | return NULL; | |
94 | } | |
95 | ||
96 | // | |
97 | // Allocate space for duplicate device path | |
98 | // | |
99 | NewDevicePath = AllocateCopyPool (Size, (VOID *) DevicePath); | |
100 | ||
101 | return NewDevicePath; | |
102 | } | |
103 | ||
104 | EFI_DEVICE_PATH_PROTOCOL * | |
105 | AppendDevicePath ( | |
106 | IN CONST EFI_DEVICE_PATH_PROTOCOL *Src1, | |
107 | IN CONST EFI_DEVICE_PATH_PROTOCOL *Src2 | |
108 | ) | |
109 | /*++ | |
110 | ||
111 | Routine Description: | |
112 | Create a new path by appending the second device path to the first. | |
113 | ||
114 | Arguments: | |
115 | Src1 - Points to the first device path. If NULL, then it is ignored. | |
116 | Src2 - Points to the second device path. If NULL, then it is ignored. | |
117 | ||
118 | Returns: | |
119 | Pointer - A pointer to the newly created device path. | |
120 | NULL - Memory could not be allocated | |
121 | or either DevicePath or DeviceNode is NULL. | |
122 | ||
123 | --*/ | |
124 | { | |
125 | UINTN Size; | |
126 | UINTN Size1; | |
127 | UINTN Size2; | |
128 | EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
129 | EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath; | |
130 | ||
131 | // | |
132 | // If there's only 1 path, just duplicate it | |
133 | // | |
134 | if (Src1 == NULL) { | |
135 | ASSERT (!IsDevicePathUnpacked (Src2)); | |
136 | return DuplicateDevicePath (Src2); | |
137 | } | |
138 | ||
139 | if (Src2 == NULL) { | |
140 | ASSERT (!IsDevicePathUnpacked (Src1)); | |
141 | return DuplicateDevicePath (Src1); | |
142 | } | |
143 | ||
144 | // | |
145 | // Allocate space for the combined device path. It only has one end node of | |
146 | // length EFI_DEVICE_PATH_PROTOCOL | |
147 | // | |
148 | Size1 = GetDevicePathSize (Src1); | |
149 | Size2 = GetDevicePathSize (Src2); | |
150 | Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
151 | ||
152 | NewDevicePath = AllocateCopyPool (Size, (VOID *) Src1); | |
153 | ||
154 | if (NewDevicePath != NULL) { | |
155 | // | |
156 | // Over write Src1 EndNode and do the copy | |
157 | // | |
158 | SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL))); | |
159 | CopyMem (SecondDevicePath, (VOID *) Src2, Size2); | |
160 | } | |
161 | ||
162 | return NewDevicePath; | |
163 | } | |
164 | ||
165 | EFI_DEVICE_PATH_PROTOCOL * | |
166 | AppendDeviceNode ( | |
167 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
168 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DeviceNode | |
169 | ) | |
170 | /*++ | |
171 | ||
172 | Routine Description: | |
173 | Creates a new path by appending the device node to the device path. | |
174 | ||
175 | Arguments: | |
176 | DevicePath - Points to the device path. | |
177 | DeviceNode - Points to the device node. | |
178 | ||
179 | Returns: | |
180 | Pointer - A pointer to the allocated device node. | |
181 | NULL - Memory could not be allocated | |
182 | or either DevicePath or DeviceNode is NULL. | |
183 | ||
184 | --*/ | |
185 | { | |
186 | EFI_DEVICE_PATH_PROTOCOL *Temp; | |
187 | EFI_DEVICE_PATH_PROTOCOL *NextNode; | |
188 | EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
189 | UINTN NodeLength; | |
190 | ||
191 | if ((DevicePath == NULL) || (DeviceNode == NULL)) { | |
192 | return NULL; | |
193 | } | |
194 | ||
195 | // | |
196 | // Build a Node that has a terminator on it | |
197 | // | |
198 | NodeLength = DevicePathNodeLength (DeviceNode); | |
199 | ||
200 | Temp = AllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), (VOID *) DeviceNode); | |
201 | if (Temp == NULL) { | |
202 | return NULL; | |
203 | } | |
204 | ||
205 | // | |
206 | // Add and end device path node to convert Node to device path | |
207 | // | |
208 | NextNode = NextDevicePathNode (Temp); | |
209 | SetDevicePathEndNode (NextNode); | |
210 | ||
211 | // | |
212 | // Append device paths | |
213 | // | |
214 | NewDevicePath = AppendDevicePath (DevicePath, Temp); | |
215 | gBS->FreePool (Temp); | |
216 | return NewDevicePath; | |
217 | } | |
218 | ||
219 | EFI_DEVICE_PATH_PROTOCOL * | |
220 | AppendDevicePathInstance ( | |
221 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
222 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance | |
223 | ) | |
224 | /*++ | |
225 | ||
226 | Routine Description: | |
227 | Creates a new path by appending the specified device path instance to the specified device path. | |
228 | ||
229 | Arguments: | |
230 | DevicePath - Points to the device path. If NULL, then ignored. | |
231 | DevicePathInstance - Points to the device path instance. | |
232 | ||
233 | Returns: | |
234 | Pointer - A pointer to the newly created device path | |
235 | NULL - Memory could not be allocated or DevicePathInstance is NULL. | |
236 | ||
237 | --*/ | |
238 | { | |
239 | UINT8 *Ptr; | |
240 | EFI_DEVICE_PATH_PROTOCOL *DevPath; | |
241 | UINTN SrcSize; | |
242 | UINTN InstanceSize; | |
243 | ||
244 | if (DevicePathInstance == NULL) { | |
245 | return NULL; | |
246 | } | |
247 | ||
248 | if (DevicePath == NULL) { | |
249 | return DuplicateDevicePath (DevicePathInstance); | |
250 | } | |
251 | ||
252 | SrcSize = GetDevicePathSize (DevicePath); | |
253 | InstanceSize = GetDevicePathSize (DevicePathInstance); | |
254 | ||
255 | Ptr = AllocateCopyPool (SrcSize + InstanceSize, (VOID *) DevicePath); | |
256 | if (Ptr != NULL) { | |
257 | ||
258 | DevPath = (EFI_DEVICE_PATH_PROTOCOL *) (Ptr + (SrcSize - sizeof (EFI_DEVICE_PATH_PROTOCOL))); | |
259 | // | |
260 | // Convert the End to an End Instance, since we are | |
261 | // appending another instacne after this one its a good | |
262 | // idea. | |
263 | // | |
264 | DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; | |
265 | ||
266 | DevPath = NextDevicePathNode (DevPath); | |
267 | CopyMem (DevPath, (VOID *) DevicePathInstance, InstanceSize); | |
268 | } | |
269 | ||
270 | return (EFI_DEVICE_PATH_PROTOCOL *) Ptr; | |
271 | } | |
272 | ||
273 | EFI_DEVICE_PATH_PROTOCOL * | |
274 | GetNextDevicePathInstance ( | |
275 | IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathInstance, | |
276 | OUT UINTN *DevicePathInstanceSize | |
277 | ) | |
278 | /*++ | |
279 | ||
280 | Routine Description: | |
281 | Creates a copy of the current device path instance and returns a pointer to the next device path instance. | |
282 | ||
283 | Arguments: | |
284 | DevicePathInstance - On input, this holds the pointer to the current device path | |
285 | instance. On output, this holds the pointer to the next | |
286 | device path instance or NULL if there are no more device | |
287 | path instances in the device path. | |
288 | DevicePathInstanceSize - On output, this holds the size of the device path instance, | |
289 | in bytes or zero, if DevicePathInstance is zero. | |
290 | ||
291 | Returns: | |
292 | Pointer - A pointer to the copy of the current device path instance. | |
293 | NULL - DevicePathInstace was NULL on entry or there was insufficient memory. | |
294 | ||
295 | --*/ | |
296 | { | |
297 | EFI_DEVICE_PATH_PROTOCOL *DevPath; | |
298 | EFI_DEVICE_PATH_PROTOCOL *ReturnValue; | |
299 | UINT8 Temp; | |
300 | ||
301 | if (*DevicePathInstance == NULL) { | |
302 | if (DevicePathInstanceSize != NULL) { | |
303 | *DevicePathInstanceSize = 0; | |
304 | } | |
305 | ||
306 | return NULL; | |
307 | } | |
308 | ||
309 | // | |
310 | // Find the end of the device path instance | |
311 | // | |
312 | DevPath = *DevicePathInstance; | |
313 | while (!IsDevicePathEndType (DevPath)) { | |
314 | DevPath = NextDevicePathNode (DevPath); | |
315 | } | |
316 | ||
317 | // | |
318 | // Compute the size of the device path instance | |
319 | // | |
320 | if (DevicePathInstanceSize != NULL) { | |
321 | *DevicePathInstanceSize = ((UINTN) DevPath - (UINTN) (*DevicePathInstance)) + sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
322 | } | |
323 | ||
324 | // | |
325 | // Make a copy and return the device path instance | |
326 | // | |
327 | Temp = DevPath->SubType; | |
328 | DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; | |
329 | ReturnValue = DuplicateDevicePath (*DevicePathInstance); | |
330 | DevPath->SubType = Temp; | |
331 | ||
332 | // | |
333 | // If DevPath is the end of an entire device path, then another instance | |
334 | // does not follow, so *DevicePath is set to NULL. | |
335 | // | |
336 | if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) { | |
337 | *DevicePathInstance = NULL; | |
338 | } else { | |
339 | *DevicePathInstance = NextDevicePathNode (DevPath); | |
340 | } | |
341 | ||
342 | return ReturnValue; | |
343 | } | |
344 | ||
345 | BOOLEAN | |
346 | IsDevicePathMultiInstance ( | |
347 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
348 | ) | |
349 | /*++ | |
350 | ||
351 | Routine Description: | |
352 | Returns whether a device path is multi-instance. | |
353 | ||
354 | Arguments: | |
355 | DevicePath - Points to the device path. If NULL, then ignored. | |
356 | ||
357 | Returns: | |
358 | TRUE - The device path has more than one instance | |
359 | FALSE - The device path is empty or contains only a single instance. | |
360 | ||
361 | --*/ | |
362 | { | |
363 | CONST EFI_DEVICE_PATH_PROTOCOL *Node; | |
364 | ||
365 | if (DevicePath == NULL) { | |
366 | return FALSE; | |
367 | } | |
368 | ||
369 | Node = DevicePath; | |
370 | while (!IsDevicePathEnd (Node)) { | |
371 | if (EfiIsDevicePathEndInstance (Node)) { | |
372 | return TRUE; | |
373 | } | |
374 | ||
375 | Node = NextDevicePathNode (Node); | |
376 | } | |
377 | ||
378 | return FALSE; | |
379 | } | |
380 | ||
381 | EFI_DEVICE_PATH_PROTOCOL * | |
382 | CreateDeviceNode ( | |
383 | IN UINT8 NodeType, | |
384 | IN UINT8 NodeSubType, | |
385 | IN UINT16 NodeLength | |
386 | ) | |
387 | /*++ | |
388 | ||
389 | Routine Description: | |
390 | Creates a device node | |
391 | ||
392 | Arguments: | |
393 | NodeType - NodeType is the device node type (EFI_DEVICE_PATH.Type) for | |
394 | the new device node. | |
395 | NodeSubType - NodeSubType is the device node sub-type | |
396 | EFI_DEVICE_PATH.SubType) for the new device node. | |
397 | NodeLength - NodeLength is the length of the device node | |
398 | (EFI_DEVICE_PATH.Length) for the new device node. | |
399 | ||
400 | Returns: | |
401 | Pointer - A pointer to the newly created device node. | |
402 | NULL - NodeLength is less than | |
403 | the size of the header or there was insufficient memory. | |
404 | ||
405 | --*/ | |
406 | { | |
407 | EFI_DEVICE_PATH_PROTOCOL *Node; | |
408 | ||
409 | if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { | |
410 | return NULL; | |
411 | } | |
412 | ||
413 | Node = (EFI_DEVICE_PATH_PROTOCOL *) AllocateZeroPool ((UINTN) NodeLength); | |
414 | if (Node != NULL) { | |
415 | Node->Type = NodeType; | |
416 | Node->SubType = NodeSubType; | |
417 | SetDevicePathNodeLength (Node, NodeLength); | |
418 | } | |
419 | ||
420 | return Node; | |
421 | } |