【Linux】嵌入式学习环境快速搭建(二)一键编译、qemu模拟运行

1. eel简介

目标:

  • 支持多种自定义配置
  • 支持arm/arm64/riscv32/riscv64
  • 一键实现atf、optee、u-boot、kernel、rootfs的编译
  • 一键模拟运行
  • 支持多个源码版本
  • 尽量遵循官方说明的编译方法,编译过程和命令对用户可见
  • 支持VS Code + qemu + gdb调试

特性:

  • 自动下载依赖包
  • 自动处理依赖,完成编译
  • 自动处理依赖,实现qemu运行

测试环境:

  1. VMWare虚拟机安装Debian 11
  2. VMWare虚拟机内Debian 11,Debian 11 Docker
  3. PVE内LXC安装Debian 11
  4. PVE内LXC安装Debian 11,Debian 11 Docker

测试版本:

sourceversion
ARM trusted firmware2.7.0/2.8.0
optee3.18.0
u-boot2020.04/2022.10
linux5.10/5.15/6.0/6.1
busybox1.35.0
buildroot2022.11

其他说明:

  1. optee-3.19.0增加了libacl,需要-lbuuid选项,未编译成功。
  2. linux-4.x版本编译时依赖compile-gcc$version.h,$version为gcc版本,源码中默认没有高版本的头文件,可以复制其他文件作为compile-gcc$version.h

1.1. gitee仓库

eel仓库下的几个仓库本身属于eel的子模块,但是 git submodule命令相对小众,使用起来也没有明显的优势,这几个仓库还是作为独立的仓库处理。

源码下载可以参考《快速上手》部分。

1.2. 主目录结构

$(EELDIR)
├── Makefile                        # 主Makefile
├── Makefile.arm                    # ARM和ARM64相关target
├── Makefile.riscv                  # riscv32和riscv64相关target
├── config.mk                       # 通用配置文件
├── config.arm.mk                   # ARM配置文件
├── config.arm64.mk                 # ARM64配置文件
├── config.riscv23.mk               # riscv32配置文件
├── config.riscv64.mk               # riscv64配置文件
├── .tmp.config.mk                  # select指定的文件
├── suburl.mk                       # eel-changes和eel-kmodules的仓库地址
├── toolchain.mk                    # 交叉编译工具链地址
├── ctools/                         # 辅助工具及脚本目录
├── docs/                           # 文档目录
|   └── README.md                   # 说明文档
├── download/                       # 下载目录
|   └── buildroot-dl/               # buildroot下载目录
├── dumpdt/                         # dump qemu用到的dtb
├── changes/                        # 与源码目录对应的修改,来自eel-changes仓库
├── mks/                            # 自定义配置文件目录
├── output/                         # 编译生成物
├── share/                          # QEMU虚拟机共享目录
├── source/                         # 源码目录
├── toolchain/                      # 交叉编译工具
└── .vscode
    └── launch.json                 # 用于VSCode GDB调试vmlinux

根文件系统中,会自动挂载主机与虚拟机共享目录到 /mnt//mnt/arch/,分别是公共共享目录和体系结构相关目录,对应主机目录分别为 $(EELDIR)/share/$(OUTDIR)/$(ARCH)/rootfs/share/

1.3. source目录

$(EELDIR)
└── source
    ├── kernel
    │   ├── linux-6.1               # linux-6.1源码解压,使用git管理,方便代码阅读
    │   └── linux-repo              # 官方git仓库
    ├── kmodules                    # 内核模块例程,按内核般般划分
    │   └── linux-6.1               # linux-6.1内核模块例程
    ├── optee
    │   ├── optee_client-repo
    │   ├── optee_examples-repo
    │   └── optee_os-repo
    ├── rootfs
    │   ├── buildroot-repo
    │   └── busybox-repo
    ├── trusted-firmware
    │   └── trusted-firmware-a-repo
    └── u-boot
        ├── u-boot-2022.10          # u-boot-2022.10源码解压,使用git管理,方便代码阅读
        └── u-boot-repo             # 官方git仓库

1.4. changes目录

$(EELDIR)
└── changes
    ├── kernel
    │   ├── linux-5.10
    │   ├── linux-5.15
    │   └── linux-6.1               # 针对linux-6.1的修改,包含deconfig等
    ├── rootfs
    │   ├── bb-etc                  # busybox根文件系统/etc目录示例
    │   ├── bootstrap               # bootstrap脚本
    │   ├── br-rfs-overlay          # 用于新增/覆盖buildroot根文件系统部分文件
    │   ├── buildroot-2022.11       # 针对buildroot-2022.11的修改,包含deconfig等
    │   └── busybox-1.35.0          # 针对busybox-1.35.0的修改,包含deconfig等
    └── u-boot
        └── u-boot-2022.10

2. 快速上手

2.1. 准备工作

做完开发环境搭建或安装 gitmake等工具后,可以使用如下命令下载。
eel下的几个子仓库地址在 suburl.mk中定义,默认使用的是https协议,如果已经把ssh公钥添加到gitee,可以改成ssh协议。

git clone https://gitee.com/kingdix10/eel.git
# git clone git@gitee.com:kingdix10/eel.git
cd eel
make ARCH=arm64 clone-chg clone-km clone-ctl

2.2. 下载源码

如果要分析、修改特定版本的代码,建议下载源码的压缩包,并创建本地git仓库

# 下载+解压
make ARCH=arm64 dec-kl KL_VERSION=6.1
# 下载+解压+创建本地git仓库
make ARCH=arm64 git-ub UB_VERSION=2022.10

也可以clone代码的官方仓库,里边会包含各个版本的tag。但是需要注意,重新编译时,在仓库里的修改会被覆盖掉。

make ARCH=arm64 clone-kl

2.3. 获取帮助

如下以 arm64为例。

方式一:select选定配置

./select arm64.config.mk
make help
make help-kernel

方式二:命令行指定变量值

make ARCH=arm64 help
make ARCH=arm64 help-kernel

方式三:export环境变量

export ARCH=arm64
make help
make help-kernel

2.4. 变量配置

config.mkconfig.$(ARCH).mk中指定了默认的一些配置,mks目录下是一些自定义的配置,可以使用select来进行选择:

$ ./select
  File: /data/eel/.tmp.config.mk -> /data/eel/mks/arm.config.mk
select from:
1. arm.config.mk
2. arm64.config.mk
3. riscv32.config.mk
4. riscv64.config.mk
input index: 2

也可以采用select + 文件名的方式:

./select arm64.config.mk
./select mks/arm64.config.mk

select之后,可以执行make相关命令,如make qemu-kl。命令含义参考《模块源码target说明》和《编译相关target说明》。

注意

  1. ARCH变量必须被指定。
  2. 变量优先级:命令行参数 > export环境变量 > .tmp.config.mk > .config.$(ARCH).mk > .config.mk
  3. 部分命令需要 root权限,需要提前修改 SUDO配置项,防止在执行过程中频繁提示输入密码,如 SUDO = echo xxxx | sudo,也可以 echo "$username ALL=NOPASSWD: ALL" > /etc/sudoers.d/$user重新登录来关掉密码。

2.5. 运行测试

如下命令会自动完成代码下载、编译,并使用QEMU模拟启动,命令含义可以参考后边的target说明。

  • make ARCH=arm64 qemu-uboot
  • make ARCH=arm64 qemu-kernel
  • make ARCH=arm64 qemu-tee

3. 其他操作

3.1. 新建defconfig

以U-Boot为例

方式一:

  1. 基于现有的 xxx_defconfig进行 make uboot-defconfig,如 make ARCH=arm64 uboot-defconfig UB_CONFIG=mine_arm64_defconfig
  2. 执行 make ARCH=arm64 ub-menuconfig,并根据需要进行修改并保存。
  3. 执行 make ARCH=arm64 uboot-savedefconfig UB_SAVECONF=mine_arm64_defconfig

方式二:

  1. 基于现有的 xxx_defconfig复制生成新的config,如 cp u-boot/configs/qemu_arm64_defconfig u-boot/configs/mine_arm64_defconfig
  2. 执行 make ARCH=arm64 ub-menuconfig,并根据需要进行修改并保存。
  3. 执行 make ARCH=arm64 uboot-savedefconfig,这一步会生成 defcong并,将 defconfig保存到 u-boot/configs/mine_arm64_defconfig

之后就可以通过修改 config.mk或使用 make ARCH=arm64 uboot UB_CONFIG=mine_arm64_defconfig进行编译。

3.2. 获取参与编译的文件列表

keepdep_patch.sh可以修改编译脚本,保留编译过程中生成的 .xxx.o.d文件,方便使用 depfilelist.sh获取参与编译的文件列表,排除不必要的文件。

可以将 keepdep_patch.sh修改后的编译脚本放到changes目录,或在编译前使用 keepdep_patch.sh修改编译脚本(需要保证不会被changes目录下没有对应文件)。

./ctools/keepdep_patch.sh source/kernel/linux-6.1/scripts/
# 执行编译
./ctools/depfilelist.sh -d output/arm64/kernel/linux-6.1/mine_defconfig/ -o filelist.txt

filelist.txt稍加修改后,可以在vim或SourceInsight等工具中使用。

注意:仅在U-Boot和Kernel测试过。

3.3. 生成函数调用SourceTrail工程

SourceTrail是一款开源免费跨平台的跨平台源码阅读和可视化工具,依赖clang解析源码。但是用它来解析u-boot或kernel代码会非常慢,而且会因为无法找到一些编译器的头文件,导致解析不成功。

GCC 10.0及之后版本支持 -fcallgraph-info编译选项,主Makefile添加此选项后,编译过程中会生成 .ci文件,ctools/cgraph/traildb.py工具利用 .ci来生成SourceTrail工程,方便查看函数关系。

ctools/cgraph/traildb.py需要用到SourceTrailDB的python接口,ctools/cgraph/下提供了基于 Debian 11编译的 sourcetraildb.py_sourcetraildb.so,如果不能使用,需要参考ctools/README下载SourceTrailDB编译替换。

# step 1
find output/arm64/kernel/linux-6.1/mine_defconfig/ -name '*.ci' > cilist.txt

# step 2
./ctools/cgraph/provider.py -I cilist -O db -o linux6.1.db -p /data/eel/source/kernel/linux-6.1/ -t linux_6_0 cilist.txt

# step 3
./ctools/cgraph/traildb.py -I db -s /data/eel/source/kernel/linux-6.1/  -o linux6.1 linux6.1.db

step 1:生成 .ci文件列表。

step 2:解析 .ci文件,生成sqlite3数据库。
-p,.ci文件中,文件路径的前缀,取kernel源码的路径,如果输出目录和源码目录一致,可以不用设置
-t,数据库中的table名,不能包含 ‘-’ 或 ‘.’

step 3:生成SourceTrail工程,包含 .srctrlprj.srctrldb文件,使用SourceTrail打开 .srctrlprj即可使用。
-s,内核源码目录,指定后可以使 .srctrldb包含源码

注意

  • 仅在U-Boot和Kernel测试过。
  • 编译会导致部分函数被优化掉,无法在SourceTrail中显示

4. 常见配置项

配置项说明
USE_TEE是否使用optee
QE_SERIALQEMU串口设备,默认为none
KL_ARGS内核bootargs

4.1. QE_SERIAL选项说明

QE_SERIALcommand优势缺点
none可直接操作只支持一个串口
file可保存完整启动日志不可交互
udpnc -u -l -p $port可查看启动日志,可交互交互时使用Ctrl + C会使nc退出,重启QEMU需重新连接
tcpnc -l -p $port可查看启动日志,可交互需先启动nc监听tcp所有端口再启动QEMU,交互时使用Ctrl + C会使nc退出,重启QEMU需重新连接
ptyminicom -D /dev/pty/$NUM可交互、可自动重连丢失部分启动日志,NUM需在QEMU启动后查看日志确定

QE_SERIAL主要用在 make qemu-teemake qemu-ub-tee时,file/pty/udp/tcp都设置了两个串口,分别用于REE和TEE。

  • file:日志分别记录到serial0.log和serial1.log
  • udp:port值为55550和55551
  • tcp:port值为55500和55501
  • pty:可查看QEMU启动最后的日志来得到NUM的值

5. 模块源码target说明

相关target都是以 xxx-$mod命名,xxx为动作,方便与后边提到的 $mod-%区分。

5.1. git仓库相关target

def_git_targets批量生成,

target说明
clone-$modgit clone
pull-$modgit pull,会拉取tag

举例:

make ARCH=arm64 clone-changes
make ARCH=arm64 clone-kmodules
make ARCH=arm64 pull-kmodules

5.2. 源码相关target

def_dl_targets批量生成

target说明
download-$mod下载源码压缩包
dec-$mod解压源码
git-$mod在源码路径创建本地git仓库
prepare-$mod使用rsync同步changes的修改到源码路径,编译前会自动执行,通常不需要手动执行

prepare-$mod的工作方式:如果没有指定版本的源码路径,如 source/kernel/linux-6.1,则选取 linurx-repo作为源码路径,并使用 git checkout <tag>切换到指定版本。

举例:

make ARCH=arm64 dec-kl          # 解压源码,如果没有下载,会自动下载
make ARCH=arm64 git-kl          # 创建本地仓库,如果没有下载解压,会自动下载、解压

6. 编译相关target说明

6.1. $mod-%说明

$mod-%表示切换到对应源码路径下,执行相应的操作,如 make ARCH=arm64 ub-help实际执行效果如下:

make -j2 \
	-C /data/eel/source/u-boot/u-boot-2022.10 \
	ARCH=arm \
	CROSS_COMPILE=/data/eel/toolchain/gcc-linaro-11.3.1-2022.06-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- \
	O=/data/eel/output/arm64/u-boot/u-boot-2022.10/qemu_arm64_defconfig \
	help

6.2. all/all-tee

编译镜像文件。

target说明
all编译uboot、kernel、kl-modules、rootfs
all-tee在all的基础上,增加atf、optee_os、optee_client、optee_examples

6.3. qemu

target说明
qemu-uboot/qemu-ub使用QEMU模拟启动U-Boot
qemu-kernel/qemu-kl使用QEMU模拟启动内核
qemu使用QEMU模拟启动U-Boot,并自动启动内核
qemu-tee使用QEMU模拟启动ARM trusted firmware,并加载optee_os和U-Boot,最终启动内核
qemu-xxx-gdb添加"-S -s"参数,QEMU模拟启动后等待gdb连接
qemu-dumpdtdump QEMU使用的dtb文件并反汇编,文件名前缀由DUMP_DT指定

6.4. atf

仅ARM和ARM64。

target说明
atf编译ARM trusted firmware,依赖uboot或optee_os生成物
atf-cleanclean

6.5. optee

仅ARM和ARM64。

target说明
opteeoptee_os、optee_client、optee_examples
clone-opteeclone optee_os、optee_client、optee_examples

6.5.1. optee_os

仅ARM和ARM64。

target说明
optee_os编译optee_os
optee_os-cleanclean

6.5.2. optee_client

仅ARM和ARM64。

target说明
optee_client编译optee_client,并生成库和头文件
optee_client-install同optee_client
optee_client-cleanclean

6.5.3. optee_examples

仅ARM和ARM64。

target说明
otex-%编译ta、ca和plugin
otex-%-host编译ca
otex-%-ta编译ta
optee_examples依赖optee_os和optee_client
optee_examples-install将ta、ca和plugin放到对应目录
optee_examples-cleanclean

6.6. uboot

target说明
uboot生成uboot镜像
uboot-defconfigmake $(UB_CONFIG)
uboot-menuconfigmenuconfig
uboot-savedefconfig保存defconfig为UB_SAVECONF,UB_SAVECONF默认同UB_CONFIG
uboot-dis反汇编u-boot ELF文件

6.7. kernel

target说明
kernel生成kernel镜像
kernel-defconfigmake $(KL_CONFIG)
kernel-menuconfigmenuconfig
kernel-savedefconfig保存defconfig为KL_SAVECONF,KL_SAVECONF默认同KL_CONFIG
kernel-dis反汇编vmlinux ELF文件
kernel-modulesmake modules
kernel-modules_installmake modules_install

6.8. kmodules

详细内容参考 eel-kmoduelsREADME

target说明
km-%执行kmodules下对应的target
kmodules同km-all,编译kmodules所有文件

6.9. rootfs

构建根文件系统,默认使用 ext4格式,可以指定 RFS_TYPE使用其他文件系统。

默认使用buildroot方式构建根文件系统,busybox方式只是为了演示建立根文件系统的基本步骤。
bootstrap方式在Debian 11上验证过,目前测试只有ARM64 + Debian 10(Buster)可以启动。root密码由 changes/rootfs/bootstrap/bs-post1-passwd.sh设置,默认密码为123。

RFS_TYPE支持的文件系统格式与 rootfs_$(RFS_MODE)相关,具体参考 rootfs_$(RFS_MODE)内容。

  • bb: busybox
  • br: buildroot
  • bs: bootstrap,debootstrap
target说明
rootfsrootfs_$(RFS_MODE)
rootfs_info输出当前使用的根文件系统信息

6.9.1. busybox

主要包含 busybox官方源码和 etc目录示例,是构建根文件系统的基本组成元素。为了方便测试交叉编译的程序,busybox使用动态链接,所以需要在制作 rootfs时指定交叉编译工具链的共享库路径。共享库路径由 config.mkCOMPILE_LIB_PATH指定。

busybox只支持 ext4erofs格式的根文件系统,根文件系统镜像位于 $(O_RFS_DIR)/rootfs_$(ARCH).$(RFS_TYPE)

  • make ARCH=arm64 rootfs_ext4
  • make ARCH=arm64 rootfs_erofs
target说明
busybox编译busybox
busybox-defconfigmake $(BB_CONFIG)
busybox-menuconfigmenuconfig
busybox-savedefconfig保存.config为BB_SAVECONF,BB_SAVECONF默认同BB_CONFIG
busybox-install将文件install到busybox输出目录的_install目录

6.9.2. rootfs_bb

busybox只支持 ext4erofs格式的根文件系统,根文件系统镜像位于 $(O_RFS_DIR)/rootfs_$(ARCH).$(RFS_TYPE)
如果需要支持其他格式,可以参考 rootfs_bb_ext4rootfs_bb_erofs修改Makefile。

target说明
rootfs_bb依赖busybox,实际执行rootfs_bb_$(RFS_TYPE)
rootfs_bb_ext4生成ext4格式的根文件系统镜像
rootfs_bb_erofs生成erofs格式的根文件系统镜像
rootfs_bb_dir存放根文件系统的临时目录

6.9.3. buildroot

buildroot支持的文件系统格式由 xxx_defconfig指定。
buildroot编译时,使用了 BUSYBOX_OVERRIDE_SRCDIR保持rootfs_br使用的busybox版本与rootfs_bb保持一致。

target说明
buildroot编译buildroot
buildroot-defconfigmake $(BR_CONFIG)
buildroot-menuconfigmenuconfig
buildroot-savedefconfig保存defconfig为BR_SAVECONF,BR_SAVECONF默认同BR_CONFIG
buildroot-modifyconfig对prepare-br放到buildroot源码目录的$(BR_CONFIG)进行修改

BR_CONFIG文件中指定了交叉编译工具链的路径和一些其他配置,可能与实际使用的不一致,使用buildroot-modifyconfig修改BR_CONFIG使配置与实际保持一致。BR_CONFIG文件内容也必须保证文件内有这些配置项。

6.9.4. rootfs_br

rootfs_br_$(RFS_TYPE)最终都是执行了buildroot。

target说明
rootfs_brrootfs_br_$(RFS_TYPE)

6.9.5. bootstrap

注意:未充分测试。

target说明
bootstrap-prepare执行update-binfmts --enable
bootstrap1执行bootstrap的步骤1,主要是下载文件
bootstrap2执行bootstrap的步骤2,主要是chroot进行配置
bootstrap-post执行changes中bootstrap指定的自定义脚本
bs-clean删除bootstrap的目录

6.9.6. rootfs_bs

target说明
rootfs_brrootfs_br_$(RFS_TYPE)
rootfs_bs_ext4将bootstrap目录制作成ext4文件系统镜像

6.10. gdb

target说明
gdb-ub/gdb-ubootgdb调试u-boot ELF文件
gdb-kl/gdb-kernelgdb调试vmlinux ELF文件
gdb/gdb-tee启动gdb调试

6.11. toolchain

target说明
toolchain解压toolchain并输出信息
dec-toolchain解压toolchain
toolchain_info输出toolchain信息

7. VS Code + GDB调试

.vscode/launch.json

TODO: VS Code + GDB

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值