读取SMBIOS第二个Type和所有Type41(根据SMBIOS 3.0 (64-bit) Entry Point)

       64位的SMBIOS EPS表可以根据SMBIOS 3.x GUID (SMBIOS3_TABLE_GUID, {F2FD1544-9794-4A2C-992EE5BBCF20E394})找到,这在所有遵循SMBIOS规范的BIOS中都是一样的。

 #define EFI_SMBIOS3_TABLE_GUID \
{ \
    0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94} \
}

       代码实现的功能是读取SMBIOS的第二个Type2,并将其Handle打印出来,读取所有的Type41,打印出Type中的DeviceType、BusNum、DevFuncNum信息。根据读出来的Bus、Device、Function号读取相应PCI配置空间信息。

       Type41在SMBIOS Spec中的描述是:“Onboard Devices Extended Information (Type 41)”,即板载设备扩展信息,这些设备的种类有Video、SCSI Controller、Ethernet、Token Ring、Sound、PATA Controller等。

       程序读取信息的步骤可以概括为:通过GUID将EPS表找到,根据EPS表的TableAddress找到所有Type的起始地址,然后遍历Type表,找到要读取的Type读取相应信息。其中遍历每一个Type表并返回每一个Type的起始地址是最关键的部分,代码中由函数LibGetSmbiosString 实现。

       代码:

#include <Uefi.h> 
#include <Library/UefiLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <IndustryStandard/SmBios.h>
#include <Library/BaseMemoryLib.h>
#include <IndustryStandard/SmBios.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>


#define INVALID_HANDLE                  (UINT16) (-1)
#define DMI_SUCCESS                     0x00
#define DMI_UNKNOWN_FUNCTION            0x81
#define DMI_FUNCTION_NOT_SUPPORTED      0x82
#define DMI_INVALID_HANDLE              0x83
#define DMI_BAD_PARAMETER               0x84
#define DMI_INVALID_SUBFUNCTION         0x85
#define DMI_NO_CHANGE                   0x86
#define DMI_ADD_STRUCTURE_FAILED        0x87
#define DMI_READ_ONLY                   0x8D
#define DMI_LOCK_NOT_SUPPORTED          0x90
#define DMI_CURRENTLY_LOCKED            0x91
#define DMI_INVALID_LOCK                0x92
 

#define PCI_BASE_ADDR 0x80000000L
#define CONFIG_ADDR 0xCF8
#define CONFIG_DATA 0xCFC



/**
  Return SMBIOS string for the given string number.

  @param[in] Smbios         Pointer to SMBIOS structure.
  @param[in] StringNumber   String number to return. -1 is used to skip all strings and
                            point to the next SMBIOS structure.

  @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == -1
**/
CHAR8*
LibGetSmbiosString (
  IN  SMBIOS_STRUCTURE_POINTER    *Smbios,
  IN  UINT16                      StringNumber
  );



 #define EFI_SMBIOS3_TABLE_GUID \
{ \
    0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94} \
}
EFI_GUID gEfiSmbiosTable3Guid = EFI_SMBIOS3_TABLE_GUID;
STATIC SMBIOS_STRUCTURE_POINTER         m_SmbiosStruct;
STATIC SMBIOS_STRUCTURE_POINTER         *mSmbiosStruct = &m_SmbiosStruct;   //用引用进行初始化,否则运行会卡退
STATIC SMBIOS_TABLE_3_0_ENTRY_POINT     *SmbiosTable   = NULL;              //Smbios EPS表结构


EFI_STATUS
EFIAPI
SmBiosTypeReadEntry(
  IN EFI_HANDLE              ImageHandle,
  IN EFI_SYSTEM_TABLE        *SystemTable
  )
{
  EFI_STATUS                 Status;
  SMBIOS_STRUCTURE_POINTER   SmBiosStruct;
  UINT8                      flag = 0;

  UINT32                     address,data,data1,data2,data3;

 
  // Get SMBIOS table from System Configure table
  //
  Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTable3Guid, &SmbiosTable);
  if((Status != EFI_SUCCESS  || SmbiosTable == NULL)  ||
    (CompareMem(SmbiosTable->AnchorString, "_SM3_", 5) != 0 )) {
    Print (L"smbios table is not found!");
    return Status;
  }

  Print (L"SmBios Table:\n");
  Print (L"  AnchorString:%c%c%c%c%c\n  EntryPointStructureChecksum:0x%x\n  EntryPointLength:0x%x\n  MajorVersion:0x%x\n  MinorVersion:0x%x\n  TableAddress:0x%x\n",  
          SmbiosTable->AnchorString[0],
          SmbiosTable->AnchorString[1],
          SmbiosTable->AnchorString[2],
          SmbiosTable->AnchorString[3],
          SmbiosTable->AnchorString[4],
          SmbiosTable->EntryPointStructureChecksum,
          SmbiosTable->EntryPointLength,
          SmbiosTable->MajorVersion,
          SmbiosTable->MinorVersion,
          SmbiosTable->TableAddress
          );
  

  mSmbiosStruct->Raw  = (UINT8 *) (UINTN) (SmbiosTable->TableAddress);
  SmBiosStruct.Raw = mSmbiosStruct->Raw;

  while(1) {  //当到Type127时break

    if(SmBiosStruct.Hdr->Handle == 0xFEFF){  //当到Type127时break
      break;
    }
    if(SmBiosStruct.Hdr->Type == 0x08){    //读取第二个Type8
      if(flag == 1){
        Print(L"The Second Type8's handle:0x%x\n",SmBiosStruct.Hdr->Handle);
        flag = 2;
      }
      else {
        flag += 1;
      }
    }
    if(SmBiosStruct.Hdr->Type == 0x29){    //读取所有的Type41,并识别其DeviceType
        Print(L"Type41 handle:0x%x\n",SmBiosStruct.Hdr->Handle);
        switch (SmBiosStruct.Type41->DeviceType & 0x7F)
        {
        case 0x01:
          Print(L"Type41 DeviceType is: Other.\n");
          break;
        case 0x02:
          Print(L"Type41 DeviceType is: Unknown.\n");
          break;
        case 0x03:
          Print(L"Type41 DeviceType is: Video.\n");
          break;
        case 0x04:
          Print(L"Type41 DeviceType is: SCSI Controller.\n");
          break;
        case 0x05:
          Print(L"Type41 DeviceType is: Ethernet.\n");
          break;
        case 0x06:
          Print(L"Type41 DeviceType is: Token Ring.\n");
          break;
        case 0x07:
          Print(L"Type41 DeviceType is: Sound.\n");
          break;
        case 0x08:
          Print(L"Type41 DeviceType is: PATA Controller.\n");
          break;
        case 0x09:
          Print(L"Type41 DeviceType is: SATA Controller.\n");
          break;
        case 0x0A:
          Print(L"Type41 DeviceType is: SAS Controller.\n");
          break;
        default:
          break;
        }
        if((SmBiosStruct.Type41->DeviceType >> 7) == 0){      //输出DeviceType
          Print(L"Device Status is:Disabled.\n");
        }else Print(L"Device Status is:Enableabled.\n");
        //输出Type41中的Bus、Device、Function号
        Print(L"Bus Number:0x%x\n",SmBiosStruct.Type41->BusNum);
        Print(L"Device Number:0x%x\n",(SmBiosStruct.Type41->DevFuncNum >> 0x03));
        Print(L"Device Number:0x%x\n",(SmBiosStruct.Type41->DevFuncNum & 0x07));

        //根据读出来的Bus、Device、Function号读取PCI配置空间信息
        //IO方式读取
        address = PCI_BASE_ADDR | ((SmBiosStruct.Type41->BusNum & 0xFF) << 16) | \
                                  (((SmBiosStruct.Type41->DevFuncNum >> 0x03) & 0x1F) << 11) | \
                                  (((SmBiosStruct.Type41->DevFuncNum & 0x07) & 0x7) << 8);
        //读取vendorIDhe DeviceID
        IoWrite32(CONFIG_ADDR, address);
        data = IoRead32(CONFIG_DATA);

        //读取sub-vendorID
        IoWrite32(CONFIG_ADDR, address | 0x2C);
        data1 = IoRead32(CONFIG_DATA);

        //读取ClassCode
        IoWrite32(CONFIG_ADDR, address | 0x08);
        data2 = IoRead32(CONFIG_DATA);

        //判断桥或设备
        IoWrite32(CONFIG_ADDR, address | 0x0C);
        data3 = IoRead32(CONFIG_DATA);

        Print(L"VendorID:%2x\n DeviceID:%2x\n SubVendorID: %2x\n SubDeviceID:%2x\n HeaderType:%2x\n ClassCode:%2x\n",(data & 0xffff),((data >> 16) & 0xffff),\
                                                                                                                     (data1 & 0xffff), ((data1 >> 16) & 0xffff),\
                                                                                                                     ((data3 >> 16) & 0xff),((data2 >> 8)));
    }
    LibGetSmbiosString (&SmBiosStruct, (UINT16) (-1));        //跳过Type的字符串区域(即找到下一个Type的起始地址,并返回给SmBiosStruct->Raw)
  }
  Print(L"SmBiosStruct.Hdr->Handle:0x%x\n",SmBiosStruct.Hdr->Handle);  //while(1)循环结束,遍历到Type127(最后一个Type),输出其Handle验证
  return Status;
}


/**
  Return SMBIOS string for the given string number.

  @param[in] Smbios         Pointer to SMBIOS structure.
  @param[in] StringNumber   String number to return. -1 is used to skip all strings and
                            point to the next SMBIOS structure.

  @return Pointer to string, or pointer to next SMBIOS strcuture if StringNumber == -1
**/
CHAR8*
LibGetSmbiosString (
  IN  SMBIOS_STRUCTURE_POINTER    *Smbios,
  IN  UINT16                      StringNumber
  )
{
  UINT16  Index;
  CHAR8   *String;

  ASSERT (Smbios != NULL);

  //
  // Skip over formatted section
  //
  String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);

  //
  // Look through unformated section
  //
  for (Index = 1; Index <= StringNumber; Index++) {
    if (StringNumber == Index) {
      return String;
    }
    //
    // Skip string
    //
    for (; *String != 0; String++);
    String++;  //这一句和上一句是分开的

    if (*String == 0) {
      //
      // If double NULL then we are done.
      //  Return pointer to next structure in Smbios.
      //  if you pass in a -1 you will always get here
      //
      Smbios->Raw = (UINT8 *)++String;
      return NULL;
    }
  }

  return NULL;
}


.inf

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = SmbiosNew
  FILE_GUID                      = CEB4D871-6C35-4E05-969D-B2539ECA8548
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = SmBiosTypeReadEntry

[Sources]
  SmbiosNew.c

[Packages]
  MdePkg/MdePkg.dec
  MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib
  IoLib
  BaseMemoryLib
  DebugLib

[Guids]
  gEfiSmbiosTableGuid


       运行结果:
在这里插入图片描述
       使用RW软件验证:
       第二个Type8:
在这里插入图片描述
       Type41:
在这里插入图片描述

       在SMBIOS Spec中,Type41表的Bus Number和Device\Function Number是这样存的:
在这里插入图片描述
       所以读出的Device和Function还需要分解。

       而Device Type的第七位为状态值,[6:0]为设备类型。
在这里插入图片描述
       所有的类型定义为:
在这里插入图片描述
       根据这些就可以判断所读数据代表的含义。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值