xref: /DragonStub/lib/dpath.c (revision 5ff74ecae8b8452e3630bb00611fb610da72ac59)
1 /*++
2 
3 Copyright (c) 1998  Intel Corporation
4 
5 Module Name:
6 
7     dpath.c
8 
9 Abstract:
10     MBR & Device Path functions
11 
12 
13 
14 Revision History
15 
16 2014/04 B.Burette - updated device path text representation, conforming to
17 	UEFI specification 2.4 (dec. 2013). More specifically:
18 	- § 9.3.5: added some media types ie. Sata()
19 	- § 9.6.1.2: Acpi(PNP0A03,0) makes more sense when displayed as PciRoot(0)
20 	- § 9.6.1.5: use commas (instead of '|') between option specific parameters
21 	- § 9.6.1.6: hex values in device paths must be preceded by "0x" or "0X"
22 
23 --*/
24 
25 #include "lib.h"
26 
27 #define ALIGN_SIZE(a)   ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0)
28 
29 
30 
31 EFI_DEVICE_PATH *
32 DevicePathFromHandle (
33     IN EFI_HANDLE       Handle
34     )
35 {
36     EFI_STATUS          Status;
37     EFI_DEVICE_PATH     *DevicePath;
38 
39     Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handle, &DevicePathProtocol, (VOID*)&DevicePath);
40     if (EFI_ERROR(Status)) {
41         DevicePath = NULL;
42     }
43 
44     return DevicePath;
45 }
46 
47 
48 EFI_DEVICE_PATH *
49 DevicePathInstance (
50     IN OUT EFI_DEVICE_PATH  **DevicePath,
51     OUT UINTN               *Size
52     )
53 {
54     EFI_DEVICE_PATH         *Start, *Next, *DevPath;
55     UINTN                   Count;
56 
57     DevPath = *DevicePath;
58     Start = DevPath;
59 
60     if (!DevPath) {
61         return NULL;
62     }
63 
64     //
65     // Check for end of device path type
66     //
67 
68     for (Count = 0; ; Count++) {
69         Next = NextDevicePathNode(DevPath);
70 
71         if (IsDevicePathEndType(DevPath)) {
72             break;
73         }
74 
75         if (Count > 01000) {
76             //
77             // BugBug: Debug code to catch bogus device paths
78             //
79             DEBUG((D_ERROR, "DevicePathInstance: DevicePath %x Size %d", *DevicePath, ((UINT8 *) DevPath) - ((UINT8 *) Start) ));
80             DumpHex (0, 0, ((UINT8 *) DevPath) - ((UINT8 *) Start), Start);
81             break;
82         }
83 
84         DevPath = Next;
85     }
86 
87     ASSERT (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE ||
88             DevicePathSubType(DevPath) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
89 
90     //
91     // Set next position
92     //
93 
94     if (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
95         Next = NULL;
96     }
97 
98     *DevicePath = Next;
99 
100     //
101     // Return size and start of device path instance
102     //
103 
104     *Size = ((UINT8 *) DevPath) - ((UINT8 *) Start);
105     return Start;
106 }
107 
108 UINTN
109 DevicePathInstanceCount (
110     IN EFI_DEVICE_PATH      *DevicePath
111     )
112 {
113     UINTN       Count, Size;
114 
115     Count = 0;
116     while (DevicePathInstance(&DevicePath, &Size)) {
117         Count += 1;
118     }
119 
120     return Count;
121 }
122 
123 
124 EFI_DEVICE_PATH *
125 AppendDevicePath (
126     IN EFI_DEVICE_PATH  *Src1,
127     IN EFI_DEVICE_PATH  *Src2
128     )
129 // Src1 may have multiple "instances" and each instance is appended
130 // Src2 is appended to each instance is Src1.  (E.g., it's possible
131 // to append a new instance to the complete device path by passing
132 // it in Src2)
133 {
134     UINTN               Src1Size, Src1Inst, Src2Size, Size;
135     EFI_DEVICE_PATH     *Dst, *Inst;
136     UINT8               *DstPos;
137 
138     //
139     // If there's only 1 path, just duplicate it
140     //
141 
142     if (!Src1) {
143         ASSERT (!IsDevicePathUnpacked (Src2));
144         return DuplicateDevicePath (Src2);
145     }
146 
147     if (!Src2) {
148         ASSERT (!IsDevicePathUnpacked (Src1));
149         return DuplicateDevicePath (Src1);
150     }
151 
152     //
153     // Verify we're not working with unpacked paths
154     //
155 
156 //    ASSERT (!IsDevicePathUnpacked (Src1));
157 //    ASSERT (!IsDevicePathUnpacked (Src2));
158 
159     //
160     // Append Src2 to every instance in Src1
161     //
162 
163     Src1Size = DevicePathSize(Src1);
164     Src1Inst = DevicePathInstanceCount(Src1);
165     Src2Size = DevicePathSize(Src2);
166     Size = Src1Size * Src1Inst + Src2Size;
167 
168     Dst = AllocatePool (Size);
169     if (Dst) {
170         DstPos = (UINT8 *) Dst;
171 
172         //
173         // Copy all device path instances
174         //
175 
176         while ((Inst = DevicePathInstance (&Src1, &Size))) {
177 
178             CopyMem(DstPos, Inst, Size);
179             DstPos += Size;
180 
181             CopyMem(DstPos, Src2, Src2Size);
182             DstPos += Src2Size;
183 
184             CopyMem(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH));
185             DstPos += sizeof(EFI_DEVICE_PATH);
186         }
187 
188         // Change last end marker
189         DstPos -= sizeof(EFI_DEVICE_PATH);
190         CopyMem(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH));
191     }
192 
193     return Dst;
194 }
195 
196 
197 EFI_DEVICE_PATH *
198 AppendDevicePathNode (
199     IN EFI_DEVICE_PATH  *Src1,
200     IN EFI_DEVICE_PATH  *Src2
201     )
202 // Src1 may have multiple "instances" and each instance is appended
203 // Src2 is a signal device path node (without a terminator) that is
204 // appended to each instance is Src1.
205 {
206     EFI_DEVICE_PATH     *Temp, *Eop;
207     UINTN               Length;
208 
209     //
210     // Build a Src2 that has a terminator on it
211     //
212 
213     Length = DevicePathNodeLength(Src2);
214     Temp = AllocatePool (Length + sizeof(EFI_DEVICE_PATH));
215     if (!Temp) {
216         return NULL;
217     }
218 
219     CopyMem (Temp, Src2, Length);
220     Eop = NextDevicePathNode(Temp);
221     SetDevicePathEndNode(Eop);
222 
223     //
224     // Append device paths
225     //
226 
227     Src1 = AppendDevicePath (Src1, Temp);
228     FreePool (Temp);
229     return Src1;
230 }
231 
232 
233 EFI_DEVICE_PATH *
234 FileDevicePath (
235     IN EFI_HANDLE       Device  OPTIONAL,
236     IN CHAR16           *FileName
237     )
238 /*++
239 
240     N.B. Results are allocated from pool.  The caller must FreePool
241     the resulting device path structure
242 
243 --*/
244 {
245     UINTN                   Size;
246     FILEPATH_DEVICE_PATH    *FilePath;
247     EFI_DEVICE_PATH         *Eop, *DevicePath;
248 
249     Size = StrSize(FileName);
250     FilePath = AllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof(EFI_DEVICE_PATH));
251     DevicePath = NULL;
252 
253     if (FilePath) {
254 
255         //
256         // Build a file path
257         //
258 
259         FilePath->Header.Type = MEDIA_DEVICE_PATH;
260         FilePath->Header.SubType = MEDIA_FILEPATH_DP;
261         SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
262         CopyMem (FilePath->PathName, FileName, Size);
263         Eop = NextDevicePathNode(&FilePath->Header);
264         SetDevicePathEndNode(Eop);
265 
266         //
267         // Append file path to device's device path
268         //
269 
270         DevicePath = (EFI_DEVICE_PATH *) FilePath;
271         if (Device) {
272             DevicePath = AppendDevicePath (
273                             DevicePathFromHandle(Device),
274                             DevicePath
275                             );
276 
277             FreePool(FilePath);
278         }
279     }
280 
281     return DevicePath;
282 }
283 
284 
285 
286 UINTN
287 DevicePathSize (
288     IN EFI_DEVICE_PATH  *DevPath
289     )
290 {
291     EFI_DEVICE_PATH     *Start;
292 
293     //
294     // Search for the end of the device path structure
295     //
296 
297     Start = DevPath;
298     while (!IsDevicePathEnd(DevPath)) {
299         DevPath = NextDevicePathNode(DevPath);
300     }
301 
302     //
303     // Compute the size
304     //
305 
306     return ((UINTN) DevPath - (UINTN) Start) + sizeof(EFI_DEVICE_PATH);
307 }
308 
309 EFI_DEVICE_PATH *
310 DuplicateDevicePath (
311     IN EFI_DEVICE_PATH  *DevPath
312     )
313 {
314     EFI_DEVICE_PATH     *NewDevPath;
315     UINTN               Size;
316 
317 
318     //
319     // Compute the size
320     //
321 
322     Size = DevicePathSize (DevPath);
323 
324     //
325     // Make a copy
326     //
327 
328     NewDevPath = AllocatePool (Size);
329     if (NewDevPath) {
330         CopyMem (NewDevPath, DevPath, Size);
331     }
332 
333     return NewDevPath;
334 }
335 
336 EFI_DEVICE_PATH *
337 UnpackDevicePath (
338     IN EFI_DEVICE_PATH  *DevPath
339     )
340 {
341     EFI_DEVICE_PATH     *Src, *Dest, *NewPath;
342     UINTN               Size;
343 
344     //
345     // Walk device path and round sizes to valid boundries
346     //
347 
348     Src = DevPath;
349     Size = 0;
350     for (; ;) {
351         Size += DevicePathNodeLength(Src);
352         Size += ALIGN_SIZE(Size);
353 
354         if (IsDevicePathEnd(Src)) {
355             break;
356         }
357 
358         Src = NextDevicePathNode(Src);
359     }
360 
361 
362     //
363     // Allocate space for the unpacked path
364     //
365 
366     NewPath = AllocateZeroPool (Size);
367     if (NewPath) {
368 
369         ASSERT (((UINTN)NewPath) % MIN_ALIGNMENT_SIZE == 0);
370 
371         //
372         // Copy each node
373         //
374 
375         Src = DevPath;
376         Dest = NewPath;
377         for (; ;) {
378             Size = DevicePathNodeLength(Src);
379             CopyMem (Dest, Src, Size);
380             Size += ALIGN_SIZE(Size);
381             SetDevicePathNodeLength (Dest, Size);
382             Dest->Type |= EFI_DP_TYPE_UNPACKED;
383             Dest = (EFI_DEVICE_PATH *) (((UINT8 *) Dest) + Size);
384 
385             if (IsDevicePathEnd(Src)) {
386                 break;
387             }
388 
389             Src = NextDevicePathNode(Src);
390         }
391     }
392 
393     return NewPath;
394 }
395 
396 
397 EFI_DEVICE_PATH*
398 AppendDevicePathInstance (
399     IN EFI_DEVICE_PATH  *Src,
400     IN EFI_DEVICE_PATH  *Instance
401     )
402 {
403     UINT8           *Ptr;
404     EFI_DEVICE_PATH *DevPath;
405     UINTN           SrcSize;
406     UINTN           InstanceSize;
407 
408     if (Src == NULL) {
409         return DuplicateDevicePath (Instance);
410     }
411     SrcSize = DevicePathSize(Src);
412     InstanceSize = DevicePathSize(Instance);
413     Ptr = AllocatePool (SrcSize + InstanceSize);
414     DevPath = (EFI_DEVICE_PATH *)Ptr;
415     ASSERT(DevPath);
416 
417     CopyMem (Ptr, Src, SrcSize);
418 //    FreePool (Src);
419 
420     while (!IsDevicePathEnd(DevPath)) {
421         DevPath = NextDevicePathNode(DevPath);
422     }
423     //
424     // Convert the End to an End Instance, since we are
425     //  appending another instacne after this one its a good
426     //  idea.
427     //
428     DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
429 
430     DevPath = NextDevicePathNode(DevPath);
431     CopyMem (DevPath, Instance, InstanceSize);
432     return (EFI_DEVICE_PATH *)Ptr;
433 }
434 
435 EFI_STATUS
436 LibDevicePathToInterface (
437     IN EFI_GUID             *Protocol,
438     IN EFI_DEVICE_PATH      *FilePath,
439     OUT VOID                **Interface
440     )
441 {
442     EFI_STATUS              Status;
443     EFI_HANDLE              Device;
444 
445     Status = uefi_call_wrapper(BS->LocateDevicePath, 3, Protocol, &FilePath, &Device);
446 
447     if (!EFI_ERROR(Status)) {
448 
449         // If we didn't get a direct match return not found
450         Status = EFI_NOT_FOUND;
451 
452         if (IsDevicePathEnd(FilePath)) {
453 
454             //
455             // It was a direct match, lookup the protocol interface
456             //
457 
458             Status =uefi_call_wrapper(BS->HandleProtocol, 3, Device, Protocol, Interface);
459         }
460     }
461 
462     //
463     // If there was an error, do not return an interface
464     //
465 
466     if (EFI_ERROR(Status)) {
467         *Interface = NULL;
468     }
469 
470     return Status;
471 }
472 
473 static VOID
474 _DevPathPci (
475     IN OUT POOL_PRINT       *Str,
476     IN VOID                 *DevPath
477     )
478 {
479     PCI_DEVICE_PATH         *Pci;
480 
481     Pci = DevPath;
482     CatPrint(Str, L"Pci(0x%x,0x%x)", Pci->Device, Pci->Function);
483 }
484 
485 static VOID
486 _DevPathPccard (
487     IN OUT POOL_PRINT       *Str,
488     IN VOID                 *DevPath
489     )
490 {
491     PCCARD_DEVICE_PATH      *Pccard;
492 
493     Pccard = DevPath;
494     CatPrint(Str, L"Pccard(0x%x)", Pccard-> FunctionNumber );
495 }
496 
497 static VOID
498 _DevPathMemMap (
499     IN OUT POOL_PRINT       *Str,
500     IN VOID                 *DevPath
501     )
502 {
503     MEMMAP_DEVICE_PATH      *MemMap;
504 
505     MemMap = DevPath;
506     CatPrint(Str, L"MemMap(%d,0x%x,0x%x)",
507         MemMap->MemoryType,
508         MemMap->StartingAddress,
509         MemMap->EndingAddress
510         );
511 }
512 
513 static VOID
514 _DevPathController (
515     IN OUT POOL_PRINT       *Str,
516     IN VOID                 *DevPath
517     )
518 {
519     CONTROLLER_DEVICE_PATH  *Controller;
520 
521     Controller = DevPath;
522     CatPrint(Str, L"Ctrl(%d)",
523         Controller->Controller
524         );
525 }
526 
527 static VOID
528 _DevPathVendor (
529     IN OUT POOL_PRINT       *Str,
530     IN VOID                 *DevPath
531     )
532 {
533     VENDOR_DEVICE_PATH                  *Vendor;
534     CHAR16                              *Type;
535     UNKNOWN_DEVICE_VENDOR_DEVICE_PATH   *UnknownDevPath;
536 
537     Vendor = DevPath;
538     switch (DevicePathType(&Vendor->Header)) {
539     case HARDWARE_DEVICE_PATH:  Type = L"Hw";        break;
540     case MESSAGING_DEVICE_PATH: Type = L"Msg";       break;
541     case MEDIA_DEVICE_PATH:     Type = L"Media";     break;
542     default:                    Type = L"?";         break;
543     }
544 
545     CatPrint(Str, L"Ven%s(%g", Type, &Vendor->Guid);
546     if (CompareGuid (&Vendor->Guid, &UnknownDevice) == 0) {
547         //
548         // GUID used by EFI to enumerate an EDD 1.1 device
549         //
550         UnknownDevPath = (UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *)Vendor;
551         CatPrint(Str, L":%02x)", UnknownDevPath->LegacyDriveLetter);
552     } else {
553         CatPrint(Str, L")");
554     }
555 }
556 
557 
558 /*
559   Type: 2 (ACPI Device Path) SubType: 1 (ACPI Device Path)
560  */
561 static VOID
562 _DevPathAcpi (
563     IN OUT POOL_PRINT       *Str,
564     IN VOID                 *DevPath
565     )
566 {
567     ACPI_HID_DEVICE_PATH        *Acpi;
568 
569     Acpi = DevPath;
570     if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
571         switch ( EISA_ID_TO_NUM( Acpi-> HID ) ) {
572             case 0x301 : {
573                 CatPrint( Str , L"Keyboard(%d)" , Acpi-> UID ) ;
574                 break ;
575             }
576             case 0x401 : {
577                 CatPrint( Str , L"ParallelPort(%d)" , Acpi-> UID ) ;
578                 break ;
579             }
580             case 0x501 : {
581                 CatPrint( Str , L"Serial(%d)" , Acpi-> UID ) ;
582                 break ;
583             }
584             case 0x604 : {
585                 CatPrint( Str , L"Floppy(%d)" , Acpi-> UID ) ;
586                 break ;
587             }
588             case 0xa03 : {
589                 CatPrint( Str , L"PciRoot(%d)" , Acpi-> UID ) ;
590                 break ;
591             }
592             case 0xa08 : {
593                 CatPrint( Str , L"PcieRoot(%d)" , Acpi-> UID ) ;
594                 break ;
595             }
596             default : {
597                 CatPrint( Str , L"Acpi(PNP%04x" , EISA_ID_TO_NUM( Acpi-> HID ) ) ;
598                 if ( Acpi-> UID ) CatPrint( Str , L",%d" , Acpi-> UID ) ;
599                 CatPrint( Str , L")" ) ;
600                 break ;
601             }
602 	}
603     } else {
604         CatPrint( Str , L"Acpi(0x%X" , Acpi-> HID ) ;
605         if ( Acpi-> UID ) CatPrint( Str , L",%d" , Acpi-> UID ) ;
606         CatPrint( Str , L")" , Acpi-> HID , Acpi-> UID ) ;
607     }
608 }
609 
610 
611 static VOID
612 _DevPathAtapi (
613     IN OUT POOL_PRINT       *Str,
614     IN VOID                 *DevPath
615     )
616 {
617     ATAPI_DEVICE_PATH       *Atapi;
618 
619     Atapi = DevPath;
620     CatPrint(Str, L"Ata(%s,%s)",
621         Atapi->PrimarySecondary ? L"Secondary" : L"Primary",
622         Atapi->SlaveMaster ? L"Slave" : L"Master"
623         );
624 }
625 
626 static VOID
627 _DevPathScsi (
628     IN OUT POOL_PRINT       *Str,
629     IN VOID                 *DevPath
630     )
631 {
632     SCSI_DEVICE_PATH        *Scsi;
633 
634     Scsi = DevPath;
635     CatPrint(Str, L"Scsi(%d,%d)", Scsi->Pun, Scsi->Lun);
636 }
637 
638 
639 static VOID
640 _DevPathFibre (
641     IN OUT POOL_PRINT       *Str,
642     IN VOID                 *DevPath
643     )
644 {
645     FIBRECHANNEL_DEVICE_PATH    *Fibre;
646 
647     Fibre = DevPath;
648     CatPrint( Str , L"Fibre%s(0x%016lx,0x%016lx)" ,
649         DevicePathType( & Fibre-> Header ) == MSG_FIBRECHANNEL_DP ? L"" : L"Ex" ,
650         Fibre-> WWN , Fibre-> Lun ) ;
651 }
652 
653 static VOID
654 _DevPath1394 (
655     IN OUT POOL_PRINT       *Str,
656     IN VOID                 *DevPath
657     )
658 {
659     F1394_DEVICE_PATH       *F1394;
660 
661     F1394 = DevPath;
662     CatPrint(Str, L"1394(%g)", &F1394->Guid);
663 }
664 
665 
666 
667 static VOID
668 _DevPathUsb (
669     IN OUT POOL_PRINT       *Str,
670     IN VOID                 *DevPath
671     )
672 {
673     USB_DEVICE_PATH         *Usb;
674 
675     Usb = DevPath;
676     CatPrint( Str , L"Usb(0x%x,0x%x)" , Usb-> Port , Usb-> Endpoint ) ;
677 }
678 
679 
680 static VOID
681 _DevPathI2O (
682     IN OUT POOL_PRINT       *Str,
683     IN VOID                 *DevPath
684     )
685 {
686     I2O_DEVICE_PATH         *I2O;
687 
688     I2O = DevPath;
689     CatPrint(Str, L"I2O(0x%X)", I2O->Tid);
690 }
691 
692 static VOID
693 _DevPathMacAddr (
694     IN OUT POOL_PRINT       *Str,
695     IN VOID                 *DevPath
696     )
697 {
698     MAC_ADDR_DEVICE_PATH    *MAC;
699     UINTN                   HwAddressSize;
700     UINTN                   Index;
701 
702     MAC = DevPath;
703 
704     /* HwAddressSize = sizeof(EFI_MAC_ADDRESS); */
705     HwAddressSize = DevicePathNodeLength( & MAC-> Header ) ;
706     HwAddressSize -= sizeof( MAC-> Header ) ;
707     HwAddressSize -= sizeof( MAC-> IfType ) ;
708     if (MAC->IfType == 0x01 || MAC->IfType == 0x00) {
709         HwAddressSize = 6;
710     }
711 
712     CatPrint(Str, L"Mac(");
713 
714     for(Index = 0; Index < HwAddressSize; Index++) {
715         CatPrint(Str, L"%02x",MAC->MacAddress.Addr[Index]);
716     }
717     if ( MAC-> IfType != 0 ) {
718         CatPrint(Str, L",%d" , MAC-> IfType ) ;
719     }
720     CatPrint(Str, L")");
721 }
722 
723 static VOID
724 CatPrintIPv4(
725     IN OUT POOL_PRINT * Str ,
726     IN EFI_IPv4_ADDRESS * Address
727     )
728 {
729     CatPrint( Str , L"%d.%d.%d.%d" , Address-> Addr[ 0 ] , Address-> Addr[ 1 ] ,
730         Address-> Addr[ 2 ] , Address-> Addr[ 3 ] ) ;
731 }
732 
733 static BOOLEAN
734 IsNotNullIPv4(
735     IN EFI_IPv4_ADDRESS * Address
736     )
737 {
738     UINT8 val ;
739     val = Address-> Addr[ 0 ] | Address-> Addr[ 1 ] ;
740     val |= Address-> Addr[ 2 ] | Address-> Addr[ 3 ] ;
741     return val != 0 ;
742 }
743 
744 static VOID
745 CatPrintNetworkProtocol(
746     IN OUT POOL_PRINT * Str ,
747     IN UINT16 Proto
748     )
749 {
750     if ( Proto == 6 ) {
751         CatPrint( Str , L"TCP" ) ;
752     } else if ( Proto == 17 ) {
753         CatPrint( Str , L"UDP" ) ;
754     } else {
755         CatPrint( Str , L"%d" , Proto ) ;
756     }
757 }
758 
759 static VOID
760 _DevPathIPv4 (
761     IN OUT POOL_PRINT       *Str,
762     IN VOID                 *DevPath
763     )
764 {
765     IPv4_DEVICE_PATH     *IP;
766     BOOLEAN show ;
767 
768     IP = DevPath;
769     CatPrint( Str , L"IPv4(") ;
770     CatPrintIPv4( Str , & IP-> RemoteIpAddress ) ;
771     CatPrint( Str , L",") ;
772     CatPrintNetworkProtocol( Str , IP-> Protocol ) ;
773     CatPrint( Str , L",%s" , IP-> StaticIpAddress ? L"Static" : L"DHCP" ) ;
774     show = IsNotNullIPv4( & IP-> LocalIpAddress ) ;
775     if ( ! show && DevicePathNodeLength( & IP-> Header ) == sizeof( IPv4_DEVICE_PATH ) ) {
776         /* only version 2 includes gateway and netmask */
777         show |= IsNotNullIPv4( & IP-> GatewayIpAddress ) ;
778         show |= IsNotNullIPv4( & IP-> SubnetMask  ) ;
779     }
780     if ( show ) {
781         CatPrint( Str , L"," ) ;
782         CatPrintIPv4( Str , & IP-> LocalIpAddress ) ;
783         if ( DevicePathNodeLength( & IP-> Header ) == sizeof( IPv4_DEVICE_PATH ) ) {
784             /* only version 2 includes gateway and netmask */
785             show = IsNotNullIPv4( & IP-> GatewayIpAddress ) ;
786             show |= IsNotNullIPv4( & IP-> SubnetMask ) ;
787             if ( show ) {
788                 CatPrint( Str , L",") ;
789                 CatPrintIPv4( Str , & IP-> GatewayIpAddress ) ;
790                 if ( IsNotNullIPv4( & IP-> SubnetMask ) ) {
791                     CatPrint( Str , L",") ;
792                     CatPrintIPv4( Str , & IP-> SubnetMask ) ;
793                 }
794             }
795         }
796     }
797     CatPrint( Str , L")") ;
798 }
799 
800 #define CatPrintIPv6_ADD( x , y ) ( ( (UINT16) ( x ) ) << 8 | ( y ) )
801 static VOID
802 CatPrintIPv6(
803     IN OUT POOL_PRINT * Str ,
804     IN EFI_IPv6_ADDRESS * Address
805     )
806 {
807     CatPrint( Str , L"%x:%x:%x:%x:%x:%x:%x:%x" ,
808         CatPrintIPv6_ADD( Address-> Addr[ 0 ] , Address-> Addr[ 1 ] ) ,
809         CatPrintIPv6_ADD( Address-> Addr[ 2 ] , Address-> Addr[ 3 ] ) ,
810         CatPrintIPv6_ADD( Address-> Addr[ 4 ] , Address-> Addr[ 5 ] ) ,
811         CatPrintIPv6_ADD( Address-> Addr[ 6 ] , Address-> Addr[ 7 ] ) ,
812         CatPrintIPv6_ADD( Address-> Addr[ 8 ] , Address-> Addr[ 9 ] ) ,
813         CatPrintIPv6_ADD( Address-> Addr[ 10 ] , Address-> Addr[ 11 ] ) ,
814         CatPrintIPv6_ADD( Address-> Addr[ 12 ] , Address-> Addr[ 13 ] ) ,
815         CatPrintIPv6_ADD( Address-> Addr[ 14 ] , Address-> Addr[ 15 ] ) ) ;
816 }
817 
818 static VOID
819 _DevPathIPv6 (
820     IN OUT POOL_PRINT       *Str,
821     IN VOID                 *DevPath
822     )
823 {
824     IPv6_DEVICE_PATH     *IP;
825 
826     IP = DevPath;
827     CatPrint( Str , L"IPv6(") ;
828     CatPrintIPv6( Str , & IP-> RemoteIpAddress ) ;
829     CatPrint( Str , L",") ;
830     CatPrintNetworkProtocol( Str, IP-> Protocol ) ;
831     CatPrint( Str , L",%s," , IP-> IPAddressOrigin ?
832         ( IP-> IPAddressOrigin == 1 ? L"StatelessAutoConfigure" :
833         L"StatefulAutoConfigure" ) : L"Static" ) ;
834     CatPrintIPv6( Str , & IP-> LocalIpAddress ) ;
835     if ( DevicePathNodeLength( & IP-> Header ) == sizeof( IPv6_DEVICE_PATH ) ) {
836         CatPrint( Str , L",") ;
837         CatPrintIPv6( Str , & IP-> GatewayIpAddress ) ;
838         CatPrint( Str , L",") ;
839         CatPrint( Str , L"%d" , & IP-> PrefixLength ) ;
840     }
841     CatPrint( Str , L")") ;
842 }
843 
844 static VOID
845 _DevPathUri (
846     IN OUT POOL_PRINT       *Str,
847     IN VOID                 *DevPath
848     )
849 {
850     URI_DEVICE_PATH  *Uri;
851 
852     Uri = DevPath;
853 
854     CatPrint( Str, L"Uri(%a)", Uri->Uri );
855 }
856 
857 static VOID
858 _DevPathInfiniBand (
859     IN OUT POOL_PRINT       *Str,
860     IN VOID                 *DevPath
861     )
862 {
863     INFINIBAND_DEVICE_PATH  *InfiniBand;
864 
865     InfiniBand = DevPath;
866     CatPrint( Str , L"Infiniband(0x%x,%g,0x%lx,0x%lx,0x%lx)" ,
867         InfiniBand-> ResourceFlags , InfiniBand-> PortGid , InfiniBand-> ServiceId ,
868         InfiniBand-> TargetPortId , InfiniBand-> DeviceId ) ;
869 }
870 
871 static VOID
872 _DevPathUart (
873     IN OUT POOL_PRINT       *Str,
874     IN VOID                 *DevPath
875     )
876 {
877     UART_DEVICE_PATH  *Uart;
878     CHAR8             Parity;
879 
880     Uart = DevPath;
881     switch (Uart->Parity) {
882         case 0  : Parity = 'D'; break;
883         case 1  : Parity = 'N'; break;
884         case 2  : Parity = 'E'; break;
885         case 3  : Parity = 'O'; break;
886         case 4  : Parity = 'M'; break;
887         case 5  : Parity = 'S'; break;
888         default : Parity = 'x'; break;
889     }
890 
891     if (Uart->BaudRate == 0) {
892         CatPrint(Str, L"Uart(DEFAULT %c",Uart->BaudRate,Parity);
893     } else {
894         CatPrint(Str, L"Uart(%d %c",Uart->BaudRate,Parity);
895     }
896 
897     if (Uart->DataBits == 0) {
898         CatPrint(Str, L"D");
899     } else {
900         CatPrint(Str, L"%d",Uart->DataBits);
901     }
902 
903     switch (Uart->StopBits) {
904         case 0  : CatPrint(Str, L"D)");   break;
905         case 1  : CatPrint(Str, L"1)");   break;
906         case 2  : CatPrint(Str, L"1.5)"); break;
907         case 3  : CatPrint(Str, L"2)");   break;
908         default : CatPrint(Str, L"x)");   break;
909     }
910 }
911 
912 static VOID
913 _DevPathSata (
914     IN OUT POOL_PRINT       *Str,
915     IN VOID                 *DevPath
916     )
917 {
918     SATA_DEVICE_PATH * Sata ;
919 
920     Sata = DevPath;
921     CatPrint( Str , L"Sata(0x%x,0x%x,0x%x)" , Sata-> HBAPortNumber ,
922         Sata-> PortMultiplierPortNumber , Sata-> Lun ) ;
923 }
924 
925 static VOID
926 _DevPathHardDrive (
927     IN OUT POOL_PRINT       *Str,
928     IN VOID                 *DevPath
929     )
930 {
931     HARDDRIVE_DEVICE_PATH   *Hd;
932 
933     Hd = DevPath;
934     switch (Hd->SignatureType) {
935         case SIGNATURE_TYPE_MBR:
936             CatPrint(Str, L"HD(Part%d,Sig%08X)",
937                 Hd->PartitionNumber,
938                 *((UINT32 *)(&(Hd->Signature[0])))
939                 );
940             break;
941         case SIGNATURE_TYPE_GUID:
942             CatPrint(Str, L"HD(Part%d,Sig%g)",
943                 Hd->PartitionNumber,
944                 (EFI_GUID *) &(Hd->Signature[0])
945                 );
946             break;
947         default:
948             CatPrint(Str, L"HD(Part%d,MBRType=%02x,SigType=%02x)",
949                 Hd->PartitionNumber,
950                 Hd->MBRType,
951                 Hd->SignatureType
952                 );
953             break;
954     }
955 }
956 
957 static VOID
958 _DevPathCDROM (
959     IN OUT POOL_PRINT       *Str,
960     IN VOID                 *DevPath
961     )
962 {
963     CDROM_DEVICE_PATH       *Cd;
964 
965     Cd = DevPath;
966     CatPrint( Str , L"CDROM(0x%x)" , Cd-> BootEntry ) ;
967 }
968 
969 static VOID
970 _DevPathFilePath (
971     IN OUT POOL_PRINT       *Str,
972     IN VOID                 *DevPath
973     )
974 {
975     FILEPATH_DEVICE_PATH    *Fp;
976 
977     Fp = DevPath;
978     CatPrint(Str, L"%s", Fp->PathName);
979 }
980 
981 static VOID
982 _DevPathMediaProtocol (
983     IN OUT POOL_PRINT       *Str,
984     IN VOID                 *DevPath
985     )
986 {
987     MEDIA_PROTOCOL_DEVICE_PATH  *MediaProt;
988 
989     MediaProt = DevPath;
990     CatPrint(Str, L"%g", &MediaProt->Protocol);
991 }
992 
993 static VOID
994 _DevPathBssBss (
995     IN OUT POOL_PRINT       *Str,
996     IN VOID                 *DevPath
997     )
998 {
999     BBS_BBS_DEVICE_PATH     *Bss;
1000     CHAR16                  *Type;
1001 
1002     Bss = DevPath;
1003     switch (Bss->DeviceType) {
1004     case BBS_TYPE_FLOPPY:               Type = L"Floppy";       break;
1005     case BBS_TYPE_HARDDRIVE:            Type = L"Harddrive";    break;
1006     case BBS_TYPE_CDROM:                Type = L"CDROM";        break;
1007     case BBS_TYPE_PCMCIA:               Type = L"PCMCIA";       break;
1008     case BBS_TYPE_USB:                  Type = L"Usb";          break;
1009     case BBS_TYPE_EMBEDDED_NETWORK:     Type = L"Net";          break;
1010     default:                            Type = L"?";            break;
1011     }
1012 
1013     CatPrint(Str, L"Bss-%s(%a)", Type, Bss->String);
1014 }
1015 
1016 
1017 static VOID
1018 _DevPathEndInstance (
1019     IN OUT POOL_PRINT       *Str,
1020     IN VOID                 *DevPath EFI_UNUSED
1021     )
1022 {
1023     CatPrint(Str, L",");
1024 }
1025 
1026 /**
1027  * Print unknown device node.
1028  * UEFI 2.4 § 9.6.1.6 table 89.
1029  */
1030 
1031 static VOID
1032 _DevPathNodeUnknown (
1033     IN OUT POOL_PRINT       *Str,
1034     IN VOID                 *DevPath
1035     )
1036 {
1037     EFI_DEVICE_PATH * Path ;
1038     UINT8 * value ;
1039     int length , index ;
1040     Path = DevPath ;
1041     value = DevPath ;
1042     value += 4 ;
1043     switch ( Path-> Type ) {
1044         case HARDWARE_DEVICE_PATH : { /* Unknown Hardware Device Path */
1045             CatPrint( Str , L"HardwarePath(%d" , Path-> SubType ) ;
1046             break ;
1047         }
1048         case ACPI_DEVICE_PATH : { /* Unknown ACPI Device Path */
1049             CatPrint( Str , L"AcpiPath(%d" , Path-> SubType ) ;
1050             break ;
1051         }
1052         case MESSAGING_DEVICE_PATH : { /* Unknown Messaging Device Path */
1053             CatPrint( Str , L"Msg(%d" , Path-> SubType ) ;
1054             break ;
1055         }
1056         case MEDIA_DEVICE_PATH : { /* Unknown Media Device Path */
1057             CatPrint( Str , L"MediaPath(%d" , Path-> SubType ) ;
1058             break ;
1059         }
1060         case BBS_DEVICE_PATH : { /* Unknown BIOS Boot Specification Device Path */
1061             CatPrint( Str , L"BbsPath(%d" , Path-> SubType ) ;
1062             break ;
1063         }
1064         default : { /* Unknown Device Path */
1065             CatPrint( Str , L"Path(%d,%d" , Path-> Type , Path-> SubType ) ;
1066             break ;
1067         }
1068     }
1069     length = DevicePathNodeLength( Path ) ;
1070     for ( index = 0 ; index < length ; index ++ ) {
1071         if ( index == 0 ) CatPrint( Str , L",0x" ) ;
1072         CatPrint( Str , L"%02x" , * value ) ;
1073 	value ++ ;
1074     }
1075     CatPrint( Str , L")" ) ;
1076 }
1077 
1078 
1079 /*
1080  * Table to convert "Type" and "SubType" to a "convert to text" function/
1081  * Entries hold "Type" and "SubType" for know values.
1082  * Special "SubType" 0 is used as default for known type with unknown subtype.
1083  */
1084 struct {
1085     UINT8   Type;
1086     UINT8   SubType;
1087     VOID    (*Function)(POOL_PRINT *, VOID *);
1088 } DevPathTable[] = {
1089 	{ HARDWARE_DEVICE_PATH,   HW_PCI_DP,                        _DevPathPci},
1090 	{ HARDWARE_DEVICE_PATH,   HW_PCCARD_DP,                     _DevPathPccard},
1091 	{ HARDWARE_DEVICE_PATH,   HW_MEMMAP_DP,                     _DevPathMemMap},
1092 	{ HARDWARE_DEVICE_PATH,   HW_VENDOR_DP,                     _DevPathVendor},
1093 	{ HARDWARE_DEVICE_PATH,   HW_CONTROLLER_DP,                 _DevPathController},
1094 	{ ACPI_DEVICE_PATH,       ACPI_DP,                          _DevPathAcpi},
1095 	{ MESSAGING_DEVICE_PATH,  MSG_ATAPI_DP,                     _DevPathAtapi},
1096 	{ MESSAGING_DEVICE_PATH,  MSG_SCSI_DP,                      _DevPathScsi},
1097 	{ MESSAGING_DEVICE_PATH,  MSG_FIBRECHANNEL_DP,              _DevPathFibre},
1098 	{ MESSAGING_DEVICE_PATH,  MSG_1394_DP,                      _DevPath1394},
1099 	{ MESSAGING_DEVICE_PATH,  MSG_USB_DP,                       _DevPathUsb},
1100 	{ MESSAGING_DEVICE_PATH,  MSG_I2O_DP,                       _DevPathI2O},
1101 	{ MESSAGING_DEVICE_PATH,  MSG_MAC_ADDR_DP,                  _DevPathMacAddr},
1102 	{ MESSAGING_DEVICE_PATH,  MSG_IPv4_DP,                      _DevPathIPv4},
1103 	{ MESSAGING_DEVICE_PATH,  MSG_IPv6_DP,                      _DevPathIPv6},
1104 	{ MESSAGING_DEVICE_PATH,  MSG_URI_DP,                       _DevPathUri},
1105 	{ MESSAGING_DEVICE_PATH,  MSG_INFINIBAND_DP,                _DevPathInfiniBand},
1106 	{ MESSAGING_DEVICE_PATH,  MSG_UART_DP,                      _DevPathUart},
1107 	{ MESSAGING_DEVICE_PATH , MSG_SATA_DP ,                     _DevPathSata } ,
1108 	{ MESSAGING_DEVICE_PATH,  MSG_VENDOR_DP,                    _DevPathVendor},
1109 	{ MEDIA_DEVICE_PATH,      MEDIA_HARDDRIVE_DP,               _DevPathHardDrive},
1110 	{ MEDIA_DEVICE_PATH,      MEDIA_CDROM_DP,                   _DevPathCDROM},
1111 	{ MEDIA_DEVICE_PATH,      MEDIA_VENDOR_DP,                  _DevPathVendor},
1112 	{ MEDIA_DEVICE_PATH,      MEDIA_FILEPATH_DP,                _DevPathFilePath},
1113 	{ MEDIA_DEVICE_PATH,      MEDIA_PROTOCOL_DP,                _DevPathMediaProtocol},
1114 	{ BBS_DEVICE_PATH,        BBS_BBS_DP,                       _DevPathBssBss},
1115 	{ END_DEVICE_PATH_TYPE,   END_INSTANCE_DEVICE_PATH_SUBTYPE, _DevPathEndInstance},
1116 	{ 0,                      0,                          NULL}
1117 };
1118 
1119 
1120 CHAR16 *
1121 DevicePathToStr (
1122     EFI_DEVICE_PATH     *DevPath
1123     )
1124 /*++
1125 
1126     Turns the Device Path into a printable string.  Allcoates
1127     the string from pool.  The caller must FreePool the returned
1128     string.
1129 
1130 --*/
1131 {
1132     POOL_PRINT          Str;
1133     EFI_DEVICE_PATH     *DevPathNode;
1134     VOID                (*DumpNode)(POOL_PRINT *, VOID *);
1135     UINTN               Index, NewSize;
1136 
1137     ZeroMem(&Str, sizeof(Str));
1138 
1139     //
1140     // Unpacked the device path
1141     //
1142 
1143     DevPath = UnpackDevicePath(DevPath);
1144     ASSERT (DevPath);
1145 
1146 
1147     //
1148     // Process each device path node
1149     //
1150 
1151     DevPathNode = DevPath;
1152     while (!IsDevicePathEnd(DevPathNode)) {
1153         //
1154         // Find the handler to dump this device path node
1155         //
1156 
1157         DumpNode = NULL;
1158         for (Index = 0; DevPathTable[Index].Function; Index += 1) {
1159 
1160             if (DevicePathType(DevPathNode) == DevPathTable[Index].Type &&
1161                 DevicePathSubType(DevPathNode) == DevPathTable[Index].SubType) {
1162                 DumpNode = DevPathTable[Index].Function;
1163                 break;
1164             }
1165         }
1166 
1167         //
1168         // If not found, use a generic function
1169         //
1170 
1171         if (!DumpNode) {
1172             DumpNode = _DevPathNodeUnknown;
1173         }
1174 
1175         //
1176         //  Put a path seperator in if needed
1177         //
1178 
1179         if (Str.len  &&  DumpNode != _DevPathEndInstance) {
1180             CatPrint (&Str, L"/");
1181         }
1182 
1183         //
1184         // Print this node of the device path
1185         //
1186 
1187         DumpNode (&Str, DevPathNode);
1188 
1189         //
1190         // Next device path node
1191         //
1192 
1193         DevPathNode = NextDevicePathNode(DevPathNode);
1194     }
1195 
1196     //
1197     // Shrink pool used for string allocation
1198     //
1199 
1200     FreePool (DevPath);
1201     NewSize = (Str.len + 1) * sizeof(CHAR16);
1202     Str.str = ReallocatePool (Str.str, NewSize, NewSize);
1203     Str.str[Str.len] = 0;
1204     return Str.str;
1205 }
1206 
1207 BOOLEAN
1208 LibMatchDevicePaths (
1209     IN  EFI_DEVICE_PATH *Multi,
1210     IN  EFI_DEVICE_PATH *Single
1211     )
1212 {
1213     EFI_DEVICE_PATH     *DevicePath, *DevicePathInst;
1214     UINTN               Size;
1215 
1216     if (!Multi || !Single) {
1217         return FALSE;
1218     }
1219 
1220     DevicePath = Multi;
1221     while ((DevicePathInst = DevicePathInstance (&DevicePath, &Size))) {
1222         if (CompareMem (Single, DevicePathInst, Size) == 0) {
1223             return TRUE;
1224         }
1225     }
1226     return FALSE;
1227 }
1228 
1229 EFI_DEVICE_PATH *
1230 LibDuplicateDevicePathInstance (
1231     IN EFI_DEVICE_PATH  *DevPath
1232     )
1233 {
1234     EFI_DEVICE_PATH     *NewDevPath,*DevicePathInst,*Temp;
1235     UINTN               Size = 0;
1236 
1237     //
1238     // get the size of an instance from the input
1239     //
1240 
1241     Temp = DevPath;
1242     DevicePathInst = DevicePathInstance (&Temp, &Size);
1243 
1244     //
1245     // Make a copy and set proper end type
1246     //
1247     NewDevPath = NULL;
1248     if (Size) {
1249         NewDevPath = AllocatePool (Size + sizeof(EFI_DEVICE_PATH));
1250     }
1251 
1252     if (NewDevPath) {
1253         CopyMem (NewDevPath, DevicePathInst, Size);
1254         Temp = NextDevicePathNode(NewDevPath);
1255         SetDevicePathEndNode(Temp);
1256     }
1257 
1258     return NewDevPath;
1259 }
1260 
1261