Ubuntu下基于u-boot搭建qemu的vexpress环境

上一篇文章搭建了基于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" 
        "dram=1024M" 
        "root=/dev/sda1 rw" 
        "mtd=armflash:1M@0x800000(uboot),7M@0x1000000(kernel)," 
            "24M@0x2000000(initrd)" 
        "flashargs=setenv bootargs root=${root} console=${console} " 
            "mem=${dram} mtdparts=${mtd} mmci.fmax=190000 " 
            "devtmpfs.mount=0  vmalloc=256M" 
        "bootflash=run flashargs; " 
            "cp ${ramdisk_addr} ${ramdisk_addr_r} ${maxramdisk}; " 
            "bootm ${kernel_addr} ${ramdisk_addr_r}"

  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
原文地址:https://www.cnblogs.com/edver/p/12117349.html