前面介绍了如何在 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进行简单的介绍,值得阅读)


Hi sir,
For the source code, you can Add/change to ….
1. SIGNATURE_32 –> #include
– Before:
// Step5. Find the FADT table
if (Entry->Signature==0x50434146) { //’FACP’
– Change:
if (Entry->Signature == SIGNATURE_32 (‘F’, ‘A’, ‘C’, ‘P’)) {
2. Get MSDM address
// Step8. Get MSDM address
if (Entry->Signature == SIGNATURE_32 (‘M’, ‘S’, ‘D’, ‘M’)) {
MSDM = (EFI_ACPI_MSDM *)((UINTN)(*EntryPtr));
if (zDebug) {
Print(L”MSDM table @[%X]\n”,MSDM);
ParseMSDM(MSDM);
}
}
//refer ‘ParseMSDM()’ functio and “EFI_ACPI_MSDM” structure from http://blog.fpmurphy.com/2015/02/retrieve-microsoft-windows-product-key-from-uefi-shell.html
Best Regards,
Timothy
Hi Timothy,
That’s great, thanks for your code.
Z.t
Hi Sir,
Thanks for your source code.
Best Regards,
Timothy
請問樓主是否有寫過讀出HDD的INFORMATION
&SMART FEATURE 相關的Application?
没有唉,不过我记得PI Spec中有一个 HDD 相关的Protocol你可以看看
樓主你好,請問Sign[0],Sign[1],Sign[2]的寫法,是為了相容的型別嗎?
為甚麼UINT32 和 CHAR16 彼此不相容的型別在Compiler下可以過關?
EX: Sign[0]= (XSDT->Signature & 0xFF);
另外裡面的0xFF只是為了取最低八位元吧,有考慮Signed 或 Unsigned的情況嗎?
http://www.programmer-club.com.tw/showSameTitleN/c/38319.html
因为取的是低8位,所以不存在类型兼容的问题。然后这种写法不需要考虑signed 或者 unsigned的情况。
是的,看MdePkg关于printlib的说明,在MdePkg.chm中搜索Printlib:
%s,The argument is a pointer to a Unicode string. This does not follow ANSI C.
部分可以简化一下,分享:
#include
#include
#include
//EfiGetSystemConfigurationTable (IN EFI_GUID *TableGuid, OUT VOID **Table)
//AsciiPrint
#include
//global gST gBS
#include
//CopyMem (OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
//ZeroMem (OUT VOID *Buffer, IN UINTN Length)
#include
//gEfiAcpi10TableGuid,gEfiAcpi20TableGuid
#include
//EFI_ACPI_DESCRIPTION_HEADER
#include
//EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER* RSDP;
EFI_ACPI_DESCRIPTION_HEADER* RSDT;
CHAR8 SignatureStr[20];
UINTN entry_counts=SystemTable->NumberOfTableEntries;
Print(L”number of entries:%u\n”,entry_counts);
for(UINTN i=0;iConfigurationTable[i].VendorGuid));
}
if(EFI_SUCCESS==EfiGetSystemConfigurationTable(&gEfiAcpi10TableGuid,(VOID **)&RSDP))
{
Print(L”ACPI 1.0 Table find.\n”);
ZeroMem(SignatureStr,sizeof(SignatureStr));
CopyMem(SignatureStr,&(RSDP->Signature),sizeof(RSDP->Signature));
AsciiPrint(“RSDP_signature_str:%a\n”,SignatureStr);
RSDT=(EFI_ACPI_DESCRIPTION_HEADER*)(&(RSDP->RsdtAddress));
ZeroMem(SignatureStr,sizeof(SignatureStr));
CopyMem(SignatureStr,&(RSDT->Signature),sizeof(RSDT->Signature));
AsciiPrint(“RSDT_signature_str:%a\n”,SignatureStr);
}else if(EFI_SUCCESS==EfiGetSystemConfigurationTable(&gEfiAcpi20TableGuid,(VOID **)&RSDP))
{
Print(L”ACPI 2.0 Table find.\n”);
}else
{//…}
return EFI_SUCCESS;
}
最后感谢博主分享。
怎么粘贴就变成乱码了?,,,sorry.
你好,我想问一下的是包含DefinitionBlock的asl文件,被编译器编译成aml文件,这种文件是如何人填入到dsdt表中的??
我记得大约是编译成一个 ffs 然后用的时候load到内存的,你可以追一下代码看看。
你好,因为我是在uefi中想添加acpi的支持,看了好几天代码,没有找到这个aml字节码是怎么添加到dsdt表中的。因为内核获取的时候是通过fadt获取到dsdt的指针,再来获取aml的,像您说的,load到内存后,内核如何知道这个数据在什么地方的 ?