1. eel简介
目标:
- 支持多种自定义配置
- 支持arm/arm64/riscv32/riscv64
- 一键实现atf、optee、u-boot、kernel、rootfs的编译
- 一键模拟运行
- 支持多个源码版本
- 尽量遵循官方说明的编译方法,编译过程和命令对用户可见
- 支持VS Code + qemu + gdb调试
特性:
- 自动下载依赖包
- 自动处理依赖,完成编译
- 自动处理依赖,实现qemu运行
测试环境:
- VMWare虚拟机安装Debian 11
- VMWare虚拟机内Debian 11,Debian 11 Docker
- PVE内LXC安装Debian 11
- PVE内LXC安装Debian 11,Debian 11 Docker
测试版本:
source | version |
---|---|
ARM trusted firmware | 2.7.0/2.8.0 |
optee | 3.18.0 |
u-boot | 2020.04/2022.10 |
linux | 5.10/5.15/6.0/6.1 |
busybox | 1.35.0 |
buildroot | 2022.11 |
其他说明:
- optee-3.19.0增加了libacl,需要-lbuuid选项,未编译成功。
- linux-4.x版本编译时依赖compile-gcc$version.h,$version为gcc版本,源码中默认没有高版本的头文件,可以复制其他文件作为compile-gcc$version.h
1.1. gitee仓库
eel仓库下的几个仓库本身属于eel的子模块,但是 git submodule
命令相对小众,使用起来也没有明显的优势,这几个仓库还是作为独立的仓库处理。
- 环境搭建脚本仓库:https://gitee.com/kingdix10/envsetup
- eel主仓库:https://gitee.com/kingdix10/eel
- eel改动仓库:https://gitee.com/kingdix10/eel-changes
- 驱动示例仓库:https://gitee.com/kingdix10/eel-kmodules
- 辅助工具仓库:https://gitee.com/kingdix10/eel-ctools
源码下载可以参考《快速上手》部分。
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. 准备工作
做完开发环境搭建或安装 git
、make
等工具后,可以使用如下命令下载。
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.mk
和 config.$(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说明》。
注意:
ARCH
变量必须被指定。- 变量优先级:
命令行参数 > export环境变量 > .tmp.config.mk > .config.$(ARCH).mk > .config.mk
- 部分命令需要
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为例
方式一:
- 基于现有的
xxx_defconfig
进行make uboot-defconfig
,如make ARCH=arm64 uboot-defconfig UB_CONFIG=mine_arm64_defconfig
。 - 执行
make ARCH=arm64 ub-menuconfig
,并根据需要进行修改并保存。 - 执行
make ARCH=arm64 uboot-savedefconfig UB_SAVECONF=mine_arm64_defconfig
。
方式二:
- 基于现有的
xxx_defconfig
复制生成新的config,如cp u-boot/configs/qemu_arm64_defconfig u-boot/configs/mine_arm64_defconfig
。 - 执行
make ARCH=arm64 ub-menuconfig
,并根据需要进行修改并保存。 - 执行
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_SERIAL | QEMU串口设备,默认为none |
KL_ARGS | 内核bootargs |
4.1. QE_SERIAL选项说明
QE_SERIAL | command | 优势 | 缺点 |
---|---|---|---|
none | 无 | 可直接操作 | 只支持一个串口 |
file | 无 | 可保存完整启动日志 | 不可交互 |
udp | nc -u -l -p $port | 可查看启动日志,可交互 | 交互时使用Ctrl + C会使nc退出,重启QEMU需重新连接 |
tcp | nc -l -p $port | 可查看启动日志,可交互 | 需先启动nc监听tcp所有端口再启动QEMU,交互时使用Ctrl + C会使nc退出,重启QEMU需重新连接 |
pty | minicom -D /dev/pty/$NUM | 可交互、可自动重连 | 丢失部分启动日志,NUM需在QEMU启动后查看日志确定 |
QE_SERIAL主要用在 make qemu-tee
或 make 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-$mod | git clone |
pull-$mod | git 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-dumpdt | dump QEMU使用的dtb文件并反汇编,文件名前缀由DUMP_DT指定 |
6.4. atf
仅ARM和ARM64。
target | 说明 |
---|---|
atf | 编译ARM trusted firmware,依赖uboot或optee_os生成物 |
atf-clean | clean |
6.5. optee
仅ARM和ARM64。
target | 说明 |
---|---|
optee | optee_os、optee_client、optee_examples |
clone-optee | clone optee_os、optee_client、optee_examples |
6.5.1. optee_os
仅ARM和ARM64。
target | 说明 |
---|---|
optee_os | 编译optee_os |
optee_os-clean | clean |
6.5.2. optee_client
仅ARM和ARM64。
target | 说明 |
---|---|
optee_client | 编译optee_client,并生成库和头文件 |
optee_client-install | 同optee_client |
optee_client-clean | clean |
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-clean | clean |
6.6. uboot
target | 说明 |
---|---|
uboot | 生成uboot镜像 |
uboot-defconfig | make $(UB_CONFIG) |
uboot-menuconfig | menuconfig |
uboot-savedefconfig | 保存defconfig为UB_SAVECONF,UB_SAVECONF默认同UB_CONFIG |
uboot-dis | 反汇编u-boot ELF文件 |
6.7. kernel
target | 说明 |
---|---|
kernel | 生成kernel镜像 |
kernel-defconfig | make $(KL_CONFIG) |
kernel-menuconfig | menuconfig |
kernel-savedefconfig | 保存defconfig为KL_SAVECONF,KL_SAVECONF默认同KL_CONFIG |
kernel-dis | 反汇编vmlinux ELF文件 |
kernel-modules | make modules |
kernel-modules_install | make modules_install |
6.8. kmodules
详细内容参考 eel-kmoduels
的README。
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 | 说明 |
---|---|
rootfs | rootfs_$(RFS_MODE) |
rootfs_info | 输出当前使用的根文件系统信息 |
6.9.1. busybox
主要包含 busybox
官方源码和 etc
目录示例,是构建根文件系统的基本组成元素。为了方便测试交叉编译的程序,busybox使用动态链接,所以需要在制作 rootfs
时指定交叉编译工具链的共享库路径。共享库路径由 config.mk
的 COMPILE_LIB_PATH
指定。
busybox只支持 ext4
和 erofs
格式的根文件系统,根文件系统镜像位于 $(O_RFS_DIR)/rootfs_$(ARCH).$(RFS_TYPE)
。
make ARCH=arm64 rootfs_ext4
make ARCH=arm64 rootfs_erofs
target | 说明 |
---|---|
busybox | 编译busybox |
busybox-defconfig | make $(BB_CONFIG) |
busybox-menuconfig | menuconfig |
busybox-savedefconfig | 保存.config为BB_SAVECONF,BB_SAVECONF默认同BB_CONFIG |
busybox-install | 将文件install到busybox输出目录的_install目录 |
6.9.2. rootfs_bb
busybox只支持 ext4
和 erofs
格式的根文件系统,根文件系统镜像位于 $(O_RFS_DIR)/rootfs_$(ARCH).$(RFS_TYPE)
。
如果需要支持其他格式,可以参考 rootfs_bb_ext4
和 rootfs_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-defconfig | make $(BR_CONFIG) |
buildroot-menuconfig | menuconfig |
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_br | rootfs_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_br | rootfs_br_$(RFS_TYPE) |
rootfs_bs_ext4 | 将bootstrap目录制作成ext4文件系统镜像 |
6.10. gdb
target | 说明 |
---|---|
gdb-ub/gdb-uboot | gdb调试u-boot ELF文件 |
gdb-kl/gdb-kernel | gdb调试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