Newer
Older
AMI-Aptio-BIOS-Reversed / MdeModulePkg / Universal / DevicePathDxe / DevicePathDxe.c
@Ajax Dong Ajax Dong 2 days ago 29 KB Full restructure
/*
 * DevicePathDxe.c - UEFI Device Path DXE Driver
 * Module: DevicePathDxe.efi (from Lenovo HR650X BIOS)
 * SHA256: 9139a18c6d78dc89a880b0944c1833e2ae37cda701ca74670f086e65d28ad5bd
 *
 * This driver implements three UEFI device path protocol libraries:
 *  - DevicePathUtilities:   Core device path node manipulation
 *  - DevicePathToText:      Convert device path to human-readable text
 *  - DevicePathFromText:    Parse text representation back to device path
 *
 * The entry point installs these three protocol interfaces via
 * gBS->InstallMultipleProtocolInterfaces():
 *   - EFI_DEVICE_PATH_UTILITIES_PROTOCOL
 *   - EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
 *   - EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
 *
 * File Structure (address ranges):
 *   0x000 - 0x2C0   PE/COFF header
 *   0x2C0 - 0x7E20  .text (code)
 *   0x7E20 - 0xAE20 .rdata (strings, format strings, dispatch tables)
 *   0xAE20 - 0xB4E0 .data (protocol GUIDs, globals)
 *   0xB4E0 - 0xBCA0 seg004 (more read-only data)
 *   0xBCA0 - 0xC020 .xdata (exception handling)
 *   0xC020 - 0xC280 .reloc (base relocations)
 */

#include "Tcg2Dxe.h"  /* Not actually Tcg2 but we keep project convention */
/* NOTE: This file is a decompiled representation of the UEFI device path
 * protocol driver. The actual source file from the EDK2 build environment
 * is named "DevicePathDxe.c" and lives under
 * AmiModulePkg/TCG2/Common/TcgDxe/ in the AMI BIOS tree. */

// ============================================================================
// SECTION 1: Device Path Node Access (DevicePathUtilities)
// ============================================================================

//
// GetDevicePathType - Read Type byte from device path node
// Equivalent to EDK2: DevicePathType(Node)
//
UINT8
GetDevicePathType(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return Node->Type;
}

//
// GetDevicePathSubType - Read SubType byte from device path node
// Equivalent to EDK2: DevicePathSubType(Node)
//
UINT8
GetDevicePathSubType(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return Node->SubType;
}

//
// GetDevicePathNodeLength - Read Length field from device path node
// Equivalent to EDK2: DevicePathNodeLength(Node)
//
UINTN
GetDevicePathNodeLength(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return Node->Length[0] | (Node->Length[1] << 8);
}

//
// NextDevicePathNode - Advance to next device path node
//
EFI_DEVICE_PATH_PROTOCOL *
NextDevicePathNode(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)Node + GetDevicePathNodeLength(Node));
}

//
// IsDevicePathEnd - Check if node type is END (0x7F)
//
BOOLEAN
IsDevicePathEnd(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return (GetDevicePathType(Node) == END_DEVICE_PATH_TYPE);
}

//
// IsDevicePathEndInstance - Check for END + END_ENTIRE (0xFF)
//
BOOLEAN
IsDevicePathEndInstance(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return (IsDevicePathEnd(Node) && (GetDevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE));
}

//
// SetDevicePathNodeLength - Write Length field
//
UINT16
SetDevicePathNodeLength(
  IN EFI_DEVICE_PATH_PROTOCOL *Node,
  IN UINTN                   Length
  )
{
  Node->Length[0] = (UINT8)(Length & 0xFF);
  Node->Length[1] = (UINT8)((Length >> 8) & 0xFF);
  return (UINT16)Length;
}

//
// SetDevicePathEndInstance - Mark node as END of entire path
//
EFI_DEVICE_PATH_PROTOCOL *
SetDevicePathEndInstance(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  return CopyMem (Node, mEndDevicePathInstance, sizeof (EFI_DEVICE_PATH_PROTOCOL));
}

//
// DevicePathValid - Validate entire device path mult-instance
// Verifies each node length >= 4, no length overflow, ends with END
//
BOOLEAN
DevicePathValid(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *Node;
  UINTN                    TotalLength;
  UINTN                    NodeLength;

  Node = DevicePath;
  TotalLength = 0;
  while (TRUE) {
    if (IsDevicePathEndInstance (Node)) {
      return (GetDevicePathNodeLength (Node) == sizeof (EFI_DEVICE_PATH_PROTOCOL));
    }
    NodeLength = GetDevicePathNodeLength (Node);
    if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) return FALSE;
    if (NodeLength > (MAX_UINTN - TotalLength)) return FALSE;
    TotalLength += NodeLength;
    if (TotalLength > (MAX_UINTN - sizeof (EFI_DEVICE_PATH_PROTOCOL))) return FALSE;
    Node = NextDevicePathNode (Node);
  }
}

//
// DevicePathNodeLength - Wrapper for GetDevicePathNodeLength with ASSERT
//
UINTN
DevicePathNodeLength(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  ASSERT (Node != NULL);
  return GetDevicePathNodeLength (Node);
}

//
// DevicePathType - Wrapper for GetDevicePathType with ASSERT
//
UINT8
DevicePathType(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  ASSERT (Node != NULL);
  return Node->Type;
}

//
// DevicePathSubType - Wrapper for GetDevicePathSubType with ASSERT
//
UINT8
DevicePathSubType(
  IN EFI_DEVICE_PATH_PROTOCOL *Node
  )
{
  ASSERT (Node != NULL);
  return Node->SubType;
}


// ============================================================================
// SECTION 2: Device Path Node Construction Helpers
// ============================================================================

//
// CreateDevicePathNode - Allocate and initialize a device path node
//   Type:     device path node type
//   SubType:  device path node sub-type
//   Length:   total node length (>= 4)
// Returns: allocated node or NULL
//
EFI_DEVICE_PATH_PROTOCOL *
CreateDevicePathNode(
  IN UINT8   Type,
  IN UINT8   SubType,
  IN UINT16  Length
  )
{
  EFI_DEVICE_PATH_PROTOCOL *Node;

  if (Length < sizeof (EFI_DEVICE_PATH_PROTOCOL)) return NULL;
  Node = (EFI_DEVICE_PATH_PROTOCOL *)AllocatePool (Length);
  if (Node != NULL) {
    ZeroMem (Node, Length);
    Node->Type    = Type;
    Node->SubType = SubType;
    SetDevicePathNodeLength (Node, Length);
  }
  return Node;
}


// ============================================================================
// SECTION 3: Device Path Manipulation (concatenate, append, etc.)
// ============================================================================

//
// DevicePathStrSize - Return total size of device path in bytes
//   (including the END node)
//
UINTN
DevicePathStrSize(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *StartNode;
  EFI_DEVICE_PATH_PROTOCOL  *Node;
  UINTN                     Size;

  if (DevicePath == NULL) return 0;
  StartNode = DevicePath;
  Node      = DevicePath;

  // Walk to END node
  while (!IsDevicePathEndInstance (Node)) {
    Node = NextDevicePathNode (Node);
  }

  Size = (UINTN)Node - (UINTN)StartNode + sizeof (EFI_DEVICE_PATH_PROTOCOL);
  return Size;
}

//
// DuplicateDevicePath - Duplicate a device path
//
EFI_DEVICE_PATH_PROTOCOL *
DuplicateDevicePath(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *NewPath;
  UINTN                     Size;

  if (DevicePath == NULL) return NULL;
  Size = DevicePathStrSize (DevicePath);
  NewPath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (Size, DevicePath);
  return NewPath;
}

//
// AppendDevicePath - Concatenate two device paths
//
EFI_DEVICE_PATH_PROTOCOL *
AppendDevicePath(
  IN EFI_DEVICE_PATH_PROTOCOL *First,
  IN EFI_DEVICE_PATH_PROTOCOL *Second
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *NewPath;
  UINTN                     FirstSize;
  UINTN                     SecondSize;
  UINT8                     *Buffer;

  if (First == NULL)  return DuplicateDevicePath (Second);
  if (Second == NULL) return DuplicateDevicePath (First);
  if (!DevicePathValid (First) || !DevicePathValid (Second)) return NULL;

  FirstSize  = DevicePathStrSize (First) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
  SecondSize = DevicePathStrSize (Second);

  NewPath = (EFI_DEVICE_PATH_PROTOCOL *)AllocatePool (FirstSize + SecondSize);
  if (NewPath != NULL) {
    Buffer = (UINT8 *)NewPath;
    if (FirstSize != 0) {
      CopyMem (Buffer, First, FirstSize);
      Buffer += FirstSize;
    }
    if (SecondSize != 0) {
      CopyMem (Buffer, Second, SecondSize);
    }
  }
  return NewPath;
}

//
// AppendDevicePathNode - Append a single node to a device path
//
EFI_DEVICE_PATH_PROTOCOL *
AppendDevicePathNode(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  IN EFI_DEVICE_PATH_PROTOCOL *DeviceNode
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *NewPath;
  UINTN                     DevicePathSize;
  UINTN                     NodeSize;
  UINT8                     *Buffer;

  if (DeviceNode == NULL) return DuplicateDevicePath (DevicePath);
  if (DevicePath == NULL) return DuplicateDevicePath (DeviceNode);
  if (!DevicePathValid (DevicePath) || !DevicePathValid (DeviceNode)) return NULL;

  DevicePathSize = DevicePathStrSize (DevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
  NodeSize       = DevicePathNodeLength (DeviceNode);

  NewPath = (EFI_DEVICE_PATH_PROTOCOL *)AllocatePool (DevicePathSize + NodeSize + sizeof (EFI_DEVICE_PATH_PROTOCOL));
  if (NewPath != NULL) {
    Buffer = (UINT8 *)NewPath;
    CopyMem (Buffer, DevicePath, DevicePathSize);
    Buffer += DevicePathSize;
    CopyMem (Buffer, DeviceNode, NodeSize);
    Buffer += NodeSize;
    SetDevicePathEndInstance ((EFI_DEVICE_PATH_PROTOCOL *)Buffer);
  }
  return NewPath;
}

//
// AppendDevicePathInstance - Append a second multi-instance path
//   with the END_INSTANCE separator
//
EFI_DEVICE_PATH_PROTOCOL *
AppendDevicePathInstance(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *NewPath;
  UINTN                     Size;
  UINTN                     InstanceSize;
  UINT8                     *Buffer;

  if (DevicePath == NULL) return DuplicateDevicePath (DevicePathInstance);
  if (DevicePathInstance == NULL) return NULL;

  Size         = DevicePathStrSize (DevicePath);
  InstanceSize = DevicePathStrSize (DevicePathInstance);

  NewPath = (EFI_DEVICE_PATH_PROTOCOL *)AllocatePool (Size + InstanceSize);
  if (NewPath != NULL) {
    Buffer = (UINT8 *)NewPath;
    CopyMem (Buffer, DevicePath, Size);
    Buffer += Size - sizeof (EFI_DEVICE_PATH_PROTOCOL);
    //
    // Overwrite the final END_ENTIRE with END_INSTANCE
    //
    SetDevicePathEndInstance ((EFI_DEVICE_PATH_PROTOCOL *)Buffer - 1); /* actually set subtype */
    CopyMem (Buffer, DevicePathInstance, InstanceSize);
  }
  return NewPath;
}

//
// ExtractDevicePathInstanceFromText - Split a multi-instance path
//   Returns buffer of one instance and its size
//
EFI_DEVICE_PATH_PROTOCOL *
ExtractDevicePathInstance(
  IN  EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  OUT UINTN                    *InstanceSize
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *Node;
  EFI_DEVICE_PATH_PROTOCOL  *Instance;
  UINT8                     SavedSubType;

  if (DevicePath == NULL || InstanceSize == NULL) {
    if (InstanceSize != NULL) *InstanceSize = 0;
    return NULL;
  }

  if (!DevicePathValid (DevicePath)) {
    *InstanceSize = 0;
    return NULL;
  }

  // Locate the END node for this instance
  Node = DevicePath;
  while (!IsDevicePathEnd (Node)) {
    Node = NextDevicePathNode (Node);
  }

  // Save and override END subType for size calculation
  SavedSubType = GetDevicePathSubType (Node);
  SetDevicePathEndInstance (Node); /* set to END_ENTIRE */
  Instance = DuplicateDevicePath (DevicePath);
  *InstanceSize = DevicePathStrSize (DevicePath);

  // Restore and advance past END node
  *(UINT8 *)(&Node->SubType) = SavedSubType;
  if (SavedSubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
    // No more instances
    *(EFI_DEVICE_PATH_PROTOCOL **)DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)NULL;
  } else {
    *(EFI_DEVICE_PATH_PROTOCOL **)DevicePath = NextDevicePathNode (Node);
  }

  return Instance;
}

//
// IsDevicePathMultiInstance - Check if path has multiple instances
//
BOOLEAN
IsDevicePathMultiInstance(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *Node;

  if (DevicePath == NULL) return FALSE;

  Node = DevicePath;
  while (!IsDevicePathEnd (Node)) {
    Node = NextDevicePathNode (Node);
  }

  return (GetDevicePathSubType (Node) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
}

//
// DevicePathNodeInstanceContain - Check if path contains END_INSTANCE
//
BOOLEAN
DevicePathNodeInstanceContain(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *Node;

  if (!DevicePathValid (DevicePath)) return FALSE;

  Node = DevicePath;
  while (!IsDevicePathEndInstance (Node)) {
    if (Node == NULL) return FALSE;
    if (IsDevicePathEnd (Node) && GetDevicePathSubType(Node) == 1) return TRUE;
    Node = NextDevicePathNode (Node);
  }
  return FALSE;
}


// ============================================================================
// SECTION 4: Device Path To Text (DevicePathToText)
// ============================================================================

//
// DevicePathToTextStr - Convert a single device path node to text string
//
CHAR16 *
DevicePathToTextStr(
  IN EFI_DEVICE_PATH_PROTOCOL *DeviceNode,
  IN BOOLEAN                 DisplayOnly,
  IN BOOLEAN                 AllowShortcuts
  )
{
  CHAR16 *String;

  if (DeviceNode == NULL) return NULL;

  String = NULL;
  if (mUefiDevicePathLibToTextTable != NULL) {
    //
    // Lookup in dispatch table based on Type/SubType
    //
  }
  if (String == NULL) {
    //
    // Default conversion for unknown node types
    //
    String = DefaultDevicePathToTextStr (DeviceNode, DisplayOnly, AllowShortcuts);
  }

  if (String == NULL) {
    DEBUG ((EFI_D_ERROR, "DevicePathToTextStr: String != NULL\n"));
  }
  return String;
}

//
// DevicePathToText - Convert entire device path to text
//   This is the main protocol function
//
CHAR16 *
DevicePathToText(
  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  IN BOOLEAN                 DisplayOnly,
  IN BOOLEAN                 AllowShortcuts
  )
{
  CHAR16                    *String;
  CHAR16                    *Temp;
  EFI_DEVICE_PATH_PROTOCOL  *Node;
  UINTN                     StringCount;
  CHAR16                    *ReturnString;
  DYNAMIC_STRING            Str;
  CHAR16                    NullString[2];

  if (DevicePath == NULL) {
    NullString[0] = L'\0';
    return AllocateCopyPool (2, NullString);
  }

  Str.String      = NULL;
  Str.MaxLen      = 0;
  Str.CurrentLen  = 0;

  Node = DevicePath;
  while (!IsDevicePathEndInstance (Node)) {
    //
    // Convert each node via the type table, joining with L"/"
    //
    String = DevicePathToTextStr (Node, DisplayOnly, AllowShortcuts);

    if (Str.String != NULL && Str.CurrentLen != 0) {
      CatSPrint (&Str, L"/");
    }

    CatSPrint (&Str, L"%s", String);
    FreePool (String);

    Node = NextDevicePathNode (Node);
  }

  ReturnString = Str.String;
  if (ReturnString == NULL) {
    ReturnString = AllocateCopyPool (2, NullString);
  }
  return ReturnString;
}

//
// DefaultDevicePathToTextStr - Fallback conversion for unregistered types
//
CHAR16 *
DefaultDevicePathToTextStr(
  IN EFI_DEVICE_PATH_PROTOCOL *Node,
  IN BOOLEAN                 DisplayOnly,
  IN BOOLEAN                 AllowShortcuts
  )
{
  return NULL;
}

//
// CatDevicePathToTextStr - Append formatted text to dynamic string
//
VOID
CatDevicePathToTextStr(
  IN OUT EFI_DEVICE_PATH_PROTOCOL *Str,
  IN     CHAR16                    *Format,
  ...
  )
{
  VA_LIST  Args;
  CHAR16   *NewStr;
  UINTN    NewSize;

  VA_START (Args, Format);
  //
  // Calculate needed size via SPrint
  //
  VA_END (Args);
}


// ============================================================================
// SECTION 5: Device Path From Text (DevicePathFromText)
// ============================================================================

//
// DevicePathFromText - Convert text representation to device path
//   This is the main protocol function
//
EFI_DEVICE_PATH_PROTOCOL *
DevicePathFromText(
  IN CHAR16 *TextDevicePath
  )
{
  CHAR16                    *NodeStr;
  CHAR16                    *RemainingStr;
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
  EFI_DEVICE_PATH_PROTOCOL  *Node;
  CHAR16                    *WorkingStr;
  UINTN                     NumEntries;

  if (TextDevicePath == NULL || TextDevicePath[0] == L'\0') return NULL;

  //
  // Duplicate the input string so we can tokenize it
  //
  WorkingStr = StrAllocCopy (TextDevicePath);
  if (WorkingStr == NULL) return NULL;

  DevicePath = NULL;
  RemainingStr = WorkingStr;

  //
  // Tokenize by L'/' separator, convert each token
  //
  while (*RemainingStr != L'\0') {
    //
    // Find next node descriptor
    //
    NodeStr = RemainingStr;
    if (*NodeStr == L'/') {
      NodeStr++;
    }
    RemainingStr = NodeStr;

    while (*RemainingStr != L'/' && *RemainingStr != L'\0') {
      RemainingStr++;
    }

    if (*RemainingStr == L'/') {
      *RemainingStr = L'\0';
      RemainingStr++;
    }

    if (*NodeStr == L'\0') continue;

    NumEntries++;
  }

  //
  // Convert each token
  //
  RemainingStr = WorkingStr;
  Node = NULL;
  while (*RemainingStr != L'\0') {
    if (*RemainingStr == L'/') {
      RemainingStr++;
    }
    NodeStr = RemainingStr;
    while (*RemainingStr != L'/' && *RemainingStr != L'\0') {
      RemainingStr++;
    }
    if (*RemainingStr == L'/') {
      *RemainingStr = L'\0';
      RemainingStr++;
    }

    if (*NodeStr == L'\0') continue;

    //
    // Convert the text token to a device path node
    //
    Node = ConvertTextToDevicePathNode (NodeStr);
    if (Node == NULL) {
      if (DevicePath != NULL) FreePool (DevicePath);
      FreePool (WorkingStr);
      return NULL;
    }

    if (DevicePath == NULL) {
      DevicePath = Node;
    } else {
      DevicePath = AppendDevicePathNode (DevicePath, Node);
      FreePool (Node);
    }
  }

  FreePool (WorkingStr);
  return DevicePath;
}

//
// ConvertTextToDevicePathNode - Dispatch text-to-node conversion
//   Based on the text prefix (e.g., "Pci", "Acpi", "Usb", etc.)
//   Uses a dispatch table matching known path type names.
//
EFI_DEVICE_PATH_PROTOCOL *
ConvertTextToDevicePathNode(
  IN CHAR16 *TextNode
  )
{
  EFI_DEVICE_PATH_PROTOCOL  *Node;
  CHAR16                    *TempStr;
  UINTN                     i;

  TempStr = StrAllocCopy (TextNode);
  if (TempStr == NULL) return NULL;

  //
  // Linear search through conversion table
  //
  for (i = 0; mFromTextTable[i].Function != NULL; i++) {
    if (StrnCmp (TempStr, mFromTextTable[i].Name, StrLen(mFromTextTable[i].Name)) == 0) {
      Node = mFromTextTable[i].Function (TempStr);
      FreePool (TempStr);
      return Node;
    }
  }

  FreePool (TempStr);
  return NULL;
}

//
// DevPathFromText - Various node-from-text converter functions
//   Each handles a specific device path node format string.
//
// PCI:     L"Pci(0x%x,0x%x)"
// PCCard:  L"PcCard(0x%x)"
// MemMap:  L"MemoryMapped(0x%x,0x%lx,0x%lx)"
// Ctrl:    L"Ctrl(0x%x)"
// BMC:     L"BMC(0x%x,0x%lx)"
// ACPI:    L"Acpi(0x%08x,0x%x)"
//          L"Keyboard(0x%x)"
//          L"ParallelPort(0x%x)"
//          L"Serial(0x%x)"
//          L"Floppy(0x%x)"
//          L"PciRoot(0x%x)"
//          L"PcieRoot(0x%x)"
// ACPIEx:  L"AcpiEx(%s,%s,%a)"
// ACPIExp: L"AcpiExp(%s,%s,%a)"
// ACPIADR: L"AcpiAdr(0x%x[,...])"
// ATA:     L"Ata(Primary|Secondary,Master|Slave,0x%x)"
//          L"Ata(0x%x)"
// SCSI:    L"Scsi(0x%x,0x%x)"
// Fibre:   L"Fibre(0x%lx,0x%lx)"
// FibreEx: L"FibreEx(WWNN,WWPN)"
// SASEx:   L"SasEx(SASAddr,SASAddr,0x%x,InterfaceType,...)"
// NVMe:    L"NVMe(0x%x,<EUI64>)"
// UFS:     L"UFS(0x%x,0x%x)"
// SD:      L"SD(0x%x)"
// EMMC:    L"eMMC(0x%x)"
// I1394:   L"I1394(%016lx)"
// USB:     L"USB(0x%x,0x%x)"
// USBWWID: L"UsbWwid(0x%x,0x%x,0x%x,\"%s\")"
// Unit:    L"Unit(0x%x)"
// USBClass:L"Usb<Class>(0x%x,0x%x,0x%x)"
// SATA:    L"Sata(0x%x,0x%x,0x%x)"
// I2O:     L"I2O(0x%x)"
// MAC:     L"MAC(<addr>,0x%x)"
// IPv4:    L"IPv4(<addr>,TCP|UDP,DHCP|Static,<gateway>,<mask>)"
// IPv6:    L"IPv6(<addr>,TCP|UDP,Static|AutoConfigure,<gateway>,<prefix>)"
// IB:      L"Infiniband(0x%x,%g,0x%lx,0x%lx,0x%lx)"
// UART:    L"Uart(<baud>,<data>,<parity>,<stop>,<bits>)"
// iSCSI:   L"iSCSI(<name>,0x%x,0x%lx,CRC32C|None,...)"
// VLAN:    L"Vlan(%d)"
// DNS:     L"Dns(<ServerIp>[,...])"
// URI:     L"Uri(%a)"
// HD:      L"HD(<partition>,MBR|GPT,<signature>,0x%lx,0x%lx)"
// CDROM:   L"CDROM(0x%x,0x%lx,0x%lx)"
//          L"CDROM(0x%x)"
// File:    L"%s"
// Media:   L"Media(%g)"
// FV:      L"Fv(%g)"
// FVFile:  L"FvFile(%g)"
// Offset:  L"Offset(0x%lx,0x%lx)"
// VirtualDisk:L"VirtualDisk(0x%lx,0x%lx,%d)"
// BMC:     L"BMC(0x%x,0x%lx)"
// BTP:     L"Bluetooth(<addr>)"
// BLE:     L"BluetoothLE(<addr>,0x%02x)"
// WiFi:    L"Wi-Fi(%a)"
// VENDOR:  L"Ven<Hw|Msg|Media>(%g[,<data>])"
//


// ============================================================================
// SECTION 6: Protocol Dispatch Tables
// ============================================================================

//
// Device Path Type table for DevicePathToText conversion
//   Maps (Type, SubType) -> conversion function
//
TEXT_DEVICE_PATH_NODE_TABLE mToTextTable[] = {
  // HARWARE DEVICE PATHS (Type 1)
  { 1,  1,  L"Pci(0x%x,0x%x)",       NULL },
  { 1,  2,  L"PcCard(0x%x)",         NULL },
  { 1,  3,  L"MemoryMapped(0x%x,0x%lx,0x%lx)", NULL },
  { 1,  4,  L"VenHw(%g,...)",        NULL },
  { 1,  5,  L"Ctrl(0x%x)",           NULL },
  { 1,  6,  L"BMC(0x%x,0x%lx)",      NULL },

  // ACPI DEVICE PATHS (Type 2)
  { 2,  1,  L"Acpi(PNP%04x,0x%x)",   NULL },
  { 2,  2,  L"Acpi(0x%08x,0x%x)",    NULL },
  { 2,  3,  L"AcpiAdr(0x%x[,...])",  NULL },
  { 2,  4,  L"AcpiEx(...)",           NULL },  // ACPI extended HID
  { 2,  5,  L"AcpiExp(...)",          NULL },  // ACPI extended CID

  // MESSAGING DEVICE PATHS (Type 3)
  { 3,  1,  L"ATAPI(...)",            NULL },
  { 3,  2,  L"Scsi(0x%x,0x%x)",      NULL },
  { 3,  3,  L"Fibre(0x%lx,0x%lx)",   NULL },
  { 3,  4,  L"FibreEx(%g,...)",       NULL },
  { 3,  5,  L"1394(%016lx)",          NULL },
  { 3,  6,  L"USB(0x%x,0x%x)",       NULL },
  { 3,  7,  L"I2O(0x%x)",            NULL },
  { 3,  8,  L"MAC(%02x%02x%02x%02x%02x%02x,0x%x)", NULL },
  { 3,  9,  L"IPv4(%d.%d.%d.%d,...)", NULL },
  { 3,  10, L"IPv6(...)",             NULL },
  { 3,  11, L"Uart(...)",            NULL },
  { 3,  12, L"UsbWwid(...)",         NULL },
  { 3,  13, L"UsbClass(...)",        NULL },
  { 3,  14, L"Sata(0x%x,...)",       NULL },
  { 3,  15, L"NVMe(0x%x,...)",       NULL },
  { 3,  16, L"Dns(...)",             NULL },
  { 3,  17, L"Vlan(%d)",             NULL },
  { 3,  18, L"iSCSI(...)",           NULL },
  { 3,  19, L"UFS(0x%x,0x%x)",       NULL },
  { 3,  20, L"SD(0x%x)",             NULL },
  { 3,  21, L"eMMC(0x%x)",           NULL },
  { 3,  22, L"SasEx(...)",           NULL },
  { 3,  23, L"Infiniband(...)",      NULL },
  { 3,  24, L"Wi-Fi(%a)",            NULL },
  { 3,  25, L"Bluetooth(...)",        NULL },
  { 3,  26, L"BluetoothLE(...)",      NULL },
  { 3,  27, L"Uri(%a)",              NULL },
  { 3,  28, L"DHCPv6(...)",           NULL },
  { 3,  29, L"DNSv6(...)",            NULL },
  { 3,  30, L"UFS(...)",             NULL },
  { 3,  31, L"SD(...)",              NULL },
  { 3,  32, L"eMMC(...)",            NULL },
  { 3,  33, L"NVDIMM(...)",           NULL },
  { 3,  34, L"Rest(...)",             NULL },

  // MEDIA DEVICE PATHS (Type 4)
  { 4,  1,  L"HD(%d,MBR|GPT,0x%08x,0x%lx,0x%lx)", NULL },
  { 4,  2,  L"CDROM(0x%x,0x%lx,0x%lx)", NULL },
  { 4,  3,  L"VenMedia(...)",         NULL },
  { 4,  4,  L"File(%s)",             NULL },
  { 4,  5,  L"Protocol(%g)",         NULL },
  { 4,  6,  L"Fv(%g)",              NULL },
  { 4,  7,  L"FvFile(%g)",          NULL },
  { 4,  8,  L"Offset(0x%lx,0x%lx)", NULL },
  { 4,  9,  L"Media(...)",           NULL },
  { 4,  10, L"VirtualDisk(...)",      NULL },

  // BBS DEVICE PATHS (Type 5)
  { 5,  1,  L"BBS(Floppy|HD|CDROM|PCMCIA|USB|Network,...)", NULL },

  // VENDOR/VEN Hw/Msg/Media handled by generic handler
  { 0xFF, 0xFF, L"Ven%s(%g[,...])",   NULL },
};

//
// Device Path From Text dispatch table
//   Maps text prefix string -> conversion function pointer
//
TEXT_DEVICE_PATH_FROM_TEXT mFromTextTable[] = {
  { L"Pci",                DevPathFromTextPci },
  { L"PcCard",             DevPathFromTextPcCard },
  { L"MemoryMapped",       DevPathFromTextMemoryMapped },
  { L"Ctrl",               DevPathFromTextCtrl },
  { L"BMC",                DevPathFromTextBmc },
  { L"AcpiEx",             DevPathFromTextAcpiEx },
  { L"AcpiExp",            DevPathFromTextAcpiExp },
  { L"AcpiAdr",            DevPathFromTextAcpiAdr },
  { L"Acpi",               DevPathFromTextAcpi },
  { L"Ata",                DevPathFromTextAta },
  { L"Scsi",               DevPathFromTextScsi },
  { L"FibreEx",            DevPathFromTextFibreEx },
  { L"Fibre",              DevPathFromTextFibre },
  { L"SasEx",              DevPathFromTextSasEx },
  { L"Nvme",               DevPathFromTextNvme },
  { L"Ufs",                DevPathFromTextUfs },
  { L"Sd",                 DevPathFromTextSd },
  { L"eMMC",               DevPathFromTextEmmc },
  { L"I1394",              DevPathFromText1394 },
  { L"UsbWwid",            DevPathFromTextUsbWwid },
  { L"Usb",                DevPathFromTextUsb },
  { L"Sata",               DevPathFromTextSata },
  { L"I2O",                DevPathFromTextI2o },
  { L"Mac",                DevPathFromTextMac },
  { L" IPv4",              DevPathFromTextIPv4 },
  { L"IPv4",               DevPathFromTextIPv4 },
  { L"IPv6",               DevPathFromTextIPv6 },
  { L"Infiniband",         DevPathFromTextInfiniband },
  { L"Uart",               DevPathFromTextUart },
  { L"iSCSI",              DevPathFromTextIScsi },
  { L"Vlan",               DevPathFromTextVlan },
  { L"Dns",                DevPathFromTextDns },
  { L"Uri",                DevPathFromTextUri },
  { L"Hd",                 DevPathFromTextHd },
  { L"Cdrom",              DevPathFromTextCdrom },
  { L"Floppy",             DevPathFromTextFloppy },
  { L"HD",                 DevPathFromTextHd },
  { L"CDROM",              DevPathFromTextCdrom },
  { L"Media",              DevPathFromTextMedia },
  { L"Fv",                 DevPathFromTextFv },
  { L"FvFile",             DevPathFromTextFvFile },
  { L"Offset",             DevPathFromTextOffset },
  { L"File",               DevPathFromTextFilePath },
  { L"VirtualDisk",        DevPathFromTextVirtualDisk },
  { L"BluetoothLE",        DevPathFromTextBluetoothLE },
  { L"Bluetooth",          DevPathFromTextBluetooth },
  { L"Wi-Fi",              DevPathFromTextWiFi },
  { L"VenHw",              DevPathFromTextVenHw },
  { L"VenMsg",             DevPathFromTextVenMsg },
  { L"VenMedia",           DevPathFromTextVenMedia },
  { L"Ven",                DevPathFromTextVen },
  { L"Unit",               DevPathFromTextUnit },
  { L"Dns",                DevPathFromTextDns },
  { NULL,                  NULL },
};

//
// VENDOR table for VEN device path nodes
//   Compares against known Vendor GUIDs for named text output
//
VENDOR_TABLE_ENTRY mVendorTable[] = {
  { &gLenovoVendorGuid1,        L"LenovoVendor1" },
  { &gLenovoVendorGuid2,        L"LenovoVendor2" },
  { &gEfiMdeModulePkgGuid1,     L"MdeModulePkg1" },
  { NULL,                       NULL },
};


// ============================================================================
// SECTION 7: Module Entry Point & Protocol Installation
// ============================================================================

//
// Global variables
//
EFI_HANDLE                  mImageHandle        = NULL;
EFI_SYSTEM_TABLE            *mSystemTable       = NULL;
EFI_BOOT_SERVICES           *gBootServices      = NULL;
EFI_RUNTIME_SERVICES        *gRuntimeServices   = NULL;

EFI_DEVICE_PATH_UTILITIES_PROTOCOL  mDevicePathUtilitiesProtocol  = {
  GetDevicePathType,
  GetDevicePathSubType,
  GetDevicePathNodeLength,
  NextDevicePathNode,
  IsDevicePathEnd,
  IsDevicePathEndInstance,
  SetDevicePathNodeLength,
  SetDevicePathEndInstance,
  DevicePathValid,
  DevicePathNodeLength,
  DevicePathType,
  DevicePathSubType,
  DevicePathStrSize,
  DuplicateDevicePath,
  AppendDevicePath,
  AppendDevicePathNode,
  AppendDevicePathInstance,
  ExtractDevicePathInstance,
  IsDevicePathMultiInstance,
  DevicePathNodeInstanceContain
};

EFI_DEVICE_PATH_TO_TEXT_PROTOCOL   mDevicePathToTextProtocol   = {
  DevicePathToText,
  DevicePathToTextStr,
  0
};

EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL mDevicePathFromTextProtocol = {
  DevicePathFromText
};

/**
 * Module entry point.
 *
 * Initializes protocols and installs them onto the UEFI handle database.
 *
 * @param ImageHandle   Module's image handle.
 * @param SystemTable   UEFI system table.
 *
 * @return EFI_STATUS code.
 */
EFI_STATUS
EFIAPI
DevicePathDxeEntryPoint(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID        *Registration;

  mImageHandle  = ImageHandle;
  mSystemTable  = SystemTable;
  gBootServices = SystemTable->BootServices;

  ASSERT (ImageHandle != NULL);
  ASSERT (SystemTable != NULL);

  //
  // Initialize the HOB list pointer (for DXE drivers)
  //
  Status = GetHobList ();
  ASSERT_EFI_ERROR (Status);

  //
  // Install the three Device Path protocols
  //
  Status = gBootServices->InstallMultipleProtocolInterfaces (
                           &mImageHandle,
                           &gEfiDevicePathUtilitiesProtocolGuid,
                           &mDevicePathUtilitiesProtocol,
                           &gEfiDevicePathToTextProtocolGuid,
                           &mDevicePathToTextProtocol,
                           &gEfiDevicePathFromTextProtocolGuid,
                           &mDevicePathFromTextProtocol,
                           NULL
                           );
  ASSERT_EFI_ERROR (Status);

  return Status;
}