使用QEMU模擬搭建ARM開發平臺(三)——添加SCSI和MTD以及NAND flash支持

使用versatile_defconfig編譯的內核不能滿足要求,現在,添加SCSI磁盤,MTD以及NAND flash的支持。

交叉編譯linux內核

下載codesourcery的交叉編譯工具鏈 https://sourcery.mentor.com/sgpp/lite/arm/portal/subscription?@template=lite, 選擇目標OS爲GNU/Linux。下載後解壓,將/path/to/arm-2011.03/bin 添加到PATH中。

$ cd linux-2.6.39.2
$ make ARCH=arm versatile_defconfig
$ make ARCH=arm menuconfig

Kernel Features
  -> Use the ARM EABI to compile the kernel
  -> Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

編譯完成後,會在arch/arm/boot/目錄下生成zImage,可以使用qemu來測試編譯的內核是否可以啓動,如果沒有安裝qemu,則安裝

# apt-get install qemu-system
$ qemu-system-arm -M versatilepb -kernel arch/arm/boot/zImage -nographic -append "console=ttyAMA0"

可以看到,內核能啓動,但是由於沒有根文件系統而panic。

構建根文件系統

$ mkdir rootfs

將codesourcery工具鏈中針對arm的lib庫複製到根文件系統中,這一步是可選的,因爲在下面將把busybox編譯成靜態鏈接的包。

$ cp -r /path/to/arm-2011.03/arm-none-linux-gnueabi/libc/lib rootfs

將庫文件strip,減小大小,可選的。

$ cd rootfs/lib
$ arm-none-linux-gnueabi-strip *.so

提示libgcc_s.so不能識別,沒關係,它是一個ASCII ld腳本,忽略即可。 現在,編譯busybox-1.18.5

$ cd busybox-1.18.5
$ make ARCH=arm defconfig
$ make ARCH=arm menuconfig
Busybox Settings
--> Build Options
  --> Build BusyBox as a static binary (no shared libs)

如果不將busybox編譯成靜態鏈接程序,那麼前面的複製lib工作就是必須的。

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- CONFIG_PREFIX=/patch/to/rootfs install // 將busybox安裝到rootfs中
將rootfs打包成一個initramfs
$ cd rootfs
$ find . | cpio -o -H newc | gzip -9 > ../rootfs.img
$ qemu-system-arm -M versatilepb -nographic -kernel zImage -initrd rootfs.img -append "console=ttyAMA0"

可以看到,內核還是發生了panic,報錯沒有根文件系統,這裏已經不是由kernel直接報錯,而是有rootfs.img報錯,因爲它試圖掛載真正的根文件系統。可以做如下測試

$ qemu-system-arm -M versatilepb -nographic -kernel zImage -initrd rootfs.img -append "console=ttyAMA0 root=/dev/ram"

現在,儘管最後還是panic,但是並不是沒有合適的root=參數了,而是文件系統不能正確掛載。再進一步

$ qemu-system-arm -M versatilepb -nographic -kernel zImage -initrd rootfs.img -append "console=ttyAMA0 root=/dev/ram rdinit=/bin/sh"

可以發現,現在不再發生panic了,因爲系統不再試圖掛載真正的根文件系統。現在啓動到了initramfs中,由於沒有啓動一個設備管理器,沒有掛載proc, sysfs文件系統,busybox不能很好的工作,可以做如下測試

$ qemu-system-arm -M versatilepb -nographic -kernel zImage -initrd rootfs.img -append "console=ttyAMA0 root=/dev/ram rdinit=/sbin/init"

當busybox的/sbin/init啓動後,會提示很多錯誤,包括沒有設備文件等。現在來解決這個問題。

$ cd rootfs
$ mkdir -p etc/init.d
$ cat > etc/init.d/rcS <<EOF
> #!/bin/sh
> mkdir /proc
> mkdir /sys
> mount -t proc proc /proc
> mount -t sysfs sysfs /sys
> mdev -s
> EOF
$ cdmod +x etc/init.d/rcS
$ find . | cpio -o -H newc | gzip -9 > ../rootfs.img
$ qemu-system-arm -M versatilepb -nographic -kernel zImage -initrd rootfs.img -append "console=ttyAMA0 root=/dev/ram rdinit=/sbin/init"

現在,系統可以工作正常了,出現了提示

Please press Enter to activate this console.

編譯mtd-utils

$ mkdir -p mtd/install
$ tar xjf zlib-1.2.5.tar.bz2
$ cd zlib-1.2.5
$ ./configure --prefix=../mtd/install

在Makefile中,將gcc, ar, ranlib命令加上前綴arm-none-linux-gnueabi-

$ make
$ make install

$ tar xzf lzo-2.05.tar.gz
$ cd lzo-2.05
$ ./configure --host=arm-none-linux-gnueabi --prefix=/root/BELS/mtd/install // --prefix需要絕對路徑
$ make
$ make install

$ git clone git://git.infradead.org/mtd-utils.git
$ cd mtd-utils
$ git checkout v1.4.5 -b v1.4.5

現在,需要對mtd-utils打一個編譯補丁,設置相應的頭文件和庫目錄爲剛纔已經編譯好的zlib, lzo。

diff --git a/Makefile b/Makefile
index 8bdba8e..ec7608f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,16 @@

# -*- sh -*-

+PREFIX = /root/BELS/mtd/install
+
+ZLIBCPPFLAGS = -I$(PREFIX)/include
+LZOCPPFLAGS = -I$(PREFIX)/include/lzo
+
+ZLIBLDFLAGS = -L$(PREFIX)/lib
+LZOLDFLAGS = -L$(PREFIX)/lib
+
+CFLAGS ?= -O2 -g $(ZLIBCPPFLAGS) $(LZOCPPFLAGS)
+
CPPFLAGS += -I./include $(ZLIBCPPFLAGS) $(LZOCPPFLAGS)

ifeq ($(WITHOUT_XATTR), 1)
@@ -12,7 +22,8 @@ else
LZOLDLIBS = -llzo2
endif

-SUBDIRS = lib ubi-utils mkfs.ubifs
+#SUBDIRS = lib ubi-utils mkfs.ubifs
+SUBDIRS = lib ubi-utils
TESTS = tests

TARGETS = ftl_format flash_erase nanddump doc_loadbios \
diff --git a/common.mk b/common.mk
index 0f3d447..fea0651 100644
--- a/common.mk
+++ b/common.mk
@@ -21,7 +21,7 @@ ifneq ($(WITHOUT_LARGEFILE), 1)
endif

DESTDIR?=
-PREFIX=/usr
+PREFIX?=/usr
EXEC_PREFIX=$(PREFIX)
SBINDIR=$(EXEC_PREFIX)/sbin
MANDIR=$(PREFIX)/share/man

注意:上面的PREFIX變量的值設置爲zlib和lzo的安裝目錄!

$ cd mtd-utils
$ patch -p1 < /path/to/this.path

然後,運行如下命令編譯

$ WITHOUT_XATTR=1 make CROSS=arm-none-linux-gnueabi-
$ WITHOUT_XATTR=1 make CROSS=arm-none-linux-gnueabi- install

由於ubifs有額外的依賴關係,所以這裏暫不編譯ubifs,補丁中有一行刪除了對ubifs的編譯。。

支持SCSI,MTD, NAND flash

$ make ARCH=arm menuconfig
menuconfig需要配置的選項如下
Kernel Features
* --> Use the ARM EABI to compile the kernel
* --> Allow old ABI binaries to run with this kernel (EXPERIMENTAL)
Bus support
* --> PCI support
Device Drivers
--> Generic Driver Options
(/sbin/mdev) path to uevent helper // 這樣,mdev能夠幫助動態創建刪除設備
* --> Memory Technology Device (MTD) support
--> Self-contained MTD device drivers
[*|M] --> MTD using block device
[*|M] --> NAND Device Support
[*|M] --> Support for NAND flash Simulator
[*|M] --> Support for generic platform NAND driver
[*|M] --> Enable UBI - Unsorted block images
[*|M] --> MTD device emulation driver (gluebi)
--> SCSI device support
[*] --> SCSI device support
[*] --> SCSI disk support
[*] --> SCSI low-level drivers
<*> --> SYM53C8XX Version 2 SCSI support // 一定要選,否則不能支持SCSI設備 
--> File systems
[*] --> Miscellaneous filesystems
[M] --> UBIFS file system support

現在重新編譯

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- INSTALL_MOD_PATH=/path/to/rootfs/ modules_install

重新打包rootfs

$ cd /path/to/rootfs
$ find . | cpio -o -H newc | gzip -9 > ../rootfs.img

用qemu模擬

$ qemu-img create -f raw block.img 64M // 創建一個64M大小的磁盤
$ qemu-system-arm -M versatilepb -kernel rootfs/boot/zImage-2.6.39.2 -initrd rootfs.img -nographic -append "console=ttyAMA0 root=/dev/ram rdinit=/sbin/init" -hda block.img

啓動過後,就可以使用block2mtd來模擬MTD設備,也可以使用nandsim模塊來模擬NAND flash設備,由於添加了/sbin/mdev爲uevent helper,所以會在/dev/目錄下自動創建/刪除相應的設備。



今天看了《Embedded Programming with the GNU Toolchain》一文,其中介紹了利用QEMU進行ARM編程實驗的一種方法。基本思想是,在一個X86的Linux開發機中安裝一種稱爲codesourcery-tools的GNU工具鏈,該工具鏈中包含了交叉編譯器,利用該工具鏈在宿主機中編譯出ARM的可執行文件,然後利用QEMU仿真一個PXA255(connex)目標機,並將可執行文件加載到目標機中運行。

這種方法簡便易行,但由於在開發機中缺少操作系統,因此在彙編語言程序中無法引發系統調用。此外,每次交叉編譯完成後還要啓動QEMU加載可執行文件,這也比較麻煩。因此想搭建一個運行在ARM上完整的Linux系統,能夠在其中方便地進行彙編編程。在網上發現了一篇文章《Emulate an ARM Plaform with QEMU on Ubuntu 10.10》,其中採用的方法能夠滿足我的需要,因此進行了相應的實驗(下面的操作都採用root用戶身份)。

這種方法的基本思路是在一個Linux宿主機中利用QEMU運行一個虛擬機,並在虛擬機中安裝一個完整的基於ARM平臺的Linux環境,然後在虛擬機中安裝必要的開發工具。這樣,就可以在虛擬機中直接進行編程。具體的配置過程如下:

  1. 宿主機是X86,其中安裝了Ubuntu 12.04。首先在宿主機中安裝QEMU。
    apt-get install qemu-kvm qemu-kvm-extras
  2. Debian提供了ARM平臺的內核鏡像文件和initrd文件,利用這兩個文件啓動QEMU後可以開始一個安裝過程,在QEMU的虛擬硬盤中安裝一個基於ARM平臺的基本操作環境。
    mkdir arm-emul; cd arm-emul
    wget ftp://ftp.debian.org/debian/dists/squeeze/main/installer-armel/current/images/versatile/netboot/vmlinuz-2.6.32-5-versatile
    wget ftp://ftp.debian.org/debian/dists/squeeze/main/installer-armel/current/images/versatile/netboot/initrd.gz
  3. 創建虛擬硬盤。
    qemu-img create -f raw hda.img 2G
  4. 啓動QEMU創建一個versatilepb虛擬機,並開始安裝過程。該安裝過程需要從Debian服務器下載安裝文件,因此在啓動QEMU之前應保證宿主機已經連接Internet。
    qemu-system-arm -m 256 -M versatilepb -kernel vmlinuz-2.6.32-5-versatile -initrd initrd.gz -hda hda.img -append "root=/dev/ram"
    整個安裝過程與通常Debian或Ubuntu的安裝過程類似,只是在最後階段選擇軟件包的時候可以將SSH服務器選上,這樣今後可以通過SSH遠程登錄虛擬機。由於虛擬機是文本界面,其窗口較小,在宿主機中遠程登錄虛擬機後就可以在較大的終端窗口中進行編程。
    qemu-system-arm -m 256 -M versatilepb -kernel vmlinuz-2.6.32-5-versatile -initrd initrd.gz -hda hda.img -append "root=/dev/ram"
  5. 安裝完成後,需要將虛擬機硬盤中的initrd文件拷貝到宿主機中。爲此,應將虛擬機關閉,然後將虛擬硬盤中用於存儲根文件系統的分區掛載到指定的目錄,最後將文件複製出來。在掛載之前應先計算出硬盤分區的偏移量。具體的計算方法見《如何掛載一個鏡像文件》一文。
    mount -o loop,offset=1048576 hda.img /mnt
    cp /mnt/boot/initrd.img-2.6.32-5-versatile .
    umount /mnt
  6. 編寫一個啓動腳本,用於在宿主機中啓用TAP,然後啓動虛擬機。虛擬機與宿主機在同一個網段中,並假設該網段中有DHCP服務器。如不存在DHCP服務,則需要相應地修改腳本。
    #! /bin/sh

    ifconfig eth0 down                  
    brctl addbr br0                     
    brctl addif br0 eth0               
    ifconfig br0 0.0.0.0 promisc up     
    ifconfig eth0 0.0.0.0 promisc up    
    dhclient br0                        
    tunctl -t tap0 -u root              
    brctl addif br0 tap0                
    ifconfig tap0 0.0.0.0 promisc up   

    qemu-system-arm -m 256 -M versatilepb -kernel vmlinuz-2.6.32-5-versatile -initrd initrd.img-2.6.32-5-versatile -hda hda.img -append "root=/dev/sda1" -net nic -net tap,ifname=tap0,script=no,downscript=no
  7. 重新啓動虛擬機後,安裝編程所需要的工具。
    apt-get install build-essential   # 工具鏈
    apt-get install jed               # 編輯器
  8. 在宿主機中開一個終端窗口,執行ssh命令遠程登錄虛擬機。現在就可以開始ARM的編程了。


參考文獻:
Embedded Programming with the GNU Toolchain
codesourcery-tools
Emulate an ARM Plaform with QEMU on Ubuntu 10.10
Debian FTP
如何掛載一個鏡像文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章