
Bootloader làm việc gì?
Trong một hệ thống Linux nhúng (embedded Linux system), bootloader có hai công việc chính: khởi tạo hệ thống (initialize the system) tới một cấp độ cơ bản và tải kernel lên (load the kernel). Thực tế, công việc thứ nhất là phụ trợ cho công việc thứ hai ở chỗ nó chỉ cần tạo được những thứ cần thiết đủ để hệ thống tải kernel lên
Ngay sau khi bật nguồn hoặc reset, dòng code đầu tiên của bootloader được thực thi (execute), hệ thống ở trong một trạng thái tối thiểu. Bộ điều khiển Bộ Nhớ Truy Cập Ngẫu Nhiên Động (DRAM – Dynamic Random Access Memory) chưa được cài đặt, do đó bộ nhớ chính (main memory) là không thể truy cập. Tương tự như vậy, những giao diện khác cũng chưa được cấu hình, bộ lưu trữ (storage) được truy cập bằng bộ điều khiển flash NAND (NOT AND), bộ điều khiển MultiMediaCard (MMC), v.v. đều chưa có sẵn. Thông thường, nguồn tài nguyên duy nhất là một core CPU đang vận hành từ lúc đầu, vài Bộ Nhớ Truy Cập Ngẫu Nhiên Tĩnh (SRAM – Static Random Access Memory), và boot ROM (Read-Only Memory – Bộ Nhớ Chỉ Đọc) trong chip.
Một hệ thống khởi động (system bootstrap) bao gồm một vài phase của code, mỗi phase sẽ đưa thêm nhiều thành phần của hệ thống vào sự vận hành. Hành động cuối cùng của bootloader sẽ tải kernel lên RAM và tạo một môi trường thực thi cho kernel. Chi tiết của mỗi giao diện nằm giữa bootloader và kernel là cấu trúc đặc trưng, nhưng trong mỗi trường hợp, no phải làm hai việc. Đầu tiên, bootloader phải truyền một pointer trỏ tới một cấu trúc có chứa thông tin về cấu hình phần cứng (hardware configuration). Thứ hai, nó phải truyền một pointer trỏ tới dòng lệnh của kernel (kernel command line).
Kernel command line là một chuỗi ký tự (text string) điều khiển hành vi của Linux. Một khi kernel đã bắt đầu thực thi, bootloader không cần sử dụng nữa và toàn bộ bộ nhớ mà nó đã chiếm có thể lấy lại.
Một công việc phụ trợ của bootloader là cung cấp một chế độ bảo trì (maintenance mode) cho việc cập nhật các cấu hình boot (updating boot configurations), load các boot image mới vào trong bộ nhớ, và cũng có thể là chạy chẩn đoán (diagnostic). Việc này thường được điều khiển bằng giao diện người dùng dòng lệnh đơn giản (simple command-line user interface) thông qua serial console.
Trình Tự Khởi Động (Boot Sequence)
Vài năm trước, chúng ta chỉ cần đặt bootloader trong bộ nhớ không bốc hơi (non-volatile memory) tại reset vector của vi xử lý (processor). Bộ nhớ flash (flash memory) NOR hay NOT OR đã thông dụng tại thời điểm đó, bởi vì nó có thể được ánh xạ (map) trực tiếp vào không gian địa chỉ (address space). Nó đã từng là phương pháp lưu trữ lý tưởng. Hình dưới đây cho ta thấy một cấu hình với reset vector tại địa chỉ 0xfffffffc tại đỉnh cuối của một vùng trong bộ nhớ flash:
Bootloader được liên kết bằng một lệnh nhảy (jump instruction) tại vị trí đó, trỏ tới vùng bắt đầu code của bootloader. Từ điểm đó, code bootloader chạy trong bộ nhớ NOR flash để có thể khởi tạo bộ điều khiển DRAM để từ đó bộ nhớ chính – DRAM – sẵn sàng. Rồi sau đó nó tự copy chính nào vào DRAM. Khi đã vận hành đầy đủ, bootloader có thể load kernel từ bộ nhớ flash vào trong DRAM và chuyển quyền điều khiển cho kernel.

Hình 1 – NOR flash
Tuy nhiên, khi bạn chuyển từ phương tiện lưu trữ địa chỉ tuyến tính đơn giản (simple linearly addressable storage) như NOR flash, trình tự khởi động (boot sequence) trở thành một quy trình phức tạp, nhiều giai đoạn. Về chi tiết thì rất khác nhau tuỳ theo mỗi SoC, nhưng nhìn chung chúng đều phải qua các giai đoạn sau.
Phase 1 – ROM code
Trong hoàn cảnh thiếu bộ nhớ ngoài (external memory), phần code chạy ngay sau khi reset hoặc power-on được lưu trong chip bên trong SoC. Cái này được gọi là ROM code. Nó được load lên chip khi sản xuất, và do đó phần ROM code này là tài sản của nhà sản xuất và không thể thay thế bởi mã nguồn mở tương đương.
ROM code không bao gồm phần code khởi tạo bộ điều khiển bộ nhớ (memory controller) bởi vì cấu hình DRAM phụ thuộc cao vào đặc điểm của thiết bị. Do đó, nó chỉ có thể xài SRAM, bởi vì SRAM không yêu cầu một memory controller. Hầu hết mọi thiết kế SoC nhúng đều có một bộ nhớ SRAM nhỏ trên chip. Kích thước bộ nhớ có thể khác nhau khoảng 4 KB tới vài trăm KB.

ROM code có thể load một đoạn code nhỏ từ một trong những vị trí được lập trình trước lên SRAM. Lấy một ví dụ, chip TI Sitara load code từ vài page đầu tiên trong NAND flash memory, hoặc từ flash memory được kết nối thông qua một SPI (Serial Peripheral Interface). Chúng cũng load code từ những sector đầu tiên trong một thiết bị MMC như là eMMC chip hoặc SD card, hoặc từ một file tên MLO (Memory Loader) trên partition đầu tiên của thiết bị MMC. Nếu đọc từ tất cả thiết bị trên thất bại, thì nó sẽ thử đọc luồng byte (byte stream) từ Ethernet, USB, hoặc UART. Cái sau được dùng chủ yếu làm phương tiện nạp code lên flash memory trong sản xuất hơn là cho sử dụng thông thường.
Hầu hết SoC nhúng có ROM code làm việc tương tự nhau. Trong các SoC nơi mà SRAM không đủ lớn để load một bootloader đầy đủ như là U-Boot, thì cần một loader trung gian gọi là Bộ Tải Chương Trình Thứ Cấp – Secondary Program Loader (SPL). Tại cuối phase ROM code, SPL hiện diện trong SRAM và ROM code nhảy sang phần đầu của đoạn code đó.
Phase 2 – Secondary Program Loader
SPL phải cài đặt memory controller và các phần thiết yếu khác của hệ thống để chuẩn bị cho việc load Bộ Tải Chương Trình Thứ Ba – Tertiary Program Loader (TPL) lên DRAM. Chức năng của SPL bị giới hạn bởi kích thước của SRAM. Nó cũng có thể đọc chương trình từ một danh sách thiết bị lưu trữ giống như ROM code, một lần nữa sử dụng những offset được lập trình trước từ phần bắt đầu của thiết bị flash.
Nếu SPL có các filesystem driver được build cùng nó, thì nó có thể đọc những tên file nổi tiếng như là ‘u-boot.img’ từ một vùng trong đĩa cứng (disk partition). SPL thường không cho phép bất kỳ người dùng nào tương tác, nhưng nó có thể in thông tin phiên bản (version information) và tin nhắn tiến trình (progress messages) để bạn có thể xem trên màn hình điều khiển (console). Sơ đồ dưới đây mô tả kiến trúc của phase 2:

Sơ đồ trước cho thấy việc nhảy từ ROM code sang SPL. Khi SPL thực thi bên trong SRAM, nó load TPL lên DRAM. Tại cuối chu kỳ phase 2, TPL đã hiện diện trong DRAM và SPL có thể thực hiện một cú nhảy sang vùng đó.
SPL có thể là open source, ví dụ như trường hợp của Atmel AT91Bootstrap. Nhưng nó thường chứa đựng code độc quyền cung cấp bởi nhà sản xuất
dưới dạng nhị phân (binary blob).
Phase 3 – Tertiary Program Loader
Tới thời điểm này, một bootloader đầy đủ chức năng sẽ được chạy, U-Boot thường được sử dụng, đây gọi là Chương Trình Tải Cấp Ba (Tertiary Program Loader – TPL). Thông thừng, nó có một giao diện dòng lệnh đơn giản để bạn thực hiện những thao tác bảo trì như là load file ảnh boot mới và kernel mới lên bộ nhớ flash. Nó có thể tự động load kernel mà không cần người dùng can thiệp. Sơ đồ dưới đây giải thích kiến trúc của phase 3:

Sơ đồ trước chỉ việc nhảy từ SPL trong SRAM sang TPL trong DRAM. Khi TPL thực thi, nó load kernel lên DRAM. Chúng ta cũng có thể chọn bổ sung FDT và/hoặc khởi động RAM disk cho image trong DRAM nếu muốn. Dù sao thì, tại cuối phase thứ ba, sẽ có một kernel trong bộ nhớ sẵn sàng chờ được bắt đầu (start). Embedded bootloader thường biến mất khỏi bộ nhớ ngay sau khi kernel chạy và không có bộ phận nào của hệ thống cần tới nó nữa. Trước khi kết thúc, TPL cần ngưng quyền điều khiển quy trình boot và chuyển cho kernel.
Đi từ bootloader sang kernel
Khi bootloader trao quyền điều khiển cho kernel, nó cần phải truyền những thông tin cơ bản bao gồm:
- Số máy (machine number) để định danh kiểu của SoC, được sử dụng trên các nền tảng PowerPC và ARM, chúng không hỗ trợ device tree
- Chi tiết cơ sở của phần cứng
- Giao diện dòng lệnh của kernel (kernel command line)
- Vị trí và kích thước của một device tree nhị phân (tuỳ chọn)
- Vị trí và kích thước của một RAM disk khởi tạo, gọi là initial RAM file system – initramfs (tuỳ chọn)
Kernel command line là một chuỗi ASCII điều khiển hành vi của Linux bằng cách gởi cho nó. Ví dụ, tên của thiết bị (device name) chứa root filesystem. Chúng ta sẽ tìm hiểu chi tiết về kernel command line ở những bài sau. Người ta thường cung cấp root filesystem như là một RAM disk, trong trường hợp nó là trách nhiệm của bootloader để load RAM disk image lên bộ nhớ.
Cách để thông tin này được truyền phụ thuộc vào kiến trúc và nó đã thay đổi trong những năm gần đây. Ví dụ như PowerPC, bootloader chỉ được sử dụng để truyền một con trỏ tới một cấu trúc thông tin của board. Trong khi đó, với ARM, nó truyền một con trỏ tới danh sách nhãn A (A tags). Có một mô tả chi tiết về về các nhãn A trong kernel source tree ở tại Documentation/arch/arm/booting.rst. Tìm kernel source tree tại URL https://github.com/torvalds/linux.
Trong cả hai trường hợp, số lượng thông tin được truyền là rất giới hạn, để cho thông tin được khám phá lúc chạy (runtime) hoặc hard-coded vô kernel như dữ liệu của platform (platform data). Sử dụng phổ biến platform data nghĩa là mỗi board phải có một cấu hình kernel và được điều chỉnh cho platform đó. Do đó, người ta cần một cách làm hiệu quả hơn, đó chính là device tree.
Trong thế giới ARM, việc rời bỏ thẻ A đã bắt đầu thực hiện nghiêm túc trong tháng 2 năm 2013 với việc phát hành Linux 3.8. Ngày nay, hầu hết các hệ thống ARM đều sử dụng device tree để thu thập thông tin đặc điểm cụ thể của hardware platform. Điều này cho phép chỉ cần một file kernel binary chạy trên nhiều ARM platform.
Vậy là chúng tao đã tìm hiểu xong bootloader làm gì, các trạng thái của boot sequence là gì, và làm sao để truyền quyền điều khiển sang kernel.
Nguồn tham khảo:
Sách Mastering Embedded Linux Development – Fourth Edition (2025) – https://www.amazon.com/Mastering-Embedded-Linux-Development-solutions/dp/1803232595
GH BOOKSTORE
DỊCH VỤ MUA SÁCH AMAZON
📌 GH Bookstore là một dịch vụ online dành những bạn nào có nhu cầu mua sách nước ngoài để học và nghiên cứu.
Amazon là một nền tảng bán rất nhiều sách của Hoa Kỳ. Bạn có thể tìm được hàng tá chủ đề sách về kỹ thuật. Tuy nhiên việc mua một quyển sách về Việt Nam tốn khá nhiều thời gian để tìm hiểu các thủ tục nhập khẩu và phương thức vận chuyển.
GH Bookstore sẽ giúp bạn tiết kiệm thời gian nếu chưa từng mua hàng ngoại quốc, chi phí thấp do bỏ qua các khâu vận chuyển trung gian, và quan trọng là đáng tin cậy vì nó do chính mình quản lý 😎.
Hãy bấm Like 👍 và Share Page GH Bookstore (https://www.facebook.com/ghbookstore.vn/) như một cách ủng hộ mình.