# eel **Repository Path**: zhangxxd/eel ## Basic Information - **Project Name**: eel - **Description**: Easing Embedded System Learning - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-01-19 - **Last Updated**: 2024-01-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [toc] # 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 测试版本: | 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 | 其他说明: 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`命令相对小众,使用起来也没有明显的优势,这几个仓库还是作为独立的仓库处理。 - 环境搭建脚本仓库:[https://gitee.com/kingdix10/envsetup](https://gitee.com/kingdix10/envsetup) - eel主仓库:[https://gitee.com/kingdix10/eel](https://gitee.com/kingdix10/eel) - eel改动仓库:[https://gitee.com/kingdix10/eel-changes](https://gitee.com/kingdix10/eel-changes) - 驱动示例仓库:[https://gitee.com/kingdix10/eel-kmodules](https://gitee.com/kingdix10/eel-kmodules) - 辅助工具仓库:[https://gitee.com/kingdix10/eel-ctools](https://gitee.com/kingdix10/eel-ctools) 源码下载可以参考《快速上手》部分。 ## 1.2. 主目录结构 ```shell $(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目录 ```shell $(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目录 ```shell $(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协议。 ```shell 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仓库 ```shell # 下载+解压 make ARCH=arm64 dec-kl KL_VERSION=6.1 # 下载+解压+创建本地git仓库 make ARCH=arm64 git-ub UB_VERSION=2022.10 ``` 也可以clone代码的官方仓库,里边会包含各个版本的tag。但是需要注意,重新编译时,在仓库里的修改会被覆盖掉。 ```shell make ARCH=arm64 clone-kl ``` ## 2.3. 获取帮助 如下以 `arm64`为例。 方式一:select选定配置 ```shell ./select arm64.config.mk make help make help-kernel ``` 方式二:命令行指定变量值 ```shell make ARCH=arm64 help make ARCH=arm64 help-kernel ``` 方式三:export环境变量 ```shell export ARCH=arm64 make help make help-kernel ``` ## 2.4. 变量配置 `config.mk`和 `config.$(ARCH).mk`中指定了默认的一些配置,mks目录下是一些自定义的配置,可以使用select来进行选择: ```shell $ ./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 + 文件名的方式: ```shell ./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目录下没有对应文件)。 ```shell ./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](ctools/README.md)下载SourceTrailDB编译替换。 ```shell # 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 | 举例: ```shell 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 `切换到指定版本。 举例: ```shell make ARCH=arm64 dec-kl # 解压源码,如果没有下载,会自动下载 make ARCH=arm64 git-kl # 创建本地仓库,如果没有下载解压,会自动下载、解压 ``` # 6. 编译相关target说明 ## 6.1. `$mod-%`说明 `$mod-%`表示切换到对应源码路径下,执行相应的操作,如 `make ARCH=arm64 ub-help`实际执行效果如下: ```shell 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](source/kernel/kmodules/README.md)。 | 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