BIOS学习实战之SMBIOS

最近事情太多,又有一段时间没做笔记了,有时候也在研究这个百敖的UIAPP框架和昆仑的UIAPP框架,思绪短时间内难理清,还是先写下SMBIOS的有关内容吧,本节主要以实践为主,仅做记录

EFI_SMBIOS_PROTOCOL

这个protocol就是操作smbios内容的,smbios怎么加载的,这个就有待去了解了,而且代码本身大部分是做好的,来看下这个protocol的里面包含了什么

struct _EFI_SMBIOS_PROTOCOL {
  EFI_SMBIOS_ADD           Add;
  EFI_SMBIOS_UPDATE_STRING UpdateString;
  EFI_SMBIOS_REMOVE        Remove;
  EFI_SMBIOS_GET_NEXT      GetNext;
  UINT8                    MajorVersion;    ///< The major revision of the SMBIOS specification supported.
  UINT8                    MinorVersion;    ///< The minor revision of the SMBIOS specification supported.
};

SMBIOS的操作给我的感觉就跟套公式一样的,咱们打开这个protocol:

  
  // open the SMBIOS protocol
  EFI_SMBIOS_PROTOCOL   *Smbios;
  Status = gBS->LocateProtocol (
    &gEfiSmbiosProtocolGuid,
    NULL,
    (VOID**)&Smbios
    );
  if (EFI_ERROR (Status)) {
    return Status;
  }

打开之后,咱们使用里面的方法:

Add

在SmbiosTablePublishEntry函数,也就是SMBIOS驱动的入口,一般逻辑是这样的,很多需要的type都会进行初始化,并通过一个void的指针去逐一的加载这些type,然后有些type可能需要写一些自己主板的特性,那么你再去单独加入更新,咱们以增加type21为例子,在打开smbios的protocol之后,咱们在它的下面新建一个函数:

Status= InstallType21Seructures(Smbios);

这个函数给我们的smbiostable新增了一个type,看下这个type的里面是啥:

typedef struct {
  SMBIOS_STRUCTURE                  Hdr;
  UINT8                             Type;                   ///< The enumeration value from BUILTIN_POINTING_DEVICE_TYPE.
  UINT8                             Interface;              ///< The enumeration value from BUILTIN_POINTING_DEVICE_INTERFACE.
  UINT8                             NumberOfButtons;
} SMBIOS_TABLE_TYPE21;
typedef struct {
  SMBIOS_TYPE    Type;
  UINT8          Length;
  SMBIOS_HANDLE  Handle;
} SMBIOS_STRUCTURE;

 通过上面的基础咱们就可以安装这个type,具体的值我瞎写的,有些值不在范围内它在系统内是反馈无效的,下面就是安装的过程,非常容易

EFI_STATUS InstallType21Seructures (IN EFI_SMBIOS_PROTOCOL   *Smbios)

{

  EFI_STATUS  Status = EFI_SUCCESS;

  SMBIOS_TABLE_TYPE21   *Type21Record;  

  EFI_SMBIOS_HANDLE     BuiltSmbiosHandle;

  Type21Record        = NULL;

  Type21Record = AllocateZeroPool(sizeof(SMBIOS_TABLE_TYPE21) + 2);

	if(Type21Record == NULL){

	  Status = EFI_OUT_OF_RESOURCES;

	}


	BuiltSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;

	Type21Record->Hdr.Type   = SMBIOS_TYPE_BUILT_IN_POINTING_DEVICE;

    Type21Record->Hdr.Length = sizeof(SMBIOS_TABLE_TYPE21);

    Type21Record->Hdr.Handle = 0;

	Type21Record->Type = 21;

	Type21Record->Interface=0;

	Type21Record->NumberOfButtons=0;

	Status = Smbios->Add (Smbios, NULL, &BuiltSmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*)Type21Record);

	FreePool (Type21Record);
  
    return Status;

}

解释一下几个关键的内容,SMBIOS_TYPE_BUILT_IN_POINTING_DEVICE的值为21,SMBIOS_HANDLE_PI_RESERVED为0xFFFE,这个值不是随便写的,而是自动分配的一个编号,也就是说你取值为0xFFFE的时候,会自动给这个type分配编号,在什么smbios信息中,这个handle的值就是这么来的,写完后编译,我们进入系统查看一下,是否生成安装了type21

BIOS学习实战之SMBIOS_第1张图片

 可以看到,一个新的type就这样生成了,有了这个type21,那么怎么去获取并修改它呢,咱们就以type1为例子,需要用到GetNext和UpdateString,一般如果你要提取smbiostable里面的新信息,使用前者就行,如果需要修改信息,那么两者都需要使用。

EFI_STATUS UpdateType1Seructures (IN EFI_SMBIOS_PROTOCOL   *Smbios)

{

EFI_STATUS                        Status;
EFI_SMBIOS_HANDLE                 SmbiosHandle;
EFI_SMBIOS_TYPE                   SmbiosType;
EFI_SMBIOS_TABLE_HEADER           *SmbiosHdr;
SMBIOS_STRUCTURE_POINTER          p;
UINTN                             StringNum;


  SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
  SmbiosType = SMBIOS_TYPE_SYSTEM_INFORMATION;
  Status = Smbios->GetNext(Smbios, &SmbiosHandle, &SmbiosType, &SmbiosHdr, NULL);

  if (!EFI_ERROR (Status)){
    // update board version
    p.Hdr         = SmbiosHdr;
    StringNum = p.Type1->ProductName;
    Status = Smbios->UpdateString(Smbios,&SmbiosHandle,&StringNum, "Anthony-PC");
  }
  else{ 
    return Status;
  }

return Status;

}

编译,我们查看效果,Product Name是不是变成了我们想要的名称呢

BIOS学习实战之SMBIOS_第2张图片

 如果我们的BIOS界面有需要用到这些信息,比如product name需要在BIOS界面下显示,应该如何操作呢,我们可以通过如下的代码形式进行;

  EFI_SMBIOS_HANDLE                 SmbiosHandle;
  EFI_SMBIOS_PROTOCOL               *Smbios;
  SMBIOS_TABLE_TYPE1                *Type1Record;
  EFI_SMBIOS_TABLE_HEADER           *Record;


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

 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
 Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);

 while (!EFI_ERROR(Status)) {
   if (Record->Type == SMBIOS_TYPE_SYSTEM_INFORMATION) {
      Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
      StrIndex = Type1Record->ProductName;
      GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
      UiCustomizeFrontPageBanner (1, TRUE, &NewString);
      HiiSetString (gFrontPagePrivate.HiiHandle, STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL), NewString, NULL);
      FreePool (NewString);
    }

 }

//其中GetOptionalStringByIndex函数如下,供代码理解

EFI_STATUS
GetOptionalStringByIndex (
  IN      CHAR8                   *OptionalStrStart,
  IN      UINT8                   Index,
  OUT     CHAR16                  **String
  )
{
  UINTN          StrSize;

  if (Index == 0) {
    *String = AllocateZeroPool (sizeof (CHAR16));
    return EFI_SUCCESS;
  }

  StrSize = 0;
  do {
    Index--;
    OptionalStrStart += StrSize;
    StrSize           = AsciiStrSize (OptionalStrStart);
  } while (OptionalStrStart[StrSize] != 0 && Index != 0);

  if ((Index != 0) || (StrSize == 1)) {
    //
    // Meet the end of strings set but Index is non-zero, or
    // Find an empty string
    //
    *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
  } else {
    *String = AllocatePool (StrSize * sizeof (CHAR16));
    AsciiStrToUnicodeStrS (OptionalStrStart, *String, StrSize);
  }

  return EFI_SUCCESS;
}

ok,smbios的一些内容的笔记就先做到这里

你可能感兴趣的:(BIOS学习实战,UEFI)