============
在arm开发板上成功运行Linux系统,我们有如下三个方面的任务:
制作bootloader;
编译linux内核、linux内核模块、linux设备树;
制作根文件系统。
我们使用qemu虚拟机来上手嵌入式linux的开发。
安装qemu与arm交叉编译工具
略
Linux内核与设备树编译
下载Linux内核:https://www.kernel.org/
git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git
https://mirror.bjtu.edu.cn/kernel/linux/kernel/
make vexpress_defconfig
make zImage
make modules
make dtbs
得到zImage、dtb
尝试启动
qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append "console=ttyAMA0"
看到
rtc-pl031 10017000.rtc: setting system clock to 2020-11-02 09:39:39 UTC (1604309979)
ALSA device list:
#0: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 33
input: ImExPS/2 Generic Explorer Mouse as /devices/platform/smb/smb:motherboard/smb:motherboard:iofpga@7,00000000/10007000.kmi/serio1/input/input2
VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
1f00 131072 mtdblock0 (driver?)
1f01 32768 mtdblock1 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.99 #1
Hardware name: ARM-Versatile Express
[<80016454>] (unwind_backtrace) from [<80012ee0>] (show_stack+0x10/0x14)
[<80012ee0>] (show_stack) from [<80243aac>] (dump_stack+0x94/0xa8)
[<80243aac>] (dump_stack) from [<800a5638>] (panic+0x9c/0x200)
[<800a5638>] (panic) from [<8062f250>] (mount_block_root+0x1c0/0x25c)
[<8062f250>] (mount_block_root) from [<8062f408>] (mount_root+0x11c/0x124)
[<8062f408>] (mount_root) from [<8062f568>] (prepare_namespace+0x158/0x1a0)
[<8062f568>] (prepare_namespace) from [<8062eeec>] (kernel_init_freeable+0x268/0x278)
[<8062eeec>] (kernel_init_freeable) from [<804a440c>] (kernel_init+0x8/0xe8)
[<804a440c>] (kernel_init) from [<8000f4f8>] (ret_from_fork+0x14/0x3c)
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
busybox
https://busybox.net/downloads/
编译生成一个 __install 文件夹
制作根文件系统
mkdir rootfs
将_install 目录里的内容拷贝到rootfs目录中
新建目录 mkdir lib
将arm交叉编译器的库复制过来:cp -r /usr/arm-linux-gnueabi/lib/* lib/
在rootfs目录下新建目录mkdir dev/,进入该目录cd dev/,创建节点sudo mknod -m 666 tty1 c 4 1(串口字符设备,主设备号为4,从设备号为1)
重复创建多个串口设备,注意分配好从设备号:
创建一个控制台节点:mknod -m 666 console c 5 1
创建一个空节点:mknod -m 666 null c 1 3
回到home目录,输入命令dd if=/dev/zero of=rootfs.ext3 bs=1M count=32生成虚拟SD卡系统镜像,可以得到一个rootfs.ext3文件。
格式化该镜像:mkfs.ext3 rootfs.ext3
挂载该镜像到本地:mount -t ext3 rootfs.ext3 /mnt -o loop
将之前准备的rootfs目录下的所有文件都拷贝到该镜像挂载点:cp -r /home/zvcv/rootfs/* /mnt/
卸载:umount /mnt/
进入linux源码目录: cd linux/
使用qemu启动内核:qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append “root=/dev/mmcblk0 rw console=ttyAMA0” -sd /home/zvcv/rootfs.ext3,这里比之前多指定了一个sd镜像。
点击回车,进入命令行,linux启动完毕。
我遇到了无法启动,原因是内核编译选项选的是ext4 ,所以格式化的时候选mkfs.ext4
uboot
https://ftp.denx.de/pub/u-boot/
不要用最新版本
scripts/kconfig/conf --syncconfig Kconfig
UPD include/config.h
GEN include/autoconf.mk.dep
CFG u-boot.cfg
GEN include/autoconf.mk
UPD include/generated/dt.h
UPD include/generated/timestamp_autogenerated.h
UPD include/config/uboot.release
*** Your GCC is older than 6.0 and is not supported
arch/arm/config.mk:66: recipe for target 'checkgcc6' failed
make: *** [checkgcc6] Error 1
我的arm-linux-gnuebi-gcc 是5.5
换2015年的uboot才能build pass
NFS
sudo apt-get install uml-utilities bridge-utils
cd linux-4.4.232/
make LOADADDR=0x60003000 uImage -j4
mkimage command not found U-Boot images will not be built —>
sudo apt-get install u-boot-tools
sudo apt-get install tftp-hpa tftpd-hpa xinetd
u-boot 要能加载uImage,需要修改
默认的bootcmd,变成tftp加载tftp server上的uImage
vim include/configs/vexpress_common.h
注释默认的 CONFIG_BOOTCOMMAND
添加
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage; setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000"
另外一个说法是
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage; tftp 0x60500000 vexpress-v2p-ca9.dtb; setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000"
可以配置IP和netmask
#define CONFIG_IPADDR 192.168.1.49
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 192.168.1.88
在Quectel的台式机虚拟机里的桥接网卡,实际配置成
#define CONFIG_IPADDR 192.168.1.49
#define CONFIG_NETMASK 255.255.254.0
#define CONFIG_SERVERIP 10.66.83.84
QEMU和主机如何ping通
在Ubuntu下使用QEMU连网
https://blog.csdn.net/yang1111111112/article/details/107811796
写一个脚本
if test -z $1 ; then
echo need a argument: down/up
exit
fi
if [ "up" = $1 ] ; then
# 新建一个网桥,名称为br0
brctl addbr br0
# 将网络设备enp0s10添加到网桥br0
ifconfig enp0s9 down
brctl addif br0 enp0s9
# 关闭生成树协议
brctl stp br0 off
ifconfig br0 192.168.1.1 netmask 255.255.255.0 promisc up
ifconfig enp0s9 192.168.1.88 netmask 255.255.255.0 promisc up
# 使用命令tunctl添加虚拟网卡tap
tunctl -t tap0 -u rlk
ifconfig tap0 192.168.1.89 netmask 255.255.255.0 promisc up
brctl addif br0 tap0
else
ifconfig tap0 down
brctl delif br0 tap0
ifconfig enp0s9 down
brctl delif br0 enp0s9
ifconfig br0 down
brctl delbr br0
ifconfig enp0s9 192.168.1.88 netmask 255.255.255.0
fi
其中enp0s9是VirtualBox里的一个Host Only添加的网卡。
生成的这个tap0 就是serverip
在qemu中可以ping 通该IP
sudo qemu-system-arm -M vexpress-a9 -m 1024M -kernel u-boot -dtb /home/rlk/QEMU/tftpboot/vexpress-v2p-ca9.dtb -nographic -net nic,macaddr=52:54:00:12:34:22 -net tap,ifname=tap0 -sd vexpress.ext3
在uboot里,
setenv serverip xxx
setenv ipaddr xxx
ping ${serverip}
网络能ping通的情况下
tftp 0x60003000 uImage
setenv bootargs ‘root=/dev/mmcblk0 console=ttyAMA0’
bootm 0x60003000
NFS
RT Thread
Ubuntu 平台开发RT-Thread
qemu 模拟 ARM 从sd卡启动 uboot 内核
http://www.vjiot.net/typecho/index.php/archives/58/
:)