ExitBootServices là gì?
ExitBootServices là ranh giới chuyển giao từ firmware sang OS. Sau lời gọi này Boot Services bị tắt, OS nhận quyền kiểm soát memory và platform.
ExitBootServices() là điểm chuyển giao lớn giữa firmware boot-time environment và OS. Sau lời gọi này, Boot Services bị tắt hoàn toàn, OS nhận quyền kiểm soát memory và platform ở mức cao hơn.
Đây là ranh giới không thể quay lại. Sau
ExitBootServices(), firmware không thể gọi lại Boot Services, không thể install/locate protocol, và không thể allocate boot-time memory nữa.
Flow chuẩn của OS loader
GetMemoryMap()
Lấy memory map và MapKey hiện tại. Sau lần GetMemoryMap cuối cùng, tránh allocate thêm.
ExitBootServices()
Gọi với MapKey vừa lấy. Nếu fail với EFI_INVALID_PARAMETER, quay lại bước 01.
SetVirtualAddressMap()
Nếu OS dùng virtual mapping cho Runtime Services, báo địa chỉ virtual cho firmware runtime code.
OS runtime
Boot Services đã tắt. Chỉ còn Runtime Services qua gRT.
MapKey - nguồn gốc của lỗi phổ biến nhất
GetMemoryMap() trả về cùng lúc memory map và một MapKey - token đại diện cho trạng thái memory tại thời điểm đó. ExitBootServices() nhận MapKey này để verify memory map chưa thay đổi.
Nếu bất kỳ AllocatePool, FreePool, AllocatePages, hay FreePages nào xảy ra giữa GetMemoryMap() và ExitBootServices(), firmware sẽ tạo MapKey mới. Gọi ExitBootServices() với key cũ sẽ trả EFI_INVALID_PARAMETER.
Flow retry chuẩn (pseudo-code rút gọn - OS loader thật cần xử lý buffer/free/error kỹ hơn):
EFI_STATUS Status;
UINTN MemoryMapSize = 0;
EFI_MEMORY_DESCRIPTOR *MemoryMap = NULL;
UINTN MapKey;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
do {
// Lấy memory map - có thể cần gọi 2 lần để lấy đúng size
Status = gBS->GetMemoryMap(
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
if (Status == EFI_BUFFER_TOO_SMALL) {
// Allocate buffer - lưu ý: AllocatePool làm MapKey thay đổi
// Nên GetMemoryMap lại sau khi allocate
MemoryMapSize += DescriptorSize * 4; // thêm buffer dự phòng
gBS->AllocatePool(EfiLoaderData, MemoryMapSize, (VOID **)&MemoryMap);
continue;
}
// Gọi ExitBootServices - nếu fail vì MapKey stale thì loop lại
Status = gBS->ExitBootServices(ImageHandle, MapKey);
} while (Status == EFI_INVALID_PARAMETER);
Sau lần GetMemoryMap() cuối cùng thành công, OS loader nên gọi ExitBootServices() càng trực tiếp càng tốt - tránh mọi thao tác có thể làm thay đổi memory map.
Điều gì xảy ra khi ExitBootServices() được gọi?
Ở mức khái niệm, firmware sẽ kết thúc boot-time environment:
1. Signal EVT_SIGNAL_EXIT_BOOT_SERVICES
→ Runtime driver có cơ hội cleanup dependency vào Boot Services
2. Kết thúc Boot Services infrastructure
→ Sau khi ExitBootServices() thành công, gBS->... không còn hợp lệ
3. Chuyển quyền kiểm soát boot-time memory cho OS
→ OS có thể reclaim EfiBootServicesCode/Data
EVT_SIGNAL_EXIT_BOOT_SERVICES là event đặc biệt mà runtime driver có thể đăng ký nếu cần dọn dẹp dependency vào Boot Services trước khi Boot Services bị tắt:
// Runtime driver đăng ký trong entry point
EFI_EVENT ExitBootServicesEvent;
gBS->CreateEventEx(
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
MyExitBootServicesHandler,
NULL,
&gEfiEventExitBootServicesGuid,
&ExitBootServicesEvent
);
// Handler chạy khi ExitBootServices() được gọi
VOID EFIAPI
MyExitBootServicesHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
// Cleanup mọi thứ phụ thuộc vào Boot Services
// Tắt timer, close event, release boot-time resource
// Handler nên chạy ngắn, tránh allocate/wait/gọi Boot Services phức tạp.
// Sau khi ExitBootServices() hoàn tất, không được gọi gBS nữa.
}
Trách nhiệm sau ExitBootServices
| Mục | Giá trị | Ghi chú |
|---|---|---|
| Firmware runtime driver | Cleanup trong EVT_SIGNAL_EXIT_BOOT_SERVICES nếu cần | Close event, release boot-time resource, dừng dùng gBS. |
| Firmware runtime driver | Update pointer trong EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE | Gọi ConvertPointer() cho mọi pointer nội bộ sau SetVirtualAddressMap. |
| OS loader | Có thể gọi SetVirtualAddressMap() sau ExitBootServices | Nếu OS dùng virtual mapping cho Runtime Services, báo địa chỉ virtual cho firmware runtime code. Chỉ gọi một lần. |
| OS | Reclaim EfiBootServicesData/Code | Vùng memory boot services có thể được OS dùng lại sau ExitBootServices. |
Khi debug ExitBootServices fail
Nếu ExitBootServices() trả lỗi hoặc treo, nguyên nhân thường là:
EFI_INVALID_PARAMETER→ MapKey stale hoặc ImageHandle/parameter không hợp lệ. Nguyên nhân phổ biến nhất là có allocate/free sauGetMemoryMap().- Hang, không return →
EVT_SIGNAL_EXIT_BOOT_SERVICEShandler của một driver nào đó bị treo - thường là do handler gọi Boot Services phức tạp bên trong.
Trường hợp hang thường khó debug nhất - cần xác định driver nào register handler và handler đó đang làm gì (thường là gọi Boot Services không hợp lệ bên trong handler).
Checklist ExitBootServices
Câu hỏi tự kiểm tra
- MapKey trong
GetMemoryMap()dùng để làm gì? - Tại sao không được allocate memory giữa
GetMemoryMap()vàExitBootServices()? ExitBootServices()trảEFI_INVALID_PARAMETER- nguyên nhân là gì?EVT_SIGNAL_EXIT_BOOT_SERVICEShandler không được làm gì?- Sau
ExitBootServices()success, OS có thể reclaim loại memory nào? SetVirtualAddressMap()được gọi khi nào và bao nhiêu lần?- Runtime driver cần đăng ký những event nào liên quan đến ExitBootServices?
Bài liên quan
Nguồn tham khảo public
- UEFI Specification 2.11 - ExitBootServices
- UEFI Specification 2.11 - SetVirtualAddressMap
- EDK II - OvmfPkg OS loader reference
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.
TSL là gì?
Giải thích Transient System Load phase trong UEFI boot flow và vai trò của OS loader trước ExitBootServices.
Runtime sau ExitBootServices là gì?
Giải thích firmware còn lại gì sau khi OS gọi ExitBootServices và vì sao Runtime Services vẫn quan trọng.
UEFI Memory Map là gì?
Quicknote giải thích UEFI Memory Map và cách đọc nhanh.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.