logo
0
0
WeChat Login
KingDix<kingdix10@qq.com>
update version to 2.0.0

1. eel简介

1.1. 特性

  • 支持多个源码版本
  • 支持一键下载、编译、运行
  • 支持一键qemu运行u-boot、kernel,支持使用busybox、buildroot、debian根文件系统
  • 支持qemu + gdb调试
  • 支持arm/arm64/riscv32/riscv64
    • arm支持:atf、optee_os、optee_client、optee_examples
    • riscv支持:opensbi
  • 支持多种自定义配置
  • 尽可能遵循官方说明的编译方法,编译过程和命令对用户可见

1.2. 测试环境

Debian 12 Docker。理论上Debian的物理机、虚拟机也可。Ubuntu系统未测试。

1.3. 测试版本

模块version
ARM trusted firmware2.7.0/2.8.0/2.10.0
optee3.18.0/4.1.0
u-boot2022.10/2024.01
linux5.10/5.15/6.0/6.1/6.6
busybox1.35.0/1.36.0
buildroot2023.02/2024.02/2024.11

1.4. 其他说明

  1. optee-3.19.0及之后版本增加了libacl,需要-lbuuid选项,依赖buildroot使能BR2_PACKAGE_UTIL_LINUX_UUIDD,如果使用buildroot编译,buildroot会自动处理依赖。这里手动编译时,临时使用宿主机的库。
  2. linux-4.x版本编译时依赖compile-gcc$version.h,$version为gcc版本,源码中默认没有高版本的头文件,可以复制其他文件作为compile-gcc$version.h

2. 仓库说明

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

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

2.1. 主目录结构

$(EELDIR) ├── Makefile # 主Makefile ├── README.md # 说明文档 ├── arch/ # 体系架构配置文件 ├── changes/ # 与源码目录对应的修改,来自eel-changes仓库 ├── configs/ # 通用配置文件目录 ├── ctools/ # 辅助工具及脚本目录 ├── democodes/ # 示例代码,包含驱动、用户程序、脚本等 ├── docs/ # 文档目录 ├── download/ # 下载目录 │ └── buildroot-dl/ # buildroot下载目录 ├── dumpdt/ # 存放qemu用到的dtb反汇编的源码 ├── function.include # 自定义函数库 ├── os/ # 与操作系统相关的配置文件 ├── output/ # 编译生成物,按系统架构划分二级目录 ├── presets/ # 预定义的配置文件目录 ├── select # 用于选择预定义的配置文件,选择后使用.tmp.config.mk链接实际的文件 ├── share/ # QEMU虚拟机共享目录 ├── source/ # 源码目录 ├── submake/ # 子模块编译规则目录 └── toolchain/ # 交叉编译工具

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

默认虚拟机启动时会自动执行share/init.sh,挂载共享目录到虚拟机。

2.2. source目录

$(EELDIR) └── source ├── kernel │ ├── linux-6.1 # linux-6.1源码解压,使用git管理,方便代码阅读 │ └── linux-repo # 官方git仓库 ├── democodes # 例程 │ └── kmodules # 内核模块例程,按内核般般划分 │ └── linux-6.6 # linux-6.6内核模块例程 ├── 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仓库

2.3. changes目录

$(EELDIR) └── changes ├── kernel │ ├── linux-5.10 │ ├── linux-5.15 │ └── linux-6.1 # 针对linux-6.1的修改,包含deconfig等 ├── rootfs │ ├── bb-etc # busybox根文件系统/etc目录示例 │ ├── 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

3. 快速上手

3.1. 准备工作

做完开发环境搭建或安装 gitmake等工具后,可以使用如下命令下载。 eel下的几个子仓库地址在 configs/repo.mk中定义,默认使用的是https协议,如果已经把ssh公钥添加到gitee,可以改成ssh协议。 开源代码默认使用gitee镜像,可能比官方仓库更新慢。

git clone https://gitee.com/kingdix10/eel.git # 或者git clone git@gitee.com:kingdix10/eel.git cd eel # 根据需要修改configs/repo.mk make ARCH=arm64 changes-gitclone ctools-gitclone democodes-gitclone

3.2. 获取帮助

为了统一代码规则,规定必须指定ARCH才可以执行make。如果没有执行过select,可以随意指定一个,比如 arm

make ARCH=arm help make ARCH=arm help-uboot

注意:同名的编译目标在不同的ARCH下可能是不一样的,help信息也是如此。比如riscv不会有atf和optee相关的帮助信息。

3.3. 下载源码

默认情况下,编译时会自动检查依赖,如果源码不存在,会自动通过clone源码。当然也可以手动clone。 这里同样需要指定ARCH,比如optee只能在ARCH为arm或者arm64时下载。如果提前使用select选择了预定义的配置,可以省略ARCH。

官方仓库会包含各个版本的tag。在编译时,会自动checkout到指定的tag。 但是需要注意,重新编译时,在仓库里的修改会被覆盖掉。

# 下载configs/kernel.mk指定的内核版本,并解压 make ARCH=arm64 kernel-gitclone

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

# 下载configs/kernel.mk指定的内核版本,并解压 make ARCH=arm64 kernel-dec # 下载、解压自己指定的内核版本,并创建本地git仓库 make ARCH=arm64 UB_VERSION=2022.10 uboot-gitlocl

3.4. 变量配置

配置文件后缀为.mk,默认的配置文件在archconfigs目录下,presets下也预定义了一些配置。默认配置的形式为VAR ?= xxx

如果需要自己添加配置,只需要在presets创建后缀为.mk的文件即可。

presets下预定义的配置可以使用select来进行选择:

$ ./select select from: 1. arm.config.mk 2. arm.tee.config.mk 3. arm64.config.mk 4. arm64.tee.config.mk Please input index: 2

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

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

另外select是按字母顺序排列的,也可以直接使用如下命令

# 通过数字选择 ./select arm64.config.mk ./select 1

select之后,可以直接执行make相关命令,如make qemu-kernel

注意

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

3.5. 一键运行

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

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

3.6. 查看详细过程

可以使用make V=n来控制编译时的日志详细程度,n取值为0~5,默认为1,数字越大,详细程度越高。详见configs/q.mk

4. 命令说明

4.1. 下载命令

以U-Boot为例,

uboot-gitclone # 下载官方仓库源码 # uboot-gitlocal依赖uboot-dec,uboot-dec依赖uboot-download # 每个命令可单独使用,Makefile中自动处理依赖 uboot-download # 下载特定版本源码压缩包 uboot-dec # 解压下载的源码压缩包 uboot-gitlocal # 在解压后的的目录建立本地git仓库 uboot-gitgc # 清理git仓库中无用的数据,压缩仓库大小

4.2. 编译命令

默认编译命令与模块名相同

ub-% # 对原u-boot命令的封装,如make ub-help,相对于make -C $uboot_dir help ARCH=... uboot # 编译生成u-boot.bin,会自动同步changes下的修改,并执行uboot-defconfig uboot-defconfig # 使用UB_CONFIG指定的config文件生成.config uboot-menuconfig # 手动修改.config,注意此时执行make uboot会导致修改失效 # 如果只是编译查看效果,可以执行make uboot-all # 如果需要执行make uboot,需要先执行make uboot-savedefconfig uboot-savedefconfig # 保持配置文件changes目录下UB_SAVECONF指定的文件,UB_SAVECONF默认与UB_CONFIG相同 uboot-dis # 反汇编elf文件

4.3. qemu命令

qemu-dumpdt # 反汇编dtb文件

4.4. arm

qemu # 启动u-boot,u-boot使用qfw加载kernel和rootfs后启动内核 qemu-uboot # 启动u-boot qemu-kernel # 直接启动kernel

4.5. arm tee模式

需要将ARM_TEE配置为1。注意此时qemu命令与非安全模式不同,使用的defconfig也可能不同。

qemu # 使用atf启动optee_os和u-boot,u-boot使用qfw加载kernel和rootfs后启动内核 qemu-uboot # 使用atf启动optee_os和u-boot

在tee模式下,qemu会有两个串口,如果不指定,命令行中使用的是normal world的串口。

如果需要指定串口,可以使用QE_SERIAL指定。

QE_SERIALcommand优势缺点
none可直接操作仅支持normal world交互
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每次运行可能会变,如果不使用-S冻结cpu,会丢失部分启动日志

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

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

make qemu QE_SERIAL=pyt QEO_EXTRA=-S后,使用minicom连接pty。再到qemu命令行输入c解冻cpu后可以看到输出。

4.6. riscv

qemu # 使用opensbi启动kernel qemu-uboot # 启动u-boot qemu-kernel # 同qemu

5. gdb

当前仅支持arm非安全模式,使用如下命令,可在qemu启动时冻结cpu。

make qemu-uboot-gdb make qemu-kernel-gdb

之后,在另一终端执行如下命令可以启动gdb命令

make gdb-uboot make gdb-kernel

6. 根文件系统

RFS_MODE选择使用busybox(bb)/buildroot(br)/debootstrap(bs),括号内是RFS_MODE的取值,默认为brRFS_TYPE选择根文件系统类型,默认为ext4

注意在ARM_TEE为1的情况,busybox和buildroot会编译optee_client和optee_examples。

6.1. busybox

6.2. buildroot

为保证buildroot使用的busybox与bb模式版本一致,使用外部busybox仓库。

6.3. bootstrap

构建需要sudo权限。构建出的根文件系统默认用户为root,密码123。

7. 其他操作

7.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进行编译。

8. 已知问题

  1. debootstrap只能构建与所属根文件系统相同的根文件系统,如Debian系统或docker不能构建Ubuntu rootfs
  2. Ubuntu dbootstrap只支持amd64和i386,不支持ARM
  3. Debian debootstrap构建riscv根文件系统要求目标为Debian 13