前面介绍了如何在 Shell下 Dump 系统中各种 ConfigurationTable的方法,这里介绍一下如何取得 ACPI 的 DSDT Table。
简单说一下原理:
1. 在ConfigurationTable中查找 GUID 为 ACPI_TABLE_GUID 和 EFI_ACPI_TABLE_GUID 的两个 Table. 检查获得 Table 的 Revision,只有 >=2 的才是我们需要的
2. 通过Table找到 XsdtAddress 这样我们能找到 XSDT Table
3. 在 XSDT 给出的Table中找到指向 FADT Table 的
4. 在 FADT 中直接给出了 DSDT 的地址
5. 最后将整个DSDT Table dump出来保存为文件即可
用图表简单描述上述过程
代码看起来很复杂,主要是各种指针比较多。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/BaseMemoryLib.h>
#include <Protocol/SimpleFileSystem.h>
#define ACPI_TABLE_GUID \
{ \
0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
}
#define EFI_ACPI_TABLE_GUID \
{ \
0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \
}
#define zDebug 1
///
/// RSD_PTR Revision (as defined in ACPI 5.0 spec.)
///
#define EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION 0x02
///< ACPISpec (Revision 5.0) says current value is 2
extern EFI_SYSTEM_TABLE *gST;
extern EFI_BOOT_SERVICES *gBS;
#pragma pack(1)
// \MdePkg\Include\IndustryStandard\Acpi50.h
//
// ACPI 5.0 table structures
//
///
/// Root System Description Pointer Structure
///
typedef struct {
UINT64 Signature;
UINT8 Checksum;
UINT8 OemId[6];
UINT8 Revision;
UINT32 RsdtAddress;
UINT32 Length;
UINT64 XsdtAddress;
UINT8 ExtendedChecksum;
UINT8 Reserved[3];
} EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER;
// \MdePkg\Include\IndustryStandard\Acpi10.h
///
/// The common ACPI description table header.
/// This structure prefaces most ACPI tables.
///
typedef struct {
UINT32 Signature;
UINT32 Length;
UINT8 Revision;
UINT8 Checksum;
UINT8 OemId[6];
UINT64 OemTableId;
UINT32 OemRevision;
UINT32 CreatorId;
UINT32 CreatorRevision;
} EFI_ACPI_DESCRIPTION_HEADER;
// \MdePkg\Include\IndustryStandard\Acpi50.h
///
/// ACPI 5.0 Generic Address Space definition
///
typedef struct {
UINT8 AddressSpaceId;
UINT8 RegisterBitWidth;
UINT8 RegisterBitOffset;
UINT8 AccessSize;
UINT64 Address;
} EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE;
// \MdePkg\Include\Protocol\AcpiSystemDescriptionTable.h
///
/// Fixed ACPI Description Table Structure (FADT)
///
typedef struct {
EFI_ACPI_DESCRIPTION_HEADER Header;
UINT32 FirmwareCtrl;
UINT32 Dsdt;
UINT8 Reserved0;
UINT8 PreferredPmProfile;
UINT16 SciInt;
UINT32 SmiCmd;
UINT8 AcpiEnable;
UINT8 AcpiDisable;
UINT8 S4BiosReq;
UINT8 PstateCnt;
UINT32 Pm1aEvtBlk;
UINT32 Pm1bEvtBlk;
UINT32 Pm1aCntBlk;
UINT32 Pm1bCntBlk;
UINT32 Pm2CntBlk;
UINT32 PmTmrBlk;
UINT32 Gpe0Blk;
UINT32 Gpe1Blk;
UINT8 Pm1EvtLen;
UINT8 Pm1CntLen;
UINT8 Pm2CntLen;
UINT8 PmTmrLen;
UINT8 Gpe0BlkLen;
UINT8 Gpe1BlkLen;
UINT8 Gpe1Base;
UINT8 CstCnt;
UINT16 PLvl2Lat;
UINT16 PLvl3Lat;
UINT16 FlushSize;
UINT16 FlushStride;
UINT8 DutyOffset;
UINT8 DutyWidth;
UINT8 DayAlrm;
UINT8 MonAlrm;
UINT8 Century;
UINT16 IaPcBootArch;
UINT8 Reserved1;
UINT32 Flags;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE ResetReg;
UINT8 ResetValue;
UINT8 Reserved2[3];
UINT64 XFirmwareCtrl;
UINT64 XDsdt;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XGpe0Blk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE XGpe1Blk;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE SleepControlReg;
EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE SleepStatusReg;
} EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE;
#pragma pack()
EFI_STATUS
PrintGuid (
IN EFI_GUID *Guid
)
/*++
Routine Description:
This function prints a GUID to STDOUT.
Arguments:
Guid Pointer to a GUID to print.
Returns:
EFI_SUCCESS The GUID was printed.
EFI_INVALID_PARAMETER The input was NULL.
--*/
{
if (Guid == NULL) {
Print(L"Parameter error!\n");
return EFI_INVALID_PARAMETER;
}
Print (
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ",
(unsigned) Guid->Data1,
Guid->Data2,
Guid->Data3,
Guid->Data4[0],
Guid->Data4[1],
Guid->Data4[2],
Guid->Data4[3],
Guid->Data4[4],
Guid->Data4[5],
Guid->Data4[6],
Guid->Data4[7]
);
return EFI_SUCCESS;
}
UINTN
CompareGUID (
IN EFI_GUID *Guid1,
IN EFI_GUID *Guid2
)
/*++
Routine Description:
This function compares 2 GUIDs
Arguments:
Guid1 Pointer to 1st GUID.
Guid2 Pointer to 12st GUID.
Returns:
0 The GUID was same.
1 The input was different.
2 PARAMETER error.
--*/
{
if ((Guid1 == NULL)||(Guid2 == NULL)) {
Print(L"Parameter error!\n");
return 2;
}
if ((Guid1->Data1 != Guid2->Data1) ||
(Guid1->Data2 != Guid2->Data2) ||
(Guid1->Data3 != Guid2->Data3) ||
(Guid1->Data4[0] != Guid2->Data4[0]) ||
(Guid1->Data4[1] != Guid2->Data4[1]) ||
(Guid1->Data4[2] != Guid2->Data4[2]) ||
(Guid1->Data4[3] != Guid2->Data4[3]) ||
(Guid1->Data4[4] != Guid2->Data4[4]) ||
(Guid1->Data4[5] != Guid2->Data4[5]) ||
(Guid1->Data4[6] != Guid2->Data4[6]) ||
(Guid1->Data4[7] != Guid2->Data4[7]))
{
return 1;
}
return 0;
}
EFI_STATUS
SaveDSDTToFile (
CHAR8 *P,
UINTN length
)
/*++
Routine Description:
Write a memory to a file
Arguments:
P Pointer to the contant
length Sizeof the contant
Returns:
EFI_SUCCESS The GUID was printed.
EFI_INVALID_PARAMETER The input was NULL.
--*/
{
EFI_STATUS Status;
EFI_FILE_PROTOCOL *Root,*FileHandle=0;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
Status = gBS->LocateProtocol(
&gEfiSimpleFileSystemProtocolGuid,
NULL,
(VOID **)&SimpleFileSystem);
if (EFI_ERROR(Status)) {
Print(L"Cannot find EFI_SIMPLE_FILE_SYSTEM_PROTOCOL \r\n");
return Status;
}
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem,&Root);
if (EFI_ERROR(Status)) {
Print(L"OpenVolume error \r\n");
return Status;
}
Status = Root -> Open(Root,
&FileHandle,
(CHAR16 *) L"dsdt.aml",
EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
0);
if (EFI_ERROR(Status) || (FileHandle==0)) {
Print(L"Open error \r\n");
return Status;
}
Status = FileHandle -> Write(FileHandle, &length, P);
Status = FileHandle -> Close (FileHandle);
return EFI_SUCCESS;
}
int
EFIAPI
main (
IN int Argc,
IN CHAR16 **Argv
)
{
UINTN i,j,EntryCount;
EFI_STATUS Status;
CHAR16 Sign[20];
UINT64 *EntryPtr;
EFI_GUID AcpiTableGuid = ACPI_TABLE_GUID;
EFI_GUID Acpi2TableGuid = EFI_ACPI_TABLE_GUID;
EFI_CONFIGURATION_TABLE *C=NULL;
EFI_ACPI_DESCRIPTION_HEADER *XSDT,*Entry,*DSDT;
EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *FADT;
EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Root;
C=gST->ConfigurationTable;
for (i=0;i<gST->NumberOfTableEntries-1;i++)
{
//Step1. Find the table for ACPI
if ((CompareGUID(&C->VendorGuid,&AcpiTableGuid) == 0) ||
(CompareGUID(&C->VendorGuid,&Acpi2TableGuid) == 0))
{
Print(L"Found table:");
Status=PrintGuid(&C->VendorGuid);
Print(L"@[0x%X]\n",C);
Root=C->VendorTable;
if (zDebug) {Print(L"ROOT SYSTEM DESCRIPTION @[0x%X]\n",Root);}
if (zDebug) {
ZeroMem(Sign,sizeof(Sign));
for (j=0;j<8;j++) { Sign[j]=(Root->Signature >> (j*8) & 0xFF); }
Print(L"Signature [%s]\n",Sign);
Print(L"Revision [%d]\n",Root->Revision);
ZeroMem(Sign,sizeof(Sign));
for (j=0;j<6;j++) { Sign[j]= (Root->OemId[j] & 0xFF); }
Print(L"OEMID [%s]\n",Sign);
}
Print(L"RSDT address= [0x%X], Length=[0x%X]\n",
Root->RsdtAddress,Root->Length);
Print(L"XSDT address= [0x%LX]\n",Root->XsdtAddress);
// Step2. Check the Revision, we olny accept Revision >= 2
if (Root->Revision>=EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION)
{
// Step3. Get XSDT address
XSDT=(EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Root->XsdtAddress;
EntryCount = (XSDT->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER))
/ sizeof(UINT64);
if (zDebug) {
ZeroMem(Sign,sizeof(Sign));
Sign[0]= (XSDT->Signature & 0xFF);
Sign[1]= (XSDT->Signature >> 8 & 0xFF);
Sign[2]= (XSDT->Signature >> 16 & 0xFF);
Sign[3]= (XSDT->Signature >> 24 & 0xFF);
Print(L"Sign [%s]\n",Sign);
Print(L"length [%d]\n",XSDT->Length);
Print(L"Counter [%d]\n",EntryCount);
}
// Step4. Check the signature of every entry
EntryPtr=(UINT64 *)(XSDT+1);
for (j=0;j<EntryCount; j++,EntryPtr++)
{
Entry=(EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
if (zDebug) {
ZeroMem(Sign,sizeof(Sign));
Sign[0]= (Entry->Signature & 0xFF);
Sign[1]= (Entry->Signature >> 8 & 0xFF);
Sign[2]= (Entry->Signature >> 16 & 0xFF);
Sign[3]= (Entry->Signature >> 24 & 0xFF);
Print(L"%d: [%s] @[%X]\n",j,Sign,Entry);
}
// Step5. Find the FADT table
if (Entry->Signature==0x50434146) { //'FACP'
FADT = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN) Entry;
// Step6. Get DSDT address
DSDT = (EFI_ACPI_DESCRIPTION_HEADER *) (FADT->Dsdt);
if (zDebug) {
Print(L"DSDT table @[%X]\n",DSDT);
}
// Step7. Save DSDT as a file
SaveDSDTToFile((CHAR8 *)DSDT,DSDT->Length);
}
}
}
}
C++;
}
return EFI_SUCCESS;
}
运行结果(注意:上述代码是在NT32模拟环境下编译通过的,但是因为模拟坏境中没有对应的 ACPI Table,所以必须在实体机上运行才有结果):
最后得到的 DSDT.AML 我们可以直接使用 ASL 工具反编译。
完整代码下载
本文代码参阅了【参考1】,这里表示感谢。
参考:
1. http://blog.fpmurphy.com/2015/01/list-acpi-tables-from-uefi-shell.html List ACPI Tables From UEFI Shell
2. http://www.cnblogs.com/junzhkevin/archive/2013/02/25/2932801.html ACPI Tables (不确定是否为文章出处。这里有对ACPI Table进行简单的介绍,值得阅读)


























