目录
- 0.课程大纲
- 1.为什么要使用QEMU学习嵌入式
- 2.搭建嵌入式开发基本环境
- 3.QEMU安装及仿真开发板介绍
- 4.编译Linux内核和dtb文件
- 5.使用Busybox制作根文件系统
- 6.使用u-boot引导启动Linux内核
- 参考资料
0.课程大纲
- 为什么要使用QEMU学习嵌入式
- 搭建嵌入式开发基本环境
- QEMU安装及A9开发板配置介绍
- 编译,运行Linux内核
- 使用Busybox制作根文件系统
- 使用u-boot引导启动Linux内核
- 挂载NFS文件系统
- 在虚拟开发板上开发应用程序,驱动
1.为什么要使用QEMU学习嵌入式
QEMU简介
- QEMU是一个模拟器,可以模拟CPU,ARM,X86,MIPS等架构
- 可以仿真的ARM处理器:ARM926E,ARM1136,Cortex-A8/A9
- 模拟真实的开发板,外设:串口,LCD,网卡,USB,SD卡...
使用QEMU可以做哪些事情?
- 研究内核虚拟化
- 模拟CPU,对于芯片公司,流片之前在QEMU上做验证,仿真,软硬件协同设计,开发BSP和驱动
- 模拟开发板,在模拟平台上进行系统软件开发,驱动开发
- 学生,工程师可以利用qemu-system-arm学习嵌入式开发,研究Bootloader,Linux内核,驱动开发,应用开发等.
当前嵌入式行业现状
- CPU厂家越来越多,各种开发板层出不穷
- 物联网芯片,AI芯片...
- SOC越来越集成化,软硬件分工越来越明显
如何适应这种变化
- 分工
- 精专
- 嵌入式80%的知识系统和技能,都可以脱离"开发板",在QEMU仿真平台上学习和练习
使用QEMU学习嵌入式有哪些好处?
- 节省学习成本
- 跳过开发板,硬件的各种"坑",缩短学习曲线
- 重构嵌入式知识体系和技能,跟硬件无关的放到QEMU上学习
- 跟开发板相关的驱动,BSP针对具体开发板深入突破
- 适应不同CPU,开发板的技术要求
驱动开发技能
- 基本的硬件知识
- Linux内核,系统架构的理解
- 芯片手册,开发板
为什么要学习Linux
-
开源,免费
-
持续更新,强大的BSP支持
-
Android,YunOS,Tizen,ubuntu等操作系统的内核
-
应用领域广:嵌入式,服务器,桌面PC,云...
-
示例
2.搭建嵌入式开发基本环境
2.1.安装u-boot-tools
- 用来生成适应U-boot引导的镜像文件格式
bash
sudo apt install -y u-boot-tools
2.2.安装交叉编译工具
什么是ABI和EABI
- ABI:二进制应用程序接口(Application Binary Interface(ABI) for the ARM Architecture),在计算机中,应用二进制接口描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口,涵盖了数据类型的大小,布局和对齐,调用约定.
- EABI:嵌入式ABI 嵌入式应用二进制接口指定了文件格式,数据类型,寄存器使用,堆积组织优化和在一个嵌入式软件中的参数的标准约定.
- Arm-none-gnueabi-linux比arm-linux-gcc要好,在可一致性,兼容性上面
- 早期u-boot和Linux编译可能使用的都不是一个arm-linux-gcc版本
bash
sudo apt install -y gcc-arm-linux-gnueabi
sudo apt install -y g++-arm-linux-gnueabi
bash
#区别
gcc-arm-linux-gnueabi
gcc-arm-linux-gnueabihf
gcc-arm-none-eabi
bash
arm-linux-gnueabi-gcc -v
arm-linux-gnueabi-gcc -o hello main.c
readelf -h hello
3.QEMU安装及仿真开发板介绍
自动安装
bash
# For full system emulation
sudo apt install qemu-system
#For emulating Linux binaries
sudo apt install qemu-user-static
手动编译安装
bash
https://www.qemu.org/
https://wiki.qemu.org/Hosts/Linux
git clone https://gitlab.com/qemu-project/qemu.git
git checkout remotes/origin/stable-8.2 -b stable-8.2
sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build
sudo apt-get install git-email
sudo apt-get install libaio-dev libbluetooth-dev libcapstone-dev libbrlapi-dev libbz2-dev
sudo apt-get install libcap-ng-dev libcurl4-gnutls-dev libgtk-3-dev
sudo apt-get install libibverbs-dev libjpeg8-dev libncurses5-dev libnuma-dev
sudo apt-get install librbd-dev librdmacm-dev
sudo apt-get install libsasl2-dev libsdl2-dev libseccomp-dev libsnappy-dev libssh-dev
sudo apt-get install libvde-dev libvdeplug-dev libvte-2.91-dev libxen-dev liblzo2-dev
sudo apt-get install valgrind xfslibs-dev
sudo apt-get install libnfs-dev libiscsi-dev
./configure --target-list=arm-softmmu --audio-drv-list=
make
sudo make install
QEMU使用
bash
qemu-system-arm --version
#查看支持的开发板
qemu-system-arm -M help
#vexpress-a9
ARM express 开发板简介
Vexpress系列开发板
- 全称versatile express family, ARM公司自己推出的开发板
- 主要用于SOC厂商设计,验证和测试自己的SOC芯片
- 采用主板+子板设计,主板提供各种外围接口,子板提供CPU运算
Vexpress系列支持的CPU
- Cortex-A9: 处理器子板 Express A9x4 (V2P-CA9x4)
- Cortex-A5: 处理器子板 Express A5x2 (V2P-CA5x2s)
- Cortex-R5:
- Cortex-A15: 处理器子板 Express A15x2 (V2P-CA15x2)
javascript
DDR
外围
DUI0448I_v2p_ca9_trm.pdf
嵌入式最小系统
CPU+DDR/SDRAM
FLASH/SD
串口+LCD
QEMU运行系统
bash
#-M vexpress-a : 指定具体开发板
#-m 512M : 指定内存大小
#-kernel ./zImage : 指定内核
#-dtb ./vexpress-v2p-ca9.dtb : 指定设备树
#-nographic : 不使用图像界面
#-append "console=ttyAMA0" : 指定串口控制台
qemu-system-arm -M vexpress-a9 -m 512M -kernel ./zImage -dtb ./vexpress-v2p-ca9.dtb -nographic -append "console=ttyAMA0"
4.编译Linux内核和dtb文件
4.1.下载Linux内核
bash
https://www.kernel.org/
longterm
4.2.修改Makefile
bash
vim Makefile
ARCH ?= arm
CROSS_COMPILE ?=arm-linux-gnueabi-
4.3.编译内核,模块,dtb文件
bash
make vexpress_defconfig
make zImage
make modules
make dtbs
5.使用Busybox制作根文件系统
5.1.什么是根文件系统?
5.1.1.文件系统
对存储设备上的数据进行组织的机制
5.1.2.为什么要使用文件系统
- Linux的哲学: 一切皆文件
- 用户与操作系统进行交互的主要工具: 文件系统调用
- 用户和底层存储的接口
5.1.3.根文件系统
- Linux内核启动后第一个挂载的文件系统
- 主要由基本的shell命令,各种库,字符设备,配置脚本组成
- 提供了根目录/
- RFS可以放在: nor/nand flash, SD卡, 磁盘, 网络空间上
5.2.使用busybox制作根文件系统
5.2.1.什么是busybox
- 一个集成100多个Linux常用命令和工具的软件
- 一个适合制作嵌入式文件系统的软件工具
5.2.2.编译安装
bash
#1.下载源代码
https://busybox.net/
#2.修改Makefile
ARCH ?= arm
CROSS_COMPILE ?=arm-linux-gnueabi-
#3.配置
make defconfig
make menuconfig
Settings ---> [*] Build static binary (no shared libs)
#4.编译
make -j2
#5.安装
make install
#安装生成目录"_install"
5.2.3.制作根文件系统
bash
mkdir rootfs
cd rootfs/
mkdir lib
cp -avf busybox-1.36.1/_install/* rootfs/
cp -avf /usr/arm-linux-gnueabi/lib/* rootfs/lib/
mkdir dev
cd dev/
#mknod: 创建块或字符设备节点
#-m 666: 权限读写
#tty1: 节点名称
#c: 字符设备
#4: 主设备号
#1: 次设备号
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
5.2.4.制作SD卡文件系统镜像
bash
#1.生成镜像
#bs: 缓冲区块的大小
#count: 块的个数
dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
#2.格式化为ext3文件系统
mkfs.ext3 rootfs.ext3
#3.将各种文件copy到文件系统镜像中
sudo mount -t ext3 rootfs.ext3 /mnt -o loop
sudo cp -avf rootfs/* /mnt
sudo umount /mnt
6.使用u-boot引导启动Linux内核
6.1.嵌入式启动概述
6.1.1.嵌入式bootloader
- 功能类似于PC的BIOS,硬件检测是否正常
- 加载操作系统镜像到RAM
- 设置不同的启动方式
6.1.2.常见的启动方式
- NOR/NAND FLASH启动
- 从SD卡启动
- Bootloader从网络加载Linux内核启动
6.2.u-boot编译
bash
#1.下载u-boot
git clone https://gitee.com/naonano/u-boot.git
git checkout --track origin/u-boot-2023.07.y
#2.修改 Makefile
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
CROSS_COMPILE ?=arm-linux-gnueabi-
#3.修改 config.mk
#ARCH := $(CONFIG_SYS_ARCH:"%"=%)
ARCH := arm
#4.配置
make vexpress_ca9x4_defconfig
#5.编译
make -j2
#6.运行u-boot
qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel ../test/u-boot/u-boot
6.3.QEMU网络功能设置
6.3.1.配置QEMU与主机的网络连接
- 采用桥接(bridge)的网络连接与Host通信
- 需要主机内核tun/tap模块支持
6.3.2.配置
参考:ubuntu 22.04 设置网桥 - netplan
bash
#1.主机安装工具包
sudo apt install -y uml-utilities bridge-utils
#2.创建tun设备文件
ls -al /dev/net/tun
#3.编辑文件
sudo touch /etc/netplan/br0.yaml
#使用ipv4 dhcp
ipv4 dhcp:
yaml
network:
version: 2
ethernets:
enp0s8: #替换为实际网卡
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [enp0s8] #替换为实际网卡
dhcp4: true
parameters:
stp: false
dhcp6: false
ipv4 静态分配:
yaml
network:
version: 2
ethernets:
enp0s8:#替换为实际网卡
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [enp0s8] #替换为实际网卡
dhcp4: false
addresses: [192.168.1.250/24]
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses: [114.114.114.114]
parameters:
stp: false
dhcp6: true
bash
sudo netplan apply
ifconfig
br0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.1.25 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::3027:2dff:fe41:8595 prefixlen 64 scopeid 0x20<link>
ether 32:27:2d:41:85:95 txqueuelen 1000 (Ethernet)
RX packets 55 bytes 9272 (9.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 89 bytes 12062 (12.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.3 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::c8ff:ec6f:253e:ad4e prefixlen 64 scopeid 0x20<link>
inet6 2409:8a1e:d52:a9b0:39df:8d80:83d3:9e prefixlen 64 scopeid 0x0<global>
inet6 2409:8a1e:d52:a9b0:3292:9a45:5481:28ad prefixlen 64 scopeid 0x0<global>
ether 08:00:27:05:ef:4f txqueuelen 1000 (Ethernet)
RX packets 962 bytes 156528 (156.5 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 836 bytes 88212 (88.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 318 bytes 29095 (29.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 318 bytes 29095 (29.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
6.4.内核配置编译
6.4.1.使用u-boot引导内核镜像
bash
#需要将内核编译为uImage格式
#需要指定uImage的加载地址
#编译时指定:
make LOADADDR=0x60003000 uImage -j2
6.5.主机TFTP工具安装
bash
#1.安装
sudo apt-get install -y tftpd-hpa tftp-hpa xinetd
#2.配置ftp服务器工作目录为"/home/tftp"
sudo vim /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/tftp"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="-l -c -s"
#3.建立目录
sudo mkdir -p /home/tftp
sudo chown lei:lei /home/tftp
chmod 777 -R /home/tftp
#4.启动服务
sudo service tftpd-hpa restart
#5.测试
#5.1测试下载
cd /home/tftp/
touch readme.txt
#在readme.txt中输入一些内容
#运行开发板,进入控制台
tftp -g -r readme.txt 192.168.10.107
#可以看出在开发板当前目录下下载了readme.txt
#5.2测试上传
#在开发板上,进入控制台运行命令
tftp -p -l uvc_app 192.168.10.107
#uvc_app为开发板当前目录下的文件
#在ubuntu上可以看到开发板上传上来的文件uvc_app
6.6.启动测试
bash
#1.复制u-boot镜像到tftp服务器目录下
cp /home/qemu/test/u-boot/u-boot /home/tftp/
#2.复制uImage镜像到tftp服务器目录下
cp /home/qemu/test/linux-6.6.18/arch/arm/boot/uImage /home/tftp/
#3.复制设备树二进制编译结果到tftp服务器目录下
cp /home/qemu/test/linux-6.6.18/arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb /home/tftp/
#4.uboot引导kernel启动
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-nographic \
-kernel /home/tftp/u-boot \
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-sd /home/qemu/test/rootfs.ext3
6.7.自动化引导
u-boot/include/configs/vexpress_common.h
c
#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 192.168.244.128
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 192.168.244.129
参考资料
B站
QEMU系列文章: https://blog.csdn.net/phmatthaus/category_12072874.html