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