Qemu Busybox U-boot

    科技2022-07-11  119

    文章目录

    前言安装u-boot-tools安装vim和gedit 安装交叉编译器工具安装Qemu和内核方法一自动安装方法二手动编译ARM express 开发板介绍Linux内核下载安装编译 使用busybox制作根文件系统制作Shell命令制作根文件系统制作SD卡文件系统镜像启动内核,挂载rootfs QEMU网络功能设置使用u-boot加载内核U-boot编译 内核配置编译主机TFTP工具安装挂载NFS文件系统完善NFS根文件系统就此结束了

    前言

    安装和配置环境: Ubuntu 18.04.4时间: 2020.10

    安装u-boot-tools

    介绍: 用来生成适应u-boot引导的镜像文件命令 sudo apt install u-boot-tools

    安装vim和gedit

    1 介绍: 编辑文本工具 2. 命令

    sudo apt install vim gedit

    安装交叉编译器工具

    介绍: 交叉编译是在一种计算机环境中编译程序,在另外一种环境下运行。或者说在一个平台上编译生成在另外一个平台上运行的可执行代码。ABI: 二进制应用程序接口(Application Binary interface(ABI) for the ARM Architecture)在计算机中,应用二进制接口描述应用程序和操作系统之间或其他应用程序的低级接口,涵盖了数据类型的大小、布局和对齐,调用约定。EABI: 嵌入式ABI早期u-boot和linux编译可能使用的都是不是一个arm-linux-gcc版本。arm-none-gnueabi-linux比arm-linux-gcc在可移植性和兼容性上更好。命令 sudo apt install gcc-arm-linux-gnueabi sudo apt install g++-arm-linux-gnueabi 查看版本号 arm-linux-gnueabi-gcc -v arm-linux-gnueabi-g++ -v 验证 在当前文件夹下面编写一个Hello.c的文件 arm-linux-gnueabi-gcc Hello.c -o Hello // 编译 readelf -h Hello 输出结果Machine 是ARM类型

    安装Qemu和内核

    方法一自动安装

    sudo apt install qemu qemu-img -V // 查看版本

    方法二手动编译

    安装 2. 安装依赖包 sudo apt install zlib1g-dev libglib2.0-0 libglib2.0-dev libsdl1.2-dev libpixman-1-dev libfdt-dev 3. 下载QEMU源码 git clone git://git.qemu-project.org/qemu.git 4. 切换稳定版本 git branch git checkout v2.7.0 5. 编译配置 ./configure --target-list=arm-softmmu --audio-drv-list= 6. 编译安装 make make install 查看 qemu-system- // 按tab键 查看qemu支持的cpu架构 qemu-system-arm --version // 查看arm架构cpu的版本 qemu-system-arm -M help // 查看支持的开发版本

    ARM express 开发板介绍

    Vexpress 系列开发板 全称: versatile express family, ARM 公司自己推出的开发板主要用于SOC厂商设计,验证和测试自己的SOC芯片采用主板+子板设计,主板提供各种外围接口,子板提供CPU运算 Express 系列支持的CPU Cortex-A9: 处理器子板 Express A9x4(V2P-CA9x4)Cortex-A5: 处理器子板 Express A5x2(V2P-CA5x2s)Cortex-R5:Cortex-A15: 处理器子板 Express A15x2(V2P-CA15x2)

    Linux内核下载安装编译

    Linux内核下载链接解压并进入文件夹中 tar -xvf linux-5.8.12.tar.xz cd linux-5.8.12 修改Makefile vim Makefile ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabi- 编译内核、模块、dtb文件 // 编译内核 make vexpress_defconfig make zImage -j6 // 编译内核模块 make modules // 编译dtb文件 make dtbs // dtbs 让编译后的内核脱离主板的限制,不同开发板的配置都在自己的dtbs文件中 // ./arch/arm/boot/ 验证 // linux-5.8.12e文件夹虾执行 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" // -M vexpress-a9 选择使用开发板 // -m 512M 选择内存大小 // -kernel arch/arm/boot/zIamge 选择内核镜像位置 // -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb 选择dtb文件 // -nographic 非图形化显示 // -append "console=ttyAMA0" 虚拟开发板的串口 由于没有制作根文件系统,不能继续执行退出 ps -a // 查找叫qemu-system-arm进程的PID kill PID 制作启动脚本 touch boot.sh sudo chmod 755 boot.sh vim boot.sh // output 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" // 注意路径问题,可能需要修改 //运行 ./boot.sh

    使用busybox制作根文件系统

    介绍: 文件系统: 对存储设备上数据进行组织的机制为什么使用文件系统: 一切皆文件; 用户与操作系统进行交互的主要工具: 文件系统调用; 用户和底层存储的接口;根文件系统: linux 内核启动后第一个挂载的文件系统 主要由基本的shell命令,各种库,字符设备,配置脚本组成; 提供了根目录/ RFS可以放在: nor/nand flash, SD卡,磁盘, 网络空间;什么是busybody? 一个集成100多个的linux 常用命令和工具的软件; 一个适合制作嵌入式文件系统的软件工具;

    制作Shell命令

    下载并解压 源代码下载 tar -xvf busybox-1.32.0.tar.bz2 // 解压 cd busybox-1.32.0 修改Makefile vim Makefile // modify ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabi- 配置 make defconfig make menuconfig // setting -> build options -> 选上 Build static binary (no shared libs) 编译 & 安装 make -j4 make install

    制作根文件系统

    制作一个目录rootfs,位置自定义 mkdir rootfs 命令 // 拷贝制作bin sbin usr等 cp -r 你的busybox路径/_install/* 你的rootfs/ 如 cp -r ~/Desktop/busybox-1.32.0/_install/* ~/Desktop/rootfs/ // 我的busybox和rootfs都放在桌面 cd rootfs mkdir lib // 根文件系统的库 // 切换到正确的位置 // 制作lib 拷贝arm的库,从交叉编译器中拷贝 cp -p /usr/arm-linux-gnueabi/lib/* rootfs/lib/ cd rootfs mkdir dev cd dev // 创建结点 sudo权限 mknod -m 666 tty1 c 4 1 mknod -m 666 tty2 c 4 2 mknod -m 666 tty3 c 4 3 mknod -m 666 tty4 c 4 4 // 创建工作台结点 mknod -m 666 console c 5 1 // null 结点 垃圾桶 mknod -m 666 null c 1 3 // 制作 etc目录(可选择不做) mkdir etc cd etc mkdir init.d cd init.d touch rcS sudo chmod a+s rcS vim rcS // rcs 编辑的内容(自定义)(此行不复制) echo echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" echo echo "Welcome to A9 vexpress borad" echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" // rcs内编辑(此行不复制)

    制作SD卡文件系统镜像

    dd命令虚拟生成SD卡 // 注在那执行下一句命令,就在那生成根文件系统文件rootfs.ext3 dd if=/dev/zero of=rootfs.ext3 bs=1M count=32 格式化SD卡 mkfs.ext3 rootfs.ext3 挂载 & 卸载SD卡 sudo mount -t ext3 rootfs.ext3 /mnt/ -o loop ls /mnt/ // output // lost+found // 将制作好的根文件系统拷贝在/mnt中 sudo cp -r rootfs/* /mnt/ ls /mnt/ // 卸载 sudo umount /mnt/

    启动内核,挂载rootfs

    修改原先制作的boot.sh脚本(boot.sh 和 linux-5.8.12是同级的) qemu-system-arm \ -M vexpress-a9 \ -m 512M \ -kernel linux-5.8.12/arch/arm/boot/zImage \ -dtb linux-5.8.12/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ -nographic \ -append "root=/dev/mmcblk0 rw console=ttyAMA0" \ -sd rootfs.ext3 图像化显示 qemu-system-arm \ -M vexpress-a9 \ -m 512M \ -kernel linux-5.8.12/arch/arm/boot/zImage \ -dtb linux-5.8.12/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ -append "root=/dev/mmcblk0 rw console=tty0" \ -sd rootfs.ext3

    QEMU网络功能设置

    配置QEMU与主机的网络连接 采用桥接bridge的网络连接与Host通信;需要主机内核tun/tap模块支持; 配置命令 // 添加依赖 sudo apt install uml-utilities bridge-utils // 创建tun设备文件/dev/net/tun // 查看当前系统下是否存在tun结点,一般系统都有 ls /dev/net/ // 查看当前主机的ip sudo apt install net-tools ifconfig // 修改/etc/network/interfaces文件,重启生效 sudo gedit /etc/network/interfaces %% 修改内容为(此行不复制) # interfaces(5) file used by ifup(8) and ifdown(8) auto lo iface lo inet loopback auto enp0s5 // 自己对应的网口名 auto br0 // 创建网口 iface br0 inet dhcp bridge_ports enp0s5 %% end(此行不复制) // 配置/etc/qemu-ifup 和 /etc/qemu-ifdown // 系统都存在着两文件就不需要进行配置 ls /etc/qemu-if* // 查看文件是否存在 sudo reboot //重启

    修改前ifconfig

    修改后ifconfig

    使用u-boot加载内核

    介绍 嵌入式bootloader 功能类似于pc 的BIOS,硬件检测是否正常; 加载操作系统镜像到RAM; 设置不同的启动方式常见的启动方式 NOR/NAND flash启动 SD卡启动 Bootloader从网络加载Linux内核启动

    U-boot编译

    类似Windows的BIOS;下载U-boot修改Makefile tar -xvf u-boot-2020.10-rc5.tar.bz2 cd u-boot-2020.10-rc5 gedit Makefiel %% 以下内容在Makefile文件内修改 // 在原有的CROSS_COMPILE ?= 下面添加下句 CROSS_COMPILE ?= arm-linux-gnueabi-

    gedit config.mk %% 以下内容在config.mk文件内修改 ARCH := $(CONFIG_SYS_ARCH:"%"=%) 改为 ARCH := arm 配置u-boot的启动方式tftp 或 nfs -自动化引导 // 当前目录u-boot-2020.10-rc5/ vim include/configs/vexpress_common.h 支持tftp启动 uImage 加载到0x60003000 vexpress-v2p-ca9.dtb 加载到0x60050000 bootargs 采用sd卡挂载系统 系统启动跳到0x60003000 CONFIG_IPADDR 开发板的ip地址,自己定义 CONFIG_SERVERIP 主机的ip/虚拟机的ip地址 /* Basic environment settings */ /*#define CONFIG_BOOTCOMMAND \ "run distro_bootcmd; " \ "run bootflash; "*/ #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 10.211.55.18 #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_SERVERIP 10.211.55.17 支持nfs启动(略过) 注nfsroot中rootfs路径对应修改 /* Basic environment settings */ /*#define CONFIG_BOOTCOMMAND \ "run distro_bootcmd; " \ "run bootflash; "*/ #define CONFIG_BOOTCOMMAND \ "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;\ setenv bootargs 'root=/dev/nfs rw \ nfsroot=10.211.55.18:/Desktop/YourHost/Desktop/rootfs init=/linuxrc \ ip=10.211.55.18 console=ttyAMA0';\ bootm 0x60003000 - 0x60500000;" #define CONFIG_IPADDR 10.211.55.18 #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_SERVERIP 10.211.55.17 不进行tftp启动 或 nfs启动设置,在测试u-boot时可能会出现镜像找不到错误

    配置与编译 // 当前目录u-boot-2020.10-rc5/ make vexpress_ca9x4_defconfig make -j4 // 编译后会在当前目录下生成多个u-boot-xxx文件 测试 & 运行 u-boot // 当前目录u-boot-2020.10-rc5/ qemu-system-arm \ -M vexpress-a9 \ -kernel u-boot \ -nographic \ -m 512M

    内核配置编译

    使用u-boot引导内核镜像 需要将内核编译为uImage格式;需要指定uImage的加载地址;编译时指定: make LOADADDR= xxx uImage -j4 编译命令 // 进入linux内核目录位置 cd linux-5.8.12 // 虚拟开发板的内存地址从0x60000000开始 make LOADADDR=0x60003000 uImage -j4 // 查看arch/arm/boot/目录下,生成了一个uImage文件 ls arch/arm/boot/

    主机TFTP工具安装

    安装配置命令 // 安装tftp工具 sudo apt install tftp-hpa tftpd-hpa xinetd // 修改配置文件 sudo vim /etc/default/tftpd-hpa // 创建tftp目录 // tftpboot目录的作用: // 虚拟开发板通过tftpboot目录从主机下载uImage 镜像文件; // 需要将uImage内核镜像放入tftpboot目录下 mkdir /home/tftpboot sudo chmod 777 tftpboot // 重启tftp服务 sudo /etc/init.d/tftpd-hpa restart 制作脚本boot_uboot.sh touch boot_uboot.sh sudo chmod 755 boot_uboot.sh gedit boot_uboot.sh %% boot_uboot.sh添加下述内容 qemu-system-arm \ -M vexpress-a9 \ -kernel u-boot \ -nographic \ -m 512M \ -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \ -sd ~/Desktop/rootfs.ext3 %% end 将uImage相关文件复制到tftpboot目录中 // 拷贝文件有u-boot boot_uboot.sh vexpress-v2p-ca9.dtb uImage // uImage cp linux-5.8.12/arch/arm/boot/uImage /home/tftpboot/ // vexpress-v2p-ca9.dtb cp linux-5.8.12/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /home/tftpboot/ // u-boot cp u-boot-2020.10-rc5/u-boot /home/tftpboot/ // boot_uboot.sh cp ~/Desktop/boot_uboot.sh /home/tftpboot/ 测试 u-boot引导uImage cd /home/tftpboot/ sudo ./boot_uboot.sh

    挂载NFS文件系统

    NFS文件系统是一种共享文件系统,针对上述出现每次修改内核文件系统时需要挂载一个SD卡,操作麻烦的问题。

    ubuntu(主机)需要支持NFS服务

    // 主机上安装NFS服务 sudo apt install nfs-kernel-server 修改/etc/exports文件 — 路径对应修改 rw: 读写sync: 同步no_root_squash: 登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限no_sbutree_check: 不检验根文件系统的子目录 sudo gedit /etc/exports // 在/etc/exports文件中末尾添加: /home/rootfs *(rw,sync,no_root_squash,no_subtree_check) // /home/rootfs目录时busybox制作的,让rootfs为根文件系统, 共享文件目录 // 我将rootfs目录存放在桌面故我添加的是 ---- 绝对路径 不能写~/Desktop/rootfs /home/UserName/Desktop/rootfs *(rw,sync,no_root_squash,no_subtree_check) 重启服务 /etc/init.d/rpcbind restart /etc/init.d/nfs-kernel-server restart 修改/include/configs/vexpress_common.h文件 路径u-boot-2020.10-rc5/include/configs/vexpress_common.h // 当前目录u-boot-2020.10-rc5/ gedit include/configs/vexpress_common.h // bootargs启动参数 1. root=/dev/mmcblk0 -> root=/dev/nfs 2. nfsroot=10.211.55.18 主机ip地址 3. /home/YourHost/Desktop/rootfs rootfs文件的路径 4. ip=10.211.55.18 虚拟主板的虚拟ip地址 %% 修改内容(此行不复制) /* Basic environment settings */ /*#define CONFIG_BOOTCOMMAND \ "run distro_bootcmd; " \ "run bootflash; "*/ #define CONFIG_BOOTCOMMAND \ "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;\ setenv bootargs 'root=/dev/nfs rw \ nfsroot=10.211.55.17:/home/YourHost/Desktop/rootfs init=/linuxrc \ ip=10.211.55.18 console=ttyAMA0';\ bootm 0x60003000 - 0x60500000;" #define CONFIG_IPADDR 10.211.55.18 #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_SERVERIP 10.211.55.17 %% end(此行不复制) // 编译 make // 拷贝 cp u-boot /home/tftpboot/ 内核支持挂载NFS文件系统 修改BOOTCOMMAND // 当前目录linux-5.8.12/ make menuconfig // File System -> Network File System 如图选择4个 // 关于Root file system on NFS选项不存在问题 // 打开第一级菜单下的Networking support -> Networking options -> TCP/IP networking -> IP: kernel level autoconfiguration。 // 如果NFS要使用DHCP,还得选上 IP: DHCP support

    // 重新编译 make LOADADDR=0x60003000 uImage -j4 // 拷贝 cp arch/arm/boot/uImage /home/tftpboot/ 运行测试 // 当前目录/home/tftproot sudo ./boot_uboot.sh

    如果主机是Ubuntu18.04系统可能会出现问题 挂载失败

    效果 - 方便开发,避免每次主机和开发板传输文件需要挂载SD卡 在主机rootfs文件内添加Hello.txt 虚拟开发板也对应产生Hello.txt文件

    完善NFS根文件系统

    增加内核的各种用户接口和重启reboot功能 0. 介绍

    启动顺序 linux 内核启动之后, 挂载NFS根文件系统; init进程boottargs ----> inittab 执行init.d/rcS 挂载各种文件目录(跟fstab有关) 执行console前执行profile 在根文件系统下etc目录下添加inittab, profile, fstab 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 var /dev tmpfs defaults 0 0 ramfs /dev ramfs defaults 0 0 profile 内容 PS1='perfect@vexpress:\w # ' export PS1 initial 内容 ::sysinit:/etc/init.d/rcS #::respawn:-/bin/sh #tty2::askfirst:-/bin/sh #::ctrlaltdel:/bin/umount -a -r console::askfirst:-/bin/sh ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r 新建tmp, sys, var, proc目录 // 在rootfs目录内添加,NFS会同步到虚拟主板上 mkdir tmp sys var proc

    就此结束了

    补充

    了解uImage和zImage: linux内核经过编译后会生成一个elf格式的可执行程序,叫做vmlinux或vmlinuz,这个是原始的未经任何处理加工的原版内核elf文件,嵌入式系统部署时烧录一般不是这个vmlinux,而是要用objcopy工具去制作成烧录镜像格式的文件Image(这个制作烧录镜像主要目的是缩减大小,节省磁盘)。原则上Image就可以直接被烧录在flash上启动执行,,但是实际并不是那么简单,实际上linux的作者们觉得Image还是太大了,所以对Image 进行了也压缩,并且在Image压缩后的文件的前端附加了一部分解压缩代码,构成了一个压缩格式的镜像叫做zImage,解压的时候,通过zImage镜像头部的解压缩代码进行自解压,然后执行自解压出来的内核镜像。 同时,uboot为了启动linux内核,还发明了一种内核格式叫做uImage,uImage是由zImage加工得到的,uboot中有一个工具,可以将zImage加工成uImage,uImage是不管linux内核的事情,linux内核只管生成zImage,然后uboot中的mkimage工具再去由zImage加工成uImage来给uboot启动,这个加工过程时间就是在zImage前边加上64字节的uImage的头信息即可。 注:如果直接在kernel底下去make uImage会提示mkimage command not found,解决方式是去uboot/tools目录下执行cp mkimage /usr/local/bin 复制mkimage工具到系统目录下,再去make uImage即可。 原则上,uboot启动时应该给他uImage格式的镜像,但是实际上uboot中也支持zImage,是否支持就看是否定义了LINUX_ZIMAGE_MAGIC这个宏,所以可以看出,有些uboot是支持zImage启动的,有些是不支持的,但是所有的uboot肯定都支持uImage启动。

    参考文章 参考文章

    Processed: 0.010, SQL: 8