uefi中的Smbios实现

需要了解的Smbios知识

(1)什么是Smbios

Smbios在百度百科中是这样解释的:Smbios(system management bios)是主板或者系统制造厂商以标准格式显示产品信息所遵循的统一规范。Smbios规范标准定义了收集的电脑信息都包含哪方面的信息,對應手冊中其實就是包含很多c语言中的结构体,每一个结构体代表一种信息。在Smbios中都有。具体请看Smbios标准。

每个主板厂商或者OEM厂商所生产的电脑,在出厂的时候都会按照smbios标准将信息写入到bios中。主要就是包含了电脑各个模块信息。厂商将这些信息写好存入到bios芯片中。这部分信息是如何存入的,当然毫无疑问肯定是以bios代码的是形式实现的,最终将代码的二进制写入到开机启动的flash芯片中。这部分代码是属于bios的一部分。在uefi中属于专门的一个驱动模块。

(2)什么是DMI

DMI(Desktop Management Interface)也就是桌面管理接口,它含有关于系统硬件的配置信息。DMI 的主要组成部分是 Management Information Format (MIF) 数据库。这个数据库包括了所有有关电脑系统和配件的信息。通过 DMI ,用户可以获取序列号、电脑厂商、串口信息以及其它系统配件信息。计算机每次启动时都对 DMI 数据进行校验,如果该数据出错或硬件有所变动,就会对机器进行检测,并把测试的数据写入 BIOS 芯片保存。DMI搜集信息,也是按照Smbios标准所进行的。因此DMI的实现,就是按照Smbios标准所实现的。

Smbiso的访问方式:

对于符合 Smbios规范的计算机,可以通过访问 Smbios 的结构获得系统信息,共有两种办法可以访问Smbios数据结构:

     1. 通过即插即用功能接口访问 SMBIOS 结构,这个在 SMBIOS2.0 标准里定义了,从 SMBIOS 2.1 开始这个访问方法不再被推荐使用。

     2 .基于表结构的方法,表内容是 table entry point 的数据,这个访问方法从 SMBIOS 2.1 以后开始被使用,从 2.1 开始,以后的版本都推荐使用这种访问方式。在 2.1 版本中允许支持这两种方法中的任意一种和两种都支持,但在 2.2 以后的版本,必须支持方法 2 。

     目前主流的访问方式都是基于表结构的访问方式。基于表结构访问 SMBIOS 的过程是先找到 Entry Point Structure ( EPS )表,然后通过 Entry Point Structure ( EPS )表的数据找到 SMBIOS 结构表。

     对于非 EFI 的系统,访问 SMBIOS EPS 表的操作过程如下:

     1 .从物理内存 0x000F0000-0x000FFFFF 之间寻找关键字 “ _SM_” 。

     2 .找到后再向后 16 个字节,看后面 5 个 BYTE 是否是关键字 “_DMI_” ,如果是, EPS 表即找到。

满足上面的两个条件,即可认为找到了Smbios的Entry Point Structure数据结构。然后程序解析这个结构中的数据来获取其他的信息。

     对于 UEFI 系统,可能通过搜索 EFI 配置表中的 SMBIOS GUID(SMBIOS_TABLE_GUID) ,然后使用指向 SMBIOS 的指针来定位 EPS 表。具体可参考 UEFI 规范。(主要就是以protocol的方式实现的)

我们这里实现的方式并没有严格按照uefi的规范来实现,还是通过前面非uefi的系统来实现的。因为我们的内核版本中现在还没有严格的按照uefi标准来解析。所以只能按照上面的非uefi系统来实现。

Smbios的数据结构:

SMBIOS EPS 表结构如下:

位置

名称

长度

描述

00H

关键字

4BYTE

固定是”_SM_”

04H

校验和

1BYTE

用于校验数据

05H

表结构长度

1BYTE

Entry Point Structure 表的长度

06H

Major 版本号

1BYTE

用于判断SMBIOS 版本

07H

Minor 版本号

1BYTE

用于判断SMBIOS 版本

08H

表结构大小

2BYTE

用于即插即用接口方法获得数据表结构长度

0AH

EPS 修正

1BYTE

 

0B-0FH

格式区域

5BYTE

存放解释EPS 修正的信息

10H

关键字

5BYTE

固定为“_DMI_”

15H

校验和

1BYTE

Intermediate Entry Point Structure (IEPS)的校验和

16H

结构表长度

2BYTE

SMBIOS 结构表的长度

18H

结构表地址

4BYTE

SMBIOS 结构表的真实内存位置

1CH

结构表个数

2BYTE

SMBIOS 结构表数目

1EH

Smbios BCD 修正

1BYTE

 

这里面主要介绍介幾個比较有用的数据:

00H和10H是用于匹配是否是entry point structure的数据。16H和18H是实现的表的起始地址和总长度。1CH是表的个数。

linux下dmidecode命令就是用用来解析这些信息的。dmidecode先到特定的地址去找到EPS,然后从EPS中拿到18H这个位置所存放的地址,然后去这个地址去解析数据。

这些数据包含了多个表的结构,每个表的含义不同,BIOS 信息 (Type 0) 、系统信息 (Type 1) 、基板(或模块)信息 (Type 2) 、系统外围或底架 (Type 3) 、处理器信息 (Type 4) 、存储控制器信息(Type 5, 已 废弃 ) 、存储模块信息 (Type 6, 已废弃 ) 、调整缓存信息 (Type 7) 、端口连接器信息 (Type 8) 、系统插槽 (Type 9) 。板载设备信息 (Type 10) 、 OEM 字符串 (Type 11) 、系统配置选项 (Type 12) 、 BIOS 语言信息 (Type 13) 、组相联 (Type 14) 、系统事件日志(Type 15) 、物理存储阵列 (Type 16) 、存储设备 (Type 17) 、 32-bit 内存错误信息 (Type 18) 、存储阵列映射地址 (Type 19) 。存储设备映射地址 (Type 20) 、内建指针设备 (Type 21) 、便携式电池 (Type 22) 、系统重置 (Type 23) 、硬件安全 (Type 24) 、系统电源控制 (Type 25) 、电压探针 (Type 26) 、冷却设备 (Type 27) 、温度传感器 (Type 28) 、电流探头 (Type 29) 。越界远程访问 (Type 30) 、引导完整性服务 (BIS) 入口点 (Type 31) 、系统引导信息 (Type 32) 、 64-bit 内存错误信息 (Type 33) 、管理设备 (Type 34) 、管理设备组件 (Type 35) 、管理设备门槛数据 (Type 36) 、存储信道 (Type 37) 、 IPMI 设备信息 (Type 38) 、系统供电电源 (Type 39) 。附加信息 (Type 40) 、板载设备扩展信息 (Type 41) 、管理控制器主机接口 (Type 42) 。不活动指示 (Type 126) 、表格结束指示 (Type 127) 。

SMBIOS 的大部分结构表数据在 CIM 模型中都有对应的实现,比如底架信息对应 CIM_Chassis ,处理器信息对应 CIM_Processor ,内存信息对应CIM_Memory 等。

每个表都含有一个相同的信息,就是表头其格式如下:

位置

名称

长度

描述

00H

TYPE 号

1BYTE

结构的TYPE 号

01H

长度

1BYTE

本结构的长度,就此TYPE 号的结构而言

02H

句柄

2BYTE

用于获得本SMBIOS 结构,其值不定

每个结构都分为格式区域字符串区域,格式区域就是一些本结构的信息,字符串区域是紧随在格式区域后的一个区域。结构 01H 处标识的结构长度仅是格式区域的长度,字符串区域的长度是不固定的。有的结构有字符串区域,有的则没有。

下面以 TYPE 0 ( BIOS information )为例说明格式区域和字符串区域的关系。 TYPE 0 ( BIOS information )格式区域如下:

位置

名称

长度

描述

00H

TYPE 号

1BYTE

结构的TYPE 号,此处是0

01H

长度

1BYTE

TYPE 0 格式区域的长度,一般为14H ,也有13H

02H

句柄

2BYTE

本结构的句柄,一般为0000H

04H

Bios 厂商信息

1BYTE

此处是bios 卖方的信息,可能是OEM 厂商名,一般为01H ,代表紧随格式区域后的字符串区域的第一个字符串

05H

BIOS 版本

1BYTE

BIOS 版本号,一般为02H ,代表字符串区域的第二个字符串

06H

Bios 开始地址段

2BYTE

用于计算常驻BIOS 镜像大小的计算,方法为

(10000H-BIOS 开始地址段)×16

08H

BIOS 发布日期

1BYTE

一般为03H ,表示字符区第三个字符串

09H

BIOS rom size

1BYTE

计算方法为(n +1 )×64K ,n 为此处读出数值

0AH

BIOS 特征

8BYTE

Bios 的功能支持特征,如PCI,PCMCIA,FLASH 等

12H

Bios 特征扩展

不定

紧随 TYPE 0 ( BIOS information )结构区域之后,即在 Bios 特征扩展域后面的就是 TYPE 0 ( BIOS information )字符串区域,每个字符串都以 00H 作为结束标志,上面的例子中有三个字符串。如果我们要找下一个 TYPE ,因为最后一个字符串以 00H 结尾,而整个字符区域又以 00H 结尾,故只要在字符串区域找到连续的 0000H 即可。


代码实现:

感覺這部分代碼的架構比較好,所以還是寫下來總結一下吧,後面在寫代碼的時候可以用得上。

首先,在uefi中Smbios部分是分爲兩部分的,第一部分是SmbiosDxe驅動,這部分主要的功能就是爲後一部分SmbiosTable部分提供接口函數的。下面看一下SmbisoDxe部分的主要代碼

(1)SmbiosDxe

這部分驅動的入韓函數爲

SmbiosDriverEntryPoint

詳細的代碼如下:

EFI_STATUS
EFIAPI
SmbiosDriverEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS            Status;

  mPrivateData.Signature                = SMBIOS_INSTANCE_SIGNATURE;
  mPrivateData.Smbios.Add               = SmbiosAdd;
  mPrivateData.Smbios.UpdateString      = SmbiosUpdateString;
  mPrivateData.Smbios.Remove            = SmbiosRemove;
  mPrivateData.Smbios.GetNext           = SmbiosGetNext;
  mPrivateData.Smbios.MajorVersion      = (UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);
  mPrivateData.Smbios.MinorVersion      = (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x00ff);

  InitializeListHead (&mPrivateData.DataListHead);
  InitializeListHead (&mPrivateData.AllocatedHandleListHead);
  EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);

  //
  // Make a new handle and install the protocol
  //
  mPrivateData.Handle = NULL;
  Status = gBS->InstallProtocolInterface (
                  &mPrivateData.Handle,                                                                                                                                                  
                  &gEfiSmbiosProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &mPrivateData.Smbios
                  );   

  return Status;
}

代碼中mPrivateData是一個本模塊的全局變量,其定義如下:SMBIOS_INSTANCE mPrivateData

SMBIOS_INSTANCE結構都包含哪些變量呢?如下:

typedef struct {
  UINT32                Signature;
  EFI_HANDLE            Handle;
  //
  // Produced protocol
  //
  EFI_SMBIOS_PROTOCOL   Smbios;
  //
  // Updates to record list must be locked.
  //
  EFI_LOCK              DataLock;
  //
  // List of EFI_SMBIOS_ENTRY structures.
  //
  LIST_ENTRY            DataListHead;
  //
  // List of allocated SMBIOS handle.
  //
  LIST_ENTRY            AllocatedHandleListHead;

} SMBIOS_INSTANCE;

這裏面最重要的變量就是EFI_SMBIOS_PROTOCOL   Smbios。mPrivateData內部這些變量的值就是在這個函數中初始化的,初始化之後,將&gEfiSmbiosProtocolGuid這個protocol安裝上,爲後面使用。這裏面最主要的函數就mPrivateData.Smbios.Add               = SmbiosAdd;

SmbiosAdd的函數就是添加每一張表的時候需要調用的函數。裏面包含了構建EPS表的代碼和要傳入數據的表還有結束表。將每張表的信息寫入到規定好的內存地址上。我們這裏規定EPS(Entry Point Structure)的位置在0x980000000fffe000的虛擬地址上,映射的物理地址就是0x0fffe000,在內存地址低256M的高16M之內,這部分地址就是bios爲內核需要的參數預留的,內核需要使用的數據在bios階段都將數據存入到高16M之內。而EPS中表的地址,是固定在0x980000000f000000,映射的物理地址就是0x0f000000對應內存地址就是低256M的高16M的起始地址。其代碼具體實現不再詳細介紹。這部分代碼我們根據我們平臺的內存地址的使用情況做了適當的調整。和源碼是不一樣。

(1)SmbiosTable

其實這部分的代碼才是最值得寫的,其架構的實現,可以爲後續在一些地方用得到。

其入口函數爲SmbiosDriverEntryPoint,其代碼如下:

EFI_STATUS
EFIAPI
SmbiosDriverEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable

  )

{
  UINTN                Index;
  EFI_STATUS           EfiStatus;
  EFI_SMBIOS_PROTOCOL  *Smbios;

  EfiStatus = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID**)&Smbios);

  if (EFI_ERROR(EfiStatus)) {
    DEBUG((EFI_D_ERROR, "Could not locate SMBIOS protocol.  %r\n", EfiStatus));
    return EfiStatus;
  }

  mHiiHandle = HiiAddPackages (
                 &gEfiCallerIdGuid,
                 NULL,
                 SmbiosTableStrings,
                 NULL
                 );
  ASSERT (mHiiHandle != NULL);
  for (Index = 0; Index < mSmbiosDataTableEntries; ++Index) {
    //
    // If the entry have a function pointer, just log the data.
    //
    if (mSmbiosDataTable[Index].Function != NULL) {
      EfiStatus = (*mSmbiosDataTable[Index].Function)(
        mSmbiosDataTable[Index].RecordData,
        Smbios
        );

      if (EFI_ERROR(EfiStatus)) {
        DEBUG((EFI_D_ERROR, "Misc smbios store error.  Index=%d, ReturnStatus=%r\n", Index, EfiStatus));
        return EfiStatus;
      }
    }
  }
  return EfiStatus;
}   

首先進入函數內部之後,先loacte smbios protocol,如果locate成功,獲取到Smbios Protocol之後才能調用Protocol中的SmbiosAdd函數,添加每一張表的信息。獲取成功之後,就遍歷mSmbiosDataTableEntries表,依次執行這個表中的成員對應的函數來添加表象。mSmbiosDataTable其定義如下:

//
// Data Table.
//
EFI_MISC_SMBIOS_DATA_TABLE  mSmbiosDataTable[] = {
  MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscBiosInfo,MiscBiosInfo ),//type 0
  MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscSystemInfo, MiscSystemInfo),//type 1
  MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscBoardInfo, MiscBoardInfo),//type 2
  MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscChassisInfo, MiscChassisInfo),//type 3
MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscProcessorInfo, MiscProcessorInfo),//type 4                                                                                          
  //MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscCacheInfo, MiscCacheInfo),//type 7
  //MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscOemString, MiscOemString),//type 11
  //MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscPhysicalStoreInfo, MiscPhysicalStoreInfo),//type 16
  MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscStoreDeviceInfo, MiscStoreDeviceInfo),//type 17
  //MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscMemMappInfo, MiscMemMappInfo),//type 19
  MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscTemperatureInfo, MiscTemperatureInfo),//type 28
  //MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscBootInformationStatus, MiscBootInformationStatus),//type 32

};

EFI_MISC_SMBIOS_DATA_TABLE又是如何定義的呢?代碼如下:

//
// Data table entry definition.
//
typedef struct {
  //  
  // intermediat input data for SMBIOS record
  //  
  VOID                              *RecordData;
  EFI_MISC_SMBIOS_DATA_FUNCTION     *Function;

} EFI_MISC_SMBIOS_DATA_TABLE;

這裏面EFI_MISC_SMBIOS_DATA_FUNCTION 的定義又如下:

//
// Data table entry update function.

//

#define EFIAPI (定義EFIAPI爲空)

typedef EFI_STATUS (EFIAPI EFI_MISC_SMBIOS_DATA_FUNCTION) (
  IN  VOID                 *RecordData,
  IN  EFI_SMBIOS_PROTOCOL  *Smbios

  );定義了EFI_MISC_SMBIOS_DATA_FUNCTION的返回值爲EFI_STATUS中的類型,函數參數包含這兩個參數。只要符合這個參數的函數都可以使用這個類型。

MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION的定義是這樣的:

// Data Table entries
//
#define MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION(NAME1, NAME2) \
{ \
  & NAME1 ## Data, \
  & NAME2 ## Function \
}

也就是將第一個參數後面加上Data在取地址,第二個參數加上Function再去地址。所以拿第一個參數爲例子,

MISC_SMBIOS_TABLE_ENTRY_DATA_AND_FUNCTION( MiscBiosInfo,MiscBiosInfo ),//type 0

其實就是


&MiscBiosInfoData,//對應*RecordData;成員

&MiscBiosInfoFunction  //對應EFI_MISC_SMBIOS_DATA_FUNCTION     *Function成員

其他的一次類推。這裏面MiscBiosInfoData是一個全局變量,其定義如下:

//
// Static (possibly build generated) Bios infomation data (type 0).
//

MISC_SMBIOS_TABLE_DATA(EFI_MISC_BIOS_DATA, MiscBiosInfo) = {
  {
    EFI_SMBIOS_TYPE_BIOS_INFORMATION,
    sizeof (SMBIOS_TABLE_TYPE0),
    0   
  },  
  1,//STRING_TOKEN(STR_MISC_BIOS_VENDOR),       // BiosVendor
  2,//STRING_TOKEN(STR_MISC_BIOS_VERSION),      // BiosVersion
  0xe000, // BiosStartingAddress
  3,//STRING_TOKEN(STR_MISC_BIOS_RELEASE_DATE), // BiosReleaseDate
  0,       // BiosPhysicalDeviceSize
  {       // BiosCharacteristics1
    0x18,
    0x05,
    0,  
    0,  
    0,  
    0,  
    0,  
    0   
  },  
  {       // BiosCharacteristicsExten
    0x80,    // BiosReserved                      :16
    0x02     // Reserved                          :32
  },  
  1,  
  0,  
  0xff,
  0xff
}; 
#defineMISC_SMBIOS_TABLE_DATA(NAME1,NAME2) \                                                                                                                           

  NAME1 NAME2 ## Data

所以上面的全局變量其實就是這樣的

EFI_MISC_BIOS_DATA MiscBiosInfoData = {
  {
    EFI_SMBIOS_TYPE_BIOS_INFORMATION,
    sizeof (SMBIOS_TABLE_TYPE0),
    0
  },
  1,//STRING_TOKEN(STR_MISC_BIOS_VENDOR),       // BiosVendor
  2,//STRING_TOKEN(STR_MISC_BIOS_VERSION),      // BiosVersion
  0xe000, // BiosStartingAddress
  3,//STRING_TOKEN(STR_MISC_BIOS_RELEASE_DATE), // BiosReleaseDate
  0,       // BiosPhysicalDeviceSize
  {       // BiosCharacteristics1
    0x18,
    0x05,
    0,
    0,
    0,
    0,
    0,
    0
  },
  {       // BiosCharacteristicsExten
    0x80,    // BiosReserved                      :16
    0x02     // Reserved                          :32
  },
  1,
  0,
  0xff,
  0xff
};


MiscBiosInfoFunction就是要執行的函數,這個函數是怎麼定義的呢?

MISC_SMBIOS_TABLE_FUNCTION(MiscBiosInfo)                                                                                                                                                 
{
  CHAR8                 *OptionalStrStart;
  UINTN                 VendorStrLen;
  UINTN                 VerStrLen;
  UINTN                 DateStrLen;
  CHAR16                *Version;
  CHAR16                *ReleaseDate;
  EFI_STATUS            Status;
  EFI_STRING            Char16String;
  STRING_REF            TokenToGet;
  STRING_REF            TokenToUpdate;
  SMBIOS_TABLE_TYPE0    *SmbiosRecord;
  EFI_SMBIOS_HANDLE     SmbiosHandle;
  EFI_MISC_BIOS_DATA    *ForType0InputData;

  ForType0InputData        = (EFI_MISC_BIOS_DATA *)RecordData;

  //
  // First check for invalid parameters.
  //
  if (RecordData == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Version = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString);
  if (StrLen (Version) > 0) {
    TokenToUpdate = STRING_TOKEN (STR_MISC_BIOS_VERSION);
    HiiSetString (mHiiHandle, TokenToUpdate, Version, NULL);
  }

  ReleaseDate = (CHAR16 *) PcdGetPtr (PcdFirmwareReleaseDateString);
  if (StrLen(ReleaseDate) > 0) {
    TokenToUpdate = STRING_TOKEN (STR_MISC_BIOS_RELEASE_DATE);
    HiiSetString (mHiiHandle, TokenToUpdate, ReleaseDate, NULL);
  }

  TokenToGet = STRING_TOKEN (STR_MISC_BIOS_VENDOR);
  Char16String = HiiGetPackageString(&gEfiCallerIdGuid, TokenToGet, NULL);
  VendorStrLen = StrLen(Char16String);
  if (VendorStrLen > SMBIOS_STRING_MAX_LENGTH) {
    return EFI_UNSUPPORTED;
  }

  TokenToGet = STRING_TOKEN (STR_MISC_BIOS_VERSION);
  Version = HiiGetPackageString(&gEfiCallerIdGuid, TokenToGet, NULL);
  VerStrLen = StrLen(Version);
  if (VerStrLen > SMBIOS_STRING_MAX_LENGTH) {
    return EFI_UNSUPPORTED;
  }

  TokenToGet = STRING_TOKEN (STR_MISC_BIOS_RELEASE_DATE);
  ReleaseDate = HiiGetPackageString(&gEfiCallerIdGuid, TokenToGet, NULL);
  DateStrLen = StrLen(ReleaseDate);
  if (DateStrLen > SMBIOS_STRING_MAX_LENGTH) {
    return EFI_UNSUPPORTED;
  }

  //
  // Two zeros following the last string.
  //
  SmbiosRecord = AllocatePool(sizeof (SMBIOS_TABLE_TYPE0) + VendorStrLen + 1 + VerStrLen + 1 + DateStrLen + 1 + 1 );
  ZeroMem(SmbiosRecord, sizeof (SMBIOS_TABLE_TYPE0) + VendorStrLen + 1 + VerStrLen + 1 + DateStrLen + 1 + 1 );
  CopyMem(SmbiosRecord, ForType0InputData, sizeof(SMBIOS_TABLE_TYPE0));

  size_t FlashSize = 0;
  tgt_flashinfo(0xbfc00000, &FlashSize);
  SmbiosRecord->BiosSize = (FlashSize>>16) - 1;

  OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);
  UnicodeStrToAsciiStr(Char16String, OptionalStrStart);
  UnicodeStrToAsciiStr(Version, OptionalStrStart + VendorStrLen + 1);
  UnicodeStrToAsciiStr(ReleaseDate, OptionalStrStart + VendorStrLen + 1 + VerStrLen + 1);

  DbgPrint(DEBUG_INFO,"%a() (type:%d) (size:0x%x)\n",__FUNCTION__,SmbiosRecord->Hdr.Type,
  sizeof (SMBIOS_TABLE_TYPE0) + VendorStrLen + 1 + VerStrLen + 1 + DateStrLen + 1 + 1 );
  //
  // Now we have got the full smbios record, call smbios protocol to add this record.
  //
  Status = AddSmbiosRecord (Smbios, &SmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord);

  FreePool(SmbiosRecord);
  return Status;
}

第一眼一看這個函數爲什麼沒有函數入參呢?其實是有的,看MISC_SMBIOS_TABLE_FUNCTION的定義:

#define MISC_SMBIOS_TABLE_FUNCTION(NAME2)   \
  EFI_STATUS EFIAPI NAME2 ## Function( \
  IN  VOID                  *RecordData, \
  IN  EFI_SMBIOS_PROTOCOL   *Smbios \

  )其參數就是*RecordData,和*Smbios,所以上面函數的第一行其實就是

EFI_STATUS EFIAPI MiscBiosInfoFunction(

IN  VOID                  *RecordData, \

  IN  EFI_SMBIOS_PROTOCOL   *Smbios \)

所以是有參數的。

再看這個函數是如何執行的,移植傳入的入參又是什麼呢?這就是在函數SmbiosDriverEntryPoint內的for循環中執行的,看代碼

  if (mSmbiosDataTable[Index].Function != NULL) {
      EfiStatus = (*mSmbiosDataTable[Index].Function)(
        mSmbiosDataTable[Index].RecordData,
        Smbios

        );

現在還是拿第一個爲例,即Index等於0的時候,mSmbiosDataTable[Index].Function是不爲NULL的因爲,我們已經把函數&MiscBiosInfoFunction的地址添加到mSmbiosDataTable表中了,所以接下來執行這個表中的Function對應的函數即

EfiStatus = (*mSmbiosDataTable[Index].Function)而需要的兩個參數是誰呢,也就是mSmbiosDataTable[Index].RecordData,

 和Smbios。所以MiscBiosInfoData的地址就是傳入的第一個參數。

到現在是不是清晰了,寫每個表其實就是執行一個函數,這個函數寫的主要數據也就是第一個參數,葉居士對應的Data的全局變量的值。

所以這種架構,在初始化一些相同結構的代碼的時候,可以使用這種架構。代碼簡介整齊,修改起來也方便。

  • 7
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值