问题描述
我编写此代码是为了使用 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_ENABLE
和SMI_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 断电实现有一些不同(正如提问者所报告的那样,它确实有效):
-
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 端口。