2 điểm bởi GN⁺ 2025-10-26 | 1 bình luận | Chia sẻ qua WhatsApp
  • Bài giải thích kỹ thuật mô tả theo từng bước quá trình từ lúc nhấn nút nguồn trên máy tính cho đến khi Linux kernel được thực thi
  • Trình bày cụ thể cách CPU khởi động ở real mode rồi chuyển sang protected modelong mode
  • Mô tả chi tiết vai trò và nguyên lý hoạt động của từng giai đoạn như firmware BIOS/UEFI, bootloader (GRUB), giải nén kernel và tái định vị địa chỉ
  • Giải thích các khái niệm cốt lõi cần cho quá trình khởi tạo kernel như memory mapping, interrupt, page table, kASLR kèm các ví dụ ngắn gọn
  • Việc hiểu cơ chế nội bộ của quá trình khởi động Linux mang lại góc nhìn về kiến trúc hệ thống, bảo mật và tối ưu hiệu năng

Part 1 — Từ nút nguồn đến lần thực thi đầu tiên của kernel

  • Khi nhấn nút nguồn, CPU được reset về real mode và thực thi lệnh khởi tạo đầu tiên

    • Real mode là một cơ chế địa chỉ đơn giản tồn tại từ thời 8086, tính địa chỉ vật lý bằng cách kết hợp segmentoffset
    • Ví dụ: physical_address = (segment << 4) + offset
    • Sau khi reset, CPU nhảy tới địa chỉ 0xFFFFFFF0 (reset vector) và chuyển quyền điều khiển cho firmware
  • Register là các ô lưu trữ siêu tốc bên trong CPU, gồm CS (code segment), IP (instruction pointer), v.v.

    • CS chỉ vị trí của mã hiện tại, còn IP trỏ tới lệnh sẽ được thực thi tiếp theo

BIOS và UEFI

  • BIOS là firmware kiểu cũ; sau POST (power-on self test), nó kiểm tra thứ tự khởi động và tìm đĩa có thể boot
    • Một đĩa có thể boot sẽ có hai byte cuối của sector 512 byte đầu tiên là 0x55AA
    • BIOS sao chép sector này tới địa chỉ 0x7C00 rồi nhảy tới đó để thực thi
  • UEFI là công nghệ thay thế hiện đại, có thể hiểu trực tiếp filesystem và nạp các chương trình boot lớn hơn
    • Khác với BIOS, nó không bị ràng buộc bởi giới hạn “sector đầu tiên”, đồng thời truyền cho hệ điều hành nhiều thông tin hệ thống phong phú hơn

Bootloader

  • Bootloader là chương trình nạp kernel vào bộ nhớ và chuẩn bị để thực thi
    • Phổ biến nhất là GRUB, nó đọc file cấu hình rồi nạp kernel và initial ramdisk (initrd) vào bộ nhớ
    • File kernel gồm một chương trình thiết lập nhỏ cho real modephần thân kernel đã được nén
    • GRUB ghi thông tin như vị trí kernel, command line, vị trí initrd vào cấu trúc setup header rồi nhảy tới mã thiết lập của kernel

Chương trình thiết lập (setup code)

  • Trước khi kernel chạy, nó tạo ra một không gian làm việc có thể dự đoán được
    • Căn chỉnh các segment register (CS, DS, SS) và xóa direction flag để thao tác sao chép bộ nhớ hoạt động nhất quán
    • Tạo stack để lưu dữ liệu tạm trong lúc gọi hàm
    • Khởi tạo vùng BSS (không gian biến toàn cục phải bắt đầu bằng 0) về 0
  • Nếu có tùy chọn earlyprintk, nó có thể cấu hình cổng serial để in ra các thông điệp debug sớm
  • Nó yêu cầu firmware cung cấp bản đồ RAM (e820) để biết vùng nhớ nào khả dụng và vùng nào được dành riêng
  • Khi mọi thứ đã sẵn sàng, nó gọi main — hàm C đầu tiên — rồi bước vào giai đoạn chuyển mode

Interrupt

  • Interrupt là cơ chế cho phép CPU tạm dừng công việc hiện tại để xử lý một sự kiện khẩn cấp
    • Các sự kiện phần cứng như phím nhấn hoặc timer là ví dụ điển hình
    • Maskable interrupt có thể bị chặn tạm thời, còn NMI (Non-Maskable Interrupt) thì luôn được xử lý
    • Trong lúc chuyển mode, interrupt sẽ bị chặn tạm thời để tránh các sự cố không mong muốn

Part 2 — Từ real mode sang 32-bit, rồi 64-bit

  • Linux hiện đại hoạt động trong long mode của kiến trúc x86_64
    • Cần chuyển tuần tự theo các bước: real mode → protected mode → long mode

Protected mode

  • Đây là chế độ 32-bit được giới thiệu để vượt qua các giới hạn của thập niên 1980, với hai cấu trúc cốt lõi
    • GDT (Global Descriptor Table): định nghĩa địa chỉ bắt đầu, kích thước và quyền truy cập của segment
      • Linux dùng flat model để đơn giản hóa toàn bộ không gian 32-bit thành một vùng liên tục duy nhất
    • IDT (Interrupt Descriptor Table): lưu địa chỉ của các handler sẽ được gọi khi có interrupt
      • Trong lúc boot chỉ nạp một IDT tối thiểu, rồi cài đặt IDT đầy đủ sau khi kernel khởi tạo xong

Quá trình chuyển mode

  • Mã thiết lập trước tiên sẽ vô hiệu hóa interrupt, dừng chip PIC, kích hoạt đường A20, và khởi tạo bộ đồng xử lý toán học
    • Đường A20 là một cơ chế lịch sử để giải quyết vấn đề quấn địa chỉ ở mốc 1MB
  • Sau khi nạp GDT và IDT tối thiểu, nó đặt bit PE của thanh ghi CR0 và thực hiện far jump
    • Từ đây CPU đi vào protected mode, rồi các segment và stack pointer được cấu hình lại theo hệ thống địa chỉ mới

Control registers

  • CR0: kích hoạt protected mode
  • CR3: lưu địa chỉ cấp cao nhất của page table
  • CR4: kích hoạt các tính năng mở rộng như PAE

Chuẩn bị vào long mode

  • Để chuyển sang chế độ 64-bit, cần hai điều kiện
    • Bật paging: thực hiện ánh xạ giữa địa chỉ ảo và địa chỉ vật lý
    • Đặt bit LME (Long Mode Enable) trong thanh ghi EFER
  • Page table ánh xạ các trang theo đơn vị 4KB; ở giai đoạn boot ban đầu, nó thường được cấu hình đơn giản bằng identity map theo đơn vị 2MB

Quy trình bật paging

  • Bật tính năng PAE trong CR4 và tạo page table tối thiểu để bao phủ vùng địa chỉ thấp theo các khối 2MB
  • Ghi địa chỉ của bảng cấp cao nhất vào CR3 rồi bật paging
  • Đặt bit LME trong EFER và nhảy sang mã 64-bit để đi vào long mode
  • Khi địa chỉ và register đã được mở rộng lên 64-bit, kernel đã sẵn sàng để thực thi

Part 3 — Giải nén kernel, chỉnh lại địa chỉ và tự di chuyển

  • Lúc này CPU đã ở chế độ 64-bit, và trong bộ nhớ đang có ảnh kernel đã được nén
    • Một stub 64-bit nhỏ sẽ đảm nhận việc giải nén kernel và điều chỉnh địa chỉ

Dọn dẹp ban đầu và thiết lập cơ chế an toàn

  • Stub tính toán vị trí thực tế mà nó đang chạy; nếu kernel có nguy cơ chồng lấn, nó sẽ tự sao chép (self-relocation) sang một vị trí an toàn
  • khởi tạo vùng BSS của chính mình và nạp một IDT đơn giản (bao gồm handler cho page fault và NMI)
    • Khi xảy ra page fault, nó có thể lập tức bổ sung ánh xạ còn thiếu để phục hồi
  • Nó tạo identity mapping cho các vùng cần thiết như kernel, boot parameter, command line buffer, v.v.

Giải nén kernel

  • Hàm extract_kernel được thực thi để giải nén kernel
    • Hỗ trợ nhiều thuật toán nén như gzip, xz, zstd, lzo
    • Sau khi giải nén, nó đọc ELF header để sao chép các section mã/dữ liệu tới đúng địa chỉ
  • Nếu địa chỉ mà kernel được build khác với địa chỉ được nạp thực tế, nó sẽ thực hiện relocation
    • Các lệnh hoặc con trỏ chứa địa chỉ sẽ được sửa lại cho khớp với vị trí thực trong bộ nhớ
  • Khi mọi thứ đã sẵn sàng, nó nhảy tới hàm start_kernel, và quá trình khởi tạo kernel chính thức bắt đầu

Cơ chế tự dịch chuyển của kernel (kASLR)

  • kASLR (Kernel Address Space Layout Randomization) ngẫu nhiên hóa địa chỉ vật lý và địa chỉ ảo của kernel để tăng độ khó cho tấn công
    • Trong lúc boot, nó chọn ngẫu nhiên hai mốc cơ sở
      • Base vật lý: địa chỉ RAM nơi kernel thực sự được đặt
      • Base ảo: điểm bắt đầu của địa chỉ ảo mà kernel sẽ sử dụng
  • Quá trình lựa chọn
    • Tạo danh sách các vùng cần được bảo vệ như bootloader, initrd, command line buffer, v.v.
    • Quét bản đồ bộ nhớ từ firmware để tìm các khoảng trống đủ lớn
    • Dùng entropy thu được từ các lệnh sinh số ngẫu nhiên phần cứng, v.v. để chọn một slot ngẫu nhiên
  • Nếu không có vùng phù hợp, nó quay về địa chỉ mặc định; với tùy chọn nokaslr, việc ngẫu nhiên hóa sẽ bị vô hiệu hóa

Tóm tắt thuật ngữ

  • Hexadecimal (hệ 16): được biểu diễn bằng tiền tố 0x, thuận tiện cho cấu trúc bit phần cứng và căn chỉnh
  • Register: bộ nhớ tạm bên trong CPU (CS, DS, SS, IP, SP, v.v.)
  • Segment/Offset: cách tính địa chỉ trong real mode (segment * 16 + offset)
  • BIOS/UEFI: firmware phụ trách khởi tạo hệ thống và nạp chương trình boot
  • Bootloader (GRUB): nạp kernel và truyền thông tin hệ thống
  • Stack/BSS: vùng lưu tạm cho hàm và vùng biến toàn cục được khởi tạo bằng 0
  • Interrupt/NMI: cơ chế xử lý sự kiện phần cứng/phần mềm
  • GDT/IDT: bảng định nghĩa segment và interrupt
  • A20 Line: công tắc ngăn hiện tượng quấn địa chỉ 1MB
  • Protected Mode/Long Mode: chế độ thực thi 32-bit và 64-bit
  • Paging/Page Tables: địa chỉ ảo và địa chỉ vật lý

1 bình luận

 
GN⁺ 2025-10-26
Ý kiến Hacker News
  • Bài viết thật sự rất hay. Vài tháng trước tôi cũng đã viết về quá trình khởi động Linux, nhưng tập trung nhiều hơn vào khía cạnh I/O đĩa (trên đĩa có gì và chúng được nạp như thế nào)
    Có thể xem bài của tôi tại Booting x86-64
  • Trong mã nguồn trang có đoạn code này
    <!-- Femboy Mode Button - Hidden on Mobile -->
    <button class="rave-button" id="raveButton" onclick="toggleRaveMode()" title="Femboy Mode" style="display: none;">
      <span class="button-text">uwu</span>
    </button>
    
    Kiểu như “cái gì đây vậy”
    • Vẫn là tính năng đang được phát triển
  • UEFI là giao diện do firmware triển khai. Tức là nó không phải bản thân firmware, mà là giao diện chuẩn để giao tiếp với firmware
    Cách nói “UEFI khởi động máy” hơi dùng thuật ngữ chưa chính xác. Thực tế là firmware khởi động máy, còn chúng ta giao tiếp với firmware thông qua UEFI
    Bài này đã lược bỏ khá nhiều phần thú vị của firmware hiện đại. Ví dụ, khi gọi ExitBootServices() thì hệ thống đã vào long mode rồi. Không cần phải đi qua quá trình chuyển đổi real/protected mode nữa
    • Tôi muốn biết có thể đọc thêm về những nội dung này ở đâu
  • Tôi từng thắc mắc liệu nút nguồn có thực sự bật CPU trực tiếp hay không. Có lẽ Intel Management Engine (hoặc cơ chế tương tự của AMD) luôn bật sẵn và nhận tín hiệu từ nút nguồn để khởi động CPU
    • Tôi nghĩ vai trò đó do Embedded Controller (EC) đảm nhiệm. Đây là phần hoạt động trước khi bootloader khởi động CPU
      Trên Chromebook, phần này được công bố mã nguồn mở cùng với bootloader coreboot
      Tài liệu liên quan có tại Chromium EC Zephyr README
  • Tôi đang tìm một phiên bản bài viết chi tiết hơn so với bài này. Tôi không muốn phải đọc trọn bộ datasheet vi xử lý, nhưng sẽ rất tốt nếu có tài liệu đi sâu hơn tới giai đoạn trước cả UEFI/BIOS
  • Bài viết thú vị đấy, nhưng đồng thời tôi cũng tự hỏi tại sao lại cần giải thích cả về hệ thập lục phân (HEX). Tôi nghĩ người đọc tới mức này chắc hẳn phải biết rồi chứ
    Một điều nữa tôi tò mò là tại thời điểm nhấn nút nguồn vật lý thì quá trình đó được nối tới reset vector như thế nào. Đó là kiểu phép thuật của phần cứng và mạch điện tử
    • HN không chỉ có dân chuyên IT đọc. Có thể có người tò mò về quá trình khởi động Linux nhưng không rành hoặc đã quên khái niệm hệ thập lục phân
  • Chủ đề thì thú vị, nhưng cảm giác quá hướng tới người mới bắt đầu
    • Khi thấy những câu như “khi nguồn điện ổn định, CPU được reset về real mode”, tôi tự hỏi liệu bà tôi có đủ thành thạo để hiểu được mấy thứ này không
    • Ở đại học tôi học về phân tích độc giả (audience analysis), và việc quyết định nên giả định sẵn kiến thức nào, cũng như nên giải thích đầy đủ những thuật ngữ hay chữ viết tắt nào, là rất quan trọng. Trong viết kỹ thuật, đây là một kiểu nghệ thuật
  • Đọc trên di động khá khó. Màu chữ quá nhạt
    • Ngay cả trên trình duyệt desktop thì phần tạo kiểu cũng không ổn. Dùng reader mode của Firefox hoặc Firefox Mobile sẽ dễ đọc hơn nhiều
    • Nó trông hơi giống kiểu thiết kế tự giễu
  • GRUB có được nhắc tới, nhưng không được nói kỹ
    Về phần này, tài liệu cấu trúc đĩa của Pixelbeat khá hữu ích
  • Bài này làm tôi nhớ đến lần trước đi phỏng vấn kỹ thuật ở Facebook. Khoảng năm 2010, đó là cuộc phỏng vấn qua điện thoại cho vị trí Production Engineer, và tôi được hỏi “hãy giải thích quá trình khởi động của một máy chủ Linux”
    Ngoài gợi ý là hãy giải thích sâu hơn thì tôi không nhận được thêm trợ giúp nào. Cuối cùng tôi đã không chuyển tới Dublin, và thôi thì mấy chuyện surveillance capitalism các kiểu, cứ coi như chùm nho vẫn còn xanh vậy