xref: /DragonStub/lib/dpath.c (revision f412fd2a1a248b546b7085648dece8d908077fab)
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     // Guid has format of IEEE-EUI64
663     CatPrint(Str, L"I1394(%016lx)", F1394->Guid);
664 }
665 
666 
667 
668 static VOID
669 _DevPathUsb (
670     IN OUT POOL_PRINT       *Str,
671     IN VOID                 *DevPath
672     )
673 {
674     USB_DEVICE_PATH         *Usb;
675 
676     Usb = DevPath;
677     CatPrint( Str , L"Usb(0x%x,0x%x)" , Usb-> Port , Usb-> Endpoint ) ;
678 }
679 
680 
681 static VOID
682 _DevPathI2O (
683     IN OUT POOL_PRINT       *Str,
684     IN VOID                 *DevPath
685     )
686 {
687     I2O_DEVICE_PATH         *I2O;
688 
689     I2O = DevPath;
690     CatPrint(Str, L"I2O(0x%X)", I2O->Tid);
691 }
692 
693 static VOID
694 _DevPathMacAddr (
695     IN OUT POOL_PRINT       *Str,
696     IN VOID                 *DevPath
697     )
698 {
699     MAC_ADDR_DEVICE_PATH    *MAC;
700     UINTN                   HwAddressSize;
701     UINTN                   Index;
702 
703     MAC = DevPath;
704 
705     /* HwAddressSize = sizeof(EFI_MAC_ADDRESS); */
706     HwAddressSize = DevicePathNodeLength( & MAC-> Header ) ;
707     HwAddressSize -= sizeof( MAC-> Header ) ;
708     HwAddressSize -= sizeof( MAC-> IfType ) ;
709     if (MAC->IfType == 0x01 || MAC->IfType == 0x00) {
710         HwAddressSize = 6;
711     }
712 
713     CatPrint(Str, L"Mac(");
714 
715     for(Index = 0; Index < HwAddressSize; Index++) {
716         CatPrint(Str, L"%02x",MAC->MacAddress.Addr[Index]);
717     }
718     if ( MAC-> IfType != 0 ) {
719         CatPrint(Str, L",%d" , MAC-> IfType ) ;
720     }
721     CatPrint(Str, L")");
722 }
723 
724 static VOID
725 CatPrintIPv4(
726     IN OUT POOL_PRINT * Str ,
727     IN EFI_IPv4_ADDRESS * Address
728     )
729 {
730     CatPrint( Str , L"%d.%d.%d.%d" , Address-> Addr[ 0 ] , Address-> Addr[ 1 ] ,
731         Address-> Addr[ 2 ] , Address-> Addr[ 3 ] ) ;
732 }
733 
734 static BOOLEAN
735 IsNotNullIPv4(
736     IN EFI_IPv4_ADDRESS * Address
737     )
738 {
739     UINT8 val ;
740     val = Address-> Addr[ 0 ] | Address-> Addr[ 1 ] ;
741     val |= Address-> Addr[ 2 ] | Address-> Addr[ 3 ] ;
742     return val != 0 ;
743 }
744 
745 static VOID
746 CatPrintNetworkProtocol(
747     IN OUT POOL_PRINT * Str ,
748     IN UINT16 Proto
749     )
750 {
751     if ( Proto == 6 ) {
752         CatPrint( Str , L"TCP" ) ;
753     } else if ( Proto == 17 ) {
754         CatPrint( Str , L"UDP" ) ;
755     } else {
756         CatPrint( Str , L"%d" , Proto ) ;
757     }
758 }
759 
760 static VOID
761 _DevPathIPv4 (
762     IN OUT POOL_PRINT       *Str,
763     IN VOID                 *DevPath
764     )
765 {
766     IPv4_DEVICE_PATH     *IP;
767     BOOLEAN show ;
768 
769     IP = DevPath;
770     CatPrint( Str , L"IPv4(") ;
771     CatPrintIPv4( Str , & IP-> RemoteIpAddress ) ;
772     CatPrint( Str , L",") ;
773     CatPrintNetworkProtocol( Str , IP-> Protocol ) ;
774     CatPrint( Str , L",%s" , IP-> StaticIpAddress ? L"Static" : L"DHCP" ) ;
775     show = IsNotNullIPv4( & IP-> LocalIpAddress ) ;
776     if ( ! show && DevicePathNodeLength( & IP-> Header ) == sizeof( IPv4_DEVICE_PATH ) ) {
777         /* only version 2 includes gateway and netmask */
778         show |= IsNotNullIPv4( & IP-> GatewayIpAddress ) ;
779         show |= IsNotNullIPv4( & IP-> SubnetMask  ) ;
780     }
781     if ( show ) {
782         CatPrint( Str , L"," ) ;
783         CatPrintIPv4( Str , & IP-> LocalIpAddress ) ;
784         if ( DevicePathNodeLength( & IP-> Header ) == sizeof( IPv4_DEVICE_PATH ) ) {
785             /* only version 2 includes gateway and netmask */
786             show = IsNotNullIPv4( & IP-> GatewayIpAddress ) ;
787             show |= IsNotNullIPv4( & IP-> SubnetMask ) ;
788             if ( show ) {
789                 CatPrint( Str , L",") ;
790                 CatPrintIPv4( Str , & IP-> GatewayIpAddress ) ;
791                 if ( IsNotNullIPv4( & IP-> SubnetMask ) ) {
792                     CatPrint( Str , L",") ;
793                     CatPrintIPv4( Str , & IP-> SubnetMask ) ;
794                 }
795             }
796         }
797     }
798     CatPrint( Str , L")") ;
799 }
800 
801 #define CatPrintIPv6_ADD( x , y ) ( ( (UINT16) ( x ) ) << 8 | ( y ) )
802 static VOID
803 CatPrintIPv6(
804     IN OUT POOL_PRINT * Str ,
805     IN EFI_IPv6_ADDRESS * Address
806     )
807 {
808     CatPrint( Str , L"%x:%x:%x:%x:%x:%x:%x:%x" ,
809         CatPrintIPv6_ADD( Address-> Addr[ 0 ] , Address-> Addr[ 1 ] ) ,
810         CatPrintIPv6_ADD( Address-> Addr[ 2 ] , Address-> Addr[ 3 ] ) ,
811         CatPrintIPv6_ADD( Address-> Addr[ 4 ] , Address-> Addr[ 5 ] ) ,
812         CatPrintIPv6_ADD( Address-> Addr[ 6 ] , Address-> Addr[ 7 ] ) ,
813         CatPrintIPv6_ADD( Address-> Addr[ 8 ] , Address-> Addr[ 9 ] ) ,
814         CatPrintIPv6_ADD( Address-> Addr[ 10 ] , Address-> Addr[ 11 ] ) ,
815         CatPrintIPv6_ADD( Address-> Addr[ 12 ] , Address-> Addr[ 13 ] ) ,
816         CatPrintIPv6_ADD( Address-> Addr[ 14 ] , Address-> Addr[ 15 ] ) ) ;
817 }
818 
819 static VOID
820 _DevPathIPv6 (
821     IN OUT POOL_PRINT       *Str,
822     IN VOID                 *DevPath
823     )
824 {
825     IPv6_DEVICE_PATH     *IP;
826 
827     IP = DevPath;
828     CatPrint( Str , L"IPv6(") ;
829     CatPrintIPv6( Str , & IP-> RemoteIpAddress ) ;
830     CatPrint( Str , L",") ;
831     CatPrintNetworkProtocol( Str, IP-> Protocol ) ;
832     CatPrint( Str , L",%s," , IP-> IPAddressOrigin ?
833         ( IP-> IPAddressOrigin == 1 ? L"StatelessAutoConfigure" :
834         L"StatefulAutoConfigure" ) : L"Static" ) ;
835     CatPrintIPv6( Str , & IP-> LocalIpAddress ) ;
836     if ( DevicePathNodeLength( & IP-> Header ) == sizeof( IPv6_DEVICE_PATH ) ) {
837         CatPrint( Str , L",") ;
838         CatPrintIPv6( Str , & IP-> GatewayIpAddress ) ;
839         CatPrint( Str , L",") ;
840         CatPrint( Str , L"%d" , & IP-> PrefixLength ) ;
841     }
842     CatPrint( Str , L")") ;
843 }
844 
845 static VOID
846 _DevPathUri (
847     IN OUT POOL_PRINT       *Str,
848     IN VOID                 *DevPath
849     )
850 {
851     URI_DEVICE_PATH  *Uri;
852 
853     Uri = DevPath;
854 
855     CatPrint( Str, L"Uri(%a)", Uri->Uri );
856 }
857 
858 static VOID
859 _DevPathInfiniBand (
860     IN OUT POOL_PRINT       *Str,
861     IN VOID                 *DevPath
862     )
863 {
864     INFINIBAND_DEVICE_PATH  *InfiniBand;
865 
866     InfiniBand = DevPath;
867     CatPrint(Str, L"Infiniband(0x%x,%g,0x%lx,0x%lx,0x%lx)",
868         InfiniBand->ResourceFlags, InfiniBand->PortGid, InfiniBand->ServiceId,
869         InfiniBand->TargetPortId, InfiniBand->DeviceId);
870 }
871 
872 static VOID
873 _DevPathUart (
874     IN OUT POOL_PRINT       *Str,
875     IN VOID                 *DevPath
876     )
877 {
878     UART_DEVICE_PATH  *Uart;
879     CHAR8             Parity;
880 
881     Uart = DevPath;
882     switch (Uart->Parity) {
883         case 0  : Parity = 'D'; break;
884         case 1  : Parity = 'N'; break;
885         case 2  : Parity = 'E'; break;
886         case 3  : Parity = 'O'; break;
887         case 4  : Parity = 'M'; break;
888         case 5  : Parity = 'S'; break;
889         default : Parity = 'x'; break;
890     }
891 
892     if (Uart->BaudRate == 0) {
893         CatPrint(Str, L"Uart(DEFAULT,");
894     } else {
895         CatPrint(Str, L"Uart(%ld,", Uart->BaudRate);
896     }
897 
898     if (Uart->DataBits == 0) {
899         CatPrint(Str, L"DEFAULT,");
900     } else {
901         CatPrint(Str, L"%d,", Uart->DataBits);
902     }
903 
904     CatPrint(Str, L"%c,", Parity);
905 
906     switch (Uart->StopBits) {
907         case 0  : CatPrint(Str, L"D)");   break;
908         case 1  : CatPrint(Str, L"1)");   break;
909         case 2  : CatPrint(Str, L"1.5)"); break;
910         case 3  : CatPrint(Str, L"2)");   break;
911         default : CatPrint(Str, L"x)");   break;
912     }
913 }
914 
915 static VOID
916 _DevPathSata (
917     IN OUT POOL_PRINT       *Str,
918     IN VOID                 *DevPath
919     )
920 {
921     SATA_DEVICE_PATH * Sata ;
922 
923     Sata = DevPath;
924     CatPrint( Str , L"Sata(0x%x,0x%x,0x%x)" , Sata-> HBAPortNumber ,
925         Sata-> PortMultiplierPortNumber , Sata-> Lun ) ;
926 }
927 
928 static VOID
929 _DevPathHardDrive (
930     IN OUT POOL_PRINT       *Str,
931     IN VOID                 *DevPath
932     )
933 {
934     HARDDRIVE_DEVICE_PATH   *Hd;
935 
936     Hd = DevPath;
937     switch (Hd->SignatureType) {
938         case SIGNATURE_TYPE_MBR:
939             CatPrint(Str, L"HD(%d,MBR,0x%08x)",
940                 Hd->PartitionNumber,
941                 *((UINT32 *)(&(Hd->Signature[0])))
942                 );
943             break;
944         case SIGNATURE_TYPE_GUID:
945             CatPrint(Str, L"HD(%d,GPT,%g)",
946                 Hd->PartitionNumber,
947                 (EFI_GUID *) &(Hd->Signature[0])
948                 );
949             break;
950         default:
951             CatPrint(Str, L"HD(%d,%d,0)",
952                 Hd->PartitionNumber,
953                 Hd->SignatureType
954                 );
955             break;
956     }
957 }
958 
959 static VOID
960 _DevPathCDROM (
961     IN OUT POOL_PRINT       *Str,
962     IN VOID                 *DevPath
963     )
964 {
965     CDROM_DEVICE_PATH       *Cd;
966 
967     Cd = DevPath;
968     CatPrint( Str , L"CDROM(0x%x)" , Cd-> BootEntry ) ;
969 }
970 
971 static VOID
972 _DevPathFilePath (
973     IN OUT POOL_PRINT       *Str,
974     IN VOID                 *DevPath
975     )
976 {
977     FILEPATH_DEVICE_PATH    *Fp;
978 
979     Fp = DevPath;
980     CatPrint(Str, L"%s", Fp->PathName);
981 }
982 
983 static VOID
984 _DevPathMediaProtocol (
985     IN OUT POOL_PRINT       *Str,
986     IN VOID                 *DevPath
987     )
988 {
989     MEDIA_PROTOCOL_DEVICE_PATH  *MediaProt;
990 
991     MediaProt = DevPath;
992     CatPrint(Str, L"%g", &MediaProt->Protocol);
993 }
994 
995 static VOID
996 _DevPathBssBss (
997     IN OUT POOL_PRINT       *Str,
998     IN VOID                 *DevPath
999     )
1000 {
1001     BBS_BBS_DEVICE_PATH     *Bss;
1002     CHAR16                  *Type;
1003 
1004     Bss = DevPath;
1005     switch (Bss->DeviceType) {
1006     case BBS_TYPE_FLOPPY:               Type = L"Floppy";       break;
1007     case BBS_TYPE_HARDDRIVE:            Type = L"Harddrive";    break;
1008     case BBS_TYPE_CDROM:                Type = L"CDROM";        break;
1009     case BBS_TYPE_PCMCIA:               Type = L"PCMCIA";       break;
1010     case BBS_TYPE_USB:                  Type = L"Usb";          break;
1011     case BBS_TYPE_EMBEDDED_NETWORK:     Type = L"Net";          break;
1012     default:                            Type = L"?";            break;
1013     }
1014 
1015     CatPrint(Str, L"Bss-%s(%a)", Type, Bss->String);
1016 }
1017 
1018 
1019 static VOID
1020 _DevPathEndInstance (
1021     IN OUT POOL_PRINT       *Str,
1022     IN VOID                 *DevPath EFI_UNUSED
1023     )
1024 {
1025     CatPrint(Str, L",");
1026 }
1027 
1028 /**
1029  * Print unknown device node.
1030  * UEFI 2.4 § 9.6.1.6 table 89.
1031  */
1032 
1033 static VOID
1034 _DevPathNodeUnknown (
1035     IN OUT POOL_PRINT       *Str,
1036     IN VOID                 *DevPath
1037     )
1038 {
1039     EFI_DEVICE_PATH * Path ;
1040     UINT8 * value ;
1041     int length , index ;
1042     Path = DevPath ;
1043     value = DevPath ;
1044     value += 4 ;
1045     switch ( Path-> Type ) {
1046         case HARDWARE_DEVICE_PATH : { /* Unknown Hardware Device Path */
1047             CatPrint( Str , L"HardwarePath(%d" , Path-> SubType ) ;
1048             break ;
1049         }
1050         case ACPI_DEVICE_PATH : { /* Unknown ACPI Device Path */
1051             CatPrint( Str , L"AcpiPath(%d" , Path-> SubType ) ;
1052             break ;
1053         }
1054         case MESSAGING_DEVICE_PATH : { /* Unknown Messaging Device Path */
1055             CatPrint( Str , L"Msg(%d" , Path-> SubType ) ;
1056             break ;
1057         }
1058         case MEDIA_DEVICE_PATH : { /* Unknown Media Device Path */
1059             CatPrint( Str , L"MediaPath(%d" , Path-> SubType ) ;
1060             break ;
1061         }
1062         case BBS_DEVICE_PATH : { /* Unknown BIOS Boot Specification Device Path */
1063             CatPrint( Str , L"BbsPath(%d" , Path-> SubType ) ;
1064             break ;
1065         }
1066         default : { /* Unknown Device Path */
1067             CatPrint( Str , L"Path(%d,%d" , Path-> Type , Path-> SubType ) ;
1068             break ;
1069         }
1070     }
1071     length = DevicePathNodeLength( Path ) ;
1072     for ( index = 0 ; index < length ; index ++ ) {
1073         if ( index == 0 ) CatPrint( Str , L",0x" ) ;
1074         CatPrint( Str , L"%02x" , * value ) ;
1075 	value ++ ;
1076     }
1077     CatPrint( Str , L")" ) ;
1078 }
1079 
1080 
1081 /*
1082  * Table to convert "Type" and "SubType" to a "convert to text" function/
1083  * Entries hold "Type" and "SubType" for know values.
1084  * Special "SubType" 0 is used as default for known type with unknown subtype.
1085  */
1086 typedef struct {
1087     UINT8   Type;
1088     UINT8   SubType;
1089     VOID    (*Function)(POOL_PRINT *, VOID *);
1090 } DevPathTable_Type;
1091 DevPathTable_Type DevPathTable[] = {
1092 	{ HARDWARE_DEVICE_PATH,   HW_PCI_DP,                        _DevPathPci},
1093 	{ HARDWARE_DEVICE_PATH,   HW_PCCARD_DP,                     _DevPathPccard},
1094 	{ HARDWARE_DEVICE_PATH,   HW_MEMMAP_DP,                     _DevPathMemMap},
1095 	{ HARDWARE_DEVICE_PATH,   HW_VENDOR_DP,                     _DevPathVendor},
1096 	{ HARDWARE_DEVICE_PATH,   HW_CONTROLLER_DP,                 _DevPathController},
1097 	{ ACPI_DEVICE_PATH,       ACPI_DP,                          _DevPathAcpi},
1098 	{ MESSAGING_DEVICE_PATH,  MSG_ATAPI_DP,                     _DevPathAtapi},
1099 	{ MESSAGING_DEVICE_PATH,  MSG_SCSI_DP,                      _DevPathScsi},
1100 	{ MESSAGING_DEVICE_PATH,  MSG_FIBRECHANNEL_DP,              _DevPathFibre},
1101 	{ MESSAGING_DEVICE_PATH,  MSG_1394_DP,                      _DevPath1394},
1102 	{ MESSAGING_DEVICE_PATH,  MSG_USB_DP,                       _DevPathUsb},
1103 	{ MESSAGING_DEVICE_PATH,  MSG_I2O_DP,                       _DevPathI2O},
1104 	{ MESSAGING_DEVICE_PATH,  MSG_MAC_ADDR_DP,                  _DevPathMacAddr},
1105 	{ MESSAGING_DEVICE_PATH,  MSG_IPv4_DP,                      _DevPathIPv4},
1106 	{ MESSAGING_DEVICE_PATH,  MSG_IPv6_DP,                      _DevPathIPv6},
1107 	{ MESSAGING_DEVICE_PATH,  MSG_URI_DP,                       _DevPathUri},
1108 	{ MESSAGING_DEVICE_PATH,  MSG_INFINIBAND_DP,                _DevPathInfiniBand},
1109 	{ MESSAGING_DEVICE_PATH,  MSG_UART_DP,                      _DevPathUart},
1110 	{ MESSAGING_DEVICE_PATH , MSG_SATA_DP ,                     _DevPathSata } ,
1111 	{ MESSAGING_DEVICE_PATH,  MSG_VENDOR_DP,                    _DevPathVendor},
1112 	{ MEDIA_DEVICE_PATH,      MEDIA_HARDDRIVE_DP,               _DevPathHardDrive},
1113 	{ MEDIA_DEVICE_PATH,      MEDIA_CDROM_DP,                   _DevPathCDROM},
1114 	{ MEDIA_DEVICE_PATH,      MEDIA_VENDOR_DP,                  _DevPathVendor},
1115 	{ MEDIA_DEVICE_PATH,      MEDIA_FILEPATH_DP,                _DevPathFilePath},
1116 	{ MEDIA_DEVICE_PATH,      MEDIA_PROTOCOL_DP,                _DevPathMediaProtocol},
1117 	{ BBS_DEVICE_PATH,        BBS_BBS_DP,                       _DevPathBssBss},
1118 	{ END_DEVICE_PATH_TYPE,   END_INSTANCE_DEVICE_PATH_SUBTYPE, _DevPathEndInstance},
1119 	{ 0,                      0,                          NULL}
1120 };
1121 
1122 
1123 CHAR16 *
1124 DevicePathToStr (
1125     EFI_DEVICE_PATH     *DevPath
1126     )
1127 /*++
1128 
1129     Turns the Device Path into a printable string.  Allcoates
1130     the string from pool.  The caller must FreePool the returned
1131     string.
1132 
1133 --*/
1134 {
1135     POOL_PRINT          Str;
1136     EFI_DEVICE_PATH     *DevPathNode;
1137     VOID                (*DumpNode)(POOL_PRINT *, VOID *);
1138     UINTN               Index, NewSize;
1139 
1140     ZeroMem(&Str, sizeof(Str));
1141 
1142     //
1143     // Unpacked the device path
1144     //
1145 
1146     DevPath = UnpackDevicePath(DevPath);
1147     ASSERT (DevPath);
1148 
1149 
1150     //
1151     // Process each device path node
1152     //
1153 
1154     DevPathNode = DevPath;
1155     while (!IsDevicePathEnd(DevPathNode)) {
1156         //
1157         // Find the handler to dump this device path node
1158         //
1159 
1160         DumpNode = NULL;
1161         for (Index = 0; DevPathTable[Index].Function; Index += 1) {
1162 
1163             if (DevicePathType(DevPathNode) == DevPathTable[Index].Type &&
1164                 DevicePathSubType(DevPathNode) == DevPathTable[Index].SubType) {
1165                 DumpNode = DevPathTable[Index].Function;
1166                 break;
1167             }
1168         }
1169 
1170         //
1171         // If not found, use a generic function
1172         //
1173 
1174         if (!DumpNode) {
1175             DumpNode = _DevPathNodeUnknown;
1176         }
1177 
1178         //
1179         //  Put a path seperator in if needed
1180         //
1181 
1182         if (Str.len  &&  DumpNode != _DevPathEndInstance) {
1183             CatPrint (&Str, L"/");
1184         }
1185 
1186         //
1187         // Print this node of the device path
1188         //
1189 
1190         DumpNode (&Str, DevPathNode);
1191 
1192         //
1193         // Next device path node
1194         //
1195 
1196         DevPathNode = NextDevicePathNode(DevPathNode);
1197     }
1198 
1199     //
1200     // Shrink pool used for string allocation
1201     //
1202 
1203     FreePool (DevPath);
1204     NewSize = (Str.len + 1) * sizeof(CHAR16);
1205     Str.str = ReallocatePool (Str.str, NewSize, NewSize);
1206     Str.str[Str.len] = 0;
1207     return Str.str;
1208 }
1209 
1210 BOOLEAN
1211 LibMatchDevicePaths (
1212     IN  EFI_DEVICE_PATH *Multi,
1213     IN  EFI_DEVICE_PATH *Single
1214     )
1215 {
1216     EFI_DEVICE_PATH     *DevicePath, *DevicePathInst;
1217     UINTN               Size;
1218 
1219     if (!Multi || !Single) {
1220         return FALSE;
1221     }
1222 
1223     DevicePath = Multi;
1224     while ((DevicePathInst = DevicePathInstance (&DevicePath, &Size))) {
1225         if (CompareMem (Single, DevicePathInst, Size) == 0) {
1226             return TRUE;
1227         }
1228     }
1229     return FALSE;
1230 }
1231 
1232 EFI_DEVICE_PATH *
1233 LibDuplicateDevicePathInstance (
1234     IN EFI_DEVICE_PATH  *DevPath
1235     )
1236 {
1237     EFI_DEVICE_PATH     *NewDevPath,*DevicePathInst,*Temp;
1238     UINTN               Size = 0;
1239 
1240     //
1241     // get the size of an instance from the input
1242     //
1243 
1244     Temp = DevPath;
1245     DevicePathInst = DevicePathInstance (&Temp, &Size);
1246 
1247     //
1248     // Make a copy and set proper end type
1249     //
1250     NewDevPath = NULL;
1251     if (Size) {
1252         NewDevPath = AllocatePool (Size + sizeof(EFI_DEVICE_PATH));
1253     }
1254 
1255     if (NewDevPath) {
1256         CopyMem (NewDevPath, DevicePathInst, Size);
1257         Temp = NextDevicePathNode(NewDevPath);
1258         SetDevicePathEndNode(Temp);
1259     }
1260 
1261     return NewDevPath;
1262 }
1263 
1264