Linux Kernel Boot Process¶
Page này mô tả quá trình boot từ góc nhìn của kernel: kernel nhận gì từ bootloader, tự khởi tạo thế nào và bàn giao cho user space ra sao. Cách dùng và cấu hình bootloader (U-Boot...) và các bước cụ thể theo từng board nằm ở phần Linux Embedded và Projects, page này chỉ link tới.
Tổng quan chuỗi boot¶
- BootROM: mã cố định trong SoC, nạp tầng boot đầu tiên từ flash/SD/QSPI...
- Bootloader (có thể nhiều tầng, ví dụ SPL/FSBL rồi U-Boot): khởi tạo DRAM và phần cứng tối thiểu, nạp kernel, device-tree (DTB), initramfs vào RAM rồi nhảy vào kernel.
- Kernel: khởi tạo CPU, bộ nhớ, các subsystem, driver; mount root
filesystem; chạy
init. - init: tiến trình đầu tiên (PID 1), khởi chạy các dịch vụ user space.
Chi tiết các tầng đầu: Bootloader trong hệ nhúng Linux và U-Boot on Zynq.
Giao diện bootloader và kernel¶
Bootloader cần chuẩn bị trong RAM và truyền cho kernel:
| Thành phần | Mô tả |
|---|---|
| Kernel image | Image (ARM64), zImage/uImage (ARM32), bzImage (x86), hoặc đóng gói trong FIT image |
| Device-tree blob (DTB) | Mô tả phần cứng cho kernel, xem Device Model |
| initramfs (tùy chọn) | Root filesystem tạm nằm trong RAM |
| Kernel command line | Chuỗi tham số, xem Kernel Command Line |
Khi nhảy vào kernel, địa chỉ DTB được truyền qua thanh ghi theo quy ước của
từng kiến trúc (ví dụ ARM64: x0 chứa địa chỉ DTB; ARM32: r2).
Kernel khởi động¶
- Early arch setup: code assembly trong
arch/<arch>/kernel/head.Sbật MMU, dựng page table ban đầu, rồi nhảy vào code C. start_kernel()(init/main.c): khởi tạo lần lượt bộ nhớ, scheduler, IRQ, timer, console, parse command line, ...rest_init(): tạo hai thread kernel làkernel_init(sau này trở thành PID 1) vàkthreadd(PID 2, cha của các kernel thread).kernel_init(): chạy các initcall, mount root filesystem, rồiexecchương trìnhinit.
Initcall¶
Các hàm khởi tạo của built-in driver/subsystem được đăng ký bằng họ macro
*_initcall và chạy theo thứ tự level:
| Level | Macro | Ví dụ dùng |
|---|---|---|
| early | early_initcall |
Khởi tạo rất sớm |
| 0 | pure_initcall |
|
| 1 | core_initcall |
Core subsystem |
| 2 | postcore_initcall |
|
| 3 | arch_initcall |
Code đặc thù kiến trúc/board |
| 4 | subsys_initcall |
Đăng ký subsystem, bus |
| 5 | fs_initcall |
File system |
| 6 | device_initcall |
module_init() của built-in driver |
| 7 | late_initcall |
Chạy sau cùng |
Với built-in module, module_init(fn) được định nghĩa thành device_initcall
(xem Kernel Module). Vì vậy bus/subsystem
(subsys_initcall) luôn sẵn sàng trước khi driver đăng ký, và device-tree được
kernel dùng để tạo các platform device trước khi probe() được gọi.
Để xem thời gian từng initcall, thêm initcall_debug vào command line.
Mount root filesystem và chạy init¶
- Có initramfs: kernel giải nén initramfs vào RAM và chạy
/inittrong đó; script này tìm và mount root filesystem thật rồiswitch_root. - Không có initramfs: kernel mount trực tiếp thiết bị trong
root=(kèmrootfstype=,rootwaitnếu thiết bị xuất hiện chậm, ví dụ SD/MMC). - Sau khi mount, kernel chạy chương trình init: thử
init=trong command line, sau đó/sbin/init,/etc/init,/bin/init,/bin/sh. Nếu không có cái nào chạy được, kernel báoKernel panic - not syncing: No working init found. - Phổ biến: systemd, BusyBox init, SysV init.
Debug quá trình boot¶
earlycon/earlyprintk: in log trước khi console thật được khởi tạo.initcall_debug: in thời gian và kết quả từng initcall.dmesg, tham sốprintk.time=1,loglevel=.dyndbg=: bậtpr_debugngay lúc boot, xem Dynamic Debug.- Panic ngay khi mount root: kiểm tra
root=, driver của thiết bị lưu trữ đã built-in chưa (nếu không dùng initramfs), và DTB có đúng không.