Bước 1: Khởi động quá trình biên dịch Kernel Linux cho kiến trúc ARM
Thực thi lệnh make để biên dịch
Chúng ta sẽ sử dụng lệnh make với tham số CROSS_COMPILE để chỉ rõ trình biên dịch ARM đã được chuẩn bị từ phần trước, đồng thời tận dụng nhiều nhân CPU để tăng tốc độ compile.
Tại sao: Tham số CROSS_COMPILE=arm-linux-gnueabihf- bảo đảm rằng trình biên dịch (gcc) sẽ sinh ra mã máy cho kiến trúc ARM 32-bit (little-endian) thay vì x86_64 của máy chủ. Tham số -j$(nproc) phân chia công việc cho tất cả các nhân CPU để giảm thời gian build từ vài tiếng xuống còn vài chục phút.
Kết quả mong đợi: Trình biên dịch sẽ chạy, xuất ra hàng loạt thông tin về việc compile các file .c thành .o, và cuối cùng thông báo Building modules, stage 2. hoặc Kernel: arch/arm/boot/zImage is ready.
cd /path/to/linux-source
make -j$(nproc) CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm
Sau khi lệnh chạy xong, hãy kiểm tra xem file kernel đã được tạo chưa bằng lệnh ls.
ls -lh arch/arm/boot/zImage
Verify kết quả: Nếu thấy file zImage xuất hiện với kích thước khoảng 6-10MB, quá trình biên dịch core kernel thành công.
Bước 2: Xử lý lỗi biên dịch liên quan đến driver đặc thù
Phân tích và loại bỏ driver không tương thích
Trong quá trình biên dịch cho HackberryPi, bạn có thể gặp lỗi error: implicit declaration of function hoặc undefined reference từ các driver phần cứng không tồn tại trong board CM5 (ví dụ: driver WiFi cũ, Bluetooth hoặc GPU không khớp).
Tại sao: Kernel mặc định thường bao gồm driver cho nhiều dòng chip khác nhau. Nếu source code của driver đó yêu cầu header file hoặc thư viện không có trong toolchain hoặc không tương thích với chip CM5, quá trình build sẽ bị lỗi.
Kết quả mong đợi: Lỗi biên dịch dừng lại và in ra dòng make: *** [drivers/.../...] Error 1.
Để sửa lỗi, chúng ta không nên cố force compile. Hãy vào menu cấu hình để tắt driver gây lỗi.
make -j$(nproc) CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm menuconfig
Trong giao diện menuconfig, sử dụng phím mũi tên để tìm đến mục Device Drivers -> [Network device drivers] hoặc [Graphics support] (tùy theo lỗi báo). Tìm tên driver gây lỗi, nhấn phím n để chuyển thành [ ] (tắt) hoặc [*] thành [ ].
Save cấu hình: Nhấn Esc để quay lại, chọn Save và nhấn Enter.
make -j$(nproc) CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm
Verify kết quả: Lệnh make chạy tiếp tục và không còn báo lỗi liên quan đến driver cũ. Nếu còn lỗi, lặp lại bước tìm và tắt driver tương ứng trong menuconfig.
Chỉnh sửa Makefile hoặc file source (Nếu bắt buộc)
Trường hợp driver đó là bắt buộc cho board CM5 (ví dụ: driver USB controller của chip) nhưng bị lỗi do thiếu header file, ta cần chỉnh sửa file source.
Tại sao: Đôi khi driver được viết cho phiên bản Linux cũ hơn hoặc mới hơn, gây xung đột cú pháp với toolchain hiện tại.
Kết quả mong đợi: Lỗi biên dịch được loại bỏ bằng cách comment dòng gây lỗi hoặc thêm include path.
vi drivers/usb/host/ehci-mv.c
Tìm dòng code gây lỗi (thường là dòng báo trong log của bước trước). Thêm dấu // để comment hoặc sửa lại tên hàm. Lưu file bằng :wq.
make -j$(nproc) CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm
Verify kết quả: Build thành công, file zImage được tạo ra.
Bước 3: Tạo file image kernel và Device Tree Blob (.dtb)
Biên dịch Device Tree (DTB) cho HackberryPi CM5
Kernel hiện đại trên ARM sử dụng Device Tree để mô tả phần cứng. HackberryPi CM5 cần file .dtb riêng biệt để kernel nhận diện đúng các thành phần như GPIO, UART, Ethernet.
Tại sao: Nếu không build DTB đúng, kernel sẽ không biết cách khởi động phần cứng của board, dẫn đến màn hình đen hoặc treo ngay sau khi boot.
Kết quả mong đợi: File hackberrypi-cm5.dtb (hoặc tên tương tự) xuất hiện trong thư mục arch/arm/boot/dts.
Thực thi lệnh để compile DTB cụ thể cho board của bạn. Thay thế tên file hackberrypi-cm5.dts bằng tên file source thực tế trong thư mục dts.
make -j$(nproc) CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm dtbs
Hoặc nếu muốn compile chỉ file riêng lẻ:
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm hackberrypi-cm5.dtb
Verify kết quả: Kiểm tra sự tồn tại của file dtb.
ls -lh arch/arm/boot/dts/hackberrypi-cm5.dtb
Gói hóa thành uImage cho U-Boot
Bootloader U-Boot thường yêu cầu kernel được đóng gói trong định dạng uImage thay vì zImage để dễ dàng load vào bộ nhớ và khởi động.
Tại sao: uImage chứa header đặc biệt của U-Boot (checksum, entry point) giúp bootloader xác minh tính toàn vẹn trước khi truyền quyền điều khiển cho kernel.
Kết quả mong đợi: File uImage xuất hiện trong thư mục arch/arm/boot.
Chạy lệnh tạo uImage sử dụng công cụ mkimage có sẵn trong package u-boot-tools hoặc lệnh make của kernel.
mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n "HackberryPi Kernel" -d arch/arm/boot/zImage arch/arm/boot/uImage
Hoặc sử dụng lệnh make tích hợp sẵn nếu có target uImage trong Makefile:
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm uImage
Verify kết quả: So sánh kích thước file uImage so với zImage (uImage thường lớn hơn một chút do có header).
ls -lh arch/arm/boot/uImage arch/arm/boot/zImage
Bước 4: Kiểm tra tính toàn vẹn của Kernel sau khi build
Kiểm tra checksum và cấu trúc file
Trước khi flash vào board, cần đảm bảo file kernel không bị lỗi bit hoặc cấu trúc file bị hỏng trong quá trình build.
Tại sao: Một file kernel bị lỗi checksum sẽ khiến board treo (hang) hoặc không boot được, gây mất thời gian debug phần cứng.
Kết quả mong đợi: Lệnh kiểm tra chạy thành công và in ra hash SHA256 hoặc thông tin header hợp lệ.
Tính toán hash SHA256 cho file uImage và zImage.
sha256sum arch/arm/boot/uImage arch/arm/boot/zImage arch/arm/boot/dts/hackberrypi-cm5.dtb
Check cấu trúc file uImage bằng lệnh mkimage để đảm bảo header đúng.
mkimage -l arch/arm/boot/uImage
Verify kết quả: Đầu ra của lệnh mkimage -l phải hiển thị:
- Image Name: "HackberryPi Kernel" (hoặc tên bạn đặt)
- Image Type: ARM Linux Kernel Image
- Data Size: Khớp với kích thước file zImage
- Load Address: 0x00008000
- Entry Point: 0x00008000
Đảm bảo không có dòng ERROR hoặc Bad Checksum xuất hiện.
So sánh với cấu hình mong đợi
Kiểm tra lại file .config đã được sinh ra để đảm bảo các tính năng quan trọng cho CM5 (như UART console, NFS root, hoặc Initramfs) đã được bật.
Tại sao: Đảm bảo rằng kernel được build đúng theo thiết kế hệ thống của series này.
grep "CONFIG_CONSOLE_LOGO=y" .config
grep "CONFIG_CMDLINE" .config
Verify kết quả: Các dòng lệnh grep phải trả về kết quả có chứa =y hoặc giá trị mong đợi (ví dụ: CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ..." ).
Điều hướng series:
Mục lục: Series: Xây dựng hệ điều hành Linux từ source cho HackberryPi CM5
« Phần 2: Cấu hình Kernel Linux cho kiến trúc ARM
Phần 4: Xây dựng môi trường người dùng (Rootfs) từ nguồn »