汇编语言
汇编语言一发入魂 – 杨河老李 (kviccn.github.io)
安装QEMU
QEMU安装有两种方式:一种是直接使用apt-get安装,一种是下载源码安装。我们选择第一种安装方式:
wit@ubuntu:~$ sudo apt-get install qemu
wit@ubuntu:~$ qemu-system-
qemu-system-aarch64 qemu-system-microblazeel qemu-system-ppc qemu-system-sparc64
qemu-system-alpha qemu-system-mips qemu-system-ppc64 qemu-system-tricore
qemu-system-arm qemu-system-mips64 qemu-system-ppc64le qemu-system-unicore32
qemu-system-cris qemu-system-mips64el qemu-system-ppcemb qemu-system-x86_64
qemu-system-i386 qemu-system-mipsel qemu-system-s390x qemu-system-xtensa
qemu-system-lm32 qemu-system-moxie qemu-system-sh4 qemu-system-xtensaeb
qemu-system-m68k qemu-system-nios2 qemu-system-sh4eb
qemu-system-microblaze qemu-system-or1k qemu-system-sparc
安装成功后,敲击qemu-system-命令,在弹出的提示中我们可以看到qemu支持不同的CPU架构。弱水三千,只取一瓢饮,我们主要是使用qemu-system-arm 和 qemu-system-aarch64命令,分别仿真ARM 32位和64位的开发平台,敲入下面的命令可以查看qemu-system-arm目前支持的开发板种类:
wit@ubuntu:~$ qemu-system-arm --version
QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.29)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
wit@ubuntu:~$ qemu-system-arm -M help
Supported machines are:
akita Sharp SL-C1000 (Akita) PDA (PXA270)
ast2500-evb Aspeed AST2500 EVB (ARM1176)
borzoi Sharp SL-C3100 (Borzoi) PDA (PXA270)
canon-a1100 Canon PowerShot A1100 IS
cheetah Palm Tungsten|E aka. Cheetah PDA (OMAP310)
collie Sharp SL-5500 (Collie) PDA (SA-1110)
connex Gumstix Connex (PXA255)
cubieboard cubietech cubieboard
emcraft-sf2 SmartFusion2 SOM kit from Emcraft (M2S010)
highbank Calxeda Highbank (ECX-1000)
imx25-pdk ARM i.MX25 PDK board (ARM926)
integratorcp ARM Integrator/CP (ARM926EJ-S)
kzm ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb Stellaris LM3S6965EVB
lm3s811evb Stellaris LM3S811EVB
mainstone Mainstone II (PXA27x)
midway Calxeda Midway (ECX-2000)
mps2-an385 ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an511 ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3
musicpal Marvell 88w8618 / MusicPal (ARM926EJ-S)
n800 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810 Nokia N810 tablet aka. RX-44 (OMAP2420)
netduino2 Netduino 2 Machine
none empty machine
nuri Samsung NURI board (Exynos4210)
palmetto-bmc OpenPOWER Palmetto BMC (ARM926EJ-S)
raspi2 Raspberry Pi 2
realview-eb ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8 ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9 ARM RealView Platform Baseboard Explore for Cortex-A9
romulus-bmc OpenPOWER Romulus BMC (ARM1176)
sabrelite Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)
smdkc210 Samsung SMDKC210 board (Exynos4210)
spitz Sharp SL-C3000 (Spitz) PDA (PXA270)
sx1 Siemens SX1 (OMAP310) V2
sx1-v1 Siemens SX1 (OMAP310) V1
terrier Sharp SL-C3200 (Terrier) PDA (PXA270)
tosa Sharp SL-6000 (Tosa) PDA (PXA255)
verdex Gumstix Verdex (PXA270)
versatileab ARM Versatile/AB (ARM926EJ-S)
versatilepb ARM Versatile/PB (ARM926EJ-S)
vexpress-a15 ARM Versatile Express for Cortex-A15
vexpress-a9 ARM Versatile Express for Cortex-A9
virt-2.10 QEMU 2.10 ARM Virtual Machine
virt QEMU 2.11 ARM Virtual Machine (alias of virt-2.11)
virt-2.11 QEMU 2.11 ARM Virtual Machine
virt-2.6 QEMU 2.6 ARM Virtual Machine
virt-2.7 QEMU 2.7 ARM Virtual Machine
virt-2.8 QEMU 2.8 ARM Virtual Machine
virt-2.9 QEMU 2.9 ARM Virtual Machine
xilinx-zynq-a9 Xilinx Zynq Platform Baseboard for Cortex-A9
z2 Zipit Z2 (PXA27x)
我们接下来想在vexpress-a9虚拟开发板上运行Linux内核镜像zImage,来检测qemu-system-arm安装是否正确。
$ touch boot.sh
$ gedit boot.sh
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-dtb ./vexpress-v2p-ca9.dtb \
-kernel ./zImage \
-append "root=/dev/mmcblk0 rw console=tty0" \
-sd rootfs.ext3
$ chmod +x boot.sh
$ ./boot.sh
创建一个启动脚本boot.sh,将上面的启动命令添加到脚本中,增加脚本执行权限,通过脚本即可直接执行qemu-system-arm,不用每次都输入命令了。
其中zImage和vexpress-v2p-ca9.dtb为A9 vexpress ARM 开发板的内核镜像和设备树文件,rootfs.ext3为SD卡文件系统镜像。为了验证软件安装是否正常,我们先使用测试镜像看是否正常启动,测试镜像下载地址,可关注公/众/号:宅学部落,然后回复:测试镜像,即可获取下载地址。
将zImage、vexpress-v2p-ca9.dtb、rootfs.ext3三个文件跟脚本boo.sh放置在同一个目录下,然后就可以运行脚本文件了。每次重启qemu-system-arm前,要将原来的qemu-system-arm进程先关掉。
如果你想在窗口控制台下启动Linux内核镜像,可以使用下面的脚本启动qemu-system-arm:
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-nographic \
-dtb ./vexpress-v2p-ca9.dtb \
-kernel ./zImage \
-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd rootfs.ext3
第08步:使用u-boot引导Linux内核
在嵌入式系统中,我们通常使用U-boot、vivi等BootLoader来引导Linux内核启动,接下来我们也在虚拟开发板上使用U-boot通过TFTP工具来引导Linux内核启动。
安装依赖的包:
$ sudo apt install net-tools
$ sudo apt install net-tools uml-utilities bridge-utils
在安装Ubuntu18.04时,我们配置了2个虚拟网卡,一个用来跟虚拟开发板桥接通信,一个用来共享主机的网络,访问互联网,保证我们能正常使用 apt/apt-get 安装软件。使用 ifconfig命令查看网卡的名字,在我的虚拟机上,分别是ens33和ens34,对应的IP分别为:
ens33:192.168.230.135
ens34:192.168.230.136
配置虚拟开发板与主机Ubuntu的桥接,修改/etc/network/interfaces文件,重启生效:
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
auto ens33
auto br0
iface br0 inet dhcp
bridge_ports ens33
重启后,再次使用ifconfig命令:
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.230.135 netmask 255.255.255.0 broadcast 192.168.230.255
inet6 fe80::20c:29ff:fed7:c2d9 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d7:c2:d9 txqueuelen 1000 (Ethernet)
RX packets 7614 bytes 925743 (925.7 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 7461 bytes 10786796 (10.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::20c:29ff:fed7:c2d9 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d7:c2:d9 txqueuelen 1000 (Ethernet)
RX packets 969 bytes 737515 (737.5 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 398 bytes 45850 (45.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens34: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.230.136 netmask 255.255.255.0 broadcast 192.168.230.255
inet6 fe80::49ca:25c9:5944:75d3 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d7:c2:e3 txqueuelen 1000 (Ethernet)
RX packets 348 bytes 44710 (44.7 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 163 bytes 16043 (16.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
如果发现出现了br0说明配置成功。接下来我们在开发板上运行u-boot,在开发板端ping 主机,看是否能ping通,来验证开发板和Ubuntu主机之间是否网络通畅。启动U-boot的脚本如下:
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-nographic \
-kernel ./u-boot \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-sd rootfs.ext3
在u-boot环境下,分别设置ipaddr和serverip,分别对应开发板的IP和主机的IP,两个IP要设置在同一个网段内,主机的IP即桥接网口br0的IP:192.168.230.135
=> setenv ipaddr 192.168.230.130
=> setenv serverip 192.168.230.135
=> ping 192.168.230.135
在开发板上ping主机host有反应,说明开发板和Ubuntu主机网络已经搞通。如果我们想使用TFTP工具从主机Ubuntu上下载uImage镜像,还得在主机上安装TFTP服务。
安装主机Host上的TFTP服务
$ sudo apt-get install tftp-hpa tftpd-hpa xinetd
在Ubuntu下修改配置文件:/etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/wit/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"
通过配置文件,开发板默认会从/home/wit/tftpboot目录下去下载指定的文件。我们需要在主机上创建这个目录:
$ sudo mkdir /home/wit/tftpboot
$ sudo chmod 777 /home/wit/tftpboot
$ sudo /etc/init.d/tftpd-hpa restart
主机的TFTP服务开起来之后,我们接下来重启u-boot,设置ipaddr和serverip,就可以直接从主机上的/home/wit/tftpboot目录下加载uImage内核镜像运行了。
=> setenv ipaddr 192.168.230.135
=> setenv serverip 192.168.230.130
=> tftp 0x60003000 uImage
=> tftp 0x60500000 vexpress-v2p-ca9.dtb
=> bootm 0x60003000 - 0x60500000
到了这一步,说明网络配置成功,u-boot可以通过网络引导Ubuntu中的内核镜像启动。
第09步:自动化引导
如果每次嫌敲命令麻烦,我们可以修改bootcmd变量,这就需要自己编译u-boot源码了。从官网上下载最新的U-boot源码,解压后,修改:include/configs/vexpress_common.h:
/*Netmask*/
196 #define CONFIG_IPADDR 192.168.230.130
197 #define CONFIG_NETMASK 255.255.255.0
198 #define CONFIG_SERVERIP 192.168.230.135
安装ARM交叉编译器,并编译u-boot:
安装编译器:$ sudo apt install gcc-arm-linux-gnueabi gcc make libncurses-dev bison flex
下载u-boot源码: http://ftp.denx.de/pub/u-boot/
最新版的u-boot2020.07,ARCH和bootcmd可以通过make menuconfig 菜单选项配置。在Architecture select选项中选择:ARM architecture
设置bootcmd命令:
在弹出的输入栏中输入bootcmd命令:
tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0';bootm 0x60003000 - 0x60500000;
将修改保存,退出菜单配置界面,然后就可以直接编译u-boot了:
$ CROSS_COMPILE=arm-linux-gnueabi-
$ export CROSS_COMPILE
$ make vexpress_ca9x4_defconfig
$ make
将生成的u-boot拷贝到/home/wit/tftpboot目录,运行脚本启动u-boot看是否能自动引导uImage启动。
第10步:挂载NFS文件系统
开发板挂载NFS文件系统,在开发板上要运行的文件不需要拷贝到开发板上,直接拷贝到主机Ubuntu的NFS上即可,非常方便。要想开发板挂载NFS文件系统,主机Ubuntu上首先要开启NFS服务:
$ sudo apt install nfs-kernel-server
在/etc/exports文件中添加:
/home/rootfs *(rw,sync,no_root_squash,no_subtree_check)
开启NFS服务:
$ sudo /etc/init.d/rpcbind restart
$ sudo /etc/init.d/nfs-kernel-server restart
修改bootargs启动参数:
tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/nfs rw nfsroot=192.168.230.139:/home/wit/rootfs,proto=tcp,nfsvers=4,nolock init=/linuxrc ip=192.168.230.130 console=ttyAMA0';bootm 0x60003000 - 0x60500000;
Ubuntu18.04使用的NFS版本是4,因此我们需要编译内核,支持NFS v4版本
接着配置和编译内核:
修改Makefile:ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
$ make vexpress_defconfig
$ make zImage
$ apt install u-boot-tools
$ make uImage LOADADDR=0x60003000
$ make dtbs
将生成的arch/arm/boot/uImage和arch/arm/boot/dts/vexpress-v2p-ca9.dtb拷贝到/home/wit/tftpboot目录下,使用下面的命令启动内核:
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-nographic \
-kernel ./u-boot \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-sd rootfs.ext3