上一篇文章搭建了基於zImage的qemu環境,基本的環境配置已經可以使用,為了還原真正的嵌入式ARM啟動場景,搭建基於u-boot的qemu環境。
1. u-boot下載及編譯
1.1 下載地址 https://ftp.denx.de/pub/u-boot/,本文使用的版本為2019.10
1.2 下載后解壓進行配置
# vim Makefile
CROSS_COMPILE = arm-linux-gnueabi-
# vim config.mk
ARCH = arm
編譯
sly@ubuntu:~/develop/u-boot-2019.10$ make vexpress_ca9x4_defconfig
sly@ubuntu:~/develop/u-boot-2019.10$ make -j20
1.3 qemu啟動u-boot
sly@ubuntu:~/develop$ qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot-2019.10/u-boot
----省略部分打印,下面打印環境變量
=> print
arch=arm
baudrate=38400
board=vexpress
board_name=vexpress
bootargs=root=/dev/sda1 rw console=ttyAMA0,38400n8 mem=1024M mtdparts=armflash:1M@0x800000(uboot),7M@0x1000000(kernel),24M@0x2000000(initrd) mmci.fmax=190000 devtmpfs.mount=0 vmalloc=256M
console=ttyAMA0,38400n8
cpu=armv7
kernel_addr=0x44100000
kernel_addr_r=0x80008000
loadaddr=0x80008000
maxramdisk=0x1800000
mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi
mtd=armflash:1M@0x800000(uboot),7M@0x1000000(kernel),24M@0x2000000(initrd)
pxefile_addr_r=0x88000000
ramdisk_addr=0x44800000
ramdisk_addr_r=0x61000000
root=/dev/sda1 rw
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done; setenv devplist
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then echo Found ${prefix}${boot_syslinux_conf}; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x88000000
stderr=serial
stdin=serial
stdout=serial
ubifs_boot=env exists bootubipart || env set bootubipart UBI; env exists bootubivol || env set bootubivol boot; if ubi part ${bootubipart} && ubifsmount ubi${devnum}:${bootubivol}; then devtype=ubi; run scan_dev_for_boot; fi
vendor=armltd
2. 准備uImage的內核,指定加載地址,編譯uImage
sly@ubuntu:~/develop/linux-5.3.7$ make LOADADDR=0x60003000 uImage -j4 HOSTCC scripts/dtc/dtc.o HOSTCC scripts/dtc/flattree.o HOSTCC scripts/dtc/fstree.o HOSTCC scripts/dtc/data.o。。。。省略部分。。。 LD vmlinux.o MODPOST vmlinux.o MODINFO modules.builtin.modinfo KSYM .tmp_kallsyms1.o KSYM .tmp_kallsyms2.o LD vmlinux SORTEX vmlinux SYSMAP System.map OBJCOPY arch/arm/boot/Image Kernel: arch/arm/boot/Image is ready GZIP arch/arm/boot/compressed/piggy_data AS arch/arm/boot/compressed/piggy.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready UIMAGE arch/arm/boot/uImage Image Name: Linux-5.3.7 Created: Mon Dec 30 21:39:49 2019 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 4583688 Bytes = 4476.26 KiB = 4.37 MiB Load Address: 60003000 Entry Point: 60003000 Kernel: arch/arm/boot/uImage is ready
3.配置qemu的網絡
Qemu虛擬機在u-boot啟動時,需要將uImage加載到內存,而uImage從哪里來?可以通過TFTP服務器下載uImage到內存指定地址。而在這之前需要通過橋接方式將網絡鏈接到Ubuntu系統
3.1 配置Qemu與主機的網絡連接
采用橋接網絡連接Host主機通信
主機內核需要支持tun/tap模塊
VMware為機器再添加一張網卡,用於配置橋接網絡
3.2 配置Xubuntu主機
安裝橋接網絡依賴的兩個工具:
sudo apt install uml-utilities bridge-utils
創建tun設備文件:/dev/net/tun(一般會自動創建)
修改/etc/network/interfaces文件配置網絡
sly@ubuntu:~/develop/u-boot-2019.10$ vi /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
#查看自己的網口的名稱
auto ens33
iface ens33 inet static
address 192.168.199.150
netmask 255.255.255.0
gateway 192.168.199.2
#這是VMware添加的第二張網卡,用來給br0綁定
#這張網卡的連接方式是橋接或者NAT或者主機模式都可以,只要下面設置br0時設置正確就可以,參照br0的說明
#auto ens38
#br0設置成靜態ip方便自己調試,ip地址可以看下ens38自動獲取時的網段,需要設置在同一網段,否則會無法使用
auto br0
iface br0 inet static
address 192.168.189.152
netmask 255.255.255.0
#iface br0 inet dhcp
bridge_ports ens38
# The tap0 network interface(s)
#供qemu的u-boot使用的server地址,這這里綁定到了br0上,所以需要設置為和br0同一網段的ip
auto tap0
iface tap0 inet manual
iface tap0 inet static
address 192.168.189.20
netmask 255.255.255.0
pre-up tunctl -t tap0 -u root # 創建一個tap0接口,只允許root用戶訪問
pre-up ifconfig tap0 0.0.0.0 promisc up # 打開tap0接口
post-up brctl addif br0 tap0 # 在虛擬網橋中增加一個tap0接口
重啟機器
sly@ubuntu:~$ sudo reboot
查看網絡狀況
sly@ubuntu:~/develop$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:f6:0e:ad brd ff:ff:ff:ff:ff:ff
inet 192.168.199.150/24 brd 192.168.199.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fef6:ead/64 scope link
valid_lft forever preferred_lft forever
3: ens38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
link/ether 00:0c:29:f6:0e:b7 brd ff:ff:ff:ff:ff:ff
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:0c:29:f6:0e:b7 brd ff:ff:ff:ff:ff:ff
inet 192.168.189.152/24 brd 192.168.189.255 scope global br0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fef6:eb7/64 scope link
valid_lft forever preferred_lft forever
5: tap0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
link/ether aa:2c:ce:3d:1d:3f brd ff:ff:ff:ff:ff:ff
inet 192.168.189.20/24 brd 192.168.189.255 scope global tap0
valid_lft forever preferred_lft forever
inet6 fe80::a82c:ceff:fe3d:1d3f/64 scope link
valid_lft forever preferred_lft forever
2.2 主機安裝TFTP以便於u-boot從主機獲取uImage
a 安裝
apt-get install tftp-hpa tftpd-hpa xinetd
b 修改配置文件,設置TFTP服務器目錄,並且創建對應的目錄,將uImage和dtb文件拷貝進去:
# /etc/default/tftpd-hpa TFTP_USERNAME="tftp" TFTP_DIRECTORY="/home/sly/develop/tftpboot" TFTP_ADDRESS=":69" TFTP_OPTIONS="--secure"
c 重啟tftp服務
sudo /etc/init.d/tftpd-hpa restart
d 設置u-boot中的內核啟動參數 vi include/configs/vexpress_common.h
#define CONFIG_BOOTCOMMAND \ "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \ setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0'; \ bootm 0x60003000 - 0x60500000;" #define CONFIG_IPADDR 192.168.189.100 #define CONFIG_SERVERIP 192.168.189.20 #define CONFIG_NETMASK 255.255.255.0
刪除同文件中如下代碼
#define CONFIG_EXTRA_ENV_SETTINGS \ CONFIG_PLATFORM_ENV_SETTINGS \ BOOTENV \ "console=ttyAMA0,38400n8\0" \ "dram=1024M\0" \ "root=/dev/sda1 rw\0" \ "mtd=armflash:1M@0x800000(uboot),7M@0x1000000(kernel)," \ "24M@0x2000000(initrd)\0" \ "flashargs=setenv bootargs root=${root} console=${console} " \ "mem=${dram} mtdparts=${mtd} mmci.fmax=190000 " \ "devtmpfs.mount=0 vmalloc=256M\0" \ "bootflash=run flashargs; " \ "cp ${ramdisk_addr} ${ramdisk_addr_r} ${maxramdisk}; " \ "bootm ${kernel_addr} ${ramdisk_addr_r}\0"
e 重新編譯u-boot后,啟動qemu
sly@ubuntu:~/develop/u-boot-2019.10$ make
f 啟動qemu添加網絡參數,因為我們自己在/etc/network/interfaces已經預先設置了網絡環境,所以qemu的ifup和ifdown顯示指定為不使用,並且掛上之前制作的文件系統
sudo qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot-2019.10/u-boot -net nic -net tap,ifname=tap0,script=no,downscript=no -sd rootfs.ext3
這里有個小問題。第一次啟動u-boot的時候下載uImage總是失敗,手動在u-boot里下載一下后再重新執行上面的命令,向后就可以成功下載了
3.啟動和停止過程寫道腳本中方便使用,后續功能逐步添加
sly@ubuntu:~/develop$ vi start.sh #!/bin/sh sudo mount -t ext3 rootfs.ext3 tmp -o loop sudo cp -rf rootfs/* tmp/ sudo umount tmp echo "start kernel with $1" #傳入參數k,直接以zImage方式啟動,否則使用u-boot導入uImage啟動 if [ $1 = "k" ]; then qemu-system-arm -M vexpress-a9 -m 512m -kernel /home/sly/develop/linux-5.3.7/arch/arm/boot/zImage -dtb linux-5.3.7/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append "root=/dev/mm cblk0 console=ttyAMA0" -sd rootfs.ext3 -s else #拷貝文件到tftp目錄 #cp -rf cp -rf linux-5.3.7/arch/arm/boot/uImage tftpboot/ #cp -rf linux-5.3.7/arch/arm/boot/bootp/vexpress-v2p-ca9.dtb tftpboot/ sudo qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot-2019.10/u-boot -net nic -net tap,ifname=tap0,script=no,downscript=no -sd rootfs.ext3 fi
sly@ubuntu:~/develop$ vi stop.sh #!/bin/sh ps -aux | grep qemu-system-arm | grep -v grep | awk '{print $2}' | xargs kill -9
