UEFI 学习3.6 - ARM QEMU上的ACPI表

如果对ACPI概念不熟悉,可以先参考这篇【UEFI基础】ACPI基础
解析代码github地址: TestPkg

ACPI 表结构

ACPI的第一张表示RSDP(Root System Description Pointer),它里面存放了R(X)DST的地址。RDST是32位地址,XDST是64位地址,其功能是一样的。后面用的是AARCH64架构,所以用的64位地址的XDST。
在这里插入图片描述
根据RSDP找到XDST后,就可以根据XDST找出一个个表项Entry,每一个Entry记录了对应表的地址。表项的类型有很多,这里可以参考ACPI 6.3 SPEC。并且Entry的类型会随着ACPI版本增加或者改动。
注意XDST第一个Entry一定是FADT。
这里只以QEMU AARCH64上用到的类型举例。QEMU上一共有8张表如下:

  • FADT (Fixed ACPI Description Table) ,主要放了一些硬件信息和DSDT的地址。
  • MADT(Multiple APIC Description Table ),描述了中断硬件相关的信息。
  • PPTT(Processor Properties Topology Table), 描述了CPU相关的信息。
  • MCFG(PCI Express memory mapped configuration space base address Description Table) PCIE内存空间先关的地址。
  • GTDT(Generic Timer Description Table), 描述了timer相关的信息。
  • SPCR(Serial Port Console Redirection Table), 描述了串口相关的信息。
  • DBG2(Debug Port Table), 描述了Debug口相关信息。
  • IORT(I/O Remapping Table), 描述了IO Remap相关信息。
    因此,在QEMU上XSDT的布局如下。Header下面就放了8个表的地址。
    AARCH64 QEMU XSDT
    FADT中包含了一些硬件相关的信息BLKs和DSDT的地址。而DSDT中包含许多硬件的定义块,定义块描述了硬件的静态和动态信息。 在这里插入图片描述

RSDP

首先来看RSDP的定义。

MdePkg/Include/IndustryStandard/Acpi63.h

typedef struct {
  UINT64    Signature;				--> 签名为"RSD PTR "
  UINT8     Checksum;				--> 此校验和仅包含此表的前20个字节,即从019,并且包含此字段本身。前20个字节的总和必须是零
  UINT8     OemId[6];				--> OEM ID字符串
  UINT8     Revision;				--> 版本号
  UINT32    RsdtAddress;			--> 32位RSDT地址
  UINT32    Length;					--> RSDP表长度
  UINT64    XsdtAddress;			--> 64位XSDT地址
  UINT8     ExtendedChecksum;		--> 这是整个表的校验和,包含两个校验和字段
  UINT8     Reserved[3];
} EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER;

RSDP存放在UEFI的configuration table中,它的guid是gEfiAcpi20TableGuid。
我们可以用如下代码来查找到RSDP的地址,原理很简单,就是遍历UEFI的configuration table,如果GUID是ACPI表,就把它拿出来。找到configuration table的VendorTable字段,它就是RSDP地址

TestPkg/TestDxeAcpi.c

EFIAPI
EFI_STATUS 
TestDxeDumpAcpi()
{
    UINTN i, j = 0, EntryCount;
    UINT8 Temp = 0;
    EFI_CONFIGURATION_TABLE *configTab = NULL;
    EFI_ACPI_DESCRIPTION_HEADER           *XSDT, *Entry, *DSDT;
    UINT64 *EntryPtr;
    EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE   *FADT;

    EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER  *Root;

    DEBUG((DEBUG_INFO, "Dump ACPI\n"));

    configTab = gST->ConfigurationTable;
    //遍历系统配置表
    for(i=0; i<gST->NumberOfTableEntries;i++)
    {
        if ((CompareGuid(&configTab->VendorGuid, &gEfiAcpiTableGuid) == TRUE) ||
        (CompareGuid(&configTab->VendorGuid, &gEfiAcpi20TableGuid) == TRUE))
        {	
            //如果是ACPI表就拿出它的地址
            DEBUG((DEBUG_INFO, "Found ACPI table\n")); 
            DEBUG((DEBUG_INFO, "Address: @[0x%p]\n",configTab));

            Root = configTab->VendorTable;								-->找到RSDP
            //打印RSDP相关字段
            DEBUG((DEBUG_INFO, "RSDP @[0x%p]\n", Root));
            DEBUG((DEBUG_INFO, "  Signature:"));
            for(j = 0; j < 8; j++) {
                Temp = (Root->Signature >> (j * 8)) & 0xff;
                DEBUG((DEBUG_INFO, "%c", Temp));
            }
            DEBUG((DEBUG_INFO, "\n"));
        
            DEBUG((DEBUG_INFO, "  Revision:%d\n", Root->Revision));
        
            DEBUG((DEBUG_INFO, "  OEM_ID:"));
            for (j = 0; j < 6; j++) {
                DEBUG((DEBUG_INFO, "%c", Root->OemId[j]));
            }
            DEBUG((DEBUG_INFO, "\n"));

            DEBUG((DEBUG_INFO, "  Length=[0x%x]\n", Root->Length));
            DEBUG((DEBUG_INFO, "  XSDT address=[0x%p]\n", Root->XsdtAddress));
            DEBUG((DEBUG_INFO, "  RSDT address=[0x%p]\n", Root->RsdtAddress));
            ...
 }
Dump ACPI
Found ACPI table
Address: @[0x43FDFBD8]
RSDP @[0x405C0018]
  Signature:RSD PTR					--> Singautre符合RSD PTR
  Revision:2
  OEM_ID:BOCHS
  Length=[0x24]						-->长度就是EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER的长度
  XSDT address=[0x405CFE98]			-->使用的是XSDT
  RSDT address=[0x0]				-->RSDT不存在

XSDT

在这里插入图片描述
XSDT没有专有的结构体定义,它只有APCI Header,然后更着一串Entry地址。XSDT的Header定义如下。后面其他的表也是用这个Header,它是一个ACPI通用的描述头。
MdePkg/Include/IndustryStandard/Acpi10.h

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;

当找到XSDT后,可以遍历它后面的Entry地址,然后找到对应的Entry
TestPkg/TestDxeAcpi.c

            if (Root->Revision >= EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
                //从RSDP中拿到XSDT的地址
                XSDT = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Root->XsdtAddress;
                //计算有多少个Entry,这里有8个Entry
                EntryCount = (XSDT->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) 
                      / sizeof(UINT64);
                DEBUG((DEBUG_INFO, "  XSDT @[0x%p]\n", XSDT));
                //打印XSDT的签名应该就是字符串"XSDT"
                DEBUG((DEBUG_INFO, "    Signature:"));
                for(j = 0; j < 4; j++) {
                    Temp = (XSDT->Signature >> (j * 8)) & 0xff;
                    DEBUG((DEBUG_INFO, "%c", Temp));
                }
                DEBUG((DEBUG_INFO, "\n"));
          
                DEBUG((DEBUG_INFO, "    Length=[%d]\n", XSDT->Length));
                DEBUG((DEBUG_INFO, "    Entry Count=[%d]\n", EntryCount));
                DEBUG((DEBUG_INFO, "    OEM_ID:"));
                for (j = 0; j < 6; j++) {
                    DEBUG((DEBUG_INFO, "%c", Root->OemId[j]));
                }
                DEBUG((DEBUG_INFO, "\n"));
        
                EntryPtr=(UINT64 *)(XSDT+1);
                //遍历XSDT中的Entry,把Entry的签名打印出来
                for (j = 0; j < EntryCount; j++, EntryPtr++) {
           
                    Entry = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
                    if (Entry == NULL) {
                    continue;
                    }
                    DEBUG((DEBUG_INFO, "    Signature:"));
                    for(j = 0; j < 4; j++) {
                    Temp = (Entry->Signature >> (j * 8)) & 0xff;
                    DEBUG((DEBUG_INFO, "%c", Temp));
                    }
                    DEBUG((DEBUG_INFO, "\n"));
                }
            }

可以看到最后的打印如下

  XSDT @[0x405CFE98]
    Signature:XSDT				--> 签名是"XSDT"
    Length=[100]				--> 长度为100 = 表头长度36 + 表项Entry长度64
    Entry Count=[8]				--> Entry Count = 8 = 64 / 8
    OEM_ID:BOCHS				--> OEM ID和RSDP一样都是BOCHS
    Signature:FACP				--> 第一张表FADT的签名"FACP"
    Signature:APIC				--> 第二张表MADT的签名"APIC"
	Signature:PPTT				--> .
	Signature:GTDT 					.
	Signature:MCFG					.
    Signature:SPCR					.
    Signature:DBG2				--> .
    Signature:IORT				--> 最后一张表的签名"IORT"

FADT

FADT的定义很长, 如下
MdePkg/Include/IndustryStandard/Acpi63.h

typedef struct {
  EFI_ACPI_DESCRIPTION_HEADER               Header;					--> 通用Header
  UINT32                                    FirmwareCtrl;			--> FACS的地址, OSPM和固件利用此字段交换控制信息。
  UINT32                                    Dsdt;					--> DSDT的地址
  UINT8                                     Reserved0;
  
  ----------------------
  *电源管理类型
  *0 - Unspecified
  *1 - Desktp
  *2 - Mobile
  *3 - Wokrstation
  *4 - Enterprise Server
  *5 - SOHO Server
  *6 - Applicance PC
  *7 - Performance Server
  *8 - Tablet
  *>8 Reserved
  -----------------------
  UINT8                                     PreferredPmProfile;
  
  -->8259模式下SCI中断绑定的系统向量。在不包含8269的系统中,此字段包含SCI中断的全局系统中断号。
  -->OSPM需要把ACPI SCI中断看成是可共享、电平触发、低有效的中断。
  UINT16                                    SciInt;	
  UINT32                                    SmiCmd;				--> SMI命令所在的端口
  UINT8                                     AcpiEnable;			--> 将此值写到SMI_CMD来重新使能ACPI硬件寄存器SMI所有权。在不支持遗留模式的系统中,此字段被保留。
  UINT8                                     AcpiDisable;		--> 将此值写到SMI_CMD来重新使屏蔽ACPI硬件寄存器SMI所有权。在不支持遗留模式的系统中,此字段被保留。
  UINT8                                     S4BiosReq;			--> 为了进入S4BIOS状态需要将此值写到SM1_CMD中。
  UINT8                                     PstateCnt;			--> 如果此字段值为非零,那么OPSM将此值写到SM1_CMD寄存器后会承担处理器性能状态控制责任
  UINT32                                    Pm1aEvtBlk;			--> PM1a事件寄存器块的系统端口地址
  UINT32                                    Pm1bEvtBlk;			--> PM1b事件寄存器块的系统端口地址
  UINT32                                    Pm1aCntBlk;			--> PM1a控制寄存器块的系统端口地址
  UINT32                                    Pm1bCntBlk;			--> PM1b控制寄存器块的系统端口地址
  UINT32                                    Pm2CntBlk;			--> PM2事件寄存器块的系统端口地址
  UINT32                                    PmTmrBlk;			--> 电源管理定时器控制寄存器的系统端口地址
  UINT32                                    Gpe0Blk;			--> 通用目的事件0寄存器块的系统端口地址
  UINT32                                    Gpe1Blk;			--> 通用目的事件1寄存器块的系统端口地址
  UINT8                                     Pm1EvtLen;			--> 由PM1a_EVT_BLK和PM1b_EVT_BLK解码的字节数
  UINT8                                     Pm1CntLen;			--> 由PM1a_CNT_BLK和PM1b_CNT_BLK解码的字节数
  UINT8                                     Pm2CntLen;			--> 由PM2_CNT_BLK解码的字节数
  UINT8                                     PmTmrLen;			--> 由PM_TMR_BLK解码的字节数
  UINT8                                     Gpe0BlkLen;			--> 由GEP0_BLK解码的字节数
  UINT8                                     Gpe1BlkLen;			--> 由GPE1_BLK解码的字节数
  UINT8                                     Gpe1Base;			--> 在ACPI通用的事件模型中GPE1事件开始处的偏移
  UINT8                                     CstCnt;				--> OSPM将此值写到SMI_CMD寄存器向OS表明对_CST对象和C状态改变通知的支持
  UINT16                                    PLvl2Lat;			--> 进入和退出C2状态的最长硬件延时
  UINT16                                    PLvl3Lat;			--> 进入和退出C3状态的最长硬件延时
  UINT16                                    FlushSize;			--> 缓存刷新步幅大小
  UINT16                                    FlushStride;		--> 处理器内存缓存的缓存行宽度
  UINT8                                     DutyOffset;			--> 在处理器的P_CNT寄存器中,表示处理器职守周期所在位置基于零的索引
  UINT8                                     DutyWidth;
  UINT8                                     DayAlrm;			--> 日期警告值所在对应的RTC_CMOS_RAM索引。
  UINT8                                     MonAlrm;			--> 月份警告值所在对应的RTC_CMOS_RAM索引。
  UINT8                                     Century;			--> 日期世纪值所对应的RTC_CMOS_RAM索引。
  UINT16                                    IaPcBootArch;		--> IA-PC启动架构标志
  UINT8                                     Reserved1;
  UINT32                                    Flags;				--> 固定特征标志
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    ResetReg;			--> 重置寄存器的地址
  UINT8                                     ResetValue;			--> 为了重启系统,此值被写到RESET_REG端口
  UINT16                                    ArmBootArch;		--> ARM架构启动标志
  UINT8                                     MinorVersion;		--> 此版本号
  UINT64                                    XFirmwareCtrl;		--> EACS的64位物理地址
  UINT64                                    XDsdt;				--> DSDT的64位物理地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XPm1aEvtBlk;		--> PM1a 事件寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XPm1bEvtBlk;		--> PM1b 事件寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XPm1aCntBlk;		--> PM1a 控制寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XPm1bCntBlk;		--> PM1b 控制寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XPm2CntBlk;			--> PM2 控制寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XPmTmrBlk;			--> PM TMR 寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XGpe0Blk;			--> GEP0 寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    XGpe1Blk;			--> GEP1 寄存器块的扩展地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    SleepControlReg;	--> 睡眠控制寄存器的地址
  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE    SleepStatusReg;		--> 睡眠状态寄存器的地址
  UINT64                                    HypervisorVendorIdentity; --> Hypevisor ID
} EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE;

解析FADT代码, 就是根据表的定义解析其结构并打印
TestPkg/TestDxeAcpi.c

                 switch (Entry->Signature) {
                        case EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:

                            FADT = (EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *)(UINTN) Entry;
                            DumpFADT(FADT);
                            DSDT = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(FADT->Dsdt);
VOID
DumpFADT(EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *FADT)
{
    char *PMProfiles[] = {
        "Unspecified",
        "Desktop",
        "Mobile",
        "WorkStation",
        "Enterprise Server",
        "SOHO Server",
        "Applicance PC",
        "Performance Server",
        "Tablet"
    };

    DEBUG((DEBUG_INFO, "\n#########Start Dump FADT##########\n"));

    DumpACPIHeader(&FADT->Header);

    DEBUG((DEBUG_INFO, "FACS:0x%x\n", FADT->FirmwareCtrl));
    DEBUG((DEBUG_INFO, "Dsdt:0x%x\n", FADT->Dsdt));
    DEBUG((DEBUG_INFO, "", FADT->PreferredPmProfile));

    if (FADT->PreferredPmProfile > 8) {
        DEBUG((DEBUG_INFO, "PreferredPmProfile: Reserved\n"));
    } else {
        DEBUG((DEBUG_INFO, "PreferredPmProfile: %a\n", PMProfiles[FADT->PreferredPmProfile]));
    }

    DEBUG((DEBUG_INFO, "SCI INT:0x%04x\n", FADT->SciInt));
    DEBUG((DEBUG_INFO, "SMI CMD:0x%08x\n", FADT->SmiCmd));
    DEBUG((DEBUG_INFO, "ACPI ENABLE:0x%02x\n", FADT->AcpiEnable));
    DEBUG((DEBUG_INFO, "ACPI DISABLE:0x%02x\n", FADT->AcpiDisable));
    DEBUG((DEBUG_INFO, "S4BIOS REQ:0x%02x\n", FADT->S4BiosReq));
    DEBUG((DEBUG_INFO, "PSTATE CNT:0x%02x\n", FADT->PstateCnt));
    DEBUG((DEBUG_INFO, "PM1a EVT BLK:0x%08x\n", FADT->Pm1aEvtBlk));
    DEBUG((DEBUG_INFO, "PM1b EVT BLK:0x%08x\n", FADT->Pm1bEvtBlk));
    DEBUG((DEBUG_INFO, "PM1a CNT BLK:0x%08x\n", FADT->Pm1aCntBlk));
    DEBUG((DEBUG_INFO, "PM1b CNT BLK:0x%08x\n", FADT->Pm1bCntBlk));
    DEBUG((DEBUG_INFO, "PM TMR BLK:0x%08x\n", FADT->PmTmrBlk));
    DEBUG((DEBUG_INFO, "GPE0 BLK:0x%08x\n", FADT->Gpe0Blk));
    DEBUG((DEBUG_INFO, "GPE1 BLK:0x%08x\n", FADT->Gpe1Blk));
    DEBUG((DEBUG_INFO, "PM1 EVT LEN:0x%02x\n", FADT->Pm1EvtLen));
    DEBUG((DEBUG_INFO, "PM1 CNT LEN:0x%02x\n", FADT->Pm1CntLen));
    DEBUG((DEBUG_INFO, "PM2 CNT LEN:0x%02x\n", FADT->Pm2CntLen));
    DEBUG((DEBUG_INFO, "PM TMR LEN:0x%02x\n", FADT->PmTmrLen));
    DEBUG((DEBUG_INFO, "GPE0 BLK LEN:0x%02x\n", FADT->Gpe0BlkLen));
    DEBUG((DEBUG_INFO, "GPE1 BLK LEN:0x%02x\n", FADT->Gpe1BlkLen));
    DEBUG((DEBUG_INFO, "GPE1 BASE:0x%02x\n", FADT->Gpe1Base));
    DEBUG((DEBUG_INFO, "CST CNT:0x%02x\n", FADT->CstCnt));
    DEBUG((DEBUG_INFO, "P LVL2 LAT:0x%04x\n", FADT->PLvl2Lat));
    DEBUG((DEBUG_INFO, "P LVL3 LAT:0x%04x\n", FADT->PLvl3Lat));
    DEBUG((DEBUG_INFO, "Flush Size:0x%04x\n", FADT->FlushSize));
    DEBUG((DEBUG_INFO, "FLUSH STRIDE:0x%04x\n", FADT->FlushStride));
    DEBUG((DEBUG_INFO, "DUTY OFFSET:0x%02x\n", FADT->DutyOffset));
    DEBUG((DEBUG_INFO, "DUTY WIDTH:0x%02x\n", FADT->DutyWidth));
    DEBUG((DEBUG_INFO, "DAY ALARM:0x%02x\n", FADT->DayAlrm));
    DEBUG((DEBUG_INFO, "MON ALARM:0x%02x\n", FADT->MonAlrm));
    DEBUG((DEBUG_INFO, "CENTURY:0x%02x\n", FADT->Century));
    DEBUG((DEBUG_INFO, "IAPC_BOOT_ARCH:0x%04x\n", FADT->IaPcBootArch));
    DEBUG((DEBUG_INFO, "Flags:0x%08x\n", FADT->Flags));
    DumpGenericAddress("Reset Reg", &FADT->ResetReg);
    DEBUG((DEBUG_INFO, "Reset Value:0x%02x\n", FADT->ResetValue));
    DEBUG((DEBUG_INFO, "ARM BOOT ARCH:0x%04x\n", FADT->ArmBootArch));
    DEBUG((DEBUG_INFO, "FADT MINOR VERSION:0x%02x\n", FADT->MinorVersion));
    DEBUG((DEBUG_INFO, "X FIRMWARE CTRL:0x%p", FADT->XFirmwareCtrl));
    DEBUG((DEBUG_INFO, "X DSDT:0x%p\n", FADT->XDsdt));
    DumpGenericAddress("X PM1a EVT BLK", &FADT->XPm1aEvtBlk);
    DumpGenericAddress("X PM1b EVT BLK", &FADT->XPm1bEvtBlk);
    DumpGenericAddress("X PM1a CNT BLK", &FADT->XPm1aCntBlk);
    DumpGenericAddress("X PM1b CNT BLK", &FADT->XPm1bCntBlk);
    DumpGenericAddress("X PM TMR BLK", &FADT->XPmTmrBlk);
    DumpGenericAddress("GPE0 BLK", &FADT->XGpe0Blk);
    DumpGenericAddress("GPE1 BLK", &FADT->XGpe1Blk);
    DumpGenericAddress("SLEEP CONTROL", &FADT->SleepControlReg);
    DumpGenericAddress("SLEEP STATUS", &FADT->SleepStatusReg);

    DEBUG((DEBUG_INFO, "###########End Dump FADT###########\n\n"));
}

log分析

#########Start Dump FADT##########
Signature:FACP							-->签名为"FACP"
Length:0x10C							-->长度就是FADT结构体的长度
Revision:0x05							-->下面是一些版本信息
Checksum:0x03
OemID:BOCHS 
OemTableId:0x2020202043505842			-
OemRevision:0x1
CreatorId:0x43505842
CreatorRevision:0x1
FACS:0x0								-->FACS地址为0,就是不存在
Dsdt:0x405C7518							-->DSDT的地址
PreferredPmProfile: Unspecified			-->没有指定电源管理的Profile
-->由于这里用的ARM AARCH64的结构,以下硬件在AARCH64架构上都是不存在的的, 所以下面这些硬件信息AARCH64都不需要
-->因此下面这些硬件信息都是0,实际上就是不存在。对于X86/X64架构是需要的。
SCI INT:0x0000							
SMI CMD:0x00000000
ACPI ENABLE:0x00
ACPI DISABLE:0x00
S4BIOS REQ:0x00
PSTATE CNT:0x00
PM1a EVT BLK:0x00000000
PM1b EVT BLK:0x00000000
PM1a CNT BLK:0x00000000
PM1b CNT BLK:0x00000000
PM TMR BLK:0x00000000
GPE0 BLK:0x00000000
GPE1 BLK:0x00000000
PM1 EVT LEN:0x00
PM1 CNT LEN:0x00
PM2 CNT LEN:0x00
PM TMR LEN:0x00
GPE0 BLK LEN:0x00
GPE1 BLK LEN:0x00
GPE1 BASE:0x00
CST CNT:0x00
P LVL2 LAT:0x0000
P LVL3 LAT:0x0000
Flush Size:0x0000
FLUSH STRIDE:0x0000
DUTY OFFSET:0x00
DUTY WIDTH:0x00
DAY ALARM:0x00
MON ALARM:0x00
CENTURY:0x00
IAPC_BOOT_ARCH:0x0000
Flags:0x00100000
Reset Reg: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
Reset Value:0x00
ARM BOOT ARCH:0x0003					--> ARM BOOT架构
FADT MINOR VERSION:0x01					--> 次版本号
X FIRMWARE CTRL:0x0
X DSDT:0x405C7518						--> XDSDT的地址
X PM1a EVT BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
X PM1b EVT BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
X PM1a CNT BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
X PM1b CNT BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
X PM TMR BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
GPE0 BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
GPE1 BLK: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
SLEEP CONTROL: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
SLEEP STATUS: AddressSpaceId:0x00, RegisterBitWidth:0x00, RegisterBitOffset:0x00, AccessSize:0x00, Address:0x00000000000
###########End Dump FADT###########

DSDT

上面已经根据FADT找到了DSDT的地址。然后我们可以把解析出来。之前讲过DSDT就只有一个头,然后下面放的就是一个个AML定义块。而AML定义块是以裸数据存在的,所以要dump出这个AML的数据,然后用工具解析。打印代码如下。
TestPkg/TestDxeAcpi.c

DSDT = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(FADT->Dsdt);
DEBUG((DEBUG_INFO, "\n#########Start Dump DSDT##########\n"));
UINT32 *temp = (UINT32 *)DSDT;
for (UINTN k = 0; k < DSDT->Length; k += 4) {
    DEBUG((DEBUG_INFO, "0x%08x\n", *temp++));
}
DEBUG((DEBUG_INFO, "#########End Dump DSDT##########\n\n"));
break;

在EDK2上我也没找到现成的可以把AML解析成字符串的代码,所以这边我将DSDT和AML定义块的数据以16进制打印出来,然后手动保存到一个文件dsdt.txt里,再利用脚本在ubuntu上调用iasl来解析DSDT。

0x54445344				--> DSDT的裸数据如下
0x0000144C
0x4F429F02
0x20534843
...
0x00444955

解析脚本

import os
import sys

f = open('dsdt.txt')
out = open('dsdt.dat', 'wb+')
for line in f:
    line = line.replace('\n', '')
    val = int(line, 16) 
    print(val)
    out.write(val.to_bytes(4,  byteorder='little'))

f.close()
out.close()

os.system('iasl -d dsdt.dat')

最后解析出来的dsdt.dsl如下。

/*
 * Intel ACPI Component Architecture
 * AML/ASL+ Disassembler version 20200925 (64-bit version)
 * Copyright (c) 2000 - 2020 Intel Corporation
 * 
 * Disassembling to symbolic ASL+ operators
 *
 * Disassembly of dsdt.dat, Wed May 25 09:14:56 2022
 */
 --------------->DSDT的Header
 * Original Table Header:
 *     Signature        "DSDT"
 *     Length           0x0000144C (5196)
 *     Revision         0x02
 *     Checksum         0x9F
 *     OEM ID           "BOCHS "
 *     OEM Table ID     "BXPC    "
 *     OEM Revision     0x00000001 (1)
 *     Compiler ID      "BXPC"
 *     Compiler Version 0x00000001 (1)
 *
DefinitionBlock ("", "DSDT", 2, "BOCHS ", "BXPC    ", 0x00000001)
{
    Scope (\_SB)
    {
    	// CPU Device的信息
        Device (C000)
        {
            Name (_HID, "ACPI0007" /* Processor Device */)  // _HID: Hardware ID
            Name (_UID, Zero)  // _UID: Unique ID
        }
		//串口的信息
        Device (COM0)
        {
            Name (_HID, "ARMH0011") ARMH0011代表ARM PL011 IP // _HID: Hardware ID 
            Name (_UID, Zero)  // _UID: Unique ID
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                Memory32Fixed (ReadWrite,
                    0x09000000,         // 串口寄存器的起始地址
                    0x00001000,         // 串口寄存器的长度
                    )
                //中断相关信息。
                Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, )
                {
                    0x00000021,
                }
            })
        }
		// FW CFG的信息
        Device (FWCF)
        {
            Name (_HID, "QEMU0002") QEMU0002代表QMEU FW CFG设备 // _HID: Hardware ID 
            Name (_STA, 0x0B)  // _STA: Status
            Name (_CCA, One)  // _CCA: Cache Coherency Attribute
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                Memory32Fixed (ReadWrite,
                    0x09020000,         // FW CFG 的起始地址
                    0x00000018,         // FW CFG 的长度
                    )
            })
        }
		// 下面一堆VIRT IO的信息,这里只留下头和尾巴, 都是一样的重复的东西
        Device (VR00)
        {
            Name (_HID, "LNRO0005")  // _HID: Hardware ID
            Name (_UID, Zero)  // _UID: Unique ID
            Name (_CCA, One)  // _CCA: Cache Coherency Attribute
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                Memory32Fixed (ReadWrite,
                    0x0A000000,         // VIRT IO0 的起始地址
                    0x00000200,         // VIRT IO0 的长度
                    )
                Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, )
                {
                    0x00000030,
                }
            })
        }

 		...
        Device (VR31)
        {
			...
        }
		//PCI0的信息 不是很了解QEMU上PCI的用法,这里就不解释了
        Device (PCI0)
        {
            Name (_HID, "PNP0A08" /* PCI Express Bus */)  // _HID: Hardware ID
            Name (_CID, "PNP0A03" /* PCI Bus */)  // _CID: Compatible ID
            Name (_SEG, Zero)  // _SEG: PCI Segment
            Name (_BBN, Zero)  // _BBN: BIOS Bus Number
            Name (_UID, Zero)  // _UID: Unique ID
            Name (_STR, Unicode ("PCIe 0 Device"))  // _STR: Description String
            Name (_CCA, One)  // _CCA: Cache Coherency Attribute
            Name (_PRT, Package (0x80)  // _PRT: PCI Routing Table
            {
                Package (0x04)
                {
                    0xFFFF, 
                    Zero, 
                    GSI0, 
                    Zero
                }, 
				...
                Package (0x04)
                {
                    0x001FFFFF, 
                    One, 
                    GSI0, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x001FFFFF, 
                    0x02, 
                    GSI1, 
                    Zero
                }, 

                Package (0x04)
                {
                    0x001FFFFF, 
                    0x03, 
                    GSI2, 
                    Zero
                }
            })
			...
        }
		// 描述Generic Evenet Device的信息
        Device (\_SB.GED)
        {
            Name (_HID, "ACPI0013" /* Generic Event Device */)  // _HID: Hardware ID
            Name (_UID, "GED")  // _UID: Unique ID
            Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
            {
                //中断信息
                Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
                {
                    0x00000029,
                }
            })
            //寄存器地址和长度
            OperationRegion (EREG, SystemMemory, 0x09080000, 0x04)
            //32位寄存器定义
            Field (EREG, DWordAcc, NoLock, WriteAsZeros)
            {
                ESEL,   32
            }
			//操作的方法
            Method (_EVT, 1, Serialized)  // _EVT: Event
            {
                Local0 = ESEL /* \_SB_.GED_.ESEL */
                If (((Local0 & 0x02) == 0x02))
                {
                    Notify (PWRB, 0x80) // Status Change
                }
            }
        }
		//按键的信息
        Device (PWRB)
        {
            Name (_HID, "PNP0C0C" /* Power Button Device */)  // _HID: Hardware ID
            Name (_UID, Zero)  // _UID: Unique ID
        }
    }
}

MADT

MADT用于描述中断硬件信息。
MdePkg/Include/IndustryStandard/Acpi63.h

typedef struct {
  EFI_ACPI_DESCRIPTION_HEADER    Header;				--> ACPI Header
  UINT32                         LocalApicAddress;		--> 处理器本地中断处理器所在的地址
  UINT32                         Flags;					--> 标志位。
} EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER;

在MADT(EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER)的后面紧跟着的是一系列的中断控制器结构体,它的大小不是恒定的,需要动态解析出来。下面的代码可以解析MADT的信息。

switch (Entry->Signature) {
...
case EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
    DumpMADT((EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)Entry);
    break;
...

DumpMADT首先解析出Header中的信息,然后遍历中断控制器结构体,分别解析对应的中断硬件信息。AARCH64上只有GIC,GICD和GIC MSI。所以只实现dump了这三种中断控制器。
TestPkg/TestDxeAcpi.c

VOID
DumpMADT(
    IN EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MADT
)
{
    UINT8 *TempPtr; 
    UINT8 Type, Length;
    UINTN Len = 0;
    DEBUG((DEBUG_INFO, "\n###########Start Dump MADT###########\n"));
    DumpACPIHeader(&MADT->Header);							//解析ACPI 头
    DEBUG((DEBUG_INFO, "Local APIC Address:0x%08x\n", MADT->LocalApicAddress));
    DEBUG((DEBUG_INFO, "Flags:0x%08x\n", MADT->Flags));

    TempPtr = (UINT8 *)(MADT + 1);
    Len = MADT->Header.Length - sizeof(EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
	//遍历中断控制器结构。
    while (Len > 0) {
        Type = *TempPtr;			//每一个中断控制器结构第一个字节是类型
        Length = *(TempPtr + 1);	//第二个字节是长度
        switch(Type)
        {
        //根据不同的类型解析相对应的中断结构体信息。
        case EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC:
        case EFI_ACPI_6_3_IO_APIC:
        case EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE:
        case EFI_ACPI_6_3_NON_MASKABLE_INTERRUPT_SOURCE:
        case EFI_ACPI_6_3_LOCAL_APIC_NMI:
        case EFI_ACPI_6_3_LOCAL_APIC_ADDRESS_OVERRIDE:
        case EFI_ACPI_6_3_IO_SAPIC:
        case EFI_ACPI_6_3_LOCAL_SAPIC:
        case EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC:
        case EFI_ACPI_6_3_LOCAL_X2APIC_NMI:
        case EFI_ACPI_6_3_GICR:
        case EFI_ACPI_6_3_GIC_ITS:
            DEBUG((DEBUG_INFO, "Parser not implemented for Type:0x%02x\n", Type));
            break;
        case EFI_ACPI_6_3_GIC:
            DumpMadtGIC((EFI_ACPI_6_3_GIC_STRUCTURE *)TempPtr);
            break;
        case EFI_ACPI_6_3_GICD:
            DumpMadtGICD((EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE *)TempPtr);
            break;
        case EFI_ACPI_6_3_GIC_MSI_FRAME:
            DumpMadtGICMSI((EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE *)TempPtr);
            break;
        default:
            DEBUG((DEBUG_INFO, "Unknown Type:0x%02x\n", Type));
            break;
        }

        Len = Len - Length;
        TempPtr = TempPtr + Length;
    }
    DEBUG((DEBUG_INFO, "###########End Dump MADT###########\n\n"));
}

在这里插入图片描述
在这里插入图片描述

VOID
DumpMadtGIC(EFI_ACPI_6_3_GIC_STRUCTURE *GIC)
{
    DEBUG((DEBUG_INFO, "GIC Information:\n"));
    DEBUG((DEBUG_INFO, "  CPU Interface Number:%d\n", GIC->CPUInterfaceNumber));
    DEBUG((DEBUG_INFO, "  Acpi Processor Uid:0x%08x\n", GIC->AcpiProcessorUid));
    DEBUG((DEBUG_INFO, "  Flags:0x%08x\n", GIC->Flags));
    DEBUG((DEBUG_INFO, "  Parking Protoco lVersion:0x%08x\n", GIC->ParkingProtocolVersion));
    DEBUG((DEBUG_INFO, "  Performance Interrupt Gsiv:0x%08x\n", GIC->PerformanceInterruptGsiv));
    DEBUG((DEBUG_INFO, "  Parked Address:0x%p\n", GIC->ParkedAddress));
    DEBUG((DEBUG_INFO, "  Physical Base Address:0x%p\n", GIC->PhysicalBaseAddress));
    DEBUG((DEBUG_INFO, "  GICV:0x%11p\n", GIC->GICV));
    DEBUG((DEBUG_INFO, "  GICH:0x%11p\n", GIC->GICH));
    DEBUG((DEBUG_INFO, "  VGIC Maintenance Interrupt:0x%x\n", GIC->VGICMaintenanceInterrupt));
    DEBUG((DEBUG_INFO, "  GICR Base Address:0x%11p\n", GIC->GICRBaseAddress));
    DEBUG((DEBUG_INFO, "  MPIDR:%11p\n", GIC->MPIDR));
    DEBUG((DEBUG_INFO, "  Processor Power Efficiency Class:0x%02x\n", GIC->ProcessorPowerEfficiencyClass));
    DEBUG((DEBUG_INFO, "  Spe Overflow Interrupt:0x%04x\n", GIC->SpeOverflowInterrupt));
}

在这里插入图片描述

VOID
DumpMadtGICD(
    IN EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE *GICD
)
{
    DEBUG((DEBUG_INFO, "GIC Distributor Information:\n"));
    DEBUG((DEBUG_INFO, "  Gic Id:0x%08x\n", GICD->GicId ));
    DEBUG((DEBUG_INFO, "  Physical Base Address:0x%11p\n", GICD->PhysicalBaseAddress));
    DEBUG((DEBUG_INFO, "  System Vector Base:0x%x\n", GICD->SystemVectorBase));
    DEBUG((DEBUG_INFO, "  Gic Version:0x%02x\n", GICD->GicVersion));
}

在这里插入图片描述


VOID 
DumpMadtGICMSI(EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE *GICMSI)
{
    DEBUG((DEBUG_INFO, "GIC MSI Information:\n"));
    DEBUG((DEBUG_INFO, "  Gic Msi Frame Id:0x%08x\n", GICMSI->GicMsiFrameId));
    DEBUG((DEBUG_INFO, "  Physical Base Address:0x%11p\n", GICMSI->PhysicalBaseAddress));
    DEBUG((DEBUG_INFO, "  Flags:0x%08x\n", GICMSI->Flags));
    DEBUG((DEBUG_INFO, "  SPI Count:0x%04x\n", GICMSI->SPICount));
    DEBUG((DEBUG_INFO, "  SPI Base:0x%04x\n", GICMSI->SPIBase));
}

最终dump出来的log如下

###########Start Dump MADT###########
Signature:APIC									-->头部信息
Length:0xA8
Revision:0x03
Checksum:0x50
OemID:BOCHS 
OemTableId:0x2020202043505842
OemRevision:0x1
CreatorId:0x43505842
CreatorRevision:0x1
Local APIC Address:0x00000000					--> 不存在Local APIC
Flags:0x00000000								
GIC Distributor Information:						
  Gic Id:0x00000000								--> GIC Distrubtor ID为0
  Physical Base Address:0x00008000000			--> GIC Distributor的物理地址
  System Vector Base:0x0						--> 必须为0
  Gic Version:0x02								--> GIC V2
GIC Information:								
  CPU Interface Number:0						--> CPU接口不存在,为0
  Acpi Processor Uid:0x00000000					--> 不存在
  Flags:0x00000001								--> GIC可以使能
  Parking Protoco lVersion:0x00000000			--> ARM-Processor Parking Protocol 版本号
  Performance Interrupt Gsiv:0x00000017			--> 性能监控的GIV中断号
  Parked Address:0x0
  Physical Base Address:0x8010000				--> GIC的物理地址
  GICV:0x00008040000							--> GIC virtual CPU interface寄存器地址
  GICH:0x00008030000							--> GIC virtual interface control block寄存器地址
  VGIC Maintenance Interrupt:0x0				--> 不存在
  GICR Base Address:0x00000000000				--> 这里是GIC V2,所以GICR不存在
  MPIDR:00000000000								
  Processor Power Efficiency Class:0x0D			--> 功耗级别
  Spe Overflow Interrupt:0x0000					-->0, 不支持Spe Overflow
GIC MSI Information:
  Gic Msi Frame Id:0x00000000					--> ID为0 
  Physical Base Address:0x00008020000			--> GIC MSI的物理地址
  Flags:0x00000001								--> The SPI Count and Base values override the values specified in the MSI_TYPER register in the associated GIC MSI frame.
  SPI Count:0x0040								--> SPI个数
  SPI Base:0x0050								
###########End Dump MADT###########

SPCR

SPCR(Serial Port Console Redirection)提供了有关串口或非遗留UART接口的配置和使用信息.。在BIOS使用此串口作为控制台输入/输出的系统中,应该使用此表来传递关于这些设置的信息,确保BIOS控制台输出和Windows EMS(Emergency Management Serivces)输出之间的平滑转换。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
MdePkg/Include/IndustryStandard/SerialPortConsoleRedirection.h

typedef struct {
  EFI_ACPI_DESCRIPTION_HEADER               Header;
  UINT8                                     InterfaceType;
  UINT8                                     Reserved1[3];
  EFI_ACPI_5_0_GENERIC_ADDRESS_STRUCTURE    BaseAddress;
  UINT8                                     InterruptType;
  UINT8                                     Irq;
  UINT32                                    GlobalSystemInterrupt;
  UINT8                                     BaudRate;
  UINT8                                     Parity;
  UINT8                                     StopBits;
  UINT8                                     FlowControl;
  UINT8                                     TerminalType;
  UINT8                                     Reserved2;
  UINT16                                    PciDeviceId;
  UINT16                                    PciVendorId;
  UINT8                                     PciBusNumber;
  UINT8                                     PciDeviceNumber;
  UINT8                                     PciFunctionNumber;
  UINT32                                    PciFlags;
  UINT8                                     PciSegment;
  UINT32                                    Reserved3;
} EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE;

Dump SPCR的代码如下

switch (Entry->Signature) {
...
case EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE:
                            DumpSPCR((EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *)Entry);
                            break;
...
}
VOID
DumpSPCR(
    IN EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *SPCR
)
{
    char *TempStr;
    DEBUG((DEBUG_INFO, "\n#########Start Dump SPCR##########\n"));
    DumpACPIHeader(&SPCR->Header);
    switch(SPCR->InterfaceType) {
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_16550:
        TempStr = "16550";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_16450:
        TempStr = "16450";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_ARM_PL011_UART:
        TempStr = "ARM PL011 UART";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_NVIDIA_16550_UART:
        TempStr = "NVIDIA 16550 UART";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_ARM_SBSA_GENERIC_UART_2X:
        TempStr = "ARM SBSA Generic UART 2.x";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_ARM_SBSA_GENERIC_UART:
        TempStr = "ARM SBSA Generic UART";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_DCC:
        TempStr = "ARM DCC";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_BCM2835_UART:
        TempStr = "BCM2835";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_16550_WITH_GAS:
        TempStr = "16550-compatible";
        break;
    default:
        TempStr = "Reserved";
        break;
    }
    DEBUG((DEBUG_INFO, "Interface:%a\n", TempStr));

    DumpGenericAddress("Base Address", (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *)&SPCR->BaseAddress);
    
    switch (SPCR->InterruptType)
    {
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_8259:
        TempStr = "8259";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_APIC:
        TempStr = "APIC";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_SAPIC:
        TempStr = "SAPIC";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC:
        TempStr = "GIC";
        break;
    default:
        
        TempStr = "Not Supported";
        break;
    }
    DEBUG((DEBUG_INFO, "Interrupt Type: %a\n", TempStr));

    DEBUG((DEBUG_INFO, "IRQ:%d\n", SPCR->Irq));
    DEBUG((DEBUG_INFO, "Global System Interrupt:0x%x\n", SPCR->GlobalSystemInterrupt));
   
    switch (SPCR->BaudRate)
    {
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_9600: 
        TempStr = "9600";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_19200:
        TempStr = "19200";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_57600:
        TempStr = "57600";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_115200:
        TempStr = "115200";
        break;
    default:
        TempStr = "Reserved";
        break;
    }
    DEBUG((DEBUG_INFO, "Baud Rate:%a\n", TempStr));

    switch (SPCR->Parity)
    {
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_PARITY_NO_PARITY:
        DEBUG((DEBUG_INFO, "Parity: No Parity\n"));
        break;
    default:
        DEBUG((DEBUG_INFO, "Parity: Reserved\n"));
        break;
    }
    
    switch (SPCR->StopBits)
    {
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_STOP_BITS_1:
        DEBUG((DEBUG_INFO, "Stop Bits:%d\n", SPCR->StopBits));
        break;
    default:
        DEBUG((DEBUG_INFO, "Stop Bits: No Stop Bits\n"));
        break;
    }


    DEBUG((DEBUG_INFO, "Flow Control: \n"));
    if (SPCR->FlowControl & EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_FLOW_CONTROL_DCD) {
        DEBUG((DEBUG_INFO, "  Support DCD\n"));
    }

    if (SPCR->FlowControl & EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_FLOW_CONTROL_RTS_CTS) {
        DEBUG((DEBUG_INFO, "  Support RTS/CTS\n"));
    }

    if (SPCR->FlowControl & EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_FLOW_CONTROL_XON_XOFF) {
        DEBUG((DEBUG_INFO, "  Support XON/XOFF\n"));
    }
    
    switch (SPCR->TerminalType)
    {
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT100:
        TempStr = "VT100";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT100_PLUS:
        TempStr = "VT100+";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT_UTF8:
        TempStr = "VI-UTF8";
        break;
    case EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_ANSI:
        TempStr = "ANSI";
        break;
    default:
        
        TempStr = "Reserved";
        break;
    }
    DEBUG((DEBUG_INFO, "Termial Type:%a\n", TempStr));
    
    DEBUG((DEBUG_INFO, "PCI Device ID:0x%04x\n", SPCR->PciDeviceId));
    DEBUG((DEBUG_INFO, "PCI Vendor ID:0x%04x\n", SPCR->PciVendorId));
    DEBUG((DEBUG_INFO, "PCI Bus Number:0x%02x\n", SPCR->PciBusNumber));
    DEBUG((DEBUG_INFO, "PCI Device Number:0x%02x\n", SPCR->PciDeviceNumber));
    DEBUG((DEBUG_INFO, "PCI Function Number:0x%02x\n", SPCR->PciFunctionNumber));
    DEBUG((DEBUG_INFO, "PCI Flags:0x%08x\n", SPCR->PciFlags));
    DEBUG((DEBUG_INFO, "PCI Segment:0x%02x\n", SPCR->PciSegment));
    DEBUG((DEBUG_INFO, "###########End Dump SPCR###########\n\n"));
}

dump出的log

#########Start Dump SPCR##########
Signature:SPCR
Length:0x50
Revision:0x02
Checksum:0xCB
OemID:BOCHS 
OemTableId:0x2020202043505842
OemRevision:0x1
CreatorId:0x43505842
CreatorRevision:0x1
Interface:ARM PL011 UART				--> 类型是ARM PL011 IP
--> 串口的物理地址在0x00009000000。
Base Address: AddressSpaceId:0x00, RegisterBitWidth:0x08, RegisterBitOffset:0x00, AccessSize:0x01, Address:0x00009000000
Interrupt Type: GIC						--> 中断类型是ARM GIC
IRQ:0						
Global System Interrupt:0x21			--> 中断号是0x21
Baud Rate:9600							--> 波特率是9600
Parity: No Parity						--> 没有奇偶校验
Stop Bits:1								--> 停止位是1位
Flow Control: 							--> 支持RTS/CTS
  Support RTS/CTS
Termial Type:VT100						--> Console类型是VT100
PCI Device ID:0xFFFF					--> 不是PCI 设备,下面字段全是无效
PCI Vendor ID:0xFFFF
PCI Bus Number:0x00
PCI Device Number:0x00
PCI Function Number:0x00
PCI Flags:0x00000000
PCI Segment:0x00
###########End Dump SPCR###########
  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: UEFI BIOS Utility-EZ Mode是一种简单易用的BIOS设置界面,它提供了基本的系统信息、启动选项、调整CPU和内存频率、设置风扇控制等功能。它的设计使得用户可以轻松地进行基本的BIOS设置,而不需要深入了解BIOS的复杂性。 ### 回答2: UEFI BIOS Utility - EZ Mode是一种UEFI BIOS配置工具,它旨在使用户可以轻松管理和调整基本系统设置。EZ Mode提供了一个简化的图形用户界面面板,使用户能够快速而准确地调整各种BIOS选项。 EZ Mode界面以图形化方式呈现各种设置和参数,这使得用户可以更轻松地了解它们的含义和作用。例如,在EZ Mode中,用户可以快速地查看CPU速度、内存用量、系统温度、风扇转速等参数,并进行必要的调整以改善系统的性能和稳定性。 除了常规的设置,EZ Mode还提供了一些高级功能。例如,用户可以选择开启或关闭诸如Intel快速启动技术、USB 3.0支持、SATA控制器等功能,以最大程度地优化系统性能。 此外,EZ Mode还支持自动检测并更新BIOS固件,这可以保证系统始终运行在最新的稳定版本中。 总之,UEFI BIOS Utility - EZ Mode 是一个非常有用和功能强大的BIOS配置工具,它使用户在处理系统设置和参数时更加轻松。无论是普通用户还是高级用户,都可以从EZ Mode的功能中受益。 ### 回答3: UEFI BIOS Utility是现代计算机使用的一种新型Firmware。UEFI位于操作系统和硬件之间,主要负责计算机启动过程中的硬件自检以及操作系统的加载过程。UEFI BIOS Utility的EZ模式是一种简化操作的模式,旨在提供用户一个更加直观的界面,以便用户轻松地对计算机进行配置。 UEFI BIOS Utility的EZ模式提供了一个清晰的界面,可以让用户更加直观地了解计算机的硬件配置,系统信息以及启动选项等。在这种模式下,用户可以很方便地进行一些常见的设置,例如修改系统时间,设置启动顺序等等。同时,EZ模式还提供了导航面板,让用户轻松地找到需要的选项。 一些重要的系统配置也可以在EZ模式下进行调整。例如,用户可以配置CPU的频率和电压,设置内存检测参数等等。此外,用户还可以对硬盘进行分区,修改RAID设置和SATA模式等。 总之,UEFI BIOS Utility的EZ模式提供了一个真正的易用界面,让用户轻松处理大量的系统配置和硬件设置。当您需要进行系统调整的时候,把您的注意力放在EZ模式中,就不需要担心在BIOS中迷路了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值