IoT固件模拟

2023-04-21
  1. 0x00:前言
  2. 0x01:安装交叉编译工具
  3. 0x02:内核源码编译
  4. 0x03:制作根文件系统
  5. 0x04:制作虚拟存储介质
  6. 0x05:参考链接

0x00:前言

模拟所需工具:1) 交叉编译工具; 2) qemu; 3) linux内核源码; 4) busybox。

IoT系统必须包含三件套:根文件系统、内核镜像、bootleader。在开发板中,一般是使用u-boot实现bootleader功能。不过由于qemu自带了bootleader,所以可以不需要u-boot。


0x01:安装交叉编译工具

在将linux源码和一些程序编译成对应目标架构时,需要用到交叉编译工具。如32位小端的arm,交叉编译工具的下载:

$ sudo apt install gcc-arm-linux-gnueabi

使用与gcc类似,只是相应的程序为arm-linux-gnueabi-gcc。工具项目目录在:/usr/arm-linux-gnueabi

注意:交叉编译工具的版本和Linux版本不能相差太大(比如我内核是5.15的,对应gcc11是没有问题的)


0x02:内核源码编译

下载内核源码:https://cdn.kernel.org/pub/linux/kernel/

我选择的版本是5.15.1,xz和gz都可以,不过xz压缩率比较高。

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.1.tar.xz
tar -xvf linux-5.15.1.tar.xz

# 注:下面的命令中“CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm” 可以在顶层的(也就是根目录下的)Makefile进行设置,这样下面命令中该字段可以省略

# 产生配置文件 .config
# 第一种方法:在已知开发板的情况下,采用该开发板默认的配置设置
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm vexpress_defconfig
# 第二种方法:自己进行指定的配置,menuconfig:图形配置界面
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm menuconfig
# 一二种方法也可以结合, xxx_defconfig大体配置, menuconfig进行微调
# 这里我仅使用了第一种

# 开始编译(时间比较久)
make -j4 CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm  # -j4:用多少个核心编译

# 两个将会用到的文件
linux-5.15.1/arch/arm/boot/zImage   # 内核镜像
linux-5.15.1/arch/arm/boot/dts/vexpress-v2p-ca9.dtb  # 设备树文件,待深入了解

xxx_defconfig有哪些默认配置可在/arch/$ARCH/configs获知。


尝试使用qemu启动

为了方便后续测试,编写个shell文件:

#!/bin/bash
qemu-system-arm \
        -M vexpress-a9 \
        -m 512M \
        -kernel ./linux-5.15.1/arch/arm/boot/zImage \
        -dtb ./linux-5.15.1/arch/arm/boot/vexpress-v2p-ca9.dtb \
        -append "console=ttyAMA0" \
        -nographic
$ chmod +x arm_start.sh
$ sudo ./arm_start.sh

由于没有根文件系统,所以会产生Kernel panic

image-20230504130936476

(注:退出qemu快捷键为Ctrl + A,按完后再按X,不要同时按! 命令:reboot -f)


0x03:制作根文件系统

Busybox官网:http://www.busybox.net/

# 下载源码
$ wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2
$ tar xvf busybox-1.35.0.tar.bz2
$ cd busybox-1.35.0/

# busybox有三种配置模式: 1)defconfig(缺省配置); 2)allyesconfig(最大配置); 3)allnoconfig(最小配置)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- defconfig
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
# # CONFIG_PREFIX可以设置保存处,否则默认_install/
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install CONFIG_PREFIX=./FS_space/arm32

make install执行成功后,在./FS_space/arm32下出现了bin linuxrc sbin usr

继续填充其它文件:

# 因为busybox编译时使用的是动态链接的方法,所以需要库文件
# 我们也可以通过menuconfig将其改为静态链接:
# Busybox Settings  --->
#       Build Options  --->
#           [*] Build BusyBox as a static binary (no shared libs)
$ mkdir ./FS_space/arm32/lib/
$ sudo cp -p /usr/arm-linux-gnueabi/lib/* ./FS_space/arm32/lib/
$ mkdir ./FS_space/arm32/dev/
$ sudo mknod ./FS_space/arm32/dev/tty1 c 4 1
$ sudo mknod ./FS_space/arm32/dev/tty2 c 4 2
$ sudo mknod ./FS_space/arm32/dev/tty3 c 4 3
$ sudo mknod ./FS_space/arm32/dev/tty4 c 4 4
$ sudo mknod -m 666 ./FS_space/arm32/console c 5 1

事故插播:

在make install时,意外地发生了报错:

image-20230504131053259

在查看Makefile.custom无关后,看这报错觉得是字符串上的问题(//多了个/)。所以直接在busybox根目录下执行:grep -r "/bin/arch"。查找结果:busybox.links:/bin/arch,busybox.links里面着是需要创建的文件或目录。在尝试性地将/bin/arch改为bin/arch后,报错点发生的转移:

image-20230504131213930

然后编写了python脚本,将前面的/都去掉了,结果还报错:

image-20230504131231295

后来尝试了好几个版本的busybox,版本低的在编译时会报编译器的兼容问题,高版本的1.36.0不能make defconfig。为了避免问题的复杂化,还是回到原来版本的问题吧。

后来想到,我是在共享文件夹(win主机,因为虚拟机空间不太够,便下载到这里)中操作的。又想到有时可以使用/bin//sh来代替/bin/sh\x00来绕过\x00,更加感觉是这个原因,然后把项目移到虚拟机空间中重复操作,成功了。至于具体原因的细节有待研究…😶


0x04:制作虚拟存储介质

在开发板中,根文件系统是保存在flash 中的。或者,通过nfs的方式挂载网络文件系统供linux内核启动时访问。为了模拟,我们需要虚拟一个存储介质。

$ dd if=/dev/zero of=rootfs.ext3 bs=1M count=512   # 用\x00初始化一个镜像
$ mkfs.ext3 rootfs.ext3   # 格式化

# 下面的挂载-拷贝-卸载,可以联想用U盘拷贝插入电脑拷贝数据后拔出的过程
$ sudo mount -t ext3 rootfs.ext3 /mnt/rootfs/ -o loop
$ sudo cp -rf ~/iot/linuxSRC/busybox-1.35.0/FS_space/arm32/* /mnt/rootfs
$ ls /mnt/rootfs/
bin  linuxrc  lost+found  sbin  usr
$ sudo umount /mnt/rootfs/
$ ls /mnt/rootfs/

qemu添加,尝试启动:

#!/bin/bash
qemu-system-arm \
        -M vexpress-a9 \
        -m 512M \
        -kernel ./linux-5.15.1/arch/arm/boot/zImage \
        -dtb ./linux-5.15.1/arch/arm/boot/vexpress-v2p-ca9.dtb \
        -append "root=/dev/mmcblk0 console=ttyAMA0" \
        -sd ./rootfs.ext3 \
        -nographic

成功执行:

image-20230504131728877

不过还是有一些警告:can't run '/etc/init.d/rcS': No such file or directory

完善方案(仅供参考):

$ sudo mount -t ext3 rootfs.ext3 /mnt/rootfs/ -o loop
$ cd /mnt/rootfs/
$ ls
bin  console  dev  lib  linuxrc  lost+found  sbin  usr
$ sudo mkdir etc mnt
$ sudo mkdir -p etc/init.d/
$ sudo vim etc/fstab
$ cat etc/fstab
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
none /tmp ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0
mdev /dev ramfs defaults 0 0
$ sudo vim etc/init.d/rcS
$ sudo chmod 755 etc/init.d/rcS
$ sudo vim etc/inittab
$ cat etc/inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::cttlaltdel:/bin/umount -a -r
$ sudo chmod 755 etc/inittab
$ sudo mknod dev/null c 1 3
$ cd ~    # 退出/mnt/rootfs才能umount
$ sudo umount /mnt/rootfs/

0x05:参考链接

https://www.orientdisplay.com/emulating-embedded-linux-systems-with-qemu/

https://blog.csdn.net/m0_56548489/article/details/124720860

返回首页