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