BIOS 对于ACPI 的支持包括以下几个方面:
- 提供ACPI 表告诉操作系统信息,包括ASL 代码
- 提供S3 唤醒功能,包括平台寄存器恢复
EFI_ACPI_SDT_PROTOCOL 是PI 规范中定义的协议。它给用户提供了接口用来获取ACPI 表,
添加ACPI 表的回调函数,并且提供接口管理AML 代码。
typedef struct _EFI_ACPI_SDT_PROTOCOL {
///
/// A bit map containing all the ACPI versions supported by this protocol.
///
EFI_ACPI_TABLE_VERSION AcpiVersion;
EFI_ACPI_GET_ACPI_TABLE2 GetAcpiTable;
EFI_ACPI_REGISTER_NOTIFY RegisterNotify;
EFI_ACPI_OPEN Open;
EFI_ACPI_OPEN_SDT OpenSdt;
EFI_ACPI_CLOSE Close;
EFI_ACPI_GET_CHILD GetChild;
EFI_ACPI_GET_OPTION GetOption;
EFI_ACPI_SET_OPTION SetOption;
EFI_ACPI_FIND_PATH FindPath;
} EFI_ACPI_SDT_PROTOCOL;
GetAcpiTable : 获取ACPI 表。
RegisterNotify: 注册ACPI 表的回调函数。
EFI_ACPI_TABLE_INSTANCE 数据结构
实现EFI_ACPI_TABLE_PROTOCOL我驱动定义了ACPI_TABLE_INSTANCE 内部数据结构。
其中最关键的是TableList, 它是系统ACPI Table 的链表。
//
// ACPI support protocol instance data structure
//
typedef struct {
UINTN Signature;
EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp1; // Pointer to RSD_PTR structure
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp3; // Pointer to RSD_PTR structure
EFI_ACPI_DESCRIPTION_HEADER *Rsdt1; // Pointer to RSDT table header
EFI_ACPI_DESCRIPTION_HEADER *Rsdt3; // Pointer to RSDT table header
EFI_ACPI_DESCRIPTION_HEADER *Xsdt; // Pointer to XSDT table header
EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt1; // Pointer to FADT table header
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt3; // Pointer to FADT table header
EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs1; // Pointer to FACS table header
EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs3; // Pointer to FACS table header
EFI_ACPI_DESCRIPTION_HEADER *Dsdt1; // Pointer to DSDT table header
EFI_ACPI_DESCRIPTION_HEADER *Dsdt3; // Pointer to DSDT table header
LIST_ENTRY TableList;
UINTN NumberOfTableEntries1; // Number of ACPI 1.0 tables
UINTN NumberOfTableEntries3; // Number of ACPI 3.0 tables
UINTN CurrentHandle;
EFI_ACPI_TABLE_PROTOCOL AcpiTableProtocol;
EFI_ACPI_SDT_PROTOCOL AcpiSdtProtocol;
LIST_ENTRY NotifyList;
} EFI_ACPI_TABLE_INSTANCE;
EFI_ACPI_TABLE_LIST 数据结构
EFI_ACPI_TABLE_INSTANCE.TableList 记录了所有ACPI table 的一个双向链表,键表结构如下:
EFI_ACPI_TABLE_LIST
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
EFI_ACPI_TABLE_VERSION Version;
EFI_ACPI_COMMON_HEADER *Table;
EFI_PHYSICAL_ADDRESS PageAddress;
UINTN NumberOfPages;
UINTN Handle;
} EFI_ACPI_TABLE_LIST;
EFI_ACPI_NOTIFY_LIST 数据结构
EFI_ACPI_TABLE_INSTANCE.NotifyList 记录了所有ACPI table 回调函数的一个双向链表,链表结构如下:
//
// ACPI Notify List Entry definition.
//
// Signature must be set to EFI_ACPI_NOTIFY_LIST_SIGNATURE
// Link is the linked list data.
// Notification is the callback function.
//
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
EFI_ACPI_NOTIFICATION_FN Notification;
} EFI_ACPI_NOTIFY_LIST;
//
// Check for invalid input parameters
//
if ((AcpiTableBuffer == NULL) || (TableKey == NULL)
|| (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTableBuffer)->Length != AcpiTableBufferSize)) {
return EFI_INVALID_PARAMETER;
}
检查AcpiTableBuffer 与Tablekey 是否为空。检查AcpiTableBufferSize 与AcpiTableBuffer 中的Length
是否一致,不一致的话返回错误。
计算AcpiTable 中的校验和。
//
// Install the ACPI table
//
AcpiTableBufferConst = AllocateCopyPool (AcpiTableBufferSize,AcpiTableBuffer);
*TableKey = 0;
Status = AddTableToList (
AcpiTableInstance,
AcpiTableBufferConst,
TRUE,
Version,
TableKey
);
if (!EFI_ERROR (Status)) {
Status = PublishTables (
AcpiTableInstance,
Version
);
}
FreePool (AcpiTableBufferConst);
//
// Add a new table successfully, notify registed callback
//
if (FeaturePcdGet (PcdInstallAcpiSdtProtocol)) {
if (!EFI_ERROR (Status)) {
SdtNotifyAcpiList (
AcpiTableInstance,
Version,
*TableKey
);
}
InstallAcpiTable通过AddTableToList 去安装ACPI 表。
如果成功的话,再调用PublishTable 把Acpi 表更新到UEFI ConfiguraitonTable 中。这样,操作系统就可以
通过UEFI ConfigurationTable 找到AcpiTable.