c - 如何在 LattePanda 上启用 ACPI(用于关机)

标签 c power-management bare-metal uefi 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, port) __asm__ __volatile__ \
    ("xor %%eax, %%eax\n\tin %%dx, %%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, %%dx\n\t" : : "a"(data), "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
  • 放在我的 U 盘根目录下
  • 通过内置的 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 断电实现有一些不同(正如提问者所报告的那样,它确实有效):

  • GRUB 不会向 SMI 端口发送任何内容。 GRUB 只有一次执行任何端口 I/O,那就是写入 PM1A 寄存器时。 (PM1B 也无所谓。) grub-core/commands/acpihalt.c 中的所有其他代码仅用于定位和解析 ACPI 表。是的,grub_acpi_halt似乎是在没有任何先前的 ACPI 初始化调用的情况下冷调用的。不过,它似乎确实事先释放了 EFI 资源,如 grub-core/lib/efi/halt.c 所示。和 grub-core/kern/i386/efi/init.c ,最终 grub-core/kern/efi/init.c (但不会终止 EFI 引导服务)。
  • GRUB 不保留“未使用”的 PM1A 寄存器位。询问者的代码首先读取 PM1A 寄存器,以便小心地屏蔽掉它不想修改的位域。 GRUB 不会打扰,它只是将零放在那里。从提问者的代码翻译成名字,似乎可以
    out16((1 << 13) | (pm1a_value << 10), pm1a_cnt_blk);
    

  • 所以首先我建议放弃 ACPI_ENABLE位完全,然后调整写入 PM1A 端口。正文ACPI 6.0规范建议只有在您实际希望接收和处理 SCI 中断时才需要前者;如果您只想关闭系统,您可以跳过它。

    关于c - 如何在 LattePanda 上启用 ACPI(用于关机),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66641127/

    相关文章:

    c - 将数组传递给函数 vs 将变量传递给函数

    ios - 如何获得更准确的电池电量百分比?

    c - ARM代码中的未定义指令异常

    c - 无操作系统执行

    c - size_t 迭代的可变尺度

    c - 打印链表导致无限循环(C)?

    c - 如何在c中使用数组打开文件

    linux - 如何在基于 ARM 的嵌入式 Linux 系统上进行省电?

    callback - PowerRegisterSuspendResumeNotification - 提供的回调函数未按预期工作

    c - Bare-Metal C : Why are some IDEs startup files doing things crt0. s 无论如何都会处理?