UEFI Boot Flow: từ Reset Vector đến ExitBootServices

Không phải học để thuộc tên phase. Học boot flow để biết máy đang chết ở đâu, và debug theo hướng nào: từ SEC đến Runtime.

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

Có những lỗi nhìn từ bên ngoài rất giống nhau: máy bật nguồn nhưng màn hình đen, logo vendor hiện lên rồi reset, SSD thấy trong setup nhưng không có trong boot menu, Windows Boot Manager có đó nhưng bấm vào lại quay về màn hình boot.

Với người dùng, tất cả chỉ là “máy không boot”.

Nhưng với firmware engineer, những lỗi đó nằm ở những lớp hoàn toàn khác nhau. Có lỗi chết từ rất sớm, khi DRAM còn chưa được khởi tạo. Có lỗi xảy ra lúc firmware đang load driver. Có lỗi chỉ xuất hiện khi BDS đọc Boot#### trong NVRAM. Có lỗi lại nằm ở ranh giới cuối cùng, khi OS loader gọi ExitBootServices.

Đây là lý do học UEFI Boot Flow không phải để thuộc lòng tên phase. SEC, PEI, DXE, BDS, TSL hay Runtime chỉ có ý nghĩa khi bạn biết mỗi phase đang có tài nguyên gì, đang dựng phần nào của hệ thống, và lỗi ở đó thì debug theo hướng nào.

Công việc của mình là custom BIOS cho hệ thống POS, kiosk và terminal thanh toán. Boot fail ở môi trường đó không phải kiểu “để từ từ xem”. Nếu máy chết ở cửa hàng lúc giờ cao điểm, điều quan trọng nhất là xác định thật nhanh: firmware đang chết ở phase nào?

Bài này sẽ đi từ Reset Vector đến ExitBootServices theo đúng góc nhìn đó. Không phải học boot flow như một sơ đồ để nhớ, mà học như một bản đồ debug.

Vì sao cần chia phase?

Vấn đề căn bản: khi CPU vừa reset, hệ thống gần như không có gì để làm việc. DRAM chưa được khởi tạo, chipset chưa được cấu hình, không có stack bình thường, không có heap. Firmware không thể làm tất cả mọi thứ ngay từ đầu.

UEFI giải quyết bằng cách chia boot thành các phase, mỗi phase dựng nền cho phase sau:

01 SEC

Security Phase

CPU reset. Tài nguyên gần như zero. Dựng temporary RAM để PEI chạy được

02 PEI

Pre-EFI Init

Khởi tạo DRAM. Dựng HOB list. Bàn giao dữ liệu platform cho DXE

03 DXE

Driver Execution

Load driver. Publish protocol. Enumerate device. Dựng toàn bộ hệ sinh thái firmware

04 BDS

Boot Device Select

Đọc BootOrder và Boot####. Resolve Device Path. Load OS loader

05 TSL

Transient System Load

OS loader đang chạy. Chuẩn bị ExitBootServices

06 Runtime

Runtime Phase

OS tiếp quản. Chỉ còn Runtime Services: variable, time, reset

UEFI/PI boot flow: mỗi phase có tài nguyên riêng và dựng nền cho phase sau

Điều quan trọng để nhớ: lỗi ở mỗi phase biểu hiện khác nhau. Không thể debug BDS nếu vấn đề thật sự nằm ở PEI. Và không thể debug DXE driver nếu root cause là HOB sai từ PEI.


SEC: khi hệ thống chưa có gì

Ngay sau khi CPU reset, hệ thống ở trạng thái cực kỳ giới hạn: DRAM chưa được khởi tạo, stack bình thường chưa tồn tại. Firmware phải bắt đầu chạy trong điều kiện này.

SEC làm đúng một việc: thiết lập môi trường tối thiểu để PEI có thể chạy.

Reset vector

Thiết lập Temporary RAM (cache-as-RAM hoặc internal SRAM)

Xác minh firmware sơ bộ nếu platform yêu cầu

Chuyển quyền sang PEI Core

SEC không làm nhiều chính sách. Nó là đoạn code “dọn đường” để PEI có chỗ đứng.

Khi nào nghi SEC?

Nếu board chết rất sớm, không có POST code, không có serial log, reset loop ngay từ đầu. Lúc này chỉ có POST code LED hoặc hardware debug port mới cho thông tin, vì các công cụ thông thường chưa có.


PEI: dựng nền tảng cho DXE

PEI là phase dựng hạ tầng tối thiểu để DXE có thể chạy. Nhiệm vụ quan trọng nhất: khởi tạo DRAM. Khi RAM chưa sẵn sàng, firmware không thể load driver, không thể tạo service, không thể làm gì nhiều hơn mức tối thiểu.

Ngoài memory init, PEI còn tạo HOB (Hand-Off Block), các khối dữ liệu mô tả memory map, firmware volume, boot mode và thông tin platform để bàn giao cho DXE:

PEI tạo HOB list:
├─ Memory Resource HOB: DXE biết RAM ở đâu, bao nhiêu
├─ Firmware Volume HOB: DXE dispatcher biết tìm driver ở đâu
├─ GUID HOB (platform-specific): thông tin board, silicon, policy
└─ Boot Mode: Normal / S3 Resume / Recovery

HOB là cầu nối giữa PEI và DXE. DXE không biết gì về hardware, trừ những gì PEI đã ghi vào HOB. Nếu HOB thiếu hoặc sai, DXE có thể vẫn khởi động nhưng với dữ liệu nền tảng không đúng.

Khi nào nghi PEI?

  • POST code dừng ở PEI range
  • Reset loop sau memory training
  • DXE bắt đầu chạy nhưng thiếu driver hoặc resource. Đừng vội sửa DXE, kiểm tra HOB list trước.

DXE: hệ sinh thái driver và service

Sau khi memory sẵn sàng và HOB có đủ dữ liệu, DXE Core bắt đầu dựng “hệ sinh thái” của UEFI: load driver, tạo handle database, publish protocol, enumerate device.

DXE Dispatcher scan firmware volume, kiểm tra DEPEX (dependency expression) của từng driver, và chỉ dispatch driver khi tất cả protocol nó cần đã được install. Điều này có nghĩa là thứ tự dispatch phụ thuộc vào dependency chain, không phải vào vị trí trong FV.

DXE Dispatcher loop:
  Scan FV → kiểm tra DEPEX
  Protocol chưa có: driver chờ
  Protocol đã có: dispatch → driver install protocol mới → unlock driver đang chờ
  Lặp lại đến khi không còn gì để dispatch → chuyển sang BDS

Khi nào nghi DXE?

Device không lên boot menu không có nghĩa là BDS sai. Hãy kiểm tra theo thứ tự:

Checklist debug DXE


BDS: từ firmware sang OS loader

BDS đọc boot option từ NVRAM, connect device cần thiết, parse Device Path, load file .efi và chuyển quyền cho OS loader.

Mỗi boot option lưu trong NVRAM dưới dạng biến Boot####:

BootOrder: 0000, 0001, 0002
Boot0000: Windows Boot Manager
  ├─ Device Path: HD(1,GPT,...)/File(\EFI\Microsoft\Boot\bootmgfw.efi)
  └─ Attributes: LOAD_OPTION_ACTIVE
Boot0001: UEFI Shell
Boot0002: PXE Boot

BDS đọc BootOrder, thử từng option. Với mỗi option, nó resolve Device Path (connect controller, tìm ESP), load file .efi, rồi gọi StartImage().

Khi nào nghi BDS?

SSD được DXE nhận nhưng Windows không boot. Trước khi nghi Windows Boot Manager, kiểm tra:

Checklist debug BDS


TSL: vùng chuyển tiếp trước OS

TSL là khoảng thời gian OS loader đã được BDS load và đang chạy, nhưng OS vẫn chưa hoàn toàn tiếp quản. Bootloader đang dùng UEFI services để đọc kernel, chuẩn bị memory, rồi gọi ExitBootServices().

ExitBootServices() là điểm không thể quay lại. Sau lời gọi này, Boot Services không còn hợp lệ và chỉ còn Runtime Services.

Lỗi TSL là một trong những lỗi khó debug nhất vì xảy ra ở ranh giới firmware và OS:

// Bootloader phải lấy memory map và gọi ExitBootServices
// với đúng MapKey. Nếu memory map thay đổi giữa hai bước: fail.
GetMemoryMap(&MapSize, MemMap, &MapKey, ...);
// Đừng allocate/free memory ở đây
ExitBootServices(ImageHandle, MapKey);  // MapKey phải khớp

Khi nào nghi TSL?

  • OS loader đã load xong nhưng kernel không lên
  • ExitBootServices() trả EFI_INVALID_PARAMETER
  • Lỗi xảy ra sau StartImage() thành công

Runtime: sau khi OS tiếp quản

Sau ExitBootServices(), OS kernel chạy. UEFI Boot Services không còn, nhưng Runtime Services vẫn có thể được gọi từ OS nếu được map đúng: đọc/ghi NVRAM variable, reset hệ thống, lấy thời gian.

Trên nhiều platform, đường đi thực tế của SetVariable là:

OS gọi SetVariable("BootOrder", ...)

Runtime Variable Service
  ↓ (nhiều platform)
SMM Variable Driver

SPI flash write

Với lỗi variable sau khi OS đã chạy, đặc biệt là BootOrder hoặc efibootmgr ghi không có tác dụng, cần kiểm tra Runtime variable path, SMM variable driver và SPI flash. Còn với setting đổi từ Setup rồi reboot mất, vẫn phải kiểm tra cả HII save flow, NVRAM và module consumer.


Debug theo triệu chứng

Khi gặp sự cố boot, câu hỏi đầu tiên không phải là “lỗi gì” mà là “chết ở phase nào”:

Debug boot theo triệu chứng
Triệu chứng Phase nên nghi ngờ Nên kiểm tra gì
Không có log, reset loop sớm SEC DRAM chưa init, chỉ có POST code LED hoặc hardware trace.
Treo ở PEI POST code, reset sau memory training PEI Memory init, HOB, PEI → DXE handoff.
Device không xuất hiện trong boot menu DXE Driver dispatch, DEPEX, Driver Binding, protocol chain.
Boot menu có nhưng OS không boot BDS BootOrder, Boot####, Device Path, LoadImage.
OS loader chạy nhưng kernel không lên TSL ExitBootServices, memory map key, loader fail.
Setting lưu không tác dụng sau reboot Runtime / HII / NVRAM Tùy setting được đổi từ OS hay từ Setup UI. Kiểm tra cả Runtime path và HII save flow.

Tóm tắt

UEFI boot flow không phải chạy từ đầu đến cuối như một hàm main(). Nó là chuỗi phase, mỗi phase có môi trường riêng, nhiệm vụ riêng và cách fail riêng.

01 SEC

Temporary RAM

CPU reset, dựng môi trường cực sớm, gọi PEI

02 PEI

Memory init

Khởi tạo DRAM, tạo HOB, bàn giao cho DXE

03 DXE

Driver model

Dispatcher, protocol, handle database, driver binding

04 BDS

Boot option

BootOrder, Boot####, Device Path, LoadImage, StartImage

05 TSL

OS loader

GetMemoryMap, ExitBootServices

06 Runtime

Runtime Services

NVRAM variable, time, reset, SMM path tùy platform

Tóm tắt UEFI boot flow theo góc nhìn debug

Khi debug, việc đầu tiên không phải là đọc source code chi tiết, mà là xác định chính xác firmware đang chết ở đâu trong chuỗi này. Khi biết phase, bạn biết lớp nào cần nhìn và lớp nào có thể bỏ qua.


Tài liệu tham khảo

Đọc tiếp

Mỗi phase trong bài này có note chuyên sâu hơn:

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.