ACPI là gì: tại sao firmware không nên tắt máy bằng cách toggle GPIO

Tại sao firmware không nên dùng GPIO trực tiếp để tắt máy? ACPI là hợp đồng firmware viết, OS đọc: table, AML, power state và cách debug sleep/wake sai.

Cập nhật 12 phút đọc
BIOS / UEFI cover

Câu hỏi ban đầu: tại sao firmware không nên tắt máy bằng cách toggle GPIO?

Tôi nhớ lúc mới bắt đầu làm quen với SMM, có một lần cần implement logic tắt máy khẩn cấp khi nhiệt độ vượt ngưỡng, loại feature hay có trên POS terminal đặt trong môi trường nóng. Suy nghĩ đầu tiên rất tự nhiên: SMM chạy ở privilege rất cao, không có OS nào can thiệp được, vậy chỉ cần toggle GPIO pin tắt nguồn là xong.

Đồng nghiệp nhìn draft code, hỏi một câu: “GPIO nào? Board nào cũng khác nhau, mày định hardcode à?”

Câu hỏi đó mở ra một chuỗi giải thích mà tôi muốn viết lại ở đây: tại sao firmware không nên tắt máy bằng cách toggle GPIO, và ACPI fill vào khoảng trống đó như thế nào.

Câu trả lời ngắn: GPIO pin nào liên quan đến power là thứ platform-specific. Nếu hardcode vào SMM hoặc firmware handler, code sẽ bị dính chặt vào một board cụ thể. Quan trọng hơn, trong flow shutdown bình thường, power transition không phải quyết định riêng của SMM. Nó là một phần của ACPI và OS power management.

Câu trả lời dài hơn cần một bước lùi để hiểu firmware và OS phân chia quyền kiểm soát phần cứng như thế nào, và đó chính là lý do ACPI tồn tại.

Firmware và OS nhìn phần cứng khác nhau

Sau khi ExitBootServices() được gọi, OS nắm quyền platform. Nhưng OS không biết chi tiết phần cứng theo nghĩa hardware-specific: GPIO pin nào là power button, EC register nào điều khiển fan, rail nào phải tắt theo thứ tự nào khi sleep.

Firmware biết tất cả những điều đó, vì firmware mới là thứ init hardware từ đầu. Nhưng firmware không thể chỉ “giải thích bằng miệng” cho OS. Nó phải để lại một bản mô tả chuẩn hóa.

ACPI là bản mô tả đó.

01 DXE

Firmware init hardware

Firmware cấu hình chipset, device, policy và platform resource

02 ACPI

Publish ACPI tables

Firmware install DSDT, SSDT, FADT, MADT và các table liên quan

03 EBS

ExitBootServices

Firmware bàn giao quyền điều khiển boot-time cho OS

04 OS

OS đọc ACPI

OS walk từ RSDP, đọc DSDT/SSDT, interpret AML

05 Runtime

OS gọi ACPI method

Device probe, sleep, wake, power button đều đi qua ACPI model

ACPI là hợp đồng: firmware publish, OS đọc và thực thi AML method khi cần

ACPI không phải API kiểu function call trực tiếp giữa OS và firmware. Nó là một hợp đồng dữ liệu và control method: firmware publish table và AML, OS đọc table rồi thực thi AML method khi cần. Mọi thao tác power management sau khi OS lên đều đi qua hợp đồng này.

Quay lại câu hỏi: tại sao không toggle GPIO trong SMM?

Trong SMM, về mặt kỹ thuật bạn có thể truy cập hardware register trực tiếp. Nhưng dùng cách đó để tắt nguồn trong flow bình thường sẽ gây nhiều vấn đề.

Thứ nhất, nó bypass ACPI power sequence. OS không có cơ hội flush disk, close file handle, notify driver cleanup hoặc chuẩn bị device trước khi mất nguồn. Kết quả có thể là filesystem corruption hoặc device rơi vào trạng thái undefined sau khi bật lại.

Thứ hai, nó không portable. GPIO pin nào, register nào, EC command nào liên quan đến power là board-specific và silicon-specific. Hardcode vào SMM handler nghĩa là firmware bị gắn chặt vào một platform.

Thứ ba, nó sai ownership. SMM sinh ra để xử lý service nhỏ, bảo vệ resource và thực thi security policy. Nó không nên thay OS làm power management vĩ mô. Trong shutdown bình thường, OS/OSPM là bên điều phối power transition.

Trong flow ACPI bình thường, firmware không phải là bên tự ý tắt máy sau khi OS đã chạy. Firmware cung cấp ACPI tables, trong đó có FADT, DSDT/SSDT và _S5. OS/OSPM đọc thông tin này, chuẩn bị device, flush filesystem, gọi các ACPI method cần thiết, rồi mới yêu cầu chipset vào S5 bằng SLP_TYPSLP_EN.

Nói cách khác: firmware viết hợp đồng, OS đọc hợp đồng và điều khiển power transition.

01 Firmware

Publish ACPI tables

FADT, DSDT/SSDT, _S5, _PTS, _WAK và device methods

02 OS/OSPM

Đọc ACPI

OS hiểu device, resource, wake source và sleep state

03 Prepare

Chuẩn bị power transition

Flush I/O, notify driver, chạy ACPI method cần thiết

04 PM Control

SLP_TYP + SLP_EN

OS yêu cầu chipset vào sleep/off state theo ACPI spec

05 Chipset

Power transition

Platform chuyển sang S5 theo đúng ACPI flow

ACPI shutdown bình thường: firmware mô tả, OS quyết định và yêu cầu power transition

Nếu đây là thermal emergency thật sự, platform có thể có đường bảo vệ phần cứng riêng như EC, PMIC, chipset thermal trip hoặc board-specific safety logic. Nhưng đó là cơ chế bảo vệ khẩn cấp, không phải flow OS-controlled shutdown bình thường. Không nên trộn emergency hardware protection với shutdown ACPI thông thường.

ACPI là gì: nhìn từ firmware engineer

ACPI (Advanced Configuration and Power Interface) không chỉ là “bảng cấu hình”. Nó gồm hai phần chính.

1. Static tables, dữ liệu firmware publish lúc boot.

2. AML code, bytecode mà OS interpreter thực thi ở runtime khi cần hỏi platform “làm gì bây giờ”.

Đây là điểm nhiều người bỏ qua: ACPI không chỉ đọc một lần khi boot. OS liên tục gọi các ACPI method trong suốt quá trình chạy, khi device được probe, khi system sleep, khi device mất điện, khi user nhấn power button.

Cấu trúc ACPI tables

Firmware publish một cây bảng. OS tìm điểm vào qua RSDP (Root System Description Pointer), từ đó walk sang các bảng khác:

RSDP → XSDT
         ├─ FADT → DSDT (AML chính)
         ├─ SSDT (AML bổ sung)
         ├─ MADT (interrupt controller)
         ├─ MCFG (PCIe ECAM base)
         └─ ... (các table khác tùy platform)

Các bảng quan trọng nhất với firmware engineer:

Các ACPI table quan trọng
Table Tên đầy đủ Vai trò khi debug
FADT Fixed ACPI Description Table Chứa PM register info, ACPI flags và pointer tới DSDT
DSDT Differentiated System Description Table AML chính của platform, chứa device namespace và control methods như _STA, _CRS, _PS0, _PRW
SSDT Secondary System Description Table Bổ sung namespace theo CPU, device, SKU hoặc Setup option
MADT Multiple APIC Description Table Mô tả APIC và interrupt routing, sai ở đây thường gây lỗi SMP hoặc interrupt
MCFG PCI ECAM Table Cho OS biết base address để access PCI config space qua ECAM

AML: ngôn ngữ chạy trong OS

Phần hay nhất, và cũng phức tạp nhất, của ACPI là AML, ACPI Machine Language.

Firmware viết ACPI Source Language (ASL), compiler dịch sang AML binary, AML được nhúng vào DSDT/SSDT. OS có một interpreter chạy AML này ở runtime.

// ASL source, firmware engineer viết cái này
Device (PWRB) {             // Power Button device
    Name (_HID, "PNP0C0C")
    Method (_STA, 0) {
        Return (0x0F)       // Present, enabled, visible, functioning
    }
}

Device (SLPB) {             // Sleep Button
    Name (_HID, "PNP0C0E")
    Method (_PRW, 0) {      // Power Resource for Wake
        Return (Package() { 0x1D, 0x04 })  // GPE 0x1D, wakes from S4
    }
}

Khi OS muốn biết power button có hoạt động không, nó gọi _STA. Khi OS muốn biết sleep button có thể wake từ S4 không, nó gọi _PRW. Firmware không cần biết OS sẽ hỏi lúc nào, nó chỉ cần viết đúng các method này.

Power state: ACPI định nghĩa, OS quyết định, firmware mô tả

ACPI định nghĩa các Global System States từ S0 đến S5:

ACPI Global System States
State Ý nghĩa Ghi chú khi debug
S0 Working, hệ thống đang chạy S0ix / Modern Standby cũng nằm trong S0
S3 Suspend to RAM DRAM giữ dữ liệu, device/rail tắt, resume nhanh
S4 Hibernate State lưu xuống storage, hệ thống gần như tắt hoàn toàn
S5 Soft Off Tắt mềm, chỉ còn logic wake và power button
G3 Mechanical Off Mất nguồn hoàn toàn, không phải S-state trong cùng nghĩa với S0-S5

Khi OS muốn sleep, ví dụ vào S3, nó không chỉ tắt màn hình. Nó cần một chuỗi chuẩn bị:

  1. Gọi _PTS (Prepare To Sleep), firmware chuẩn bị platform
  2. Tắt device từng cái theo _PS3 của mỗi device
  3. Gọi method tắt power resource nếu platform có mô tả
  4. Ghi vào PM Control Register để chipset vào sleep state
  5. Khi có wake event, firmware chạy lại một phần khởi động
  6. OS gọi _WAK, firmware restore state cần thiết
  7. Device được bật lại theo _PS0

Đây là lý do firmware không nên “tắt máy trực tiếp” bằng một GPIO riêng lẻ trong flow bình thường. Mỗi bước trong ACPI power transition đều có lý do. Nếu bỏ qua _PS3 của một device, device đó có thể ở trạng thái undefined sau khi bật lại. Nếu bỏ qua _PTS, EC có thể không được thông báo về sleep state sắp xảy ra.

Firmware viết ACPI ở đâu trong boot flow?

ACPI tables được tạo và publish trong DXE phase, trước khi BDS load OS:

01 DXE

Platform DXE module

Đọc Setup option, board config, SKU và policy

02 Patch

Patch DSDT/SSDT

Tạo hoặc chỉnh ACPI table theo config thực tế

03 Install

InstallAcpiTable()

Gọi EFI_ACPI_TABLE_PROTOCOL->InstallAcpiTable()

04 BDS

Load OS

BDS load OS loader

05 OS

Read ACPI

OS đọc tables qua RSDP và interpret AML

ACPI tables được firmware tạo/publish trong DXE trước khi OS chạy

Điều quan trọng: ACPI table phản ánh Setup option. Nếu user tắt một feature trong BIOS Setup, firmware có thể patch _STA của device tương ứng để trả 0x00, device biến mất khỏi OS dù phần cứng vẫn có trên board.

Đây là nguồn gốc của nhiều bug khó giải thích: device không có trong Device Manager dù đo điện thì vẫn có điện. Không phải driver OS sai, là _STA đang trả 0x00 vì một Setup option nào đó đang tắt nó.

Kịch bản thực tế: sleep/wake sai sau khi thay BIOS

Một pattern rất hay gặp khi làm BIOS:

Triệu chứng: máy sleep OK, nhưng sau resume touchpad/USB mất

Cách debug đúng không phải cài lại driver OS. Mà là đi theo ACPI.

Bước 1: Xác định device nào mất sau resume

Device Manager hoặc lspci, lsusb, dmesg trên Linux có thể giúp xác định device nào có warning hoặc không quay lại sau resume.

Bước 2: Dump ACPI tables

# Linux
sudo acpidump -o acpi.dat
acpixtract acpi.dat
iasl -d DSDT.dat SSDT*.dat

Bước 3: Tìm method liên quan device đó

Tìm _PS0_PS3 của device trong AML đã decompile. Kiểm tra:

  • Power sequence có đúng không: rail → delay → clock → reset
  • GPIO state sau resume có được restore không
  • EC command có được gửi lại không

Bước 4: Kiểm tra _PRW của device

// _PRW không đúng có thể gây instant wake
Method (_PRW, 0) {
    Return (Package() { 0x1D, 0x03 })  // GPE, sleep state
}

Nếu GPE trong _PRW bị active trước khi sleep, máy sẽ wake ngay lập tức sau khi vừa sleep.

Checklist debug sleep/wake và ACPI

SMM và ACPI: hai tầng khác nhau, không phải đối thủ

Để kết lại câu hỏi ban đầu: SMM và ACPI không cạnh tranh nhau. Chúng có vai trò khác nhau.

SMM xử lý service bảo mật nhỏ, bảo vệ resource, xử lý event mà OS không nên biết. Nó chạy nhanh và không nên làm những việc lớn như quản lý power state bình thường.

ACPI là hợp đồng giữa firmware và OS về toàn bộ hardware description và power management. Mọi thứ liên quan đến power state, device enumerate, sleep/wake đều phải đi qua ACPI model.

Trong shutdown bình thường, OS/OSPM là bên đọc _S5, chuẩn bị hệ thống, rồi yêu cầu chipset vào S5 bằng SLP_TYPSLP_EN.

Nếu là thermal emergency thật sự, platform thường dùng đường bảo vệ riêng như EC, PMIC, chipset thermal trip hoặc board-specific safety logic. Đó là cơ chế bảo vệ khẩn cấp, không phải flow shutdown ACPI bình thường.

Tóm tắt

  • ACPI là hợp đồng firmware viết, OS đọc, mô tả hardware, power state, và control method
  • AML là bytecode trong DSDT/SSDT, OS interpreter chạy ở runtime khi cần
  • Power state (S0-S5) được ACPI định nghĩa, OS quyết định, firmware mô tả và hỗ trợ bằng table/method
  • Firmware không nên toggle GPIO để tắt máy vì bypass power sequence, không portable, và sai ownership trong flow bình thường
  • Debug device mất hoặc sleep/wake sai nên bắt đầu từ ACPI, dump table, decompile AML, kiểm tra method

Tài liệu tham khảo

Đọc tiếp

Thấy nội dung này hữu ích?

Lưu lại hoặc chia sẻ cho người cũng đang học firmware, BIOS/UEFI và embedded systems.

Nội dung liên quan

Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.

Đọc thêm về BIOS/UEFI

Khám phá các bài viết về BIOS/UEFI, embedded firmware, debugging và system-level thinking.