Debian 12 Docker。理论上Debian的物理机、虚拟机也可。Ubuntu系统未测试。
| 模块 | version |
|---|---|
| ARM trusted firmware | 2.7.0/2.8.0/2.10.0 |
| optee | 3.18.0/4.1.0 |
| u-boot | 2022.10/2024.01 |
| linux | 5.10/5.15/6.0/6.1/6.6 |
| busybox | 1.35.0/1.36.0 |
| buildroot | 2023.02/2024.02/2024.11 |
-lbuuid选项,依赖buildroot使能BR2_PACKAGE_UTIL_LINUX_UUIDD,如果使用buildroot编译,buildroot会自动处理依赖。这里手动编译时,临时使用宿主机的库。eel仓库下的几个仓库本身属于eel的子模块,但是 git submodule命令相对小众,使用起来也没有明显的优势,这几个仓库还是作为独立的仓库处理。
源码下载可以参考《快速上手》部分。
$(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,挂载共享目录到虚拟机。
$(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仓库
$(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
做完开发环境搭建或安装 git、make等工具后,可以使用如下命令下载。
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
为了统一代码规则,规定必须指定ARCH才可以执行make。如果没有执行过select,可以随意指定一个,比如 arm:
make ARCH=arm help make ARCH=arm help-uboot
注意:同名的编译目标在不同的ARCH下可能是不一样的,help信息也是如此。比如riscv不会有atf和optee相关的帮助信息。
默认情况下,编译时会自动检查依赖,如果源码不存在,会自动通过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
配置文件后缀为.mk,默认的配置文件在arch和configs目录下,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。
注意:
ARCH变量必须被指定。命令行参数 > export环境变量 > .tmp.config.mk(CONF=) > arch/$(ARCH)/*.mk > configs/*.mkroot权限,需要提前修改 SUDO配置项,防止在执行过程中频繁提示输入密码,如 SUDO = echo xxxx | sudo,也可以 echo "$username ALL=NOPASSWD: ALL" > /etc/sudoers.d/$user后重新登录来关掉密码。如下命令会自动完成代码下载、编译,并使用QEMU模拟启动,命令含义可以参考命令说明部分。
make ARCH=arm64 qemu-ubootmake ARCH=arm64 qemu-kernelmake ARCH=arm64 qemu可以使用make V=n来控制编译时的日志详细程度,n取值为0~5,默认为1,数字越大,详细程度越高。详见configs/q.mk。
以U-Boot为例,
uboot-gitclone # 下载官方仓库源码
# uboot-gitlocal依赖uboot-dec,uboot-dec依赖uboot-download
# 每个命令可单独使用,Makefile中自动处理依赖
uboot-download # 下载特定版本源码压缩包
uboot-dec # 解压下载的源码压缩包
uboot-gitlocal # 在解压后的的目录建立本地git仓库
uboot-gitgc # 清理git仓库中无用的数据,压缩仓库大小
默认编译命令与模块名相同
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文件
qemu-dumpdt # 反汇编dtb文件
qemu # 启动u-boot,u-boot使用qfw加载kernel和rootfs后启动内核 qemu-uboot # 启动u-boot qemu-kernel # 直接启动kernel
需要将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_SERIAL | command | 优势 | 缺点 |
|---|---|---|---|
| none | 无 | 可直接操作 | 仅支持normal world交互 |
| 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每次运行可能会变,如果不使用-S冻结cpu,会丢失部分启动日志 |
QE_SERIAL主要用在 make qemu-tee或 make qemu-ub-tee时,file/pty/udp/tcp都设置了两个串口,分别用于REE和TEE。
make qemu QE_SERIAL=pyt QEO_EXTRA=-S后,使用minicom连接pty。再到qemu命令行输入c解冻cpu后可以看到输出。
qemu # 使用opensbi启动kernel qemu-uboot # 启动u-boot qemu-kernel # 同qemu
当前仅支持arm非安全模式,使用如下命令,可在qemu启动时冻结cpu。
make qemu-uboot-gdb make qemu-kernel-gdb
之后,在另一终端执行如下命令可以启动gdb命令
make gdb-uboot make gdb-kernel
RFS_MODE选择使用busybox(bb)/buildroot(br)/debootstrap(bs),括号内是RFS_MODE的取值,默认为br。
RFS_TYPE选择根文件系统类型,默认为ext4。
注意在ARM_TEE为1的情况,busybox和buildroot会编译optee_client和optee_examples。
为保证buildroot使用的busybox与bb模式版本一致,使用外部busybox仓库。
构建需要sudo权限。构建出的根文件系统默认用户为root,密码123。
以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进行编译。