在某些情況下,如果我們沒有Mini2440開發板,或者開發板某些硬件損壞了,這時候我們還要繼續學習linux內核移植和驅動開發,我們應該怎么辦,這里我們可以采用qemu搭建linux開發環境。
在之前的u-boot系列博客中我們已經介紹了u-boot的移植、以及linux內核移植、根文件系統制作。並且嘗試將編譯后的程序燒錄到開發板中運行。而這一節我們將嘗試在qemu上搭建這一套開發環境。
由於我們要使用qemu模擬一個開發板,在安裝了qemu之后,在系統環境下輸入: qemu-system-arm -M help 可以查看qemu支持的ARM平台的開發板的型號,如下圖所示:
這里是沒有smdk2440這塊板子的,結合一下網上的資料后發現 有關 vexpress-a9 的資料和討論最多,所以我們選擇這個開發板來進行模擬。
一、准備工作
1.1 qemu介紹
qemu 是一個硬件虛擬化程序( hypervisor that performs hardware virtualization),與傳統的 VMware / VirtualBox 之類的虛擬機不同,它可以通過 binary translation 模擬各種硬件平台(比如在 x86 機器上模擬 ARM 處理器)。而 VirtualBox 等更多是通過虛擬化來進行資源隔離,以便在其上運行多個 guest os。
基於 qemu 的硬件模擬能力,我們可以輕松搭建指定硬件平台的運行實驗環境。
qemu 與 VirtualBox 另一個不同點在於,在 VirtualBox 上必須安裝一個完整的操作系統套件,而通過 qemu 我們可以通過參數直接啟動到一個裸的 Linux Kernel,連 bootloader 都不需要關心。在此之外,按需配置相關工具套件與啟動好的 Kernel 一起工作即可。
qemu 提供的這種高度可定制化的白盒能力,使得我們可以按需構建快速、輕量級的開發環境,提供流暢的開發體驗。
1.2 安裝qemu
在ubuntu環境下安裝qemu:
sudo apt install qemu
二、編譯linux內核
2.1 編譯配置
這里我們使用linux-5.2.8源碼,執行如下命令:
cd /work/linux-5.2.8 #源碼放在這個路徑 make ARCH=arm vexpress_defconfig
配置完成后相應的配置項會保存在 .config 文件中。下一次執行 make menuconfig 時可以 load 這份配置文件,在此基礎上進行修改。
進入菜單配置,進行以下設置:
make ARCH=arm menuconfig
System Type -->
- [ ] Enable the L2x0 outer cache controller 取消該選項,否則qemu運行不起來
Kernel Features -->
- [*] Use the ARM EABI to compile the kernel 確保該選項被選擇
2.2 編譯內核和模塊
編譯內核鏡像時,執行:
make ARCH=arm CROSS_COMPILE=arm-linux-
編譯成功后,arch/arm/boot目錄下生成內核鏡像文件zImage。
同時在路徑下生成設備樹文件:arch/arm/boot/dts/vexpress-v2p-ca9.dtb
需要注意編譯linux內核使用的是arm-linux-gcc4.6.4。
2.3 運行測試
編譯好內核以后,我們就可以使用qemu啟動內核了。只需要使用-kernel參數告訴qemu內核文件的位置即可:
qemu-system-arm \ -M vexpress-a9 \ -m 512M \ -kernel /work/linux-5.2.8/arch/arm/boot/zImage \ -dtb /work/linux-5.2.8/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ -nographic \ -append "console=ttyAMA0"
-m指定內存大小;
-kernel:指定內核文件路徑;
-nographic: 不使用圖形界面,只使用串口;
-dtb: 指定dtb文件路徑;
-append :內核啟動參數,這里是告訴內核運行的串口設備是什么;
也可以使用 qemu-system-arm --help 來查看其他參數的使用說明。
不出意外的話,就可以在啟動窗口中看到內核的啟動日志了。在內核啟動的最后,會出現一條 panic 日志:
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---
從日志內容可以看出,內核啟動到一定階段后嘗試加載根文件系統,但我們沒有指定任何磁盤設備,所以無法掛載根文件系統。
而且編譯出來的內核模塊現在也沒有用上,內核模塊也需要存放到文件系統中供內核需要的時候進行加載。
所以,接下來需要制作一個磁盤鏡像文件供內核作為根文件系統加載。
注意:如果需要退出qemu:在qemu中輸入ctrl+a 抬起后,再輸入’x’。
三、根文件系統制作
根文件系統的制作,需要使用busybox工具,參考之前的文章Mini2440之yaffs2根文件系統移植,按照這篇文章的前兩節進行操作,生成rootfs文件夾即可:
制作SD卡鏡像:
cd /work/sambashare
dd if=/dev/zero of=rootfs.ext4.img bs=1M count=32
此時會在當前路徑下生成rootfs.ext4.img文件:
-rw-r--r-- 1 root root 33554432 2月 8 22:24 rootfs.ext4.img
顯然,rootfs.ext4.img並不是真正的SD卡設備,它只是我們在磁盤上創建的一個文件(為qemu創建的虛擬SD卡)。
接下來我們會假裝它是一張SD卡,並正兒八經的對其進行格式化、掛載等操作。先將它按照ext4文件系統格式進行格式化:
mkfs.ext4 rootfs.ext4.img
成功后顯示如下:
把這個鏡像文件按照ext4文件系統類型進行掛載,從而方便往里面拷貝內容。
注意,rootfs.ext4.img不是真正的SD卡,實質是一個文件,一個包含有文件系統格式的文件,也就是一個loop設備。所以掛載的時候要添加loop選項:
mkdir -p /mnt/rootfs # 沒有才創建
mount -t ext4 -o loop rootfs.ext4.img /mnt/rootfs
這里我們將rootfs.ext4.img掛載到/mnt/rootfs路徑下。
最后,將我們通過busybox創建的根文件系統拷貝到掛載點/mnt/rootfs上,並卸載rootfs.ext4.img:
cp -a rootfs/* /mnt/rootfs/ umount /mnt/rootfs
此時文件系統將會被拷貝到rootfs.ext4.img文件系統中。
四、在qemu上利用啟動kernel
制作好根文件系統鏡像之后,就可以使用qemu運行kernel了,看看能不能成功掛載根文件系統。運行如下命令:
qemu-system-arm \ -M vexpress-a9 \ -m 512M \ -kernel /work/linux-5.2.8/arch/arm/boot/zImage \ -dtb /work/linux-5.2.8/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ -nographic \ -sd /work/sambashare/rootfs.ext4.img \ -append "root=/dev/mmcblk0 rw console=ttyAMA0"
啟動成功后,最后出現如下圖示:
Please press Enter to activate this console.
按提示按下 Enter 鍵之后將會啟動 shell,進行到我們熟悉的環境,可以執行各種常用命令了。
比如運行命令:
[root@zy:/]# ls bin lib mnt sbin usr dev linuxrc proc sys etc lost+found root tmp
設備文件也被自動創建了:
[root@zy:/]# ls /dev console tty10 tty53 cpu_dma_latency tty11 tty54 full tty12 tty55 gpiochip0 tty13 tty56 gpiochip1 tty14 tty57 ...
五、總結
到了這里,基於qemu的linux開發環境已經搭建成功了。這里從網上找到一張linux內核啟動流程圖:
參考文章:
[2]搭建基於qemu的linux開發環境(部分轉載)