UEFI Spec 介绍了一个 EFI_ACPI_TABLE_PROTOCOL,定义如下:
从介绍可以看出,我们能够使用这个 PROTOCOL 添加(Install)或者删除(Uninstall)一个 ACPI Table。
首先准备一个 ACPI Table, 这里顶一个一个叫做 LBZT 的 Table。
DefinitionBlock ("LABZT.AML", "LBZT", 2, "", "", 0x0)
{
Name(BUF1, Buffer(){0x00,0x01,0x02,0x03,0x04,0x05})
Name(BUF2, "www.lab-z.com")
}
DefinitionBlock语法定义如下【参考1】:
AMLFileName 是给编译器看的,用于指定输出的 AML 文件名;
TableSignature 是 ACPI Table 的名字(4字节)
ComplianceRevision, 2以及大于2是指定64位;1或者0指定32位(这里我不清楚具体差别,做了一个实验,比如定义:Name(BUF3, 0x1122334455),当ComplianceRevision为0时,编译之后结果发生截断,实际定义是Name(BUF3, 0x22334455);但是当ComplianceRevision为2时,编译结果和代码相同)。如果在处理较大的数值时,需要特别注意这里。
OEMID OEM自定义 ID
TableID OEM自定义Table 名称(8Bytes)
OEMRevision OEM自定义数值
接下来我们首先自定义一个 ACPI Table 如下:
DefinitionBlock ("LABZ64.AML", "LABZ", 2, "", "", 0x0)
{
Name(BUF1, Buffer(){0x00,0x01,0x02,0x03,0x04,0x05})
Name(BUF2, "www.lab-z.com")
Name(BUF3, 0x1122334455)
}
编译之:
得到的是一个二进制文件LABZ64.aml
使用工具转化为C的定义,我们就可以在代码中直接使用了。测试代码如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/AcpiTable.h>
extern EFI_BOOT_SERVICES *gBS;
EFI_GUID gEfiAcpiTableProtocolGuid ={
0xFFE06BDD, 0x6107, 0x46A6,
{ 0x7B, 0xB2, 0x5A, 0x9C, 0x7E, 0xC5, 0x27, 0x5C }};
/* Contents of file LABZ64.aml */
const long int LABZ64_aml_size = 85;
const unsigned char LABZ64_aml[85] = {
0x4C, 0x41, 0x42, 0x5A, 0x55, 0x00, 0x00, 0x00, 0x02, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,
0x18, 0x10, 0x19, 0x20, 0x08, 0x42, 0x55, 0x46, 0x31, 0x11, 0x09, 0x0A, 0x06, 0x00, 0x01, 0x02,
0x03, 0x04, 0x05, 0x08, 0x42, 0x55, 0x46, 0x32, 0x0D, 0x77, 0x77, 0x77, 0x2E, 0x6C, 0x61, 0x62,
0x2D, 0x7A, 0x2E, 0x63, 0x6F, 0x6D, 0x00, 0x08, 0x42, 0x55, 0x46, 0x33, 0x0E, 0x55, 0x44, 0x33,
0x22, 0x11, 0x00, 0x00, 0x00
};
int
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
EFI_STATUS Status;
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
UINTN TableKey;
Status = gBS->LocateProtocol(
&gEfiAcpiTableProtocolGuid,
NULL,
(VOID **)&AcpiTableProtocol);
if (EFI_ERROR(Status)) {
Print(L"Cannot find ACPI_TABLE_PROTOCOL \r\n");
return Status;
}
AcpiTableProtocol->InstallAcpiTable(
AcpiTableProtocol,
(VOID *)LABZ64_aml,
LABZ64_aml_size,
&TableKey);
gBS->CloseProtocol (
AcpiTableProtocol,
&gEfiAcpiTableProtocolGuid,
gImageHandle,
NULL );
return EFI_SUCCESS;
}
实体机上进行测试,运行 att.efi 之后可以使用 Acpiview 命令查看到如下:
--------------- LABZ Table ---------------
Address : 0x44B1D000
Length : 85
00000000 : 4C 41 42 5A 55 00 00 00 - 02 7A 00 00 00 00 00 00 LABZU....z......
00000010 : 00 00 00 00 00 00 00 00 - 00 00 00 00 49 4E 54 4C ............INTL
00000020 : 18 10 19 20 08 42 55 46 - 31 11 09 0A 06 00 01 02 ... .BUF1.......
00000030 : 03 04 05 08 42 55 46 32 - 0D 77 77 77 2E 6C 61 62 ....BUF2.www.lab
00000040 : 2D 7A 2E 63 6F 6D 00 08 - 42 55 46 33 0E 55 44 33 -z.com..BUF3.UD3
00000050 : 22 11 00 00 00 "....
Table Checksum : OK
ACPI Table Header :
Signature : LABZ
Length : 85
Revision : 2
Checksum : 0x7A
Oem ID :
Oem Table ID :
Oem Revision : 0x0
Creator ID : INTL
Creator Revision : 0x20191018
Table Statistics:
0 Error(s)
0 Warning(s)
再进一步,启动到 Windows后用 RW 进行查看也可以看到 LABZ Table
完整代码下载:
参考:
1. https://acpica.org/sites/acpica/files/asl_tutorial_v20190625.pdf