]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.c
remove some comments introduced by tools.
[mirror_edk2.git] / MdePkg / Library / UefiDevicePathLib / UefiDevicePathLib.c
CommitLineData
e386b444 1/** @file\r
2 Device Path services. The thing to remember is device paths are built out of\r
3 nodes. The device path is terminated by an end node that is length\r
4 sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)\r
5 all over this file.\r
6\r
7 The only place where multi-instance device paths are supported is in\r
8 environment varibles. Multi-instance device paths should never be placed\r
9 on a Handle.\r
10\r
11 Copyright (c) 2006, Intel Corporation \r
12 All rights reserved. This program and the accompanying materials \r
13 are licensed and made available under the terms and conditions of the BSD License \r
14 which accompanies this distribution. The full text of the license may be found at \r
15 http://opensource.org/licenses/bsd-license.php \r
16\r
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
19\r
e386b444 20**/\r
21\r
22//\r
c7d265a9 23// The package level header files this module uses\r
e386b444 24//\r
c7d265a9 25#include <Uefi.h>\r
26//\r
27// The protocols, PPI and GUID defintions for this module\r
28//\r
29#include <Protocol/DevicePath.h>\r
30//\r
31// The Library classes this module consumes\r
32//\r
33#include <Library/DevicePathLib.h>\r
34#include <Library/BaseMemoryLib.h>\r
35#include <Library/DebugLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/UefiBootServicesTableLib.h>\r
38#include <Library/BaseLib.h>\r
e386b444 39\r
40/**\r
41 Returns the size of a device path in bytes.\r
42\r
43 This function returns the size, in bytes, of the device path data structure specified by\r
44 DevicePath including the end of device path node. If DevicePath is NULL, then 0 is returned.\r
45\r
46 @param DevicePath A pointer to a device path data structure.\r
47\r
48 @return The size of a device path in bytes.\r
49\r
50**/\r
51UINTN\r
52EFIAPI\r
53GetDevicePathSize (\r
54 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
55 )\r
56{\r
57 CONST EFI_DEVICE_PATH_PROTOCOL *Start;\r
58\r
59 if (DevicePath == NULL) {\r
60 return 0;\r
61 }\r
62\r
63 //\r
64 // Search for the end of the device path structure\r
65 //\r
66 Start = DevicePath;\r
67 while (!EfiIsDevicePathEnd (DevicePath)) {\r
68 DevicePath = EfiNextDevicePathNode (DevicePath);\r
69 }\r
70\r
71 //\r
72 // Compute the size and add back in the size of the end device path structure\r
73 //\r
74 return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
75}\r
76\r
77/**\r
78 Creates a new device path by appending a second device path to a first device path.\r
79\r
80 This function allocates space for a new copy of the device path specified by DevicePath. If\r
81 DevicePath is NULL, then NULL is returned. If the memory is successfully allocated, then the\r
82 contents of DevicePath are copied to the newly allocated buffer, and a pointer to that buffer\r
83 is returned. Otherwise, NULL is returned. \r
84 \r
85 @param DevicePath A pointer to a device path data structure.\r
86\r
87 @return A pointer to the duplicated device path.\r
88\r
89**/\r
90EFI_DEVICE_PATH_PROTOCOL *\r
91EFIAPI\r
92DuplicateDevicePath (\r
93 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
94 )\r
95{\r
96 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
97 UINTN Size;\r
98\r
99 //\r
100 // Compute the size\r
101 //\r
102 Size = GetDevicePathSize (DevicePath);\r
103 if (Size == 0) {\r
104 return NULL;\r
105 }\r
106\r
107 //\r
108 // Allocate space for duplicate device path\r
109 //\r
110 NewDevicePath = AllocateCopyPool (Size, DevicePath);\r
111\r
112 return NewDevicePath;\r
113}\r
114\r
115/**\r
116 Creates a new device path by appending a second device path to a first device path.\r
117\r
118 This function creates a new device path by appending a copy of SecondDevicePath to a copy of\r
119 FirstDevicePath in a newly allocated buffer. Only the end-of-device-path device node from\r
120 SecondDevicePath is retained. The newly created device path is returned. \r
121 If FirstDevicePath is NULL, then it is ignored, and a duplicate of SecondDevicePath is returned. \r
122 If SecondDevicePath is NULL, then it is ignored, and a duplicate of FirstDevicePath is returned. \r
123 If both FirstDevicePath and SecondDevicePath are NULL, then NULL is returned. \r
124 If there is not enough memory for the newly allocated buffer, then NULL is returned.\r
125 The memory for the new device path is allocated from EFI boot services memory. It is the\r
126 responsibility of the caller to free the memory allocated.\r
127\r
128 @param FirstDevicePath A pointer to a device path data structure.\r
129 @param SecondDevicePath A pointer to a device path data structure.\r
130\r
131 @return A pointer to the new device path.\r
132\r
133**/\r
134EFI_DEVICE_PATH_PROTOCOL *\r
135EFIAPI\r
136AppendDevicePath (\r
137 IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath, OPTIONAL\r
138 IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath OPTIONAL\r
139 )\r
140{\r
141 UINTN Size;\r
142 UINTN Size1;\r
143 UINTN Size2;\r
144 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
145 EFI_DEVICE_PATH_PROTOCOL *DevicePath2;\r
146\r
147 //\r
148 // If there's only 1 path, just duplicate it.\r
149 //\r
150 if (FirstDevicePath == NULL) {\r
151 return DuplicateDevicePath (SecondDevicePath);\r
152 }\r
153\r
154 if (SecondDevicePath == NULL) {\r
155 return DuplicateDevicePath (FirstDevicePath);\r
156 }\r
157\r
158 //\r
159 // Allocate space for the combined device path. It only has one end node of\r
160 // length EFI_DEVICE_PATH_PROTOCOL.\r
161 //\r
162 Size1 = GetDevicePathSize (FirstDevicePath);\r
163 Size2 = GetDevicePathSize (SecondDevicePath);\r
164 Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
165\r
166 NewDevicePath = AllocatePool (Size);\r
167\r
168 if (NewDevicePath != NULL) {\r
169 NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);\r
170 //\r
171 // Over write FirstDevicePath EndNode and do the copy\r
172 //\r
173 DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +\r
174 (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
175 CopyMem (DevicePath2, SecondDevicePath, Size2);\r
176 }\r
177\r
178 return NewDevicePath;\r
179}\r
180\r
181/**\r
182 Creates a new path by appending the device node to the device path.\r
183\r
184 This function creates a new device path by appending a copy of the device node specified by\r
185 DevicePathNode to a copy of the device path specified by DevicePath in an allocated buffer.\r
186 The end-of-device-path device node is moved after the end of the appended device node.\r
187 If DevicePath is NULL, then NULL is returned.\r
188 If DevicePathNode is NULL, then NULL is returned.\r
189 If there is not enough memory to allocate space for the new device path, then NULL is returned. \r
190 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to\r
191 free the memory allocated.\r
192\r
193 @param DevicePath A pointer to a device path data structure.\r
194 @param DevicePathNode A pointer to a single device path node.\r
195\r
196 @return A pointer to the new device path.\r
197\r
198**/\r
199EFI_DEVICE_PATH_PROTOCOL *\r
200EFIAPI\r
201AppendDevicePathNode (\r
202 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, OPTIONAL\r
203 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL\r
204 )\r
205{\r
206 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
207 EFI_DEVICE_PATH_PROTOCOL *NextNode;\r
208 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
209 UINTN NodeLength;\r
210\r
211 if (DevicePath == NULL || DevicePathNode == NULL) {\r
212 return NULL;\r
213 }\r
214 //\r
215 // Build a Node that has a terminator on it\r
216 //\r
217 NodeLength = DevicePathNodeLength (DevicePathNode);\r
218\r
219 TempDevicePath = AllocatePool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
220 if (TempDevicePath == NULL) {\r
221 return NULL;\r
222 }\r
223 TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);\r
224 //\r
225 // Add and end device path node to convert Node to device path\r
226 //\r
227 NextNode = NextDevicePathNode (TempDevicePath);\r
228 SetDevicePathEndNode (NextNode);\r
229 //\r
230 // Append device paths\r
231 //\r
232 NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);\r
233\r
234 FreePool (TempDevicePath);\r
235\r
236 return NewDevicePath;\r
237}\r
238\r
239/**\r
240 Creates a new device path by appending the specified device path instance to the specified device\r
241 path.\r
242 \r
243 This function creates a new device path by appending a copy of the device path instance specified\r
244 by DevicePathInstance to a copy of the device path secified by DevicePath in a allocated buffer.\r
245 The end-of-device-path device node is moved after the end of the appended device path instance\r
246 and a new end-of-device-path-instance node is inserted between. \r
247 If DevicePath is NULL, then a copy if DevicePathInstance is returned.\r
248 If DevicePathInstance is NULL, then NULL is returned.\r
249 If there is not enough memory to allocate space for the new device path, then NULL is returned. \r
250 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to\r
251 free the memory allocated.\r
252 \r
253 @param DevicePath A pointer to a device path data structure.\r
254 @param DevicePathInstance A pointer to a device path instance.\r
255\r
256 @return A pointer to the new device path.\r
257\r
258**/\r
259EFI_DEVICE_PATH_PROTOCOL *\r
260EFIAPI\r
261AppendDevicePathInstance (\r
262 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, OPTIONAL\r
263 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance OPTIONAL\r
264 )\r
265{\r
266 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
267 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
268 UINTN SrcSize;\r
269 UINTN InstanceSize;\r
270\r
271 if (DevicePath == NULL) {\r
272 return DuplicateDevicePath (DevicePathInstance);\r
273 }\r
274\r
275 if (DevicePathInstance == NULL) {\r
276 return NULL;\r
277 }\r
278\r
279 SrcSize = GetDevicePathSize (DevicePath);\r
280 InstanceSize = GetDevicePathSize (DevicePathInstance);\r
281\r
282 NewDevicePath = AllocatePool (SrcSize + InstanceSize);\r
283 if (NewDevicePath != NULL) {\r
284 \r
285 TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize);;\r
286 \r
287 while (!IsDevicePathEnd (TempDevicePath)) {\r
288 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
289 }\r
290 \r
291 TempDevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;\r
292 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
293 CopyMem (TempDevicePath, DevicePathInstance, InstanceSize);\r
294 }\r
295\r
296 return NewDevicePath;\r
297}\r
298\r
299/**\r
300 Creates a copy of the current device path instance and returns a pointer to the next device path\r
301 instance.\r
302\r
303 This function creates a copy of the current device path instance. It also updates DevicePath to\r
304 point to the next device path instance in the device path (or NULL if no more) and updates Size\r
305 to hold the size of the device path instance copy.\r
306 If DevicePath is NULL, then NULL is returned.\r
307 If there is not enough memory to allocate space for the new device path, then NULL is returned. \r
308 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to\r
309 free the memory allocated.\r
310 If Size is NULL, then ASSERT().\r
311 \r
312 @param DevicePath On input, this holds the pointer to the current device path\r
313 instance. On output, this holds the pointer to the next device\r
314 path instance or NULL if there are no more device path\r
315 instances in the device path pointer to a device path data\r
316 structure.\r
317 @param Size On output, this holds the size of the device path instance, in\r
318 bytes or zero, if DevicePath is NULL.\r
319\r
320 @return A pointer to the current device path instance.\r
321\r
322**/\r
323EFI_DEVICE_PATH_PROTOCOL *\r
324EFIAPI\r
325GetNextDevicePathInstance (\r
326 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,\r
327 OUT UINTN *Size\r
328 )\r
329{\r
330 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
331 EFI_DEVICE_PATH_PROTOCOL *ReturnValue;\r
332 UINT8 Temp;\r
333\r
334 ASSERT (Size != NULL);\r
335\r
336 if (DevicePath == NULL || *DevicePath == NULL) {\r
337 *Size = 0;\r
338 return NULL;\r
339 }\r
340\r
341 //\r
342 // Find the end of the device path instance\r
343 //\r
344 DevPath = *DevicePath;\r
345 while (!IsDevicePathEndType (DevPath)) {\r
346 DevPath = NextDevicePathNode (DevPath);\r
347 }\r
348\r
349 //\r
350 // Compute the size of the device path instance\r
351 //\r
352 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
353 \r
354 //\r
355 // Make a copy and return the device path instance\r
356 //\r
357 Temp = DevPath->SubType;\r
358 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
359 ReturnValue = DuplicateDevicePath (*DevicePath);\r
360 DevPath->SubType = Temp;\r
361\r
362 //\r
363 // If DevPath is the end of an entire device path, then another instance\r
364 // does not follow, so *DevicePath is set to NULL.\r
365 //\r
366 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {\r
367 *DevicePath = NULL;\r
368 } else {\r
369 *DevicePath = NextDevicePathNode (DevPath);\r
370 }\r
371\r
372 return ReturnValue;\r
373}\r
374\r
375/**\r
376 Creates a copy of the current device path instance and returns a pointer to the next device path\r
377 instance.\r
378\r
379 This function creates a new device node in a newly allocated buffer of size NodeLength and\r
380 initializes the device path node header with NodeType and NodeSubType. The new device path node\r
381 is returned.\r
382 If NodeLength is smaller than a device path header, then NULL is returned. \r
383 If there is not enough memory to allocate space for the new device path, then NULL is returned. \r
384 The memory is allocated from EFI boot services memory. It is the responsibility of the caller to\r
385 free the memory allocated.\r
386\r
387 @param NodeType The device node type for the new device node.\r
388 @param NodeSubType The device node sub-type for the new device node.\r
389 @param NodeLength The length of the new device node.\r
390\r
391 @return The new device path.\r
392\r
393**/\r
394EFI_DEVICE_PATH_PROTOCOL *\r
395EFIAPI\r
396CreateDeviceNode (\r
397 IN UINT8 NodeType,\r
398 IN UINT8 NodeSubType,\r
399 IN UINT16 NodeLength\r
400 )\r
401{\r
402 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
403\r
404 if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {\r
405 //\r
406 // NodeLength is less than the size of the header.\r
407 //\r
408 return NULL;\r
409 }\r
410 \r
411 DevicePath = AllocatePool (NodeLength);\r
412 if (DevicePath != NULL) {\r
413 DevicePath->Type = NodeType;\r
414 DevicePath->SubType = NodeSubType;\r
415 SetDevicePathNodeLength (DevicePath, NodeLength);\r
416 }\r
417\r
418 return DevicePath;\r
419}\r
420\r
421/**\r
422 Determines if a device path is single or multi-instance.\r
423\r
424 This function returns TRUE if the device path specified by DevicePath is multi-instance.\r
425 Otherwise, FALSE is returned. If DevicePath is NULL, then FALSE is returned.\r
426\r
427 @param DevicePath A pointer to a device path data structure.\r
428\r
429 @retval TRUE DevicePath is multi-instance.\r
430 @retval FALSE DevicePath is not multi-instance or DevicePath is NULL.\r
431\r
432**/\r
433BOOLEAN\r
434EFIAPI\r
435IsDevicePathMultiInstance (\r
436 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
437 )\r
438{\r
439 CONST EFI_DEVICE_PATH_PROTOCOL *Node;\r
440\r
441 if (DevicePath == NULL) {\r
442 return FALSE;\r
443 }\r
444\r
445 Node = DevicePath;\r
446 while (!EfiIsDevicePathEnd (Node)) {\r
447 if (EfiIsDevicePathEndInstance (Node)) {\r
448 return TRUE;\r
449 }\r
450\r
451 Node = EfiNextDevicePathNode (Node);\r
452 }\r
453\r
454 return FALSE;\r
455}\r
456\r
457\r
458/**\r
459 Retrieves the device path protocol from a handle.\r
460\r
461 This function returns the device path protocol from the handle specified by Handle. If Handle is\r
462 NULL or Handle does not contain a device path protocol, then NULL is returned.\r
463 \r
464 @param Handle The handle from which to retrieve the device path protocol.\r
465\r
466 @return The device path protocol from the handle specified by Handle.\r
467\r
468**/\r
469EFI_DEVICE_PATH_PROTOCOL *\r
470EFIAPI\r
471DevicePathFromHandle (\r
472 IN EFI_HANDLE Handle\r
473 )\r
474{\r
475 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
476 EFI_STATUS Status;\r
477\r
478 Status = gBS->HandleProtocol (\r
479 Handle,\r
480 &gEfiDevicePathProtocolGuid,\r
481 (VOID *) &DevicePath\r
482 );\r
483 if (EFI_ERROR (Status)) {\r
484 DevicePath = NULL;\r
485 }\r
486 return DevicePath;\r
487}\r
488\r
489/**\r
490 Allocates a device path for a file and appends it to an existing device path.\r
491\r
492 If Device is a valid device handle that contains a device path protocol, then a device path for\r
493 the file specified by FileName is allocated and appended to the device path associated with the\r
494 handle Device. The allocated device path is returned. If Device is NULL or Device is a handle\r
495 that does not support the device path protocol, then a device path containing a single device\r
496 path node for the file specified by FileName is allocated and returned.\r
497 If FileName is NULL, then ASSERT().\r
498\r
499 @param Device A pointer to a device handle. This parameter is optional and\r
500 may be NULL.\r
501 @param FileName A pointer to a Null-terminated Unicode string.\r
502\r
503 @return The allocated device path.\r
504\r
505**/\r
506EFI_DEVICE_PATH_PROTOCOL *\r
507EFIAPI\r
508FileDevicePath (\r
509 IN EFI_HANDLE Device, OPTIONAL\r
510 IN CONST CHAR16 *FileName\r
511 )\r
512{\r
513 UINTN Size;\r
514 FILEPATH_DEVICE_PATH *FilePath;\r
515 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
516 EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;\r
517\r
518 DevicePath = NULL;\r
519\r
520 Size = StrSize (FileName);\r
521 FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + EFI_END_DEVICE_PATH_LENGTH);\r
522 if (FileDevicePath != NULL) {\r
523 FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath;\r
524 FilePath->Header.Type = MEDIA_DEVICE_PATH;\r
525 FilePath->Header.SubType = MEDIA_FILEPATH_DP;\r
526 CopyMem (&FilePath->PathName, FileName, Size);\r
527 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);\r
528 SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));\r
529\r
530 if (Device != NULL) {\r
531 DevicePath = DevicePathFromHandle (Device);\r
532 }\r
533\r
534 DevicePath = AppendDevicePath (DevicePath, FileDevicePath);\r
535 FreePool (FileDevicePath);\r
536 }\r
537\r
538 return DevicePath;\r
539}\r
540\r