SMM là gì?
SMM là chế độ CPU đặc biệt để firmware xử lý tác vụ nhạy cảm ngoài tầm kiểm soát OS. Hiểu SMM giúp debug variable write treo, flash fail và security issue.
SMM (System Management Mode) là chế độ CPU đặc biệt dùng cho firmware xử lý các tác vụ rất nhạy cảm bên ngoài tầm kiểm soát trực tiếp của OS. Code SMM chạy trong SMRAM - vùng memory được hardware/chipset bảo vệ. Sau khi SMRAM được cấu hình và lock đúng trong một boot session bình thường, software ngoài SMM không thể mở lại hoặc đọc/ghi trực tiếp vào vùng này.
SMM thường dùng cho: power management, chipset workaround, secure variable write, flash protection, và một số OEM feature. Vì quyền rất cao và cô lập với OS, SMM cũng là vùng phải thiết kế cực kỳ cẩn thận về security.
Flow SMM
SMI xảy ra
Software SMI, GPIO, timer, chipset event - CPU nhận tín hiệu vào SMM.
CPU save state
Hardware tự động save CPU state cần thiết vào SMRAM Save State Area.
SMM handler chạy
CPU chạy handler trong SMM/SMRAM, tách khỏi execution context thông thường của OS/DXE.
Resume
Lệnh RSM restore CPU state và trả quyền về context trước khi SMI.
SMRAM - vùng memory đặc biệt
SMRAM là vùng RAM được chipset bảo vệ phần cứng:
- Chỉ CPU khi đang ở SMM mode mới có thể truy cập
- Sau khi SMRAM được lock (thường cuối DXE/trước ExitBootServices), software ngoài SMM không thể mở lại trong boot session bình thường
- Sau khi SMRAM được cấu hình và lock đúng, OS, DXE driver và hypervisor thông thường không thể đọc/ghi trực tiếp vào SMRAM
- Kích thước thường vài MB, tùy platform
Physical Memory Layout:
┌─────────────────────────┐
│ OS Memory (DRAM) │ ← OS có thể truy cập
├─────────────────────────┤
│ SMRAM │ ← Chỉ SMM mode mới đọc/ghi được
│ ├─ SMM Handler code │
│ ├─ SMM Save State │ ← CPU register khi enter SMM
│ └─ SMM data/stack │
├─────────────────────────┤
│ Firmware regions │
└─────────────────────────┘
SMM driver trong EDK II
Trong EDK II, DXE_SMM_DRIVER được SMM infrastructure (SMM IPL / SMM Core) phát hiện và nạp vào SMRAM trong DXE phase:
DXE phase:
SMM IPL / SMM Core phát hiện DXE_SMM_DRIVER trong FV
→ Module được nạp vào SMRAM
→ SMM driver được khởi tạo trong SMM environment
→ Driver dùng gSmst / EFI_SMM_SYSTEM_TABLE2 để đăng ký SMI handler
(qua gSmst->SmiHandlerRegister hoặc SMM dispatch protocol)
Runtime khi SMI xảy ra:
→ CPU enter SMM
→ SMM handler chạy từ SMRAM
→ Handler dùng SMM services/protocols - không dùng gBS hoặc DXE services
→ RSM → return
Các SMM interface quan trọng trong EDK II:
| Mục | Giá trị | Ghi chú |
|---|---|---|
| EFI_SMM_BASE2_PROTOCOL | Bridge tới SMM services | Dùng InSmm() để kiểm tra có đang ở SMM context không, GetSmstLocation() để lấy EFI_SMM_SYSTEM_TABLE2. |
| EFI_SMM_SYSTEM_TABLE2 (gSmst) | SMM System Table | Chứa SMM services như SmiHandlerRegister, SmmLocateProtocol, SmmAllocatePool. Tương tự EFI_SYSTEM_TABLE nhưng cho SMM. |
| gSmst->SmiHandlerRegister() | Đăng ký SMI handler theo GUID | Thường dùng cho SMM communication handler. Handler được gọi khi GUID tương ứng được trigger. |
| EFI_SMM_COMMUNICATION_PROTOCOL | DXE ↔ SMM communication | DXE driver dùng để gửi dữ liệu sang SMM handler qua communication buffer. |
| EFI_SMM_CPU_PROTOCOL | Đọc CPU Save State | SMM handler dùng để đọc register của CPU tại thời điểm SMI xảy ra. |
SMM Communication Buffer
DXE driver và SMM handler không thể gọi nhau trực tiếp - giao tiếp phải qua communication buffer:
// DXE side: allocate communication buffer ở non-SMRAM memory
// Buffer phải nằm ngoài SMRAM và thuộc vùng được platform cho phép
// Memory type phụ thuộc driver lifetime; ví dụ boot-time dùng EfiBootServicesData
EFI_SMM_COMMUNICATE_HEADER *Header;
UINTN Size;
gBS->AllocatePool(EfiBootServicesData, BufferSize, (VOID **)&Header);
// Fill header với GUID của handler và data
CopyGuid(&Header->HeaderGuid, &gMySmHandlerGuid);
Header->MessageLength = sizeof(MY_SMM_DATA);
// ... fill data vào Header->Data ...
// Trigger communication - gửi buffer sang SMM
Size = OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data) + Header->MessageLength;
SmmCommunication->Communicate(SmmCommunication, Header, &Size);
// SMM side: handler nhận và validate trước khi dùng
EFI_STATUS EFIAPI
MySmHandler (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *Context,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
EFI_SMM_COMMUNICATE_HEADER *Header;
MY_SMM_DATA *Data;
// Validate pointer và size tối thiểu
if (CommBuffer == NULL || CommBufferSize == NULL ||
*CommBufferSize < OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)) {
return EFI_BAD_BUFFER_SIZE;
}
Header = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;
// Validate GUID và message length
if (!CompareGuid(&Header->HeaderGuid, &gMySmHandlerGuid) ||
Header->MessageLength < sizeof(MY_SMM_DATA)) {
return EFI_INVALID_PARAMETER;
}
// Validate CommBufferSize đủ chứa header + payload
// Tránh đọc vượt buffer khi Header->MessageLength bị attacker set bất thường
UINTN HeaderSize = OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data);
if (Header->MessageLength > *CommBufferSize - HeaderSize) {
return EFI_BAD_BUFFER_SIZE;
}
// Copy vào local SMRAM buffer để tránh TOCTOU
MY_SMM_DATA LocalData;
CopyMem(&LocalData, Header->Data, sizeof(MY_SMM_DATA));
// Xử lý từ LocalData - không đọc lại từ CommBuffer
Data = &LocalData;
return EFI_SUCCESS;
}
Security: những gì SMM handler phải làm
SMM có đặc quyền rất cao - code sai trong handler có thể bị khai thác:
| Mục | Giá trị | Ghi chú |
|---|---|---|
| Validate communication buffer | Bắt buộc | Buffer đến từ non-SMRAM, có thể bị OS modify. Kiểm tra size, range, GUID, MessageLength. Không tin data mù quáng. |
| Kiểm tra buffer không overlap SMRAM | Bắt buộc | Nếu buffer trỏ vào trong SMRAM, đây là attack vector. Phải reject ngay. |
| Copy vào local SMRAM buffer | Khuyến nghị mạnh | Sau khi validate, copy data cần xử lý vào local SMRAM buffer để tránh TOCTOU: OS có thể modify buffer sau khi validate nhưng trước khi handler dùng. |
| Không dùng Boot Services/DXE services trong SMM | Bắt buộc | SMM handler dùng SMM services từ gSmst và SMM protocols. Không gọi gBS như DXE driver. |
| Handler chạy ngắn | Khuyến nghị | SMI có thể làm gián đoạn CPU và ảnh hưởng latency toàn hệ thống. Handler kéo dài gây vấn đề latency và real-time behavior. |
| Không giữ lock quá lâu | Khuyến nghị | SMM lock dài có thể gây latency lớn, deadlock/livelock, hoặc block handler khác tùy thiết kế. |
Khi debug liên quan SMM
SMM bug thường khó thấy vì OS không trace được:
- Variable write treo → variable service trên nhiều platform đi qua SMM; SMM handler lỗi sẽ làm
SetVariable()không return - Flash update fail → SPI flash write thường protected bởi SMM; nếu handler sai thì write bị block
- System freeze ngắn theo chu kỳ → periodic SMI handler chạy quá lâu
- Security tool báo SMM vulnerability → communication buffer không validate đúng
Checklist SMM
Câu hỏi tự kiểm tra
- SMRAM khác với DRAM thông thường ở điểm nào?
- Tại sao SMRAM phải được lock trước
ExitBootServices()? - SMM communication buffer đến từ đâu và tại sao phải validate?
- SMM handler có thể gọi
gBS->AllocatePool()không? - Nếu
SetVariable()không return, nguyên nhân có thể là gì?
Bài liên quan
Nguồn tham khảo public
- UEFI PI Specification 1.9 - SMM
- EDK II MdeModulePkg - SMM infrastructure
- EDK II - SmmBase2Protocol.h
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.
SMM trong UEFI: System Management Mode từ góc debug
SMM không phải phase tuyến tính mà là isolated execution mode. Hiểu SMI trigger, SMRAM, handler timing, SmmReadyToLock và debug SetVariable không lưu được.
SMI là gì?
SMI là interrupt đưa CPU vào SMM để chạy handler. Có nhiều nguồn SMI: SW, GPIO, timer, chipset. Hiểu SMI giúp debug latency spike và SMM communication.
SMRAM là gì?
Giải thích SMRAM như vùng memory bảo vệ cho SMM: layout, open/closed/locked state, Save State và checklist debug protection.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.