1. 問題背景
最近了解到一個強大的開源虛擬機軟件:qemu。利用它可以仿真arm板,正好可以用來鞏固一下移植相關的操作。網上關於qemu仿真vexpress開發板的例子較多,我試了幾個,感覺還是下面這篇文章比較靠譜:
https://www.cnblogs.com/pengdonglin137/p/5023342.html 。目前我進行到用qemu加載u-boot,或者加載內核並掛載ramdis根文件系統,也可以利用u-boot來引導內核啟動,但是無法掛載根文件系統。
2. 環境介紹
虛擬機系統:Ubuntu 14.04
u-boot: u-boot-2015-04
linux kernel: linux-3.4.4
busybox: busybox-1.21.0
toolchain: arm-none-linux-gnueabi- (4.6.4)
qemu: QEMU emulator version 1.7.91
這個qemu是直接通過apt在線安裝的,在模擬某個arm板前,先看看qemu支不支持。
1 qemu-system-arm -M ?
3. U-boot配置
3.1 u-boot缺省配置
在u-boot-2015.04目錄下,先看看關於vexpress的默認配置有哪些,這里我們選vexpress_ca9x4_defconfig來進行默認的配置,使用make指令,可以在命令行指定架構和交叉編譯器,也可以寫死在Makefile中。
1 ls configs/ | grep vexpress 2 make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- vexpress_ca9x4_defconfig
3.2 u-boot環境變量
這里主要設置bootargs,bootcmd和bootm。我們可以把這些東西寫死到include/configs/vexpress_common.h中,否則就要進入u-boot后手動敲命令設置,而且設置好后也不能save(沒有flash)。
bootcmd:對應宏CONFIG_BOOTCOMMAND,是u-boot啟動時會自動執行的命令。
bootargs:是u-boot傳遞內核的參數。
bootm: ${kernel_addr} ${ramdisk_addr} ${dtb_addr} 依次是內核鏡像地址,根文件鏡像地址,設備樹地址
211 /* Basic environment settings */ 212 #if 0 213 #define CONFIG_BOOTCOMMAND "run bootflash;" //將原有的宏注釋掉 214 #endif 215 216 #define CONFIG_IPADDR 192.168.222.21 //本機IP 217 #define CONFIG_NETMASK 255.255.255.0 //掩碼 218 #define CONFIG_SERVERIP 192.168.222.20 //服務器IP:tftp服務和nfs服務 219 220 #define CONFIG_BOOTCOMMAND \ 221 "tftp 0x60008000 uImage3.4.4; " \ 222 "tftp 0x63000000 ramdisk_zy.img; " \ 223 "setenv bootargs root=/dev/mmcblk0 console=ttyAMA0; " \ 224 "bootm 0x60008000 0x63000000; "
3.3 生成u-boot.bin
同樣使用make指令,指定一下ARCH和CROSS_COMPILE。后面的-j2是指定2個核同時編譯,增加編譯速度。目標文件是一個二進制文件,u-boot.bin,這就是要燒寫到flash或者qemu要加載的對象。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- -j2
生成好u-boot后,先用qemu測試一下能否加載。這里參數的意義就直接抄過來吧。
-M vexpress-a9 模擬vexpress-a9單板,你可以使用-M ?參數來獲取該qemu版本支持的所有單板
-m 512M 單板運行物理內存512M
-kernel /root/tq2440_work/kernel/linux-stable/out_vexpress_3_16/arch/arm/boot/zImage 告訴qemu單板運行內核鏡像路徑
-nographic 不使用圖形化界面,只使用串口
-append "console=ttyAMA0" 內核啟動參數,這里告訴內核vexpress單板運行,串口設備是哪個tty。
20 qemu-system-arm \ 21 -M vexpress-a9 \ 22 -m 256M \ 23 -kernel /home/linux/qemu_linux/u-boot-2015.04/u-boot \ 24 -serial stdio \ 25 -append "root=/dev/mmcblk0 nolock rw console=tty0" \
啟動后使用print指令打印環境變量,可以發現在3.2中設置的環境變量在u-boot中有所體現。
4. Linux內核配置
和u-boot的配置步驟類似。先找找缺省配置文件。
ls arch/arm/configs/ | grep vexpress
make 默認配置。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- vexpress_defconfig
4.1 內核加載地址和啟動選項配置
編譯內核我們可以通過menucofig先看一下具體的配置內容。在boot option中我們可以配置一下下圖中的內容,這是用來設定內核啟動一些參數,可以通過boot loader來傳遞參數(bootargs),也可以設定默認參數。
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- menuconfig
編譯內核。這里要說明一下LOADADDR=0x60008000,在上一篇博客我有簡單的搜集一些資料,可以參考(雖然還是似懂非懂。。。),不過按照設置可以在qemu中跑起來。這里的LOADADDR我是參考arch/arm/mach-vexpress/Makefile.boot來設置的,其內容如下圖。
這里直接生成了uImage(用於u-boot引導),當然zImage也會同時生成。如果編譯過程中提示缺少mkimage工具,可以通過apt在線安裝,也可以自己下,這里就不再多說。
make LOADADDR=0x60008000 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage -j2
同樣,可以先用qemu加載一下。內核可以起來,但是由於沒有指定根文件系統,內核會報錯。所以下一步我們要制作根文件系統。
20 qemu-system-arm \ 21 -M vexpress-a9 \ 22 -m 256M \ 23 -kernel uImage \ 24 -serial stdio \ 25 -append "root=/dev/mmcblk0 nolock rw console=tty0" \
5. busybox制作根文件系統
5.1 配置busybox
本文制作的根文件系統 = busybox(包含基礎的Linux命令) + 運行庫 。那么根文件系統放在哪里?依賴於每個開發板支持的存儲設備,可以放到Nor Flash上,也可以放到SD卡,甚至外部磁盤上。最關鍵的一點是你要清楚知道開發板有什么存儲設備。
進入busybox,運行 make menuconfig。配置靜態建立busybox。
File systems ---> Pseudo filesystems ---> [*] Virtual memory file system support (former shm fs) [*] Tmpfs POSIX Access Control Lists
然后運行 make install 。完成后,會在busybox目錄下生成_install目錄,該目錄下的程序就是單板運行所需要的命令。將這里面的內容全部復制到一個新建的文件夾,如rootfs下面。
還有很重要的一點就是etc/目錄下的內容,這里一般有4個文件,可以手動進行配置,也可以直接從網上下。http://files.cnblogs.com/files/pengdonglin137/etc.tar.gz
簡單說一下4個文件的作用:
- /etc/fstab 文件負責配置Linux開機時自動掛載的分區。
- rcS是一個腳本文件,在inittab文件中本解析調用,用於配置Linux系統。這個可以參考https://www.cnblogs.com/lp1129/articles/3148858.html。
- init程序需要讀取配置文件/etc/inittab.inittab是一個不可執行的文本文件,它有若干行指令所組成。可以參考https://www.cnblogs.com/jason-lu/articles/3272963.html
- /etc/profile:這個文件是每個用戶登錄時都會運行的環境變量設置,注意是全局的
到目前為止,一個mini的根文件系統就制作好了,我們可以通過nfs來直接掛載到這個rootfs,也可以把它制作成ramdisk鏡像,直接燒錄到flash中。
5.2 制作ramdisk鏡像
運行以下命令,這里解釋一下4-7的作用,先創建一個臨時目錄,用於掛載制作好的根文件系統,再把rootfs的內容復制到這個根文件系統中,類似於我們平時使用u盤。
1 sudo dd if=/dev/zero of=rootfs.ext3 bs=1M count=32 2 sudo mkfs.ext3 rootfs.ext3 3 4 sudo mkdir -p tmpfs 5 sudo mount -t ext3 rootfs.ext3 tmpfs/ -o loop 6 sudo cp -r rootfs/* tmpfs/ 7 sudo umount tmpfs·
接下來,用qemu加載內核和ramdisk。最后的 -sd 即是模擬一個sd卡,里面存放着跟文件系統。
qemu-system-arm \ -M vexpress-a9 \ -m 256M \ -kernel /home/linux/qemu_linux/linux-3.4.4/arch/arm/boot/zImage \ -nographic \ -append "root=/dev/mmcblk0 rw console=ttyAMA0" \ -sd ~/qemu_linux/rootfs.ext3
6. 結果
理想結果,用qemu加載u-boot,再通過u-boot來引導內核,內核直接加載ramdisk,或者通過nfs來加載rootfs。
實際結果:上面黃字標注的沒有實現成功。。。
如下圖,u-boot自啟動后成功從tftp服務器下載了內核鏡像和ramdisk。
但是無法掛載根文件系統: