Quy trình Flash Image và Kiểm tra Boot lần đầu
Để đưa hệ điều hành tùy biến lên Raspberry Pi Compute Module 5, bạn cần flash file image vào thẻ SD hoặc EEPROM (tùy cấu hình boot) của CM5. Sau đó, kết nối board qua cáp USB-C và Serial để theo dõi quá trình khởi động.
Tạo một script shell tự động để flash image vào thẻ SD đã được gắn vào máy chủ build hoặc máy tính host. Lệnh này sẽ ghi file `wic` (hoặc `raw`) trực tiếp vào device block.
sudo dd if=deploy/rpi-cm5-custom-image.wic of=/dev/sdX bs=4M conv=fsync status=progress
sync
Thay thế `sdX` bằng đường dẫn device thực tế của thẻ SD (ví dụ: `sdb`). Kết quả mong đợi là thông báo tốc độ ghi (MB/s) và không có lỗi `I/O error`.
Sử dụng công cụ `raspi-config` hoặc `rpi-imager` (nếu dùng file `.img` chuẩn) hoặc flash trực tiếp qua `flashrom` nếu boot từ EEPROM. Sau khi flash, lắp thẻ SD vào slot của CM5 và cấp nguồn.
Kết nối Serial Console (UART0) để xem log khởi động. CM5 thường dùng cổng GPIO 14 (TX) và 15 (RX). Cấu hình `screen` hoặc `minicom` với baud rate 115200.
screen /dev/ttyUSB0 115200
Thay `ttyUSB0` bằng cổng serial USB-serial adapter đang dùng. Kết quả mong đợi là dòng log `Booting Linux on physical CPU...` xuất hiện ngay lập tức sau khi cấp nguồn.
Verify kết quả
Xem thông báo `Kernel panic` hoặc `Boot successful`. Nếu thấy prompt shell (ví dụ: `root@rpi-cm5:~#`), quá trình boot thành công.
Debug lỗi khởi động qua Serial Console và dmesg
Khi hệ thống không boot, nguyên nhân thường nằm ở giai đoạn Bootloader, Kernel Early Init, hoặc Initramfs. Serial Console là công cụ duy nhất để nhìn thấy log ở giai đoạn này vì màn hình HDMI có thể chưa được kích hoạt.
Cấu hình thêm tham số debug vào dòng lệnh boot (cmdline) trong file `bootcmdline` hoặc `uEnv.txt` (tùy bootloader) để kích hoạt log chi tiết hơn.
loglevel=8 earlycon=uart8250,mmio32,0x7d501000 console=ttyS0,115200
Dòng này được thêm vào file cấu hình boot. Kết quả mong đợi là mọi thông báo kernel (bao gồm cả mức độ debug) sẽ hiện trên terminal serial.
Sử dụng lệnh `dmesg` ngay sau khi hệ thống boot (hoặc trong initramfs) để xem log kernel đã lưu. Nếu boot bị treo, log sẽ dừng ở một dòng cụ thể.
dmesg | grep -i "error\|fail\|panic\|timeout"
Lệnh này lọc các dòng lỗi quan trọng. Kết quả mong đợi là danh sách các thông báo lỗi giúp định vị vấn đề (ví dụ: driver GPU không load, clock không ổn định).
Trong trường hợp Kernel Panic, bạn cần kích hoạt `panic=1` trong cmdline để hệ thống tự động reboot sau 1 giây, giúp quan sát lỗi liên tục.
echo "panic=1" >> /boot/cmdline.txt
Thêm dòng này vào file `cmdline.txt`. Kết quả mong đợi là hệ thống sẽ tự động restart ngay khi gặp lỗi nghiêm trọng, giúp bạn bắt được lỗi qua serial console.
Verify kết quả
Quan sát dòng log cuối cùng trên terminal serial. Nếu thấy `Kernel panic - not syncing: ...`, bạn đã xác định được nguyên nhân treo máy.
Xử lý các lỗi phổ biến: Kernel Panic, Driver, Network
Lỗi Kernel Panic thường do driver thiết bị (GPU, GPU, Clock) không tương thích hoặc cấu hình sai trong Device Tree. Driver không load do thiếu module trong initramfs hoặc không được enable trong config kernel.
Xử lý lỗi Kernel Panic do Device Tree: Kiểm tra file `.dtb` trong thư mục `/boot`. Đảm bảo file `.dtb` tương ứng với CM5 (ví dụ: `bcm2711-rpi-cm5.dt.b`).
ls /boot/*.dtb | grep cm5
Kết quả mong đợi là thấy file `bcm2711-rpi-cm5.dt.b`. Nếu không thấy, cần build lại kernel với `ARCH=arm64` và `DTB_FILES` chính xác.
Xử lý lỗi driver không load: Kiểm tra xem module có được compile vào kernel hay không (y) hoặc dưới dạng module (m). Nếu là module, cần đảm bảo nó được copy vào `/lib/modules/...`.
zcat /proc/config.gz | grep CONFIG_
modprobe
Thay `` bằng tên driver (ví dụ: `CONFIG_MMC_SDHCI`). Kết quả mong đợi là không có lỗi `modprobe: FATAL: Module ... not found`.
Xử lý lỗi Network fail (cable không nhận): CM5 sử dụng Ethernet qua PCIe hoặc USB. Kiểm tra xem driver `rpi-net` hoặc `smsc95xx` có load không.
ip link show
ethtool eth0
Kết quả mong đợi là thấy interface `eth0` hoặc `enpXsY` ở trạng thái `UP` hoặc `DOWN` (nhưng tồn tại). Nếu không thấy interface, cần thêm driver vào `initramfs`.
Cấu hình lại initramfs để bao gồm các driver cần thiết. Chạy lệnh sau trong thư mục build của Yocto hoặc rootfs.
update-initramfs -u -k $(uname -r)
# Hoặc nếu dùng Yocto, thêm vào IMAGE_INSTALL_append trong layer custom
IMAGE_INSTALL_append = " rpi-firmware linux-firmware"
Kết quả mong đợi là file `initramfs` được tạo lại và boot lần sau sẽ load driver network đúng.
Verify kết quả
Chạy `ping -c 3 8.8.8.8` để kiểm tra kết nối internet. Nếu ping thành công, lỗi network đã được xử lý.
Mẹo nâng cao: Cơ chế OTA và Backup/Restore
Để triển khai hệ thống CM5 ở quy mô lớn, bạn cần cơ chế cập nhật không gián đoạn (OTA - Over-The-Air) và khả năng sao lưu/khôi phục dữ liệu nhanh chóng.
Tạo một script OTA đơn giản sử dụng `rsync` để cập nhật file hệ thống, sau đó dùng `kexec` để reboot mà không cần reset phần cứng. Script này sẽ chạy trên hệ thống đang hoạt động.
#!/bin/bash
# /usr/local/bin/ota-update.sh
NEW_ROOTFS="/mnt/new-rootfs"
TARGET_ROOT="/"
if [ ! -d "$NEW_ROOTFS" ]; then
echo "Error: New rootfs not found"
exit 1
fi
# Sync files excluding boot and proc
rsync -avx --exclude={"/proc/*","/sys/*","/dev/*","/boot/*","/run/*","/mnt/*"} "$NEW_ROOTFS/" "$TARGET_ROOT/"
# Update boot partition if needed
rsync -avx /boot/ "$TARGET_ROOT/boot/"
# Prepare kexec
kexec -l /boot/Image --initrd=/boot/initramfs.img --command-line="$(cat /proc/cmdline)"
echo "System will reboot to new image in 5 seconds..."
sleep 5
kexec -e
Lưu script vào `/usr/local/bin/ota-update.sh` và cấp quyền execute. Kết quả mong đợi là hệ thống đồng bộ file mới và tự động reboot vào rootfs mới sau 5 giây.
Cấu hình file `systemd.timer` để tự động kiểm tra cập nhật hàng ngày.
[Unit]
Description=Daily OTA Check
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
Lưu nội dung trên vào file `/etc/systemd/system/ota-check.timer`. Kết quả mong đợi là hệ thống sẽ tự động chạy script kiểm tra cập nhật lúc 3 giờ sáng mỗi ngày.
Tạo script Backup/Restore để sao lưu toàn bộ rootfs (trừ partition boot) thành file nén, và khôi phục lại khi cần.
#!/bin/bash
# /usr/local/bin/backup-system.sh
BACKUP_DIR="/var/backup"
DATE=$(date +%F)
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/rootfs-backup-$DATE.tar.gz --exclude={"/proc/*","/sys/*","/dev/*","/boot/*","/run/*","/tmp/*","/var/backup/*"} /
echo "Backup completed: $BACKUP_DIR/rootfs-backup-$DATE.tar.gz"
Lưu script vào `/usr/local/bin/backup-system.sh`. Kết quả mong đợi là file `.tar.gz` chứa toàn bộ hệ thống được tạo trong thư mục `/var/backup`.
Khôi phục hệ thống từ file backup. Chạy script restore để giải nén file backup vào rootfs hiện tại.
#!/bin/bash
# /usr/local/bin/restore-system.sh
BACKUP_FILE="/var/backup/rootfs-backup-2023-10-27.tar.gz"
if [ ! -f "$BACKUP_FILE" ]; then
echo "Backup file not found"
exit 1
fi
cd /
tar -xzf $BACKUP_FILE
echo "Restore completed. Reboot to apply."
Lưu script vào `/usr/local/bin/restore-system.sh`. Kết quả mong đợi là toàn bộ file hệ thống được khôi phục về trạng thái tại thời điểm backup.
Verify kết quả
Chạy `systemctl status ota-check.timer` để đảm bảo timer đang chạy. Chạy `ls -lh /var/backup` để xác nhận file backup đã được tạo. Chạy script restore và reboot để kiểm tra tính toàn vẹn của hệ thống.
Điều hướng series:
Mục lục: Series: Xây dựng hệ điều hành Linux tùy biến từ source cho Raspberry Pi CM5
« Phần 6: Tích hợp ứng dụng người dùng và tối ưu hóa hiệu năng