zCore入门-面向对象的Rust微内核

原创 thatway 那路谈OS与SoC嵌入式软件 2022-12-07 18:32

前面介绍的**rCore**  

操作系统:rCore入门-来自清华的OS前沿教程
,是清华的教学OS,相当于使用Rust语言山寨了下Linux
,是一个宏内核
。之前我有一篇文章介绍了微内核
seL4微内核入门-微内核介绍
,相对来说微内核在学术上更严谨先进
一些,尽管性能不如宏内核,其他方面有点多,特别是安全性
。所以清华又搞了一个zCore
思路还是山寨,这次瞄上了谷歌Fuchsia的Zicron
微内核,见之前的文章Fuchsia入门-简介和代码介绍
,总结下:

  • rCore

    使用Rust语言山寨宏内核**Linux**

  • zCore

    使用Rust语言山寨微内核**Zicron**

注意:这里说的山寨不是完全参考,不同语言也全参考不了,实现方式有很多不同之处。上图
是王润基同学恶搞
了下谷歌Fuchsia的发布
,改成自己的了
真是新iPhone还没出来山寨就有了

总结下,这些OS其实都有一个技术指向:**Rust**  

+微内核
。谷歌的Fuchsia比较难产,所以逼急了又推出来一个KataOS
,见之前文章:KataOS入门-简介和代码编译
,直接用现成的seL4微内核+Rust
应用框架Sparrow
搞了。

回归正题,关于zCore基本所有的资料在下面网址:  

https://github.com/rcore-os/zcore_tutorial_developers

1. zCore简介

  • zCore 是用 Rust 语言重新实现的 Zircon 微内核

  • 它运行在内核态,对外提供与 Zircon 完全相同的系统调用,因此能够运行原生的 Fuchsia 用户程序

    之前的文章介绍过Fuchsia的强大,其应用程序更是兼容了安卓,另外对于微内核驱动也是应用,也可以应用Fuchsia强大的驱动程序。可见这个zCore的巨大应用价值。

2. 面向对象的内核

Zicron是用**c++**  

写的,更适合用Rust
重写。有一个问题:
什么时候需要面向对象?
假如世界上只有一个上帝
,那就不需要面向对象。但是世界上还有几亿的人,人都有非常多的共性
,那答案就是有很多个
实例的时候就需要面向对象。回到内核,第一直觉是进程,这东西是多个
的,特别是用户进程,这必须可以面向对象啊,然后IPC通信,有很多进程直接又很多个
通道通信,很多个
就又可以面向对象。凡是可以有多个
的东西,都可以面向对象

在c语言编写的内核或者宏内核中,经常用到抽象出来的**结构体**  

,多个的表达就是结构体数组
或者结构体链表
,其辅助处理函数都要自己写,例如查找插入改变值等,很繁琐
。然后所有的东西都往进程结构体PCB
里面塞,很多机制理解起来很费力,要去看那个很大的PCB结构体去理解,一下就懵了
。人还是容易理解抽象出来的事物
然后加上简单的思维逻辑
,不抽象的混乱思维一会就晕了。

**Zircon 是一个基于对象的内核**  

。下面带你领略下面向对象的魅力,真是轻松学内核
的法宝。先来看一个zCore内核运行时组件层次框架图:

大家知道一般程序处理的流程:**用户程序**  

-》系统调用
-》内核
-》硬件
里面去处理。上图中
红框
里面就是把内核里面跟硬件无关的元素抽象出来,用面向对象
的方法表示出来。例如系统里面有多个
Process,一个Process实例里面有很多个
Handle和Rights指向其他的对象。

内核对象相关的三个重要概念:对象(Object),句柄(Handle),权限(Rights)。

  • 对象(Object)
    具备属性和行为的客体
    。客体之间可有各种联系。从简单的整数到复杂的操作系统进程等都可看做对象,它不仅仅表示具体的事物,还能表示抽象的规则、计划或事件。

  • 句柄(Handle)
    标识对象
    的符号,也可看成是一种指向对象的变量(也可称为标识符、引用、ID等)。

  • 权限(Rights)
    :是指对象的访问者被允许在对象上执行的操作
    ,即对象的访问权限。当对象访问者打开对象的句柄,该句柄具有对其对象的访问权限的某种组合。

    说下我的理解,
    内核的资源都被抽象成对象,对象之间用句柄产生联系,这种联系为了安全性有权限限制,当没有句柄指向的对象也就是没用了会被收回。

用户程序操作内核对象的一些细节:

  • 创建
    :每一种内核对象都存在一个系统调用来创建它,例如
    zx_channel_create
    。创建对象时一般需要传入一个参数选项 options,若创建成功则内核会将一个新句柄写入用户指定的内存中。

  • 使用
    :获得对象句柄后可以通过若干系统调用对它进行操作,例如
    zx_channel_write
    。这类系统调用一般需要传入句柄 handle 作为第一个参数,内核首先对其进行检查,如果句柄非法或者对象类型与系统调用不匹配就会报错。接下来内核会检查句柄的权限是否满足操作的要求,例如 write 操作一般要求句柄具有 WRITE 权限,如果权限不满足就会继续报错。

  • 关闭
    :当用户程序不再使用对象时,会调用
    zx_handle_close
    关闭句柄。当用户进程退出时,仍处于打开状态的句柄也都会自动关闭。

    总之,面向对象的代码很清晰
    ,很容易理解
    ,不绕弯子,利用面向对象的语法,代码行数能大大缩减
    ,预计5倍以上。上面的介绍大部分都是zCore教程里面的,这个教程更加的干货
    ,直接介绍核心概念,对OS基础知识进行了省略。同rCore教程一样也是从零开始自己写一个OS的教程
    ,这个感觉做的更好。

具体zCore的教程:
http://rcore-os.cn/zCore-Tutorial/index.html

```  
# 3. rCore整体架构  

zCore的设计主要有两个出发点:  
- 内核对象的**封装**  
:将内核对象代码封装为一个库,保证可重用  

- 硬件接口的设计:使硬件与内核对象的设计**相对独立**  
,只向上提供统一、抽象的API接口  

项目设计从上到下,上层更远离硬件,下层更接近硬件,**架构**  
如下图所示:  

![][9]  

为了让 zCore 能够同时运行在内核态和用户态,我们在最下面设计了一个硬件抽象层(**HAL**  
),将内核所依赖的**底层**  
操作封装起来,在裸机环境和 Linux/macOS 环境上分别提供不同的实现。  

在 HAL 之上的核心是zircon-object,也就是 Zircon **内核对象**  
,这里面包含了所有内核机制的实现。  

在对象层之上是**系统调用**  
层,它负责将内核对象的功能封装成 Zircon syscall ABI 暴露给用户进程。  

再往上就是整个 OS 的顶层模块,它负责完成系统**初始化和加载**  
第一个用户进程的工作,并将所有模块组装到一起,生成一个可执行文件。  

zCore 设计的顶层是上层**操作系统**  
,比如   
zCore、rCore、Zircon
LibOS 和 Linux LibOS  
。在项目架构中,各版本的操作系统有部分**公用代码**  
。与 zCore 微内核设计实现相关的部分则主要是图中左侧**蓝色**  
线部分。  

    乍一看,真是**四不像**  
,有点像**嫁接**  
,共用一个根,嫁接上不同的枝条,枝条上可以结出不同的水果。感觉这就是程序的**高级玩法**  
,殊途同归,万法归一,还能相互转化,实在是高,万能工具啊  
。好处是,这几种OS上的应用都可以在zCore上运行,跟  
吃了几种水果一样甜  
啊。  

![][10]  
# 4. OS界的变形金刚  

![][11]  

    不仅如此,它还可以作为一个普通的用户进程运行在 Linux 或 macOS 的**用户态**  
,我们一般把这种模式称为 **LibOS**  
或 User-Mode OS。你甚至无需安装 QEMU 模拟器,只需装上 Rust 官方工具链,就可以编译运行体验 zCore!

git clone https://github.com/rcore-os/zCore --recursive cd zCore git lfs pull cargo run --release -p zircon-loader prebuilt/zircon



    既然可以用户态运行,那么它其实就是一个普通的用户程序。这带来了巨大的好处:我们可以在用户态开发,用 **gdb**  
配合 **IDE**  
调试,用**cargo test**  
 跑单元测试,统计测试覆盖率……这在之前的内核开发中是难以想象的。  

![][12]  

    zCore 作为 rCore 的继承者,它并没有把前辈丢掉。事实上,zCore 并不是一个独立的 OS,在它的仓库里还**藏着一个小 rCore**  
!只需使用以下命令,即可快速把它召唤出来,我们来运行一个原生 Linux 程序——Busybox:

make rootfs cargo run --release -p linux-loader /bin/busybox



![][13]  

    这里面的奥秘在于,Zircon 作为微内核,其实已经提供了内核中最关键的内存管理和进程管理的功能。我们只需在它基础上补充 Linux 作为**宏内**  
核的其它功能(例如文件系统),并对外提供**Linux 系统调用**  
接口,即可重新构造出一个新的 rCore。  
这就是微内核运行宏内核程序的关键,缺的东西再加一层壳子,再封装一层系统调用。  
# 5. 编程语言分析  

![][14]  

    官方 Zircon 是用 C++ 语言编写的,代码量约有 **10w**  
 行。而 zCore 只用了**1w**  
 行 Rust 就实现了其中大部分核心功能。虽然我们还差一些没有实现,但相差一个数量级的规模还是让我感到有些诧异。不过至少据我观察,C++ 的 Zircon 代码从设计上就**比较复杂**  
,用了各种**自己造的轮**  
子,并且充斥着魔法操作。相比之下,Rust 的 zCore 代码看起来更加自然,核心库自带的**基础设施**  
再加上一些社区库的辅助,用起来还是非常**舒服**  
的。  

    关于 Rust 大家更关心的另一个话题是 **unsafe**  
。在 zCore 中我们尽量避免了 unsafe 的使用,但没有绝对禁止(毕竟禁止就写不出来了)。据统计,在 HAL 之上大约有 20 个 unsafe,其中大部分用在了两个对象之间互相取 Weak 引用的操作,剩下的也比较容易检验正确性。而 HAL 之下 unsafe 就比较多了,由于贴近底层硬件,几乎处处 unsafe,也就跟 C 没什么区别了。不过好在 HAL 代码还是比较少的,不过几百行而已。  

    Rust 唯一的问题就是**门槛太高**  
了。然而对于编写内核这种对性能、稳定性、安全性都要求极高的程序而言,门槛高一点未必是坏处。在被 Rust 编译器反复教做人之后,才知道自己当初太天真,写出来的程序处处是隐患。  

**async 机制**  

    除了上面提到的用户态运行之外,zCore 还有一大创新之处:首次在内核中引入了 async **无栈协程**  
机制。  

    熟悉主流编程语言的朋友会知道,async 是近几年开始流行的一种语言特性,能够让开发者用同步的风格编写**异步**  
代码。它本质上是将代码变换成状态机,在 OS 线程的基础上又提供了一层轻量级的“协程”,使得程序能够高效处理异步 IO,同时保持开发的高效率。  

    Rust 语言于 2019 年底正式稳定了 **async-await**  
 语法,并于今年 3 月份的   
PR#69033  
 中为 no_std 环境下使用 async 扫清了障碍。这使得在内核中全面应用 async 机制成为了可能,而 zCore 可能是第一个吃螃蟹的人。(C++20 中也引入了同样的特性,不过考虑到历史包袱和生态问题,我比较怀疑能否真正用起来)  

    在传统 OS 中,每个内核线程需要有自己独立的**内核栈**  
。当线程挂起时,它的状态就保存在栈上。由于内核线程可能很多,因此每个线程的栈都不能太大,在 Linux 中一般是两个页也就是 8KB。而在 zCore 中,所有**内核线程都变成了协程**  
,在一个 CPU 核上共享同一个内核栈。当进入用户态时,内核栈不再清空,因为要保留必要的信息,于是内核-用户切换的风格从传统的「**用户态中断调用内核处理函数**  
」变成了「**内核主动调用函数切换到用户态执行**  
」。当任务挂起时,协程的状态被包装成 Future 存储在堆上。根据计算,目前每个 Future 状态机的大小约为 600B 左右,大幅节省了内存空间。  

    无栈协程相比线程的好处除了**空间占用少**  
以外,还有更小的**上下文切换开销**  
,进而实现更高的并发和吞吐率。不过它的缺点在于协作式、不可抢占,这可能会为系统的实时性带来挑战。关于二者之间的对比,还有待进一步的测试和分析。  
# zCore 的主要特性和创新点:  
- 第一个完全山寨的 Zircon 内核  

- 使用 Rust 编写,实现精简,层级清晰  

- 支持用户态开发、测试和运行  

- 第一个在内核中使用 async 机制  

    总的来说,zCore 应该是目前为止我们能想到、做到的,Rust 语言操作系统的集大成之作了。  

上面都是截取的,有兴趣参考王润基同学**官宣**  
的  
文章:  


https://zhuanlan.zhihu.com/p/137733625  

# 6. 代码下载体验  

![][15]  

已经运行过rCore环境的机器,可以直接下载zCore的代码体验下。  

参考代码:  


https://github.com/rcore-os/zCore  

**下载**  
命令:

Git clone https://github.com/rcore-os/zCore.git



**编译运行**  
命令:

cargo qemu --arch riscv64 ```

还是基于RISC-V
硬件的qemu虚拟机运行:

其实一个更好更全面的资料潘庆霖
的毕业论文:

https://raw.githubusercontent.com/wiki/rcore-os/zCore/files/pql-thesis.pdf

后记:

到此**微内核入门**  

相关的一些OS介绍完了,基本只有一篇文章,给了些资料,简介,但是也写的很吃力,真是
万事开头难
。后续会根据大家的兴趣和自己的研究再深入剖析一下。另外,关于很多学术论文
的OS这里就不介绍了,目前要学的已经挺多了。

啥都懂一点
啥都不精通

干啥都能干
干啥啥不是

专业入门劝退
堪称程序员杂家
”。

后续会继续更新,  

纯干货
分析,无广告,不打赏,欢迎
分享给朋友
,欢迎
评论交流

results matching ""

    No results matching ""