Boot chain trong embedded Linux: từ Boot ROM tới userspace

Boot chain trong embedded Linux là chuỗi các stage khởi động đi từ Boot ROM, qua bootloader, tới kernel và cuối cùng là userspace. So với nhiều hệ MCU, quá trình này thường dài hơn vì hệ thống phải chuẩn bị thêm DRAM, storage, Device Tree, kernel image và root filesystem trước khi phần mềm mức cao có thể chạy.

Boot chain là gì

Boot chain là chuỗi các stage khởi động chạy nối tiếp nhau từ lúc chip vừa reset cho tới khi userspace bắt đầu hoạt động. Mỗi stage chỉ đảm nhiệm một phần việc nhất định, rồi chuyển quyền điều khiển cho stage kế tiếp.

Cách gọi này nhấn mạnh cấu trúc nhiều tầng của quá trình boot: stage trước chuẩn bị điều kiện tối thiểu để stage sau có thể chạy. Vì vậy, khi phân tích lỗi boot trên embedded Linux, không thể chỉ nhìn riêng bootloader hay kernel mà cần nhìn toàn bộ chuỗi khởi động và điểm giao tiếp giữa các stage.

Vì sao embedded Linux cần nhiều stage

Ở những chu kỳ đầu tiên sau reset, phần cứng mới chỉ ở trạng thái tối thiểu. SRAM ít, DRAM chưa được init, clock và pinmux có thể còn chưa sẵn sàng, nên hệ thống không thể chạy ngay một bootloader lớn hoặc kernel Linux đầy đủ. Vì vậy quá trình boot phải được chia thành nhiều stage.

Stage đầu thường chỉ đủ khả năng làm những việc tối thiểu như xác định boot source hoặc nạp một image nhỏ vào SRAM. Các stage sau có nhiều tài nguyên hơn nên mới có thể xử lý những việc nặng hơn như init DRAM, load kernel, đọc Device Tree hoặc chọn boot target.

Các stage thường gặp trong một boot chain

Một boot chain điển hình thường gồm các stage khởi động chạy nối tiếp nhau từ phần cứng sớm nhất cho tới kernel và userspace. Tên gọi cụ thể có thể khác nhau giữa các SoC, nhưng flow phổ biến thường gần như sau:

  • Boot ROM chạy đầu tiên.
  • First-stage Bootloader hoặc Secondary Program Loader (SPL), được khởi động bởi Boot ROM.
  • Bootloader chính hay còn gọi là Second-stage Bootloader (thường là U-Boot), tiếp quản phần boot logic cao hơn, được khởi động bởi First-stage Bootloader.
  • Trong flow phổ biến, Linux Kernel được load vào RAM cùng Device Tree bởi Second-stage Bootloader.
  • Kernel mount root filesystem và khởi động userspace.

Không phải hệ thống nào cũng có đúng số stage như trên. Có hệ gộp bớt, có hệ tách thêm tùy theo yêu cầu tối ưu, ví dụ cần khởi tạo sớm một phần hardware trước cả kernel. Với các hệ có yêu cầu bảo mật cao hơn, boot chain còn có thể thêm Secure Monitor hoặc Trusted Firmware trước bootloader chính.

Vai trò của Boot ROM

Boot ROM là code do nhà sản xuất chip cung cấp và chạy ngay sau reset. Đây là stage sớm nhất mà phần lớn lập trình viên hệ thống không tự sửa được.

Nhiệm vụ của Boot ROM thường là xác định boot source, load stage kế tiếp từ storage phù hợp và khởi tạo phần tối thiểu để stage đó có thể chạy, thường là trong SRAM. Trên một số nền tảng, Boot ROM còn tham gia secure boot hoặc kiểm tra image ở mức cơ bản.

First-stage bootloader hoặc SPL

First-stage bootloader, hay SPL trong nhiều hệ dùng U-Boot, là stage trung gian nhỏ chạy sau Boot ROM và trước bootloader chính. Vai trò của nó là chuẩn bị các điều kiện tối thiểu cần thiết, đặc biệt là DRAM init, để stage sau có thể tiếp tục chạy.

Trong hệ dùng U-Boot, stage này thường được gọi là SPL, tức Secondary Program Loader. Nhưng không phải nền tảng nào cũng dùng cái tên này.

Second-stage bootloader – Bootloader chính

Second-stage bootloader là bootloader chính chịu trách nhiệm xử lý phần logic boot ở mức cao hơn sau khi phần cứng đã được chuẩn bị đủ. Đây thường là nơi chọn boot target, load kernel image, load Device Tree, thiết lập bootargs và quyết định boot flow cuối cùng.

Trong rất nhiều hệ embedded Linux, bootloader chính là U-Boot. Nhưng bản thân bài toán boot chain rộng hơn U-Boot, vì U-Boot chỉ là một stage trong toàn chuỗi.

Vị trí của kernel và userspace trong boot chain

Kernel và userspace là hai phần cuối của boot chain, nơi hệ thống chuyển từ giai đoạn chuẩn bị boot sang trạng thái runtime của Linux. Sau khi bootloader đã chuẩn bị xong image và tham số cần thiết, kernel Linux bắt đầu chạy.

Kernel sẽ khởi tạo driver, quản lý bộ nhớ, mount root filesystem và cuối cùng khởi động userspace. Khi userspace lên ổn định, ta mới có shell, systemd, init process hoặc ứng dụng chính của thiết bị.

Sự khác nhau giữa boot chain và boot flow

Hai cụm này gần nhau nhưng không hoàn toàn trùng nhau.

Boot chain nhấn mạnh chuỗi stage nào chạy nối tiếp stage nào.

Boot flow nhấn mạnh hệ thống ra quyết định boot theo nhánh nào, lấy image ở đâu, fallback ra sao và chuyển trạng thái thế nào.

Nói cách khác, boot chain nghiêng về cấu trúc thực thi. Boot flow nghiêng về logic điều khiển. Nếu anh muốn nhìn lại cách tư duy boot flow theo hướng đơn giản hơn trên MCU, có thể xem bài Vòng đời khởi động của một hệ thống embedded, từ reset đến application.

Độ phức tạp khi debug boot trên embedded Linux

Debug boot trên embedded Linux khó hơn vì lỗi có thể xuất hiện ở nhiều stage khác nhau trong cùng một chuỗi khởi động. Mỗi stage có thể đến từ một project khác nhau, in log ở thời điểm khác nhau và phụ thuộc vào storage hay cấu hình khác nhau.

Một lỗi nhìn như kernel panic có thể bắt nguồn từ bootargs sai. Một lỗi tưởng nằm ở root filesystem có thể thực ra do bootloader load sai Device Tree. Một lỗi không boot được từ eMMC có thể bắt đầu từ Boot ROM chọn sai boot source. Chuỗi phụ thuộc dài hơn nên việc debug cũng khó hơn nhiều.

Các thành phần quan trọng sẽ xuất hiện xuyên suốt series

Các thành phần dưới đây là những khái niệm sẽ xuất hiện lặp lại xuyên suốt series embedded Linux. Nắm được tên gọi và vai trò cơ bản của chúng ngay từ đầu sẽ giúp các bài sau dễ theo dõi hơn.

  • Device Tree.
  • Kernel image.
  • Initramfs.
  • Root filesystem.
  • U-Boot và SPL.
  • Bootargs, environment và boot target.

Nếu chưa chắc từng khái niệm này là gì cũng không sao. Điều quan trọng ở bài này là nhìn ra bức tranh tổng thể trước, rồi từ đó đi sâu dần vào từng phần ở các bài tiếp theo.

Kết luận

Tóm lại, boot chain trong embedded Linux là chuỗi nhiều stage nối tiếp nhau từ Boot ROM tới userspace. Mỗi stage giải quyết một phần việc riêng, và vì trong nhiều hệ chuỗi này dài hơn đáng kể so với MCU nên việc thiết kế, debug và bảo mật boot trên embedded Linux cũng phức tạp hơn rõ rệt.

Nắm được boot chain là nền tảng để hiểu tiếp các phần như U-Boot, kernel image, Device Tree, root filesystem và các lỗi boot thường gặp. Nếu muốn đi tiếp theo đúng mạch này, bài U-Boot là gì trong embedded Linux sẽ là điểm nối tự nhiên sau phần tổng quan này.

Phản hồi về bài viết

Cùng thảo luận chút nhỉ!

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.