如何在 LattePanda 上启用 ACPI用于关机

问题描述

我编写此代码是为了使用 ACPI 通过从 64 位 UEFI 启动的程序关闭计算机。

(抱歉代码太长,但我认为所有部分都是必需的)

#include <stdint.h>

#define in8(data,port) __asm__ __volatile__ \
    ("xor %%eax,%%eax\n\tin %%dx,%%al\n\t" : "=a"(data) : "d"(port))

#define in16(data,%%ax\n\t" : "=a"(data) : "d"(port))

#define out8(data,port) __asm__ __volatile__ \
    ("out %%al,%%dx\n\t" : : "a"(data),"d"(port))

#define out16(data,port) __asm__ __volatile__ \
    ("out %%ax,"d"(port))

void initSerialPort(void) {
    /* set speed to 115200bps */
    out8(0x83,0x03FB); /* enable LSB/MSB register */
    out8(0x00,0x03F9); /* MSB */
    out8(0x01,0x03F8); /* LSB */
    /* set line info */
    out8(0x03,0x03FB); /* disable LSB/MSB register,no parity,no 2-bit stop,8-bit data */
    /* set modem info */
    out8(0x03,0x03FC); /* no loopback,no interrupt,RTS on,DTR on */
    /* enable FIFO */
    out8(0x07,0x03FA); /* interrupt at 1 byte,clear TX,clear RX,enable */
    /* disable interrupt */
    out8(0x00,0x03F9);
}

void printChar(int c) {
    int status;
    /* wait until TX buffer is empty */
    do {
        in8(status,0x03FD);
    } while (!(status & 0x20));
    /* put data to send */
    out8(c,0x03F8);
}

void printString(const char* str) {
    while (*str != '\0') printChar((unsigned char)*(str++));
}

void printInt(uint64_t value,int radix) {
    char vStr[128] = "";
    char* pStr = vStr + 120;
    do {
        *(pStr--) = "0123456789ABCDEF"[value % radix];
        value /= radix;
    } while (value > 0);
    printString(pStr + 1);
}

void stop(void) {
    __asm__ __volatile__(
        "cli\n\t"
        "1:\n\t"
        "hlt\n\t"
        "jmp 1b\n\t"
    );
}

char* searchPuttern(char* text,uint64_t textSize,const char* puttern,uint64_t putternSize) {
    uint64_t i,j;
    if (textSize < putternSize) return 0;
    for (i = 0; i <= textSize - putternSize; i++) {
        int ok = 1;
        for (j = 0; j < putternSize; j++) {
            if (text[i + j] != puttern[j]) {
                ok = 0;
                break;
            }
        }
        if (ok) return text + i;
    }
    return 0;
}

void entry(void* unused,uint64_t* table) {
    uint64_t* guidTable;
    uint64_t guidTableNumElements;
    uint64_t i;
    uint64_t* rsdp;
    uint32_t* rsdt,*xsdt;
    uint32_t* fadt_from_rsdt,*fadt,*dsdt;
    uint64_t xsdtNumElements;
    uint32_t smi_cmd,acpi_enable,pm1a_cnt_blk,pm1b_cnt_blk;
    uint32_t amlLength;
    char* aml,*s5;
    int pm1a_value,pm1b_value;
    int status;
    int printLimit;

    (void)unused;
    initSerialPort();

    /* parse things to get required values */
    printString("argument table = 0x"); printInt((uint64_t)table,16); printChar('\n');
    guidTable = (uint64_t*)table[14];
    guidTableNumElements = table[13];
    printString("GUID table = 0x"); printInt((uint64_t)guidTable,16); printChar('\n');
    printString("GUID table size = "); printInt(guidTableNumElements,10); printChar('\n');
    rsdp = 0;
    for (i = 0; i < guidTableNumElements; i++) {
        if (guidTable[i * 3 + 0] == UINT64_C(0x11D3E4F18868E871) &&
        guidTable[i * 3 + 1] == UINT64_C(0x81883CC7800022BC)) {
            rsdp = (uint64_t*)guidTable[i * 3 + 2];
            break;
        }
    }
    if (rsdp == 0) {
        printString("RSDP not found\n");
        stop();
    }
    printString("RSDP = 0x"); printInt((uint64_t)rsdp,16); printChar('\n');
    printString("RSDP signature = 0x"); printInt(rsdp[0],16); printChar('\n');
    rsdt = (uint32_t*)(rsdp[2] & UINT64_C(0xffffffff));
    xsdt = (uint32_t*)rsdp[3];
    printString("RSDT = 0x"); printInt((uint64_t)rsdt,16); printChar('\n');
    fadt_from_rsdt = 0;
    if (rsdt != 0) {
        uint64_t rsdtNumElements;
        printString("RSDT signature = 0x"); printInt(rsdt[0],16); printChar('\n');
        printString("RSDT length = "); printInt(rsdt[1],10); printChar('\n');
        rsdtNumElements = (rsdt[1] - 36) / 4;
        fadt = 0;
        for (i = 0; i < rsdtNumElements; i++) {
            uint32_t* addr = (uint32_t*)(uint64_t)rsdt[9 + i];
            printString("*0x"); printInt((uint64_t)addr,16);
            printString(" = 0x"); printInt(addr[0],16);
            printChar('\n');
            if ((addr[0] & UINT64_C(0xffffffff)) == UINT64_C(0x50434146)) {
                fadt_from_rsdt = addr;
            }
        }
    }
    printString("XSDT = 0x"); printInt((uint64_t)xsdt,16); printChar('\n');
    if (xsdt == 0) {
        printString("XSDT not found\n");
        stop();
    }
    printString("XSDT signature = 0x"); printInt(xsdt[0],16); printChar('\n');
    printString("XSDT length = "); printInt(xsdt[1],10); printChar('\n');
    xsdtNumElements = (xsdt[1] - 36) / 8;
    fadt = 0;
    for (i = 0; i < xsdtNumElements; i++) {
        uint32_t* addr = (uint32_t*)((uint64_t*)&xsdt[9])[i];
        printString("*0x"); printInt((uint64_t)addr,16);
        printString(" = 0x"); printInt(addr[0],16);
        printChar('\n');
        if ((addr[0] & UINT64_C(0xffffffff)) == UINT64_C(0x50434146)) {
            fadt = addr;
        }
    }
    printString("FADT from RSDT = 0x"); printInt((uint64_t)fadt_from_rsdt,16); printChar('\n');
    printString("FADT from XSDT = 0x"); printInt((uint64_t)fadt,16); printChar('\n');
    if (fadt == 0) fadt = fadt_from_rsdt;
    if (fadt == 0) {
        printString("FADT not found\n");
        stop();
    }
    printString("FADT = 0x"); printInt((uint64_t)fadt,16); printChar('\n');
    printString("FADT signature = 0x"); printInt(fadt[0],16); printChar('\n');
    printString("FADT length = "); printInt(fadt[1],10); printChar('\n');
    dsdt = (uint32_t*)(uint64_t)fadt[10];
    smi_cmd = fadt[12];
    acpi_enable = fadt[13] & 0xff;
    pm1a_cnt_blk = fadt[16];
    pm1b_cnt_blk = fadt[17];
    printString("DSDT = 0x"); printInt((uint64_t)dsdt,16); printChar('\n');
    printString("SMI_CMD = 0x"); printInt(smi_cmd,16); printChar('\n');
    printString("ACPI_ENABLE = 0x"); printInt(acpi_enable,16); printChar('\n');
    printString("PM1a_CNT_BLK = 0x"); printInt(pm1a_cnt_blk,16); printChar('\n');
    printString("PM1b_CNT_BLK = 0x"); printInt(pm1b_cnt_blk,16); printChar('\n');
    printString("PM1_CNT_LEN = "); printInt((fadt[22] >> 8) & 0xff,10); printChar('\n');
    if (fadt[1] >= 148) {
        printString("X_DSDT = 0x");
        printInt(fadt[35] | ((uint64_t)fadt[36] << 32),16);
        printChar('\n');
    }
    if (fadt[1] >= 184) {
        printString("X_PM1a_CNT_BLK = 0x"); printInt(fadt[43],16);
        printString(" 0x"); printInt(fadt[44],16);
        printString(" 0x"); printInt(fadt[45],16);
        printChar('\n');
    }
    if (fadt[1] >= 196) {
        printString("X_PM1b_CNT_BLK = 0x"); printInt(fadt[46],16);
        printString(" 0x"); printInt(fadt[47],16);
        printString(" 0x"); printInt(fadt[48],16);
        printChar('\n');
    }

    printString("DSDT signature = 0x"); printInt(dsdt[0],16); printChar('\n');
    printString("DSDT length = "); printInt(dsdt[1],10); printChar('\n');
    if (dsdt[1] < 36) {
        printString("DSDT too short\n");
        stop();
    }
    amlLength = dsdt[1] - 36;
    aml = (char*)&dsdt[9];
    s5 = searchPuttern(aml,amlLength,"\x08_S5_\x12",6);
    if (s5 == 0) {
        printString("_S5_ not found\n");
        stop();
    }
    printString("_S5_ dump:\n");
    for (i = 0; i < 16; i++) {
        if (i > 0) printChar(' ');
        printString("0x"); printInt((unsigned char)s5[i],16);
    }
    printChar('\n');
    if (s5[8] == 0) {
        pm1a_value = 0;
        if (s5[9] == 0) pm1b_value = 0; else pm1b_value = (unsigned char)s5[10];
    } else {
        pm1a_value = (unsigned char)s5[9];
        if (s5[10] == 0) pm1b_value = 0; else pm1b_value = (unsigned char)s5[11];
    }
    printString("value for PM1a_CNT.SLP_TYP = 0x"); printInt(pm1a_value,16); printChar('\n');
    printString("value for PM1b_CNT.SLP_TYP = 0x"); printInt(pm1b_value,16); printChar('\n');

    /* enable ACPI for powering off */
    in16(status,pm1a_cnt_blk);
    printString("status = 0x"); printInt(status,16); printChar('\n');
    if (!(status & 1)) {
        printString("sending ACPI_ENABLE to SMI_CMD\n");
        out8(acpi_enable,smi_cmd);
        printLimit = 10;
        do {
            in16(status,pm1a_cnt_blk);
            if (printLimit-- > 0) {
                printString("status = 0x"); printInt(status,16); printChar('\n');
            }
        } while (!(status & 1));
    }

    /* power off */
    printString("switching state\n");
    in16(status,pm1a_cnt_blk);
    out16((status & ~(7 << 10)) | ((pm1a_value & 7) << 10) | (1 << 13),pm1a_cnt_blk);
    if (pm1b_cnt_blk != 0) {
        in16(status,pm1b_cnt_blk);
        out16((status & ~(7 << 10)) | ((pm1b_value & 7) << 10) | (1 << 13),pm1b_cnt_blk);
    }

    printString("state switch sent\n");
    stop();
}

我用 TDM-GCC (gcc (tdm64-1) 9.2.0) 编译了这个。

编译命令为:

C:\MyInstalledApps\TDM-GCC-64\bin\gcc -Wall -Wextra -nostdlib -e entry -m64 -Wl,--subsystem=10 acpi_test.c -o bootx64.efi

它没有给我任何警告或错误消息。

我在我的 LattePanda(带有 2G RAM 和 32G emmC)上尝试了这个代码,但它无法关闭它。查看跟踪,似乎无法通过将 ACPI_ENABLE 发送到端口 SMI_CMD 来启用 ACPI。 我的意思是 SCI_EN 寄存器中的 PM1a_CNT_BLK 位似乎没有设置。

我也在 QEMU 和 VirtualBox 上尝试了这段代码并成功关闭了电源,但它看起来没有帮助,因为这些 VM 软件中似乎已经启用了 ACPI。

我的 QEMU 版本是 QEMU emulator version 5.1.92 (v5.2.0-rc2-11843-gf571c4ffb5-dirty) 并使用 GitHub - BlankOn/ovmf-blobs: BIOS.bin for qemu to support UEFI 作为 BIOS。

从串口的输出来看,ACPI_ENABLESMI_CMD的值看起来比较合理。 (我不知道他们是否真的正确)

我是否忽略了什么?我应该怎么做才能在 LattePanda 上启用 ACPI 并从我从 UEFI 启动的程序中关闭电源?

LattePanda 串口输出

argument table = 0x7BA13F18
GUID table = 0x7BA12E18
GUID table size = 13
RSDP = 0x7B12E000
RSDP signature = 0x2052545020445352
RSDT = 0x7B12E028
RSDT signature = 0x54445352
RSDT length = 124
*0x7B12E188 = 0x50434146
*0x7B14AB40 = 0x43495041
*0x7B14ABC8 = 0x54445046
*0x7B14AC10 = 0x54444946
*0x7B14ACB0 = 0x4D44534D
*0x7B14AD08 = 0x4746434D
*0x7B14AD48 = 0x54445353
*0x7B14EEC0 = 0x54445353
*0x7B14F518 = 0x54445353
*0x7B14F570 = 0x49464555
*0x7B14F5B8 = 0x54445353
*0x7B14F828 = 0x54455048
*0x7B14F860 = 0x54445353
*0x7B14FFC8 = 0x54445353
*0x7B150258 = 0x54445353
*0x7B1503D8 = 0x5449504C
*0x7B1504E0 = 0x47464342
*0x7B150620 = 0x4D415250
*0x7B150650 = 0x54524742
*0x7B150688 = 0x324D5054
*0x7B1506C0 = 0x54525343
*0x7B150810 = 0x54414457
XSDT = 0x7B12E0A8
XSDT signature = 0x54445358
XSDT length = 212
*0x7B14AA30 = 0x50434146
*0x7B14AB40 = 0x43495041
*0x7B14ABC8 = 0x54445046
*0x7B14AC10 = 0x54444946
*0x7B14ACB0 = 0x4D44534D
*0x7B14AD08 = 0x4746434D
*0x7B14AD48 = 0x54445353
*0x7B14EEC0 = 0x54445353
*0x7B14F518 = 0x54445353
*0x7B14F570 = 0x49464555
*0x7B14F5B8 = 0x54445353
*0x7B14F828 = 0x54455048
*0x7B14F860 = 0x54445353
*0x7B14FFC8 = 0x54445353
*0x7B150258 = 0x54445353
*0x7B1503D8 = 0x5449504C
*0x7B1504E0 = 0x47464342
*0x7B150620 = 0x4D415250
*0x7B150650 = 0x54524742
*0x7B150688 = 0x324D5054
*0x7B1506C0 = 0x54525343
*0x7B150810 = 0x54414457
FADT from RSDT = 0x7B12E188
FADT from XSDT = 0x7B14AA30
FADT = 0x7B14AA30
FADT signature = 0x50434146
FADT length = 268
DSDT = 0x7B12E210
SMI_CMD = 0xB2
ACPI_ENABLE = 0xA0
PM1a_CNT_BLK = 0x404
PM1b_CNT_BLK = 0x0
PM1_CNT_LEN = 2
X_DSDT = 0x7B12E210
X_PM1a_CNT_BLK = 0x2001001 0x404 0x0
X_PM1b_CNT_BLK = 0x1 0x0 0x0
DSDT signature = 0x54445344
DSDT length = 116766
_S5_ dump:
0x8 0x5F 0x53 0x35 0x5F 0x12 0x7 0x4 0xA 0x7 0x0 0x0 0x0 0x14 0x1E 0x5F
value for PM1a_CNT.SLP_TYP = 0x7
value for PM1b_CNT.SLP_TYP = 0x0
status = 0x0
sending ACPI_ENABLE to SMI_CMD
status = 0x0
status = 0x0
status = 0x0
status = 0x0
status = 0x0
status = 0x0
status = 0x0
status = 0x0
status = 0x0
status = 0x0

QEMU 的串口输出

argument table = 0x7EED018
GUID table = 0x7EED0D8
GUID table size = 9
RSDP = 0x7EF9014
RSDP signature = 0x2052545020445352
RSDT = 0x7EF8074
RSDT signature = 0x54445352
RSDT length = 52
*0x7EF5000 = 0x50434146
*0x7EF4000 = 0x43495041
*0x7EF3000 = 0x54455048
*0x7EF2000 = 0x54454157
XSDT = 0x7EF80E8
XSDT signature = 0x54445358
XSDT length = 68
*0x7EF5000 = 0x50434146
*0x7EF4000 = 0x43495041
*0x7EF3000 = 0x54455048
*0x7EF2000 = 0x54454157
FADT from RSDT = 0x7EF5000
FADT from XSDT = 0x7EF5000
FADT = 0x7EF5000
FADT signature = 0x50434146
FADT length = 116
DSDT = 0x7EF6000
SMI_CMD = 0xB2
ACPI_ENABLE = 0xF1
PM1a_CNT_BLK = 0xB004
PM1b_CNT_BLK = 0x0
PM1_CNT_LEN = 2
DSDT signature = 0x54445344
DSDT length = 5060
_S5_ dump:
0x8 0x5F 0x53 0x35 0x5F 0x12 0x6 0x4 0x0 0x0 0x0 0x0 0x10 0x3B 0x5C 0x2E
value for PM1a_CNT.SLP_TYP = 0x0
value for PM1b_CNT.SLP_TYP = 0x0
status = 0x1
switching state
state switch sent

VirtualBox 6.1.18 r142142 (qt5.6.2) 的串口输出

argument table = 0x6FEE018
GUID table = 0x6FEEC98
GUID table size = 10
RSDP = 0x6FFA014
RSDP signature = 0x2052545020445352
RSDT = 0x6FF9074
RSDT signature = 0x54445352
RSDT length = 52
*0x6FF7000 = 0x50434146
*0x6FF8000 = 0x43495041
*0x6FF3000 = 0x54445353
*0x5E39000 = 0x54524742
XSDT = 0x6FF90E8
XSDT signature = 0x54445358
XSDT length = 68
*0x6FF7000 = 0x50434146
*0x6FF8000 = 0x43495041
*0x6FF3000 = 0x54445353
*0x5E39000 = 0x54524742
FADT from RSDT = 0x6FF7000
FADT from XSDT = 0x6FF7000
FADT = 0x6FF7000
FADT signature = 0x50434146
FADT length = 244
DSDT = 0x6FF4000
SMI_CMD = 0x442E
ACPI_ENABLE = 0xA1
PM1a_CNT_BLK = 0xB004
PM1b_CNT_BLK = 0x0
PM1_CNT_LEN = 2
X_DSDT = 0x6FF4000
X_PM1a_CNT_BLK = 0x2001001 0xB004 0x0
X_PM1b_CNT_BLK = 0x0 0x0 0x0
DSDT signature = 0x54445344
DSDT length = 8997
_S5_ dump:
0x8 0x5F 0x53 0x35 0x5F 0x12 0x6 0x2 0xA 0x5 0xA 0x5 0x14 0x23 0x5F 0x50
value for PM1a_CNT.SLP_TYP = 0x5
value for PM1b_CNT.SLP_TYP = 0x5
status = 0x1
switching state

LattePanda 环境:

BIOS information
BIOS vendor              American Megatrends
Core Version             5.011
Compliancy               UEFI 2.4; PI 1.3
Project Version          S70CR200 3.06 x64
Build Date and Time      03/30/2018 14:41:43

根据@user3840170 的建议,我

  • Super Grub2 Disk下载super_grub2_disk_standalone_x86_64_efi_2.04s1.EFI
  • 将它放在我的 USB 闪存驱动器的根目录中
  • 通过内置的 UEFI Shell 在我的 LattePanda 上启动它
  • 菜单上的 c 进入命令行模式
  • 输入以下命令:
serial --speed=115200
terminal_output --append serial
set debug=acpi
halt

然后,我得到了以下日志并且我的 LattePanda 关机了。

grub> halt
commands/acpihalt.c:403: rsdp1=0x7b12e000
commands/acpihalt.c:423: PM1a port=404
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 24
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 2e
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 34
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 3c
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 43
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 4d
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 55
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 5d
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 64
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 6b
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 75
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 7d
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 87
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 8f
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 99
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell a3
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell a9
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell af
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell b5
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell bb
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell c1
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell c7
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell cd
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell d3
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell d9
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell e1
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell eb
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell f5
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell fc
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 103
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 10a
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 111
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 118
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 11f
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 125
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 12b
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 131
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 137
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 13d
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 143
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 149
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 153
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 15d
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 167
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 171
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 177
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 17d
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 187
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 191
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 19b
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 1a5
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 1ab
commands/acpihalt.c:107: data type = 0xa
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 1b2
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x5b
commands/acpihalt.c:242: Tell 1bc
commands/acpihalt.c:188: Extended opcode: 0x80
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x5b
commands/acpihalt.c:242: Tell 1cb
commands/acpihalt.c:188: Extended opcode: 0x81
commands/acpihalt.c:241: Opcode 0x14
commands/acpihalt.c:242: Tell 84f
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 858
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 862
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 868
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 86e
commands/acpihalt.c:107: data type = 0x0
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 874
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 87a
commands/acpihalt.c:107: data type = 0xb
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 882
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 88c
commands/acpihalt.c:107: data type = 0xc
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 896
commands/acpihalt.c:107: data type = 0x1
commands/acpihalt.c:241: Opcode 0x10
commands/acpihalt.c:242: Tell 89c
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 8a3
commands/acpihalt.c:107: data type = 0x11
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8b2
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8bb
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8c4
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8cd
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8d6
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8df
commands/acpihalt.c:241: Opcode 0x6
commands/acpihalt.c:242: Tell 8e8
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 8f1
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell a42
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell b65
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell b9f
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell bd1
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell c0b
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell c3d
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell c77
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell ca9
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell ce3
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x10
commands/acpihalt.c:242: Tell d15
commands/acpihalt.c:241: Opcode 0x5b
commands/acpihalt.c:242: Tell d1d
commands/acpihalt.c:188: Extended opcode: 0x82
commands/acpihalt.c:241: Opcode 0x10
commands/acpihalt.c:242: Tell 207b
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 2081
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 208d
commands/acpihalt.c:107: data type = 0x12
commands/acpihalt.c:241: Opcode 0x8
commands/acpihalt.c:242: Tell 209a
commands/acpihalt.c:269: S5 found
commands/acpihalt.c:444: SLP_TYP = 7,port = 0x404

RSDP 地址、PM1a 端口和 SLP_TYP 看起来与我的程序获得的相同。

解决方法

我不知道这是否真的会有所帮助,但我注意到与 GRUB 中的 ACPI 断电实现有一些不同(正如提问者所报告的那样,它确实有效):

  1. GRUB 不会向 SMI 端口发送任何内容。 GRUB 只有一次执行任何端口 I/O,那就是写入 PM1A 寄存器时。 (PM1B 也无所谓。)grub-core/commands/acpihalt.c 中的所有其他代码仅用于定位和解析 ACPI 表。是的,grub_acpi_halt 似乎是在没有任何前面的 ACPI 初始化调用的情况下冷调用的。不过,它似乎确实事先释放了 EFI 资源,如 grub-core/lib/efi/halt.cgrub-core/kern/i386/efi/init.c 以及最终 grub-core/kern/efi/init.c 中所见(但终止 EFI 引导服务)。

  2. GRUB 不保留“未使用”的 PM1A 寄存器位。询问者的代码首先读取 PM1A 寄存器,以便小心地屏蔽掉它不想修改的位域。 GRUB 不会打扰,它只是将零放在那里。从提问者的代码翻译成名字,好像可以

    out16((1 << 13) | (pm1a_value << 10),pm1a_cnt_blk);
    

所以首先我建议完全删除 ACPI_ENABLE 位,然后调整写入 PM1A 端口。