然后结合我们的具体qemu运行代码,妥妥的在实践中学习。
福利:这里先给出一个周贺贺老师的完整资料: Armv8/armv9架构入门指南根据ARM官网DEN0024A_v8_architecture_PG_1.0.pdf翻译整理而来的,也可以去看英文的。
1. 大软件模型
周贺贺老师本小节的视频是免费公开的,大家可以自己去看: https://www.bilibili.com/cheese/play/ep92791?query_from=0&search_id=5894568997539276737&search_query=ATF+ARM&csource=common_hpsearch_null_null&spm_id_from=333.337.search-card.all.click
上图是目前流行的一个软件框架,不仅限于安卓和linux,底层还有很多其他固件,从而巩固安全的需求。
异常中断是ARM架构的重要内容。上图是异常等级的切换模型。
切程序地址需要异常向量表,需要异常指令触发异常。异常就会进入高级别再切回来,就像V字形。
reset的时候也可以进行异常等级切换。这个是EL3,没有high level就需要使用warm reset。
对于64位系统,上层可以运行32位。但是上层64位,下层不可以32位。
上面是secure boot的过程,里面各个固件的异常等级不一样,就需要使用异常跳来跳去。
上图是一个设计的例子,里面uboot跳kernel需要smc到BL31再eret到kernel
2. 编译过程探究
2.1 log打印
按照之前的流程运行起来后,首先我们应该做点什么呢?
那必须上手改改代码打点log小试身手啊。然后再探索下这个代码是怎么编译运行的,这样就能完全控制了这套代码。
例如上面的打印:BL1: v2.10.0,我们使用vscode在atf代码里面搜索“BL1:”
NOTICE(FIRMWARE_WELCOME_STR);
NOTICE("hello BL1: %s\n", version_string);
NOTICE("BL1: %s\n", build_message);
修改代码加一个hello,然后make run后可以看到:
可见NOTICE进行了打印,但是我们下面的INFO并没有打印
#if LOG_LEVEL >= LOG_LEVEL_INFO
# define INFO(...) tf_log(LOG_MARKER_INFO __VA_ARGS__)
#else
# define INFO(...) no_tf_log(LOG_MARKER_INFO __VA_ARGS__)
#endif
LOG_LEVEL控制了打印级别,在根目录的Makefile文件中
ifneq (${DEBUG}, 0)
BUILD_TYPE := debug
TF_CFLAGS += -g -gdwarf-4
ASFLAGS += -g -Wa,-gdwarf-4
# Use LOG_LEVEL_INFO by default for debug builds
LOG_LEVEL := 40
else
BUILD_TYPE := release
# Use LOG_LEVEL_NOTICE by default for release builds
LOG_LEVEL := 20
endif #(Debug)
include/common/debug.h中的定义如下。可见编译atf的时候并没有打开${DEBUG},一个简单粗暴的方式就是在使用LOG_LEVEL的地方直接重定义
#define LOG_LEVEL_NONE U(0)
#define LOG_LEVEL_ERROR U(10)
#define LOG_LEVEL_NOTICE U(20)
#define LOG_LEVEL_WARNING U(30)
#define LOG_LEVEL_INFO U(40)
#define LOG_LEVEL_VERBOSE U(50)
#undef LOG_LEVEL
#define LOG_LEVEL LOG_LEVEL_INFO
这样重新make run下就可以看到:
2.2 去掉默认gdb
make run是先编译后运行, make -f qemu_v8.mk run-only是只运行
qemu运行gdb就需要加这个-s -S的参数,我们可以去掉:
这样一启动,不用输入c就可以直接启动了。
2.3 只编译atf
make run是全编,但是比较慢。比如我们只对atf关心,那么来一探究竟吧,在arm/optee/build/qemu_v8.mk中
115 TARGET_DEPS := arm-tf buildroot linux optee-os qemu
all: $(TARGET_DEPS)
487 run: all
488 $(MAKE) run-only
arm-tf的编译如下:
218 arm-tf: $(BL32_DEPS) $(BL33_DEPS)
219 $(TF_A_EXPORTS) $(MAKE) -C $(TF_A_PATH) $(TF_A_FLAGS) all fip
220 mkdir -p $(BINARIES_PATH)
那么就直接:make arm-tf就可以了
在编译make all的依赖里面还有buildroot。这个东西有什么用?
大家都知道linux内核有make menuconfig的配置,非常方便裁剪,图形化的界面。但是对于大软件模型,除了Linux内核之外还有很多固件、应用、文件系统等软件,这些软件是否也可以有一个图形化的配置工具进行裁剪,这就诞生了buildroot。关于buildroot可以单独写一个文章,总之对于大软件系统,必须有一个这样的统一编译工具。
可以看到DEBUG的值是0,那么怎么改为1呢?
make arm-tf DEBUG=1
后记:
万事开头难,关于ATF有非常多的知识点。而且其跟secure boot联系紧密,这篇文章也只是开头的开头,还没到代码分析,下一篇开始代码分析。
虽然写的不太深入,但是跟着这系列文章去学习ATF,相信会有一个入门的效果。