Fuchsia入门-zircon微内核单独编译启动
原创 thatway 那路谈OS与SoC嵌入式软件 2023-03-07 18:06
“**实践出真知**”,对新手来说,别人给你说代码架构是怎样怎样的,给你一堆文档,看完还是**一头雾水**。实践很简单,就是代码编译运行,打log。之前的文章:[Fuchsia入门-简介和代码介绍](http://mp.weixin.qq.com/s?__biz=MzUzMDMwNTg2Nw==&mid=2247484294&idx=1&sn=f95790f9d109f8653974fd2ca0a8dbc6&chksm=fa5285a2cd250cb45f99a71e3d58539ea55c4090204c909fc0a12ae260ed15563bd437b12ef5&scene=21#wechat_redirect)
,介绍Fuchsia的代码编译运行,但是操作起来很不爽:
下载代码需要几个小时
代码下载编译后达到将近100G空间
编译需要两个小时
qemu运行卡顿
这还怎么**学习调试**
,官网就是给咱摆了一道
,然后官网基本就是纯概念的讲解。针对这种情况,还想学习Fuchsia主要是zircon微内核原理的人就很痛苦,要么直接看网页代码
:https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/;bpv=0;bpt=0
然后看官网文档:
https://fuchsia.dev/fuchsia-src/get-started?hl=en上看看纯概念文档。
但是还是那句话,**不运行这能学吗?**这也是本篇文章要解决的问题,我们需要**小而精**而且可以qemu运行的代码,直接上干货:**https://github.com/PanQL/zircon**
1. Zircon内核编译运行
https://github.com/PanQL/zircon这个是清华的一个同学从Fuchsia官方的20190715版本代码仓库中分离出来的**Zircon代码**
,用于进行Zircon内核学习,现在已经没有了。可以通过Makefile脚本进行编译并在qemu上运行
。
Zircon
是为
Fuchsia
提供支持的核心平台
。
Zircon
由内核(源代码在
/zircon/kernel
)以及系统启动、与硬件对话、加载用户空间所必需的一小组用户空间服务、驱动程序和库(源代码在
/zircon/system/
)组成处理并运行它们等。
Fuchsia
在此基础之上构建了一个更大的操作系统。
可以这么说,学习
Fuchsia
的
精华和原理
,搞清楚这个
Zircon
就差不多了。
编译环境搭建:
为了减小仓库体积,将prebuilt目录进行了大幅调整;因此运行之前请下载google预编译好的**clang**
:
https://chrome-infra-packages.appspot.com/p/fuchsia/clang/linux-amd64/+/
解压后放到某个权限合适的位置,这里我们放入/home/book/tools/clang
然后在代码的public/gn/toolchain/clang.gni
绝对目录
修改为对应位置,如下:
默认x64
架构编译运行
,在代码根目录下执行:
Make build
Make run
如果想在arm平台
上执行,需要修改out/args.gn中的legacy-image-x64为legacy-image-arm64,然后执行:
make build
make runarm
2. 学习感想分享
现在我们有**可运行代码**
和
文档
,就像
OS
入门系列里面各个
OS
都有这两个东西,但是直接看代码也看不懂,直接看文档也不行,然后入门很困难,这里有一个大的误区:
面对一个复杂系统,代码和文档**只看一遍是肯定不行的**
,需要三遍起步,而且要代码文档循环的一遍一遍看。
事实就是这么残酷,没有不劳而获,只能付出时间。万事开头难,还有一个关键就是**怎么开头**
,我感觉开头首先要调动兴趣和积极性
,从自己擅长的角度,比如我觉得这个代码可以运行能打印出来我写的log
,我就会相信这个代码,感觉有兴趣去探索,那我们开始:
我们先抛开官网那一堆概念,**直接看代码的启动过程**
,遇到不懂的代码再去看官网概念文档。然后接触一部分概念后,再整体去看一般概念(记不全),然后就是继续看代码,看代码有瓶颈了再看一般文档,循环往复,直到代码和文档都懂了。
修改代码:
运行:
到这里,是否能提起你的兴趣
去探索这个代码?
假如你已经有兴趣探索这个代码,那么接下来按照上面说的代码+文档循环往复,这里有一个**功力**
的问题:
有的人看的快,有的人看的慢
。或许你会说这跟
工作经验
有关系,大佬看一天的进度,小白可能需要一星期还得加班。是什么造成这样的差异?我们先扯点我自己的见解再开始进入代码,功力的高低的表现,比如有人说看代码如喝水,千把行不歇的,有让你说每一行看着都困难,一个函数摸索老半天,我感觉这里的功力
与共性知识
的积累相关,看的多了,积累的基础共性知识就多了,就看的更快。那么共性知识的本质是什么,还是人类理解世界的能力
,纵观人类的组织结构例如一个王朝
的组织就跟操作系统
里面很多机制很像,再本质一点为什么人类会这么组织,那就是我们的基因
,基因又是从自然
而来,假如换一个星球一切的根基就又不同了,像三体游戏里面从文明
的角度来看了,人类是有局限性,但是这种局限性促使我们更快的了解人类的共识,发展自我。
我们去理解一个新的事物可以借助**共识**
,但是不能拘泥于细节和条条框框,站在共识的角度更容易去创新,例如最近马斯克说的汽车这么多零部件,当然这些零部件都是有用的,但是为什么不一体浇筑
岂不是更简单有效率,这种野蛮而又简单的想法像狼入羊群
一样,冲击传统思维但是又符合基本规律
。
有时自己也有一些疑问,比如**学习这些东西对自己有多大帮助**
,以后忘记了怎么办,这点还想需要一个大局观,把握本质
脉络可能就是学习的真意,就像领导不看你细节的代码描述只要一个流程图或者框架图,随着这些知识的理解融汇
,最后达到一个复杂的、不可替代的程度,算是一个人才
了。
路漫漫,笔者也是一个技术菜鸟,啥都不精通,毅力也不够,天赋也没有,写的这些文章也都是入门篇,之后代码分析估计你会体会到**一顿乱拳**
的感觉。只是去想想这些,总有点帮助。下面进入代码的的世界。
3. 编译过程分析
编译就是执行make build
,在代码根目录Makefile
中:
build: config
cd out && ../buildtools/ninja
config:
buildtools/gn gen --export-compile-commands=x64 out
build依赖于config,conffig用了gn命令
,然后build中又使用了ninja命令
就完成了编译
代码doc文档里面有这两个工具的解释,都是谷歌很好用的编译工具。不细研究,我们先知道gn就是生成需要编译那些文件到out/compile_commands.json,ninja就去编译这些文件成二进制,ninja的优势就是增量编译和并行编译,代码修改后二次编译非常的快,就是这个痛点谷歌大牛
搞了这个工具,用着
超级棒
。
运行代码执行:make run
./scripts/run-zircon-x64 -z
./out/legacy-image-x64.zbi -t ./out/multiboot.bin
./scripts/run-zircon-x64是个脚本:
exec $DIR/run-zircon -a x64 "$@"
exec $DIR/run-zircon也是个脚本:
exec $QEMU -kernel "$QEMU_KERNEL"
-initrd "$QEMU_INITRD" \
$ARGS -append "$CMDLINE"
"$@"
- $QEMU_KERNEL就是./out/legacy-image-x64.zbi,也就是
kernel镜像
$QEMU_INITRD就是./out/multiboot.bin
$ARGS就是
qemu命令
的参数
- $CMDLINE就是传给
内核的参数
,在内核代码里面可以获取这些信息
那么./out/multiboot.bin是个什么东西?
Multiboot
是一个协议
,一般协议就是一个约定为了对接两部分的执行实体,具体来说BootLoader去适配Kernel,一般来说是一对一的关系,那么某个bootloader就不具有通用性,有问题就可以通过抽象一层来解决,所以就有了Multiboot协议,满足这个协议的bootloader和kernel可以随意的适配
。启动的顺序为qemu->bootloader->multiboot->kernel
Bootloader和multiboot的代码在zicron工程下有,这里不深入研究,直接看kernel。
4. kernel入口分析
Kernel的入口为_start
,代码在kernel/arch/x86/start.S
中
从进入_start开始,到跳转到C语言入口lk_main
之前,start.S中主要依次完成以下这些任务:
设置临时栈
清空bss段(此处涉及KASLR的实现,清空之前进行了复制)
初始化boot时期的alloc机制
设置新的页表
跳转到fixups代码所在位置,修正KASLR带来的偏差
设置中断向量表
平台初始化可以参考:https://blog.csdn.net/ganyao939543405/article/details/85204534
进入lk_main()函数就是大家熟系的c++语言
了,这里我们之前也加了打印。
为什么kernel的入口是_start?
legacy-image-x64.zbi可见kernel的格式是zbi(Zircon Boot Image),参考:https://fuchsia.dev/fuchsia-src/concepts/process/everything_between_power_on_and_your_component
ZBI
格式
是一种简单的容器格式
,它嵌入了引导加载程序传递的项目,包括特定于硬件的信息、提供引导选项的
内核
“
命令行
”
和
RAM
磁盘映像(通常是压缩的)。
内核在引导的早期阶段提取一些基本信息供自己使用。
kernel/target/pc/multiboot/multiboot-main.c中对zbi进行了解析
// Find the kernel item.
const zbi_header_t* kernel_item_header = NULL;
result = zbi_for_each(zbi, &find_kernel_item,
&kernel_item_header);
if (result != ZBI_RESULT_INCOMPLETE_KERNEL)
{
panic("ZBI missing kernel");
}
// This is the kernel item's payload, but it expects the whole
// zircon_kernel_t (i.e. starting with the container header) to be loaded
// at PHYS_LOAD_ADDRESS.
const zbi_kernel_t* kernel_header = (const void*)(kernel_item_header + 1);
zbi是二进制文件,里面开头放了zbi_header_t
和zbi_kernel_t
这两个结构体的定义见system/public/zircon/boot/image.h,这个文件也是ZBI格式定义的核心文件。
Multiboot解析zbi文件后把kernel入口地址放入了寄存器,之后就跳转执行了
"a"(kernel_entry), // %rax: kernel entry point
再来看_start,在kernel/arch/x86/start.S中
// These symbols are used by image.S
.global IMAGE_ELF_ENTRY
IMAGE_ELF_ENTRY = _start
在kernel/image.ld链接文件中,规定了入口地址
ENTRY(IMAGE_ELF_ENTRY)
但是看这个链接文件上面的解释,zicrcon并没有用到这个ENTRY而是对zbi二进制文件直接解析找到的IMAGE_ELF_ENTRY,同样在kernel/arch/x86/start.S中如下:
// ZBI file header (zbi_header_t)
ZBI_CONTAINER_HEADER(_zbi_file_header,
boot_load_end - _zbi_kernel_header)
// ZBI kernel header (zbi_header_t)
DATA(_zbi_kernel_header)
.int ZBI_TYPE_KERNEL_X64
.int boot_load_end - _zbi_kernel_payload
.int 0
.int ZBI_FLAG_VERSION
.int 0
.int 0
.int ZBI_ITEM_MAGIC
.int ZBI_ITEM_NO_CRC32
END_DATA(_zbi_kernel_header)
// ZBI_TYPE_KERNEL payload (zbi_kernel_t)
DATA(_zbi_kernel_payload)
.quad PHYS(IMAGE_ELF_ENTRY) //该处地址为start.S中的_start地址
.quad boot_bss_end - boot_load_end // 在该image加载之后,还应该余下多少内存空间
END_DATA(_zbi_kernel_payload)
篇幅有限,下次继续从**lk_main**
介绍启动流程
,可能会更多的涉及zicron内核里面的内核对象
,这些内核对象是OS里面很基本和简单的抽象,不像linux宏内核那么复杂,更容易理解OS。
后记:
Fuchsia入门文章:[Fuchsia入门-简介和代码介绍](http://mp.weixin.qq.com/s?__biz=MzUzMDMwNTg2Nw==&mid=2247484294&idx=1&sn=f95790f9d109f8653974fd2ca0a8dbc6&chksm=fa5285a2cd250cb45f99a71e3d58539ea55c4090204c909fc0a12ae260ed15563bd437b12ef5&scene=21#wechat_redirect)
的阅读量
目前还是最高
的,说明大家对这个系统很有兴趣,一起来学习吧。
“啥都懂一点
,啥都不精通
,
干啥都能干
,干啥啥不是
,
专业入门劝退
,堪称程序员杂家
”。
后续会继续更新,
纯干货
分析,无广告,不打赏,欢迎
分享给朋友
,欢迎
评论交流
!