]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/RuntimeDxe/EfiRuntimeLib/RtDevicePath.c
Sync all bug fixes between EDK1.04 and EDK1.06 into EdkCompatibilityPkg.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / RuntimeDxe / EfiRuntimeLib / RtDevicePath.c
CommitLineData
3eb9473e 1/*++\r
2\r
3e99020d 3Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
4ea9375a 4This program and the accompanying materials \r
3eb9473e 5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 RtDevicePath.c\r
15\r
16Abstract:\r
17\r
18 Device Path services. The thing to remember is device paths are built out of\r
19 nodes. The device path is terminated by an end node that is length\r
20 sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)\r
21 all over this file.\r
22\r
23 The only place where multi-instance device paths are supported is in\r
24 environment varibles. Multi-instance device paths should never be placed\r
25 on a Handle.\r
26\r
27--*/\r
28\r
29#include "Tiano.h"\r
30#include "EfiRuntimeLib.h"\r
31#include "RtDevicePath.h"\r
32#include EFI_GUID_DEFINITION (FrameworkDevicePath)\r
33#include EFI_PROTOCOL_DEFINITION (DevicePath)\r
34\r
35STATIC\r
36VOID *\r
37InternalAllocatePool (\r
38 IN UINTN AllocationSize\r
39 )\r
40/*++\r
41\r
42Routine Description:\r
43\r
44 Allocate BootServicesData pool.\r
45\r
46Arguments:\r
47\r
48 AllocationSize - The size to allocate\r
49\r
50Returns:\r
51\r
52 Pointer of the buffer allocated.\r
53\r
54--*/\r
55{\r
56 VOID *Memory;\r
57\r
58 Memory = NULL;\r
59 gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory);\r
60 return Memory;\r
61}\r
62\r
63STATIC\r
64VOID *\r
65InternalAllocateCopyPool (\r
66 IN UINTN AllocationSize,\r
67 IN VOID *Buffer\r
68 )\r
69/*++\r
70\r
71Routine Description:\r
72\r
73 Allocate BootServicesData pool and use a buffer provided by \r
74 caller to fill it.\r
75\r
76Arguments:\r
77\r
78 AllocationSize - The size to allocate\r
79 \r
80 Buffer - Buffer that will be filled into the buffer allocated\r
81\r
82Returns:\r
83\r
84 Pointer of the buffer allocated.\r
85\r
86--*/\r
87{\r
88 VOID *Memory;\r
89\r
90 Memory = NULL;\r
91 gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory);\r
92 if (Memory != NULL) {\r
93 gBS->CopyMem (Memory, Buffer, AllocationSize);\r
94 }\r
95\r
96 return Memory;\r
97}\r
98\r
99STATIC\r
100VOID *\r
101InternalAllocateZeroPool (\r
102 IN UINTN AllocationSize\r
103 )\r
104/*++\r
105\r
106Routine Description:\r
107\r
108 Allocate BootServicesData pool and zero it.\r
109\r
110Arguments:\r
111\r
112 AllocationSize - The size to allocate\r
113\r
114Returns:\r
115\r
116 Pointer of the buffer allocated.\r
117\r
118--*/\r
119{\r
120 VOID *Memory;\r
121\r
122 Memory = InternalAllocatePool (AllocationSize);\r
123 if (Memory != NULL) {\r
124 gBS->SetMem (Memory, AllocationSize, 0);\r
125 }\r
126\r
127 return Memory;\r
128}\r
129\r
130EFI_DEVICE_PATH_PROTOCOL *\r
131RtEfiDevicePathInstance (\r
132 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,\r
133 OUT UINTN *Size\r
134 )\r
135/*++\r
136\r
137Routine Description:\r
138 Function retrieves the next device path instance from a device path data structure.\r
139\r
140Arguments:\r
141 DevicePath - A pointer to a device path data structure.\r
142\r
143 Size - A pointer to the size of a device path instance in bytes.\r
144\r
145Returns:\r
146\r
147 This function returns a pointer to the current device path instance.\r
148 In addition, it returns the size in bytes of the current device path instance in Size,\r
149 and a pointer to the next device path instance in DevicePath.\r
150 If there are no more device path instances in DevicePath, then DevicePath will be set to NULL.\r
151\r
152--*/\r
153{\r
154 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
155 EFI_DEVICE_PATH_PROTOCOL *ReturnValue;\r
156 UINT8 Temp;\r
157\r
158 if (*DevicePath == NULL) {\r
159 if (Size != NULL) {\r
160 *Size = 0;\r
161 }\r
162\r
163 return NULL;\r
164 }\r
165\r
166 //\r
167 // Find the end of the device path instance\r
168 //\r
169 DevPath = *DevicePath;\r
170 while (!IsDevicePathEndType (DevPath)) {\r
171 DevPath = NextDevicePathNode (DevPath);\r
172 }\r
173\r
174 //\r
175 // Compute the size of the device path instance\r
176 //\r
177 if (Size != NULL) {\r
178 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
179 }\r
180\r
181 //\r
182 // Make a copy and return the device path instance\r
183 //\r
184 Temp = DevPath->SubType;\r
185 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
186 ReturnValue = RtEfiDuplicateDevicePath (*DevicePath);\r
187 DevPath->SubType = Temp;\r
188\r
189 //\r
190 // If DevPath is the end of an entire device path, then another instance\r
191 // does not follow, so *DevicePath is set to NULL.\r
192 //\r
193 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {\r
194 *DevicePath = NULL;\r
195 } else {\r
196 *DevicePath = NextDevicePathNode (DevPath);\r
197 }\r
198\r
199 return ReturnValue;\r
200}\r
201\r
202BOOLEAN\r
203RtEfiIsDevicePathMultiInstance (\r
204 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
205 )\r
206/*++\r
207\r
208Routine Description:\r
209 Return TRUE is this is a multi instance device path.\r
210\r
211Arguments:\r
212 DevicePath - A pointer to a device path data structure.\r
213\r
214\r
215Returns:\r
216 TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi\r
217 instance.\r
218\r
219--*/\r
220{\r
221 EFI_DEVICE_PATH_PROTOCOL *Node;\r
222\r
223 if (DevicePath == NULL) {\r
224 return FALSE;\r
225 }\r
226\r
227 Node = DevicePath;\r
228 while (!EfiIsDevicePathEnd (Node)) {\r
229 if (EfiIsDevicePathEndInstance (Node)) {\r
230 return TRUE;\r
231 }\r
232\r
233 Node = EfiNextDevicePathNode (Node);\r
234 }\r
235\r
236 return FALSE;\r
237}\r
238\r
239UINTN\r
240RtEfiDevicePathSize (\r
241 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
242 )\r
243/*++\r
244\r
245Routine Description:\r
246\r
247 Calculate the space size of a device path.\r
248\r
249Arguments:\r
250\r
251 DevicePath - A specified device path\r
252\r
253Returns:\r
254\r
255 The size.\r
256\r
257--*/\r
258{\r
259 EFI_DEVICE_PATH_PROTOCOL *Start;\r
260\r
261 if (DevicePath == NULL) {\r
262 return 0;\r
263 }\r
264\r
265 //\r
266 // Search for the end of the device path structure\r
267 //\r
268 Start = DevicePath;\r
269 while (!EfiIsDevicePathEnd (DevicePath)) {\r
270 DevicePath = EfiNextDevicePathNode (DevicePath);\r
271 }\r
272\r
273 //\r
274 // Compute the size and add back in the size of the end device path structure\r
275 //\r
276 return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
277}\r
278\r
279EFI_DEVICE_PATH_PROTOCOL *\r
280RtEfiDevicePathFromHandle (\r
281 IN EFI_HANDLE Handle\r
282 )\r
283/*++\r
284\r
285Routine Description:\r
286\r
287 Get the device path protocol interface installed on a specified handle.\r
288\r
289Arguments:\r
290\r
291 Handle - a specified handle\r
292\r
293Returns:\r
294\r
295 The device path protocol interface installed on that handle.\r
296\r
297--*/\r
298{\r
299 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
300\r
301 DevicePath = NULL;\r
302 gBS->HandleProtocol (\r
303 Handle,\r
304 &gEfiDevicePathProtocolGuid,\r
305 (VOID *) &DevicePath\r
306 );\r
307 return DevicePath;\r
308}\r
309\r
310EFI_DEVICE_PATH_PROTOCOL *\r
311RtEfiDuplicateDevicePath (\r
312 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
313 )\r
314/*++\r
315\r
316Routine Description:\r
317\r
318 Duplicate a device path structure.\r
319\r
320Arguments:\r
321\r
322 DevicePath - The device path to duplicated.\r
323\r
324Returns:\r
325\r
326 The duplicated device path.\r
327\r
328--*/\r
329{\r
330 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
331 UINTN Size;\r
332\r
333 if (DevicePath == NULL) {\r
334 return NULL;\r
335 }\r
336\r
337 //\r
338 // Compute the size\r
339 //\r
340 Size = RtEfiDevicePathSize (DevicePath);\r
341 if (Size == 0) {\r
342 return NULL;\r
343 }\r
344\r
345 //\r
346 // Allocate space for duplicate device path\r
347 //\r
348 NewDevicePath = InternalAllocateCopyPool (Size, DevicePath);\r
349\r
350 return NewDevicePath;\r
351}\r
352\r
353EFI_DEVICE_PATH_PROTOCOL *\r
354RtEfiAppendDevicePath (\r
355 IN EFI_DEVICE_PATH_PROTOCOL *Src1,\r
356 IN EFI_DEVICE_PATH_PROTOCOL *Src2\r
357 )\r
358/*++\r
359\r
360Routine Description:\r
361 Function is used to append a Src1 and Src2 together.\r
362\r
363Arguments:\r
364 Src1 - A pointer to a device path data structure.\r
365\r
366 Src2 - A pointer to a device path data structure.\r
367\r
368Returns:\r
369\r
370 A pointer to the new device path is returned.\r
371 NULL is returned if space for the new device path could not be allocated from pool.\r
372 It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed.\r
373\r
374--*/\r
375{\r
376 UINTN Size;\r
377 UINTN Size1;\r
378 UINTN Size2;\r
379 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
380 EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath;\r
381\r
382 //\r
383 // If there's only 1 path, just duplicate it\r
384 //\r
385 if (!Src1) {\r
386 ASSERT (!IsDevicePathUnpacked (Src2));\r
387 return RtEfiDuplicateDevicePath (Src2);\r
388 }\r
389\r
390 if (!Src2) {\r
391 ASSERT (!IsDevicePathUnpacked (Src1));\r
392 return RtEfiDuplicateDevicePath (Src1);\r
393 }\r
394\r
395 //\r
396 // Allocate space for the combined device path. It only has one end node of\r
397 // length EFI_DEVICE_PATH_PROTOCOL\r
398 //\r
399 Size1 = RtEfiDevicePathSize (Src1);\r
400 Size2 = RtEfiDevicePathSize (Src2);\r
401 Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
402\r
403 NewDevicePath = InternalAllocateCopyPool (Size, Src1);\r
404\r
405 if (NewDevicePath != NULL) {\r
406\r
407 //\r
408 // Over write Src1 EndNode and do the copy\r
409 //\r
410 SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
411 EfiCopyMem (SecondDevicePath, Src2, Size2);\r
412 }\r
413\r
414 return NewDevicePath;\r
415}\r
416\r
417EFI_DEVICE_PATH_PROTOCOL *\r
418RtEfiAppendDevicePathNode (\r
419 IN EFI_DEVICE_PATH_PROTOCOL *Src1,\r
420 IN EFI_DEVICE_PATH_PROTOCOL *Node\r
421 )\r
422/*++\r
423\r
424Routine Description:\r
425 Function is used to append a device path node to the end of another device path.\r
426\r
427Arguments:\r
428 Src1 - A pointer to a device path data structure.\r
429\r
430 Node - A pointer to a device path data structure.\r
431\r
432Returns:\r
433 This function returns a pointer to the new device path.\r
434 If there is not enough temporary pool memory available to complete this function,\r
435 then NULL is returned.\r
436\r
437\r
438--*/\r
439{\r
440 EFI_DEVICE_PATH_PROTOCOL *Temp;\r
441 EFI_DEVICE_PATH_PROTOCOL *NextNode;\r
442 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
443 UINTN NodeLength;\r
444\r
445 //\r
446 // Build a Node that has a terminator on it\r
447 //\r
448 NodeLength = DevicePathNodeLength (Node);\r
449\r
450 Temp = InternalAllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), Node);\r
451 if (Temp == NULL) {\r
452 return NULL;\r
453 }\r
454\r
455 //\r
456 // Add and end device path node to convert Node to device path\r
457 //\r
458 NextNode = NextDevicePathNode (Temp);\r
459 SetDevicePathEndNode (NextNode);\r
460\r
461 //\r
462 // Append device paths\r
463 //\r
464 NewDevicePath = RtEfiAppendDevicePath (Src1, Temp);\r
465 gBS->FreePool (Temp);\r
466 return NewDevicePath;\r
467}\r
468\r
469EFI_DEVICE_PATH_PROTOCOL *\r
470RtEfiFileDevicePath (\r
471 IN EFI_HANDLE Device OPTIONAL,\r
472 IN CHAR16 *FileName\r
473 )\r
474/*++\r
475\r
476Routine Description:\r
477\r
478 This function allocates a device path for a file and appends it to an existiong\r
479 device path.\r
480\r
481Arguments:\r
482 Device - A pointer to a device handle.\r
483\r
484 FileName - A pointer to a Null-terminated Unicodestring.\r
485\r
486Returns:\r
487 A device path contain the file name.\r
488\r
489--*/\r
490{\r
491 UINTN Size;\r
492 FILEPATH_DEVICE_PATH *FilePath;\r
493 EFI_DEVICE_PATH_PROTOCOL *Eop;\r
494 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
495\r
496 for (Size = 0; FileName[Size] != 0; Size++)\r
497 ;\r
498 Size = (Size + 1) * 2;\r
499\r
500 FilePath = InternalAllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
501\r
502 DevicePath = NULL;\r
503\r
504 if (FilePath != NULL) {\r
505\r
506 //\r
507 // Build a file path\r
508 //\r
509 FilePath->Header.Type = MEDIA_DEVICE_PATH;\r
510 FilePath->Header.SubType = MEDIA_FILEPATH_DP;\r
511 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);\r
512 EfiCopyMem (FilePath->PathName, FileName, Size);\r
513 Eop = NextDevicePathNode (&FilePath->Header);\r
514 SetDevicePathEndNode (Eop);\r
515\r
516 //\r
517 // Append file path to device's device path\r
518 //\r
519\r
520 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;\r
521 if (Device != NULL) {\r
522 DevicePath = RtEfiAppendDevicePath (\r
523 RtEfiDevicePathFromHandle (Device),\r
524 DevicePath\r
525 );\r
526\r
527 gBS->FreePool (FilePath);\r
528 }\r
529 }\r
530\r
531 return DevicePath;\r
532}\r
533\r
534EFI_DEVICE_PATH_PROTOCOL *\r
535RtEfiAppendDevicePathInstance (\r
536 IN EFI_DEVICE_PATH_PROTOCOL *Src,\r
537 IN EFI_DEVICE_PATH_PROTOCOL *Instance\r
538 )\r
539/*++\r
540\r
541Routine Description:\r
542\r
543 Append a device path instance to another.\r
544\r
545Arguments:\r
546\r
547 Src - The device path instance to be appended with.\r
548 Instance - The device path instance appending the other.\r
549\r
550Returns:\r
551\r
552 The contaction of these two.\r
553\r
554--*/\r
555{\r
556 UINT8 *Ptr;\r
557 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
558 UINTN SrcSize;\r
559 UINTN InstanceSize;\r
560\r
561 if (Src == NULL) {\r
562 return RtEfiDuplicateDevicePath (Instance);\r
563 }\r
564\r
565 SrcSize = RtEfiDevicePathSize (Src);\r
566 InstanceSize = RtEfiDevicePathSize (Instance);\r
567\r
568 Ptr = InternalAllocateCopyPool (SrcSize + InstanceSize, Src);\r
569 if (Ptr != NULL) {\r
570\r
571 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
572\r
573 while (!IsDevicePathEnd (DevPath)) {\r
574 DevPath = NextDevicePathNode (DevPath);\r
575 }\r
576 //\r
577 // Convert the End to an End Instance, since we are\r
578 // appending another instacne after this one its a good\r
579 // idea.\r
580 //\r
581 DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;\r
582\r
583 DevPath = NextDevicePathNode (DevPath);\r
584 EfiCopyMem (DevPath, Instance, InstanceSize);\r
585 }\r
586\r
587 return (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
588}\r
589\r
590VOID\r
591EFIAPI\r
592RtEfiInitializeFwVolDevicepathNode (\r
593 IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode,\r
594 IN EFI_GUID *NameGuid\r
595 )\r
596/*++\r
597\r
598Routine Description:\r
599\r
600 Initialize a Firmware Volume (FV) Media Device Path node.\r
601 \r
3eb9473e 602Arguments:\r
603\r
604 FvDevicePathNode - Pointer to a FV device path node to initialize\r
605 NameGuid - FV file name to use in FvDevicePathNode\r
606\r
607Returns:\r
608\r
609 None\r
610\r
611--*/\r
612{\r
3eb9473e 613 FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH;\r
614 FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP;\r
615 SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));\r
616\r
3eb9473e 617 EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID));\r
618}\r
619\r
620EFI_GUID *\r
621EFIAPI\r
622RtEfiGetNameGuidFromFwVolDevicePathNode (\r
623 IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode\r
624 )\r
625/*++\r
626\r
627Routine Description:\r
628\r
629 Check to see if the Firmware Volume (FV) Media Device Path is valid.\r
630 \r
3eb9473e 631Arguments:\r
632\r
633 FvDevicePathNode - Pointer to FV device path to check\r
634\r
635Returns:\r
636\r
637 NULL - FvDevicePathNode is not valid.\r
638 Other - FvDevicePathNode is valid and pointer to NameGuid was returned.\r
639\r
640--*/\r
641{\r
3eb9473e 642 if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&\r
643 DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) {\r
644 return &FvDevicePathNode->NameGuid;\r
645 }\r
646\r
3e99020d 647 return NULL;\r
3eb9473e 648}\r
649\r