alder_lake_bios/Insyde/InsydeModulePkg/Library/DeviceInfoLib/DeviceInfoLib.c

446 lines
16 KiB
C

/** @file
This library class provides helper functions to access the Device Information.
;******************************************************************************
;* Copyright (c) 2018 - 2021, Insyde Software Corporation. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Uefi.h>
#include <Protocol/DevicePath.h>
#include <Protocol/DevicePathFromText.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/DeviceInfoLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#define IS_PCI_ROOT(DevNodePtr) (((ACPI_HID_DEVICE_PATH *) DevNodePtr)->HID == EFI_PNP_ID (0x0a03))
typedef struct _H2O_DEVICE_INFO_PCD_DATA {
UINTN PcdTokenNum;
UINT32 AttribCount;
CHAR8 **AttribAsciiStrPtrArray;
CHAR8 **ValueAsciiStrPtrArray;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
} H2O_DEVICE_INFO_PCD_DATA;
H2O_DEVICE_INFO_PCD_DATA *mDevInfoList = NULL;
EFI_GUID mInternalDeviceInfoListGuid = {0x13b319ad, 0xa7d6, 0x4ab1, 0xb9, 0x74, 0xa0, 0x2a, 0x53, 0x88, 0xa8, 0x7d};
/**
Get last device node, which is not end type, from device path.
@param[in] DevicePath Pointer to device p
@return Pointer to the last device node or NULL if input parameter DevPath is NULL or only contains end type device node.
**/
STATIC
EFI_DEVICE_PATH_PROTOCOL *
GetLastDevNode (
IN EFI_DEVICE_PATH_PROTOCOL *DevPath
)
{
EFI_DEVICE_PATH_PROTOCOL *DevNode;
EFI_DEVICE_PATH_PROTOCOL *LastDevNode;
if (DevPath == NULL) {
return NULL;
}
LastDevNode = NULL;
for (DevNode = DevPath; !IsDevicePathEnd (DevNode); DevNode = NextDevicePathNode (DevNode)) {
LastDevNode = DevNode;
}
return LastDevNode;
}
/**
Enumerate all device info PCDs in gH2ODeviceInfoTokenSpaceGuid.
@param[out] DevInfoList Pointer to a returned pointer to a device info data list
@retval EFI_SUCCESS Enumerate all device info PCDs successfully.
@retval EFI_OUT_OF_RESOURCES Allocate memory failed.
@retval Other Fail to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL.
**/
STATIC
EFI_STATUS
EnumerateAllDevInfoPcd (
OUT H2O_DEVICE_INFO_PCD_DATA **DevInfoList
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromText;
UINTN TokenNumber;
UINTN PcdDataSize;
CHAR8 *PcdData;
UINT32 PcdCount;
CHAR8 *DevPathAsciiStr;
UINTN DevPathAsciiStrSize;
CHAR16 *DevPathStr;
UINT32 AttribCount;
UINTN Offset;
H2O_DEVICE_INFO_PCD_DATA *DevInfo;
CHAR8 *AttribPtr;
CHAR8 *ValuePtr;
Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **) &DevicePathFromText);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return Status;
}
for (TokenNumber = LibPcdGetNextToken (&gH2ODeviceInfoTokenSpaceGuid, 0), PcdCount = 0;
TokenNumber != 0;
TokenNumber = LibPcdGetNextToken (&gH2ODeviceInfoTokenSpaceGuid, TokenNumber)) {
if (LibPcdGetExSize (&gH2ODeviceInfoTokenSpaceGuid, TokenNumber) <= sizeof ("")) {
continue;
}
PcdCount++;
}
if (PcdCount == 0) {
*DevInfoList = NULL;
return EFI_SUCCESS;
}
*DevInfoList = AllocateZeroPool ((PcdCount + 1) * sizeof (H2O_DEVICE_INFO_PCD_DATA));
if (*DevInfoList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (TokenNumber = LibPcdGetNextToken (&gH2ODeviceInfoTokenSpaceGuid, 0), PcdCount = 0;
TokenNumber != 0;
TokenNumber = LibPcdGetNextToken (&gH2ODeviceInfoTokenSpaceGuid, TokenNumber)) {
PcdDataSize = LibPcdGetExSize (&gH2ODeviceInfoTokenSpaceGuid, TokenNumber);
PcdData = LibPcdGetExPtr (&gH2ODeviceInfoTokenSpaceGuid, TokenNumber);
if (PcdData == NULL || PcdDataSize <= sizeof ("") || PcdData[PcdDataSize - 1] != CHAR_NULL) {
continue;
}
PcdData = AllocateCopyPool (PcdDataSize, PcdData);
if (PcdData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// The PCD data consists of one or more null-terminated ASCII strings.
// The first ASCII string specify the device path of the on-board device.
// The second and following strings specify an attribute for that device in the format attribute=value.
//
DevInfo = &((*DevInfoList)[PcdCount++]);
DevInfo->PcdTokenNum = TokenNumber;
DevPathAsciiStr = PcdData;
DevPathAsciiStrSize = AsciiStrSize (DevPathAsciiStr);
DevPathStr = AllocatePool (DevPathAsciiStrSize * sizeof (CHAR16));
if (DevPathStr != NULL) {
AsciiStrToUnicodeStrS (DevPathAsciiStr, DevPathStr, DevPathAsciiStrSize);
DevInfo->DevPath = DevicePathFromText->ConvertTextToDevicePath (DevPathStr);
FreePool (DevPathStr);
}
AttribCount = 0;
Offset = DevPathAsciiStrSize;
while (Offset < PcdDataSize) {
Offset += AsciiStrSize (PcdData + Offset);
AttribCount++;
}
if (AttribCount == 0) {
continue;
}
DevInfo->AttribAsciiStrPtrArray = AllocateZeroPool (AttribCount * sizeof (CHAR8 *));
DevInfo->ValueAsciiStrPtrArray = AllocateZeroPool (AttribCount * sizeof (CHAR8 *));
if (DevInfo->AttribAsciiStrPtrArray == NULL ||
DevInfo->ValueAsciiStrPtrArray == NULL) {
continue;
}
AttribCount = 0;
Offset = DevPathAsciiStrSize;
while (Offset < PcdDataSize) {
AttribPtr = PcdData + Offset;
Offset += AsciiStrSize (PcdData + Offset);
ValuePtr = AsciiStrStr (AttribPtr, "=");
ASSERT (ValuePtr != NULL);
if (ValuePtr == NULL) {
continue;
}
*ValuePtr = CHAR_NULL;
ValuePtr++;
DevInfo->AttribAsciiStrPtrArray[AttribCount] = AttribPtr;
DevInfo->ValueAsciiStrPtrArray[AttribCount] = ValuePtr;
AttribCount++;
}
DevInfo->AttribCount = AttribCount;
}
return EFI_SUCCESS;
}
/**
Get device info PCD data.
@param[in] PcdTokenNum Unsigned integer that specifies the PCD token associated with a device's information.
@return Pointer to the device info PCD data or NULL if not found.
**/
STATIC
H2O_DEVICE_INFO_PCD_DATA *
GetDevInfoPcdData (
IN UINTN PcdTokenNum
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
UINTN Index;
if (mDevInfoList == NULL) {
//
// Device info list pointer is saved in an internal protocol. All of library instances can access the same database.
//
Status = gBS->LocateProtocol (&mInternalDeviceInfoListGuid, NULL, (VOID **) &mDevInfoList);
if (EFI_ERROR (Status)) {
EnumerateAllDevInfoPcd (&mDevInfoList);
Handle = NULL;
gBS->InstallProtocolInterface (&Handle, &mInternalDeviceInfoListGuid, EFI_NATIVE_INTERFACE, (VOID *) mDevInfoList);
}
if (mDevInfoList == NULL) {
return NULL;
}
}
for (Index = 0; mDevInfoList[Index].PcdTokenNum != 0; Index++) {
if (mDevInfoList[Index].PcdTokenNum == PcdTokenNum) {
return &mDevInfoList[Index];
}
}
return NULL;
}
/**
This function returns basic information about a device.
@param[in] TokenNumber Unsigned integer that specifies the PCD token associated with a device's information.
@param[out] DevicePath Pointer to a returned pointer to a device path that indicates the device's device path.
The format of the returned device path is consistent with the format specified in the
UEFI specification. The device path must not be freed by the caller.
@param[out] DeviceAttribCount Pointer to a returned unsigned integer that indicates the number of device attributes
associated with the device indicated by DevicePath.
@retval EFI_SUCCESS Function returned successfully.
@retval EFI_INVALID_PARAMETER DevicePath was NULL or DeviceAttribCount was NULL.
@retval EFI_VOLUME_CORRUPTED The format of the device path in the PCD was invalid.
@retval EFI_NOT_FOUND There is no device information associated with the specified TokenNumber.
**/
EFI_STATUS
GetDeviceInfo (
IN UINTN TokenNumber,
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
OUT UINT32 *DeviceAttribCount
)
{
H2O_DEVICE_INFO_PCD_DATA *DevInfoPcdData;
if (DevicePath == NULL || DeviceAttribCount == NULL) {
return EFI_INVALID_PARAMETER;
}
DevInfoPcdData = GetDevInfoPcdData (TokenNumber);
if (DevInfoPcdData == NULL) {
return EFI_NOT_FOUND;
}
if (DevInfoPcdData->DevPath == NULL) {
return EFI_VOLUME_CORRUPTED;
}
*DevicePath = DevInfoPcdData->DevPath;
*DeviceAttribCount = DevInfoPcdData->AttribCount;
return EFI_SUCCESS;
}
/**
This function returns a name and value of attribute associated with the device associated with the PCD token number.
@param[in] TokenNumber Unsigned integer that specifies the PCD token associated with a device's information.
@param[in] DeviceAttribIndex Unsigned integer that specifies the index of the device attribute. This value must be
less than the value returned by the parameter DeviceAttribCount from GetDeviceInfo.
Indices are numbered starting with 0 and continue until the last attribute. There are no gaps.
@param[out] DeviceAttribName Pointer to a returned pointer to a null-terminated ASCII string that indicates the name
of the device attribute associated with the device.
The string value must not be freed by the caller.
@param[out] DeviceAttribValue Pointer to a returned pointer to a null-terminated ASCII string that indicates the value
of the device attribute associated with the device.
The string value must not be freed by the caller.
@retval EFI_SUCCESS Function returned successfully.
@retval EFI_INVALID_PARAMETER DeviceAttribName was NULL or DeviceAttribValue was NULL.
@retval EFI_NOT_FOUND There is no device information associated with the specified TokenNumber.
**/
EFI_STATUS
GetDeviceAttrib (
IN UINTN TokenNumber,
IN UINT32 DeviceAttribIndex,
OUT CHAR8 **DeviceAttribName,
OUT CHAR8 **DeviceAttribValue
)
{
H2O_DEVICE_INFO_PCD_DATA *DevInfoPcdData;
if (DeviceAttribName == NULL || DeviceAttribValue == NULL) {
return EFI_INVALID_PARAMETER;
}
DevInfoPcdData = GetDevInfoPcdData (TokenNumber);
if (DevInfoPcdData == NULL) {
return EFI_NOT_FOUND;
}
if (DevInfoPcdData->AttribCount <= DeviceAttribIndex ||
DevInfoPcdData->AttribAsciiStrPtrArray == NULL ||
DevInfoPcdData->ValueAsciiStrPtrArray == NULL) {
return EFI_NOT_FOUND;
}
*DeviceAttribName = DevInfoPcdData->AttribAsciiStrPtrArray[DeviceAttribIndex];
*DeviceAttribValue = DevInfoPcdData->ValueAsciiStrPtrArray[DeviceAttribIndex];
return EFI_SUCCESS;
}
/**
This function returns the device attribute value associated with the device associated with the PCD token number
and the device attribute name.
@param[in] TokenNumber Unsigned integer that specifies the PCD token associated with a device's information.
@param[in] DeviceAttribName Pointer to a null-terminated ASCII string that specifies the name of the device
attribute associated with the device.
@param[out] DeviceAttribValue Pointer to a returned pointer to a null-terminated ASCII string that indicates the value
of the device attribute associated with the device.
The string value must not be freed by the caller.
@retval EFI_SUCCESS Function returned successfully.
@retval EFI_INVALID_PARAMETER DeviceAttribName was NULL or DeviceAttribValue was NULL.
@retval EFI_NOT_FOUND There is no device information associated with the specified TokenNumber.
**/
EFI_STATUS
GetDeviceInfoAttribByName (
IN UINTN TokenNumber,
IN CONST CHAR8 *DeviceAttribName,
OUT CHAR8 **DeviceAttribValue
)
{
H2O_DEVICE_INFO_PCD_DATA *DevInfoPcdData;
UINT32 Index;
if (DeviceAttribName == NULL || DeviceAttribValue == NULL) {
return EFI_INVALID_PARAMETER;
}
DevInfoPcdData = GetDevInfoPcdData (TokenNumber);
if (DevInfoPcdData == NULL) {
return EFI_NOT_FOUND;
}
if (DevInfoPcdData->AttribAsciiStrPtrArray == NULL ||
DevInfoPcdData->ValueAsciiStrPtrArray == NULL) {
return EFI_NOT_FOUND;
}
for (Index = 0; Index < DevInfoPcdData->AttribCount; Index++) {
if (AsciiStrCmp (DevInfoPcdData->AttribAsciiStrPtrArray[Index], DeviceAttribName) == 0) {
*DeviceAttribValue = DevInfoPcdData->ValueAsciiStrPtrArray[Index];
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
This function returns whether the specified device is a PCI device.
This determination is made by checking the final device node within the device's path to see if it is a PCI root or PCI
device. If it is, the function will return TRUE. If it is not, or if the TokenNumber does not specify a valid device,
it will return FALSE.
@param[in] TokenNumber Unsigned integer that specifies the PCD token associated with a device's information.
@return TRUE, if the specified device's path ends in a PCI or PCI root device node. Otherwise, FALSE.
**/
BOOLEAN
IsDevicePathPci (
IN UINTN TokenNumber
)
{
H2O_DEVICE_INFO_PCD_DATA *DevInfoPcdData;
EFI_DEVICE_PATH_PROTOCOL *LastDevNode;
DevInfoPcdData = GetDevInfoPcdData (TokenNumber);
if (DevInfoPcdData == NULL || DevInfoPcdData->DevPath == NULL) {
return FALSE;
}
LastDevNode = GetLastDevNode (DevInfoPcdData->DevPath);
if (LastDevNode == NULL) {
return FALSE;
}
if ((DevicePathType (LastDevNode) == ACPI_DEVICE_PATH && DevicePathSubType (LastDevNode) == ACPI_DP && IS_PCI_ROOT(LastDevNode)) ||
(DevicePathType (LastDevNode) == HARDWARE_DEVICE_PATH && DevicePathSubType (LastDevNode) == HW_PCI_DP)) {
return TRUE;
}
return FALSE;
}
/**
This function returns whether the specified device is a USB device.
This determination is made by checking the final device node within the device's path to see if it is a USB device node.
If it is, the function will return TRUE. If it is not, or if the TokenNumber does not specify a valid device, it will
return FALSE.
@param[in] TokenNumber Unsigned integer that specifies the PCD token associated with a device's information.
@return TRUE, if the specified device's path ends in a USB device node. Otherwise, FALSE.
**/
BOOLEAN
IsDevicePathUsb (
IN UINTN TokenNumber
)
{
H2O_DEVICE_INFO_PCD_DATA *DevInfoPcdData;
EFI_DEVICE_PATH_PROTOCOL *LastDevNode;
DevInfoPcdData = GetDevInfoPcdData (TokenNumber);
if (DevInfoPcdData == NULL || DevInfoPcdData->DevPath == NULL) {
return FALSE;
}
LastDevNode = GetLastDevNode (DevInfoPcdData->DevPath);
if (LastDevNode == NULL) {
return FALSE;
}
if (DevicePathType (LastDevNode) == MESSAGING_DEVICE_PATH && DevicePathSubType (LastDevNode) == MSG_USB_DP) {
return TRUE;
}
return FALSE;
}