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