From 6064c1e48b622f53538f4df9bdd402c607a87d51 Mon Sep 17 00:00:00 2001 From: Konstantin Aladyshev Date: Sat, 10 Jul 2021 00:04:40 +0300 Subject: Move lessons to separate folder Signed-off-by: Konstantin Aladyshev --- Lessons/Lesson_28/README.md | 551 +++++++++++++++++++++ .../Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c | 106 ++++ .../Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf | 24 + 3 files changed, 681 insertions(+) create mode 100644 Lessons/Lesson_28/README.md create mode 100644 Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c create mode 100644 Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf (limited to 'Lessons/Lesson_28') diff --git a/Lessons/Lesson_28/README.md b/Lessons/Lesson_28/README.md new file mode 100644 index 0000000..3927045 --- /dev/null +++ b/Lessons/Lesson_28/README.md @@ -0,0 +1,551 @@ +The latest ACPI specification can be found under UEFI specifications page https://uefi.org/specifications + +The current latest specification is "ACPI Specification Version 6.4 (released January 2021)" (https://uefi.org/specs/ACPI/6.4/) + + +Use the same tactic we used for SMBIOS tables to print ACPI entry point table address: +``` +#include +#include + +#include + +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + for (UINTN i=0; iNumberOfTableEntries; i++) { + if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) { + Print(L"ACPI table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable); + } + } + return EFI_SUCCESS; +} +``` + +Use `dmem` to peak inside ACPI table memory: +``` +FS0:\> AcpiInfo.efi +ACPI table is placed at 7B7E014 + +FS0:\> dmem 7B7E014 30 +Memory Address 0000000007B7E014 30 Bytes + 07B7E014: 52 53 44 20 50 54 52 20-4E 42 4F 43 48 53 20 02 *RSD PTR NBOCHS .* + 07B7E024: 74 D0 B7 07 24 00 00 00-E8 D0 B7 07 00 00 00 00 *t...$...........* + 07B7E034: 66 00 00 00 AF AF AF AF-AF AF AF AF AF AF AF AF *f...............* +FS0:\> +``` + +The signature `RSP PTR` stands for `Root System Description Pointer (RSDP) Structure` (https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#root-system-description-pointer-rsdp-structure). + +It contains addresses for `RSDT` and `XSDT` tables. If you calculate offsets, you'll get these addresses from our memory dump: +``` +XSDT=0x07B7D0E8 +RSDT=0x07B7D074 +``` +These tables in turn would cointain pointers to other ACPI tables that actualy contain data useful to OS. + +According to the spec "platforms provide the RSDT to enable compatibility with ACPI 1.0 operating systems. The XSDT supersedes RSDT functionality". So if you peak these addresses with `dmem`, table contents would be pretty much the same except table signatures. Therefore in our app code we would be parsing XSDT table data. + +Ok, it's time to write some code. ACPI structures are defined in the following header files: +``` +$ ls -1 MdePkg/Include/IndustryStandard/Acpi* +MdePkg/Include/IndustryStandard/Acpi.h +MdePkg/Include/IndustryStandard/Acpi10.h +MdePkg/Include/IndustryStandard/Acpi20.h +MdePkg/Include/IndustryStandard/Acpi30.h +MdePkg/Include/IndustryStandard/Acpi40.h +MdePkg/Include/IndustryStandard/Acpi50.h +MdePkg/Include/IndustryStandard/Acpi51.h +MdePkg/Include/IndustryStandard/Acpi60.h +MdePkg/Include/IndustryStandard/Acpi61.h +MdePkg/Include/IndustryStandard/Acpi62.h +MdePkg/Include/IndustryStandard/Acpi63.h +MdePkg/Include/IndustryStandard/AcpiAml.h +``` + +Keep in mind that headers for latter standards include headers for earlier standards in itself. +``` +Acpi.h > Acpi63.h > Acpi62.h > ... > Acpi10.h > AcpiAml.h +``` + +Let's look at RSDP structure definition at the most latest ACPI standard header file +https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi63.h +``` +/// +/// 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_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER; +``` + +We can use it to print addresses of RSDT/XSDT tables. +``` +EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER* RSDP = NULL; + +for (UINTN i=0; iNumberOfTableEntries; i++) { + if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) { + Print(L"RSDP table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable); + RSDP = SystemTable->ConfigurationTable[i].VendorTable; + } +} + +if (!RSDP) { + Print(L"No ACPI2.0 table was found in the system\n"); + return EFI_SUCCESS; +} + +if (((CHAR8)((RSDP->Signature >> 0) & 0xFF) != 'R') || + ((CHAR8)((RSDP->Signature >> 8) & 0xFF) != 'S') || + ((CHAR8)((RSDP->Signature >> 16) & 0xFF) != 'D') || + ((CHAR8)((RSDP->Signature >> 24) & 0xFF) != ' ') || + ((CHAR8)((RSDP->Signature >> 32) & 0xFF) != 'P') || + ((CHAR8)((RSDP->Signature >> 40) & 0xFF) != 'T') || + ((CHAR8)((RSDP->Signature >> 48) & 0xFF) != 'R') || + ((CHAR8)((RSDP->Signature >> 56) & 0xFF) != ' ')) { + Print(L"Error! RSDP signature is not valid!\n"); + return EFI_SUCCESS; +} + +Print(L"System description tables:\n"); +Print(L"\tRSDT table is placed at address %p\n", RSDP->RsdtAddress); +Print(L"\tXSDT table is placed at address %p\n", RSDP->XsdtAddress); +Print(L"\n"); +``` + +In the same file (https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi63.h) you can find description for XSDT structure: +``` +// +// Extended System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers. +// +``` + +The definition for `EFI_ACPI_DESCRIPTION_HEADER` can be found here https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi10.h: +``` +#pragma pack(1) +/// +/// 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; +#pragma pack() +``` + +Let's check information about other ACPI tables that are present in the system: +``` +EFI_ACPI_DESCRIPTION_HEADER* XSDT = (EFI_ACPI_DESCRIPTION_HEADER*)RSDP->XsdtAddress; +if (((CHAR8)((XSDT->Signature >> 0) & 0xFF) != 'X') || + ((CHAR8)((XSDT->Signature >> 8) & 0xFF) != 'S') || + ((CHAR8)((XSDT->Signature >> 16) & 0xFF) != 'D') || + ((CHAR8)((XSDT->Signature >> 24) & 0xFF) != 'T')) { + Print(L"Error! XSDT signature is not valid!\n"); + return EFI_SUCCESS; +} + +Print(L"Main ACPI tables:\n"); +UINT64 offset = sizeof(EFI_ACPI_DESCRIPTION_HEADER); +while (offset < XSDT->Length) { + UINT64* table_address = (UINT64*)((UINT8*)XSDT + offset); + EFI_ACPI_6_3_COMMON_HEADER* table = (EFI_ACPI_6_3_COMMON_HEADER*)(*table_address); + TableName[0] = (CHAR16)((table->Signature>> 0)&0xFF); + TableName[1] = (CHAR16)((table->Signature>> 8)&0xFF); + TableName[2] = (CHAR16)((table->Signature>>16)&0xFF); + TableName[3] = (CHAR16)((table->Signature>>24)&0xFF); + TableName[4] = 0; + + Print(L"\t%s table is placed at address %p with length 0x%x\n", + TableName, + table, + table->Length); + offset += sizeof(UINT64); +} +``` + +If you build our app and execute it under OVMF now you would get: +``` +FS0:\> AcpiInfo.efi +RSDP table is placed at 7B7E014 + +System description tables: + RSDT table is placed at address 7B7D074 + XSDT table is placed at address 7B7D0E8 + +Main ACPI tables: + FACP table is placed at address 7B7A000 with length 0x74 + APIC table is placed at address 7B79000 with length 0x78 + HPET table is placed at address 7B78000 with length 0x38 + BGRT table is placed at address 7B77000 with length 0x38 +``` + +Pretty neat, our system has 4 ACPI data tables: +- Fixed ACPI Description Table (`FACP`) - https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#fixed-acpi-description-table-fadt +- Multiple APIC Description Table (`MADT`) - https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt +- IA-PC High Precision Event Timer Table (`HPET`) - http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf - This one is not present in ACPI spec, but in a separate document from the page https://uefi.org/acpi +- Boot Graphics Resource Table (`BGRT`) - https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#boot-graphics-resource-table-bgrt + + +Keep in mind that as with SMBIOS tables we could use a protocol to get the same data. `GetAcpiTable()` function of a `EFI_ACPI_SDT_PROTOCOL` can help to get the same information. This protocol also is defined by UEFI PI specification. + +In edk2 it is defined under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/AcpiSystemDescriptionTable.h + +# Use `EFI_SHELL_PROTOCOL` to save table data + +Now let's try to save ACPI tables from memory to files. + +To do this we can utilize `EFI_SHELL_PROTOCOL` that is defined in UEFI Shell specification (https://uefi.org/sites/default/files/resources/UEFI_Shell_2_2.pdf). It has many functions for File I/O. + +The necessary header in edk2 is https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Shell.h +``` +typedef struct _EFI_SHELL_PROTOCOL { + EFI_SHELL_EXECUTE Execute; + EFI_SHELL_GET_ENV GetEnv; + EFI_SHELL_SET_ENV SetEnv; + EFI_SHELL_GET_ALIAS GetAlias; + EFI_SHELL_SET_ALIAS SetAlias; + EFI_SHELL_GET_HELP_TEXT GetHelpText; + EFI_SHELL_GET_DEVICE_PATH_FROM_MAP GetDevicePathFromMap; + EFI_SHELL_GET_MAP_FROM_DEVICE_PATH GetMapFromDevicePath; + EFI_SHELL_GET_DEVICE_PATH_FROM_FILE_PATH GetDevicePathFromFilePath; + EFI_SHELL_GET_FILE_PATH_FROM_DEVICE_PATH GetFilePathFromDevicePath; + EFI_SHELL_SET_MAP SetMap; + EFI_SHELL_GET_CUR_DIR GetCurDir; + EFI_SHELL_SET_CUR_DIR SetCurDir; + EFI_SHELL_OPEN_FILE_LIST OpenFileList; + EFI_SHELL_FREE_FILE_LIST FreeFileList; + EFI_SHELL_REMOVE_DUP_IN_FILE_LIST RemoveDupInFileList; + EFI_SHELL_BATCH_IS_ACTIVE BatchIsActive; + EFI_SHELL_IS_ROOT_SHELL IsRootShell; + EFI_SHELL_ENABLE_PAGE_BREAK EnablePageBreak; + EFI_SHELL_DISABLE_PAGE_BREAK DisablePageBreak; + EFI_SHELL_GET_PAGE_BREAK GetPageBreak; + EFI_SHELL_GET_DEVICE_NAME GetDeviceName; + EFI_SHELL_GET_FILE_INFO GetFileInfo; + EFI_SHELL_SET_FILE_INFO SetFileInfo; + EFI_SHELL_OPEN_FILE_BY_NAME OpenFileByName; + EFI_SHELL_CLOSE_FILE CloseFile; + EFI_SHELL_CREATE_FILE CreateFile; + EFI_SHELL_READ_FILE ReadFile; + EFI_SHELL_WRITE_FILE WriteFile; + EFI_SHELL_DELETE_FILE DeleteFile; + EFI_SHELL_DELETE_FILE_BY_NAME DeleteFileByName; + EFI_SHELL_GET_FILE_POSITION GetFilePosition; + EFI_SHELL_SET_FILE_POSITION SetFilePosition; + EFI_SHELL_FLUSH_FILE FlushFile; + EFI_SHELL_FIND_FILES FindFiles; + EFI_SHELL_FIND_FILES_IN_DIR FindFilesInDir; + EFI_SHELL_GET_FILE_SIZE GetFileSize; + EFI_SHELL_OPEN_ROOT OpenRoot; + EFI_SHELL_OPEN_ROOT_BY_HANDLE OpenRootByHandle; + EFI_EVENT ExecutionBreak; + UINT32 MajorVersion; + UINT32 MinorVersion; + // Added for Shell 2.1 + EFI_SHELL_REGISTER_GUID_NAME RegisterGuidName; + EFI_SHELL_GET_GUID_NAME GetGuidName; + EFI_SHELL_GET_GUID_FROM_NAME GetGuidFromName; + EFI_SHELL_GET_ENV_EX GetEnvEx; +} EFI_SHELL_PROTOCOL; +``` + +We will use 3 functions from this protocol `OpenFileByName`/`WriteFile`/`CloseFile`: +``` +EFI_SHELL_PROTOCOL.OpenFileByName() + +Summary: +Opens a file or a directory by file name. + +Prototype: +typdef +EFI_STATUS +(EFIAPI *EFI_SHELL_OPEN_FILE_BY_NAME) ( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode + ); + +Parameters: +FileName Points to the null-terminated UCS-2 encoded file name. +FileHandle On return, points to the file handle. +OpenMode File open mode. + +Description: +This function opens the specified file in the specified OpenMode and returns a file handle. +``` +``` +EFI_SHELL_PROTOCOL.WriteFile() + +Summary: +Writes data to the file. + +Prototype: +typedef +EFI_STATUS +(EFIAPI EFI_SHELL_WRITE_FILE)( + IN SHELL_FILE_HANDLE FileHandle, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +Parameters: +FileHandle The opened file handle for writing. +BufferSize On input, size of Buffer. +Buffer The buffer in which data to write. + +Description: +This function writes the specified number of bytes to the file at the current file position. The current file position is advanced the actual number of bytes +written, which is returned in BufferSize. Partial writes only occur when there has been a data error during the write attempt (such as “volume space full”). +The file automatically grows to hold the data, if required. +``` +``` +EFI_SHELL_PROTOCOL.CloseFile() + +Summary: +Closes the file handle. + +Prototype: +typedef +EFI_STATUS +(EFIAPI *EFI_SHELL_CLOSE_FILE)( + IN SHELL_FILE_HANDLE FileHandle + ); + +Parameters: +FileHandle The file handle to be closed +Description This function closes a specified file handle. All “dirty” cached file data is flushed + to the device, and the file is closed. In all cases, the handle is closed. + +``` + +Now let's start coding. Add necessary include to our *.c file: +``` +#include +``` +And necessary protocol guid to our *.inf file: +``` +[Protocols] + gEfiShellProtocolGuid +``` + +In our program we need to acquire `EFI_SHELL_PROTOCOL`, this can be done via `LocateProtocol` function from the BootServices: +``` +EFI_SHELL_PROTOCOL* ShellProtocol; +EFI_STATUS Status = gBS->LocateProtocol( + &gEfiShellProtocolGuid, + NULL, + (VOID **)&ShellProtocol +); + +if (EFI_ERROR(Status)) { + Print(L"Can't open EFI_SHELL_PROTOCOL: %r\n", Status); + return EFI_SUCCESS; +} +``` + +Then use `EFI_SHELL_PROTOCOL` functions in our while loop to create files with ACPI table data. For every table we will create a file ".aml". We use `.aml` extension for our files because in ACPI language source files usually have *.asl/*.dsl extension (ACPI Source Language), and compiled files have *.aml extension (ACPI Machine Language): +``` +CHAR16 FileName[9] = {0}; +StrCpyS(FileName, 9, TableName); +StrCatS(FileName, 9, L".aml"); +Print(L"%s\n", FileName); +SHELL_FILE_HANDLE FileHandle; +Status = ShellProtocol->OpenFileByName(FileName, + &FileHandle, + EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ); + +if (!EFI_ERROR(Status)) { + UINTN size = table->Length; + Status = ShellProtocol->WriteFile(FileHandle, &size, (VOID*)table); + if (EFI_ERROR(Status)) { + Print(L"Error in WriteFile: %r\n", Status); + } + Status = ShellProtocol->CloseFile(FileHandle); + if (EFI_ERROR(Status)) { + Print(L"Error in CloseFile: %r\n", Status); + } +} else { + Print(L"Error in OpenFileByName: %r\n", Status); +} +``` + +To create a string with a file name we use `StrCatS` and `StrCpyS` functions. They are safe versions of string concatention/string copy functions similar to their C++ analogs `strcat_s`/`strcpy_s`. You can check out them in a library https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/SafeString.c + +With a help of `EFI_SHELL_PROTOCOL` file operation functions writing data to a file is pretty similar to standard system programming. We open handle, write data to it, and finally close handle. + +If you build our app and execute it under OVMF you would get 4 files in our `UEFI_disk` shared folder: +``` +$ ls -1 ~/UEFI_disk/*.aml +/home/kostr/UEFI_disk/apic.aml +/home/kostr/UEFI_disk/bgrt.aml +/home/kostr/UEFI_disk/facp.aml +/home/kostr/UEFI_disk/hpet.aml +``` + +You can use `iasl` compiler to disassemle ACPI table data: +``` +$ iasl -d ~/UEFI_disk/*.aml + +Intel ACPI Component Architecture +ASL+ Optimizing Compiler/Disassembler version 20190509 +Copyright (c) 2000 - 2019 Intel Corporation + +File appears to be binary: found 81 non-ASCII characters, disassembling +Binary file appears to be a valid ACPI table, disassembling +Input file /home/kostr/UEFI_disk/apic.aml, Length 0x78 (120) bytes +ACPI: APIC 0x0000000000000000 000078 (v01 BOCHS BXPCAPIC 00000001 BXPC 00000001) +Acpi Data Table [APIC] decoded +Formatted output: /home/kostr/UEFI_disk/apic.dsl - 4935 bytes +File appears to be binary: found 32 non-ASCII characters, disassembling +Binary file appears to be a valid ACPI table, disassembling +Input file /home/kostr/UEFI_disk/bgrt.aml, Length 0x38 (56) bytes +ACPI: BGRT 0x0000000000000000 000038 (v01 INTEL EDK2 00000002 01000013) +Acpi Data Table [BGRT] decoded +Formatted output: /home/kostr/UEFI_disk/bgrt.dsl - 1628 bytes +File appears to be binary: found 91 non-ASCII characters, disassembling +Binary file appears to be a valid ACPI table, disassembling +Input file /home/kostr/UEFI_disk/facp.aml, Length 0x74 (116) bytes +ACPI: FACP 0x0000000000000000 000074 (v01 BOCHS BXPCFACP 00000001 BXPC 00000001) +Acpi Data Table [FACP] decoded +Formatted output: /home/kostr/UEFI_disk/facp.dsl - 4892 bytes +File appears to be binary: found 33 non-ASCII characters, disassembling +Binary file appears to be a valid ACPI table, disassembling +Input file /home/kostr/UEFI_disk/hpet.aml, Length 0x38 (56) bytes +ACPI: HPET 0x0000000000000000 000038 (v01 BOCHS BXPCHPET 00000001 BXPC 00000001) +Acpi Data Table [HPET] decoded +Formatted output: /home/kostr/UEFI_disk/hpet.dsl - 1887 bytes +``` + +Now you have *.dsl files in the same `UEFI_disk` shared folder. + +For example here is a content for `APIC` table: +``` +$ cat ~/UEFI_disk/apic.dsl +/* + * Intel ACPI Component Architecture + * AML/ASL+ Disassembler version 20190509 (64-bit version) + * Copyright (c) 2000 - 2019 Intel Corporation + * + * Disassembly of /home/kostr/UEFI_disk/apic.aml, Sat Jul 3 00:09:16 2021 + * + * ACPI Data Table [APIC] + * + * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue + */ + +[000h 0000 4] Signature : "APIC" [Multiple APIC Description Table (MADT)] +[004h 0004 4] Table Length : 00000078 +[008h 0008 1] Revision : 01 +[009h 0009 1] Checksum : ED +[00Ah 0010 6] Oem ID : "BOCHS " +[010h 0016 8] Oem Table ID : "BXPCAPIC" +[018h 0024 4] Oem Revision : 00000001 +[01Ch 0028 4] Asl Compiler ID : "BXPC" +[020h 0032 4] Asl Compiler Revision : 00000001 + +[024h 0036 4] Local Apic Address : FEE00000 +[028h 0040 4] Flags (decoded below) : 00000001 + PC-AT Compatibility : 1 + +[02Ch 0044 1] Subtable Type : 00 [Processor Local APIC] +[02Dh 0045 1] Length : 08 +[02Eh 0046 1] Processor ID : 00 +[02Fh 0047 1] Local Apic ID : 00 +[030h 0048 4] Flags (decoded below) : 00000001 + Processor Enabled : 1 + Runtime Online Capable : 0 + +[034h 0052 1] Subtable Type : 01 [I/O APIC] +[035h 0053 1] Length : 0C +[036h 0054 1] I/O Apic ID : 00 +[037h 0055 1] Reserved : 00 +[038h 0056 4] Address : FEC00000 +[03Ch 0060 4] Interrupt : 00000000 + +[040h 0064 1] Subtable Type : 02 [Interrupt Source Override] +[041h 0065 1] Length : 0A +[042h 0066 1] Bus : 00 +[043h 0067 1] Source : 00 +[044h 0068 4] Interrupt : 00000002 +[048h 0072 2] Flags (decoded below) : 0000 + Polarity : 0 + Trigger Mode : 0 + +[04Ah 0074 1] Subtable Type : 02 [Interrupt Source Override] +[04Bh 0075 1] Length : 0A +[04Ch 0076 1] Bus : 00 +[04Dh 0077 1] Source : 05 +[04Eh 0078 4] Interrupt : 00000005 +[052h 0082 2] Flags (decoded below) : 000D + Polarity : 1 + Trigger Mode : 3 + +[054h 0084 1] Subtable Type : 02 [Interrupt Source Override] +[055h 0085 1] Length : 0A +[056h 0086 1] Bus : 00 +[057h 0087 1] Source : 09 +[058h 0088 4] Interrupt : 00000009 +[05Ch 0092 2] Flags (decoded below) : 000D + Polarity : 1 + Trigger Mode : 3 + +[05Eh 0094 1] Subtable Type : 02 [Interrupt Source Override] +[05Fh 0095 1] Length : 0A +[060h 0096 1] Bus : 00 +[061h 0097 1] Source : 0A +[062h 0098 4] Interrupt : 0000000A +[066h 0102 2] Flags (decoded below) : 000D + Polarity : 1 + Trigger Mode : 3 + +[068h 0104 1] Subtable Type : 02 [Interrupt Source Override] +[069h 0105 1] Length : 0A +[06Ah 0106 1] Bus : 00 +[06Bh 0107 1] Source : 0B +[06Ch 0108 4] Interrupt : 0000000B +[070h 0112 2] Flags (decoded below) : 000D + Polarity : 1 + Trigger Mode : 3 + +[072h 0114 1] Subtable Type : 04 [Local APIC NMI] +[073h 0115 1] Length : 06 +[074h 0116 1] Processor ID : FF +[075h 0117 2] Flags (decoded below) : 0000 + Polarity : 0 + Trigger Mode : 0 +[077h 0119 1] Interrupt Input LINT : 01 + +Raw Table Data: Length 120 (0x78) + + 0000: 41 50 49 43 78 00 00 00 01 ED 42 4F 43 48 53 20 // APICx.....BOCHS + 0010: 42 58 50 43 41 50 49 43 01 00 00 00 42 58 50 43 // BXPCAPIC....BXPC + 0020: 01 00 00 00 00 00 E0 FE 01 00 00 00 00 08 00 00 // ................ + 0030: 01 00 00 00 01 0C 00 00 00 00 C0 FE 00 00 00 00 // ................ + 0040: 02 0A 00 00 02 00 00 00 00 00 02 0A 00 05 05 00 // ................ + 0050: 00 00 0D 00 02 0A 00 09 09 00 00 00 0D 00 02 0A // ................ + 0060: 00 0A 0A 00 00 00 0D 00 02 0A 00 0B 0B 00 00 00 // ................ + 0070: 0D 00 04 06 FF 00 00 01 // ........ +``` + + diff --git a/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c new file mode 100644 index 0000000..0511f59 --- /dev/null +++ b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c @@ -0,0 +1,106 @@ +#include +#include + +#include +#include + +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_SHELL_PROTOCOL* ShellProtocol; + EFI_STATUS Status = gBS->LocateProtocol( + &gEfiShellProtocolGuid, + NULL, + (VOID **)&ShellProtocol + ); + + if (EFI_ERROR(Status)) { + Print(L"Can't open EFI_SHELL_PROTOCOL: %r\n", Status); + return EFI_SUCCESS; + } + + EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER* RSDP = NULL; + + for (UINTN i=0; iNumberOfTableEntries; i++) { + if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) { + Print(L"RSDP table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable); + RSDP = SystemTable->ConfigurationTable[i].VendorTable; + } + } + + if (!RSDP) { + Print(L"No ACPI2.0 table was found in the system\n"); + return EFI_SUCCESS; + } + + if (((CHAR8)((RSDP->Signature >> 0) & 0xFF) != 'R') || + ((CHAR8)((RSDP->Signature >> 8) & 0xFF) != 'S') || + ((CHAR8)((RSDP->Signature >> 16) & 0xFF) != 'D') || + ((CHAR8)((RSDP->Signature >> 24) & 0xFF) != ' ') || + ((CHAR8)((RSDP->Signature >> 32) & 0xFF) != 'P') || + ((CHAR8)((RSDP->Signature >> 40) & 0xFF) != 'T') || + ((CHAR8)((RSDP->Signature >> 48) & 0xFF) != 'R') || + ((CHAR8)((RSDP->Signature >> 56) & 0xFF) != ' ')) { + Print(L"Error! RSDP signature is not valid!\n"); + return EFI_SUCCESS; + } + + Print(L"System description tables:\n"); + Print(L"\tRSDT table is placed at address %p\n", RSDP->RsdtAddress); + Print(L"\tXSDT table is placed at address %p\n", RSDP->XsdtAddress); + Print(L"\n"); + + EFI_ACPI_DESCRIPTION_HEADER* XSDT = (EFI_ACPI_DESCRIPTION_HEADER*)RSDP->XsdtAddress; + if (((CHAR8)((XSDT->Signature >> 0) & 0xFF) != 'X') || + ((CHAR8)((XSDT->Signature >> 8) & 0xFF) != 'S') || + ((CHAR8)((XSDT->Signature >> 16) & 0xFF) != 'D') || + ((CHAR8)((XSDT->Signature >> 24) & 0xFF) != 'T')) { + Print(L"Error! XSDT signature is not valid!\n"); + return EFI_SUCCESS; + } + + Print(L"Main ACPI tables:\n"); + UINT64 offset = sizeof(EFI_ACPI_DESCRIPTION_HEADER); + while (offset < XSDT->Length) { + UINT64* table_address = (UINT64*)((UINT8*)XSDT + offset); + EFI_ACPI_6_3_COMMON_HEADER* table = (EFI_ACPI_6_3_COMMON_HEADER*)(*table_address); + CHAR16 TableName[5]; + TableName[0] = (CHAR16)((table->Signature>> 0)&0xFF); + TableName[1] = (CHAR16)((table->Signature>> 8)&0xFF); + TableName[2] = (CHAR16)((table->Signature>>16)&0xFF); + TableName[3] = (CHAR16)((table->Signature>>24)&0xFF); + TableName[4] = 0; + + Print(L"\t%s table is placed at address %p with length 0x%x\n", + TableName, + table, + table->Length); + CHAR16 FileName[9] = {0}; + StrCpyS(FileName, 9, TableName); + StrCatS(FileName, 9, L".aml"); + SHELL_FILE_HANDLE FileHandle; + Status = ShellProtocol->OpenFileByName(FileName, + &FileHandle, + EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ); + if (!EFI_ERROR(Status)) { + UINTN size = table->Length; + Status = ShellProtocol->WriteFile(FileHandle, &size, (VOID*)table); + if (EFI_ERROR(Status)) { + Print(L"Error in WriteFile: %r\n", Status); + } + Status = ShellProtocol->CloseFile(FileHandle); + if (EFI_ERROR(Status)) { + Print(L"Error in CloseFile: %r\n", Status); + } + } else { + Print(L"Error in OpenFileByName: %r\n", Status); + } + offset += sizeof(UINT64); + } + + return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf new file mode 100644 index 0000000..53d0356 --- /dev/null +++ b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf @@ -0,0 +1,24 @@ +[Defines] + INF_VERSION = 1.25 + BASE_NAME = AcpiInfo + FILE_GUID = 18998798-69a2-4ab5-9ffc-a8ee2494b029 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + AcpiInfo.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + +[Guids] + gEfiAcpi20TableGuid + +[Protocols] + gEfiShellProtocolGuid + -- cgit v1.2.3-18-g5258