ATF入门-2大软件模型和代码编译运行探究

之前的文章:ATF入门-1qmeu搭建ARM全套源码学习环境中我们提到了ATF基本概念和系统启动流程,然后搭建了qemu运行开源代码的基础。
可以说是万事俱备,只欠东风了。思考下一步怎么写这个系列,还是按照周贺贺老师的收费课程顺序来挑战下,不过其是收费的,笔者肯定是不会花钱买的,找了一个知乎大神lgjjeff:https://www.zhihu.com/people/lgjjeff的芯片启动专栏文章:
https://www.zhihu.com/column/c_1513091402841554944
然后结合我们的具体qemu运行代码,妥妥的在实践中学习。
福利:这里先给出一个周贺贺老师的ARM中文资料:Armv8/armv9架构入门指南:http://hehezhou.cn/arm/index.html
其根据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的地方直接**#undef**后重定义
#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是只运行,
但是默认启动起来后需要在gdb里面输入c才能启动有打印,我们可以去掉输入c。

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呢?执行如下,这样就可以不用暴力修改LOG打印宏了。
make arm-tf DEBUG=1
后记:
万事开头难,关于ATF有非常多的知识点。而且其跟secure boot联系紧密,这篇文章也只是开头的开头,还没到代码分析,下一篇开始代码分析。
虽然写的不太深入,但是跟着这系列文章去学习ATF,相信会有一个入门的效果。
“啥都懂一点,啥都不精通,
干啥都能干,干啥啥不是,
专业入门劝退,堪称程序员杂家”。
欢迎各位有自己公众号的留言:申请转载!
纯干货持续更新,欢迎分享给朋友、点赞、收藏、在看、划线和评论交流!
“那路谈OS与SoC嵌入式软件”,欢迎关注!
个人文章汇总:https://thatway1989.github.io
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)