PC系统:Windows10
虚拟机:VMware12
虚拟机系统:ubuntu16.04
模拟的开发板:vexpress
我测试时使用的是以下版本
linux-4.13.1(Linux Kernel)
u-boot-2018.01
busybox-1.29.3
arm-none-linux-gnueabihf-gcc (9.2.1)
- 安装交叉编译器
自定义一个目录,添加到环境变量就行,这个网上一堆教程,不再赘述 - 安装qemu
sudo apt install qemu
查看qemu版本
qemu-system-arm --version
查看qemu支持的开发板
qemu-system-arm –M help
qemu运行格式
qemu-system-arm -M vexpress-a9 -m 1024M -kernel ./zImage -dtb
./vexpress-v2p-ca9.dtb -nographic -append “console=ttyAMA0”
-M 指定开发板
-m 指定内存大小
-kernel 指定执行文件
-dtb 指定dtb文件
-nographic 指定不需要图形界面 -append 指定扩展显示界面,串口或者LCD
- 测试单独运行kernel
编译kernel
make vexpress_defconfig
make zImage -j4
make dtbs
结果:
arch/arm/boot/zImage
arch/arm/boot/dts/vexpress-v2p-ca9.dtb
把zImage和vexpress-v2p-ca9.dtb复制到自定义的out目录,方便后面操作
写一个 qemu启动命令脚本调试更方便
#! /bin/bash
qemu-system-arm \
-M vexpress-a9 \
-m 1024M \
-kernel out/zImage \
-dtb out/vexpress-v2p-ca9.dtb \
-nographic \
-append “console=ttyAMA0”
此时运行脚本,内核启动后会卡在启动rootfs的地方,因为还没指定rootfs,下面接着制作rootfs
- 制作rootfs
这都和平常使用busybox工具的方式一样,修改以下环境变量或者在Makefile修改
cd busybox
export ARCH = arm
export CROSS_COMPILE =arm-none-linux-gnueabihf-
编译选择使用glibc静态库
make menuconfig Settings —>
Build Options —>
[*]Build static binary (no shared libs)
编译安装
make
make install
将busybox编译生成的_install目录拷贝到out目录并修改目录名
cp _install …/out/rootfs -a
复制glibc库
找到交叉编译器安装目录,拷贝lib目录到rootfs
cp /usr/arm-linux-gnueabi/lib/* rootfs/lib/ -rfp
静态创建设备文件
mkdir rootfs/dev
cd rootfs/dev
sudo mknod -m 666 tty1 c 4 1
sudo mknod -m 666 tty2 c 4 2
sudo mknod -m 666 tty3 c 4 3
sudo mknod -m 666 tty4 c 4 4
sudo mknod -m 666 console c 5 1
sudo mknod -m 666 null c 1 3
修改文件所属用户及用户组
sudo chown your_name *
sudo chgrp your_name *
- 制作系统镜像:
dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
- 格式化为ext3文件系统:
mkfs.ext3 rootfs.ext3
sudo mount -t ext3 rootfs.ext3 /mnt -o loop sudo
cp -rf rootfs/* /mnt/
sudo umount /mnt
- 修改启动脚本
添加以下内容
-append “root=/dev/mmcblk0 rw console=ttyAMA0” \
-sd out/rootfs.ext3
此时再运行脚本就能进入rootfs目录了。做到这是不是觉得少了点什么——uboot,没有uboot的系统怎么能完整呢,看下面。
- 测试编译uboot
cd u-boot
make vexpress_ca9x4_defconfig ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf-
make
如果编译过程报错
/bin/sh: 1: bison: not found
scripts/Makefile.lib:217: recipe for target 'scripts/kconfig/zconf.tab.c' failed
make[2]: *** [scripts/kconfig/zconf.tab.c] Error 127
bin/sh: 1: flex: not found
scripts/Makefile.lib:202: recipe for target 'scripts/kconfig/zconf.lex.c' failed
这是缺少依赖包,安装上再编译就好了
sudo apt-get install bison flex
因为我们要从uboot开始执行程序,那么我们在上面的脚本中的-kernel参数指定的zImage就要修改成uboot了,那我们怎么加载内核呢,此时就要用到tftp服务了,是不是感觉和真实的开发板环境一样。
准备工作:
安装桥接网络依赖的两个工具:
sudo apt install uml-utilities bridge-utils
查看是否有这个设备文件 /dev/net/tun
配置桥接
修改/etc/network/interfaces文件配置网络
sudo vim /etc/network/interfaces
auto lo
iface lo inet loopback
auto ens33 #根据ifconfig命令查看虚拟网络名
auto br0
iface br0 inet dhcp
bridge_ports ens33
安装tftp服务
sudo apt install tftp-hpa tftpd-hpa xinetd
修改配置文件,设置TFTP服务器目录:
sudo vi /etc/default/tftpd-hpa
修改这个字段指定tftp目录:
目录都可以自定义,不过要把目录修改成当前的用户和用户组,使用chown和chgrp命令
TFTP_DIRECTORY="/opt/tftpboot"
Linux主机上创建tftp目录:
mkdir /opt/tftpboot
chmod 777 /opt/tftpboot
重启tftp服务:
sudo /etc/init.d/tftpd-hpa restart
修改uboot指定的默认命令行
vi u-boot/include/configs/vexpress_common.h
#define CONFIG_BOOTCOMMAND \
“tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-c9.dtb;
setenv bootargs ‘root=/dev/mmcblk0 console=ttyAMA0’;
bootm 0x60003000-0x60500000;”
设置uboot中ipaddr、netmask、serverip环境变量,也可以在uboot启动后设置这几个变量,不过每次启动都要修改太麻烦,ipaddr是这个uboot的ip地址,serverip是tftp主机的IP地址。
#define CONFIG_IPADDR 192.168.1.11
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 192.168.1.103
再次编译uboot, uboot准备好了,就要准备uboot能加载的uImage
cd kernel
make LOADADDR=0x60003000 uImage -j4
把编译好的uImage和uboot都复制到out目录下
设置qemu启动参数
qemu-system-arm \
-M vexpress-a9 \
-m 1024M \
-kernel u-boot \
#-dtb vexpress-v2p-ca9.dtb \
-nographic \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
#-append "root=/dev/mmcblk0 rw console=ttyAMA0" \
-sd rootfs.ext3
此时就可以看到从uboot启动,倒数计时后tftp下载kernel,然后加载rootfs。
如果此时你还觉得每次修改rootfs都要重新制作rootfs.ext3调试不方便,想用nfs挂载rootfs,也没问题
- nfs挂载rootfs
- 安装nfs
sudo apt install nfs-kernel-server
vi /etc/exports
/opt/rootfs *(rw, sync, no_root_squash, no_subtree_check)
创建这个nfs指定的目录
mkdir /opt/rootfs
修改uboot命令行,还是上面那个目录
vi u-boot/include/configs/vexpress_common.h
#define CONFIG_BOOTCOMMAND \
"tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \
setenv bootargs 'root=/dev/nfs rw \
nfsroot=192.168.1.103:/opt/nfsroot/vexpress_rootfs init=/linuxrc \
ip=192.168.1.11 console=ttyAMA0'; \
bootm 0x60003000 - 0x60500000;"
重新编译uboot后复制到out目录
nfsrootf指定的是nfs主机的ip地址和目录,ip指定uboot的ip地址。目录和ip根据自己的实际情况修改。
- 重新制作rootfs
修改busybox
make menuconfg Linux System Utilities —>
[**] mount (30 kb)
[*] Support mounting NFS file systems on Linux < 2.6.23
重新编译后按照上面的步骤复制到nfs目录
在rootfs中创建启动脚本
- 创建etc/inittab文件添加以下内容
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r
#console::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
- 创建init.d/rcS
#! /bin/sh
PATH=/sbin:/bin:/user/sbin:/usr/bin
LD_LIBRARY_PATH=/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir -p /dev/pts
mount -t devpts devpts dev/pts
mdev -s
mkdir -p /var/lock
- 创建etc/fstab
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0