1、概述
在主板上电后,UEFI会将HW信息包括, CPU、Memory、FW、PM等信息以SMBIOS table形式上存储到一段内存区域中,进入OS后,OS通过解析该段内存即可获取相关配置。 SMBIOS是通过DXE驱动加载到系统表的,入口函数为SmbiosDriverEntryPoint,该驱动程序生成一个实例。实例包含了增加、更新、移除、获取 SMBIOS的函数,入口函数还初始化数据链表和句柄头部链表。最后实现的实例安装到新的句柄上,在DXE阶段调用。
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;
}
2、创建表结构
SmbiosCreateTable (
OUT VOID **TableEntryPointStructure
)
{
.....
EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;
EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;
EntryPointStructureData.SmbiosBcdRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);
PhysicalAddress = 0xffffffff;
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiRuntimeServicesData,
EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
&PhysicalAddress
);
....
}
创建表结构的主要功能为 1、根据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 | |
与SMBIOS的SMBIOS_TABLE_ENTRY_POINT结构体对应起来
typedef struct {
UINT8 AnchorString[4];
UINT8 EntryPointStructureChecksum;
UINT8 EntryPointLength;
UINT8 MajorVersion;
UINT8 MinorVersion;
UINT16 MaxStructureSize;
UINT8 EntryPointRevision;
UINT8 FormattedArea[5];
UINT8 IntermediateAnchorString[5];
UINT8 IntermediateChecksum;
UINT16 TableLength;
UINT32 TableAddress;
UINT16 NumberOfSmbiosStructures;
UINT8 SmbiosBcdRevision;
} SMBIOS_TABLE_ENTRY_POINT;
2、创建表头部
位置 | 名称 | 长度 | 描述 |
---|
00H | TYPE 号 | 1BYTE | 结构的TYPE 号 | 01H | 长度 | 1BYTE | 本结构的长度,就此TYPE 号的结构而言 | 02H | 句柄 | 2BYTE | 用于获得本SMBIOS 结构,其值不定 |
EndStructure.Header.Type = SMBIOS_TYPE_END_OF_TABLE;
EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);
EndStructure.Header.Handle = SmbiosHandle;
3 增加SMBIOS表
mPrivateData.Smbios.Add = SmbiosAdd;
EFI_STATUS
EFIAPI
SmbiosAdd (
IN CONST EFI_SMBIOS_PROTOCOL *This,
IN EFI_HANDLE ProducerHandle, OPTIONAL
IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
IN EFI_SMBIOS_TABLE_HEADER *Record
)
Add an SMBIOS record.
@param This The EFI_SMBIOS_PROTOCOL instance.
@param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
means no handle.
@param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle
will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,
EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
@param Record The data for the fixed portion of the SMBIOS record. The format of the record is
determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
a set of null terminated strings and a null.
@retval EFI_SUCCESS Record was added.
@retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
@retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
1、核实SmbiosHandle是否在使用中 2、计算record的大小和字符数字 找到1个0,是一个字段的长度 找到两个0,就是一条record的大小 3、分配record的内存空间 TotalSize = sizeof (EFI_SMBIOS_ENTRY) + sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize; 4、构建句柄入口并且增加到链表中
HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;
HandleEntry->SmbiosHandle = *SmbiosHandle;
InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);
5、构建record 的头结构并且增加到内部的链表中
InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);
InternalRecord->RecordSize = RecordSize;
InternalRecord->ProducerHandle = ProducerHandle;
InternalRecord->NumberOfStrings = NumberOfStrings;
SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
SmbiosEntry->RecordHeader = InternalRecord;
SmbiosEntry->RecordSize = TotalSize;
SmbiosEntry->Smbios32BitTable = Smbios32BitTable;
SmbiosEntry->Smbios64BitTable = Smbios64BitTable;
InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);
6、安装SMBIOS表到系统表中
typedef
EFI_STATUS
(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE)(
IN EFI_GUID *Guid,
IN VOID *Table
);
Adds, updates, or removes a configuration table entry from the EFI System Table.
@param[in] Guid A pointer to the GUID for the entry to add, update, or remove.
@param[in] Table A pointer to the configuration table for the entry to add, update, or
remove. May be NULL.
@retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
@retval EFI_NOT_FOUND An attempt was made to delete a nonexistent entry.
@retval EFI_INVALID_PARAMETER Guid is NULL.
@retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
4、获得SMBIOS Record
mPrivateData.Smbios.GetNext = SmbiosGetNext;
EFI_STATUS
EFIAPI
GetNextSmbiosRecord (
IN CONST EFI_SMBIOS_PROTOCOL *This,
IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry,
OUT EFI_SMBIOS_TABLE_HEADER **Record
)
1、CurrentSmbiosEntry,在退出时,指针指向包含SMBIOS记录信息的入口地址,如果CurrentSmbiosEntry指针在入口时为空,第一个smbios 的入口地址将被返回。 2、Record,在退出时,指向SMBIOS记录,该记录由格式化区域组成,然后是 无格式的区域。 无格式区域可选地包含文本字符串。 通过链表遍历的方法获得SMBIOS record
5、更新或移除SMBIOS Record
mPrivateData.Smbios.UpdateString = SmbiosUpdateString; mPrivateData.Smbios.Remove = SmbiosRemove;
更新:重新构建InternalRecord,再加载到系统表
6、增加一条SMBIOS table记录
smbios 驱动加载完成,怎样实际增加一条type0/type1/type2…记录 1、先根据gEfiSmbiosProtocolGuid 获得mSmbios接口 Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios); 2、再通过接口中add 函数加载到系统表中 EFI_SMBIOS_PROTOCOL *mSmbios; Status = mSmbios->Add ( mSmbios, NULL, &SmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *)SmbiosRecord );
|