zCore入门-面向对象的Rust微内核
前面介绍的**rCore**操作系统[rCore入门-来自清华的OS前沿教程](http://mp.weixin.qq.com/s?__bizMzUzMDMwNTg2Nwmid2247484314idx1sn432ea8fcf8113831c457bc50ce4a5659chksmfa5285becd250ca896dbbf785ffd58f87b8a9f98ea6d6279840a34e1561454d5bb436829c08ascene21#wechat_redirect)是清华的教学OS相当于使用**Rust语言山寨了下Linux**是一个**宏内核**。之前我有一篇文章介绍了**微内核**[seL4微内核入门-微内核介绍](http://mp.weixin.qq.com/s?__bizMzUzMDMwNTg2Nwmid2247484178idx1snedd650ee186ace6235e68b449ccb1e57chksmfa528536cd250c205987558ad3e90e0a7dcc102968a900b97f9f517a4233f55ac74786143c3ascene21#wechat_redirect)相对来说微内核在学术上**更严谨先进**一些尽管性能不如宏内核其他方面有点多特别是**安全性**。所以清华又搞了一个**zCore**思路还是山寨这次瞄上了谷歌Fuchsia的**Zicron**微内核见之前的文章[Fuchsia入门-简介和代码介绍](http://mp.weixin.qq.com/s?__bizMzUzMDMwNTg2Nwmid2247484294idx1snf95790f9d109f8653974fd2ca0a8dbc6chksmfa5285a2cd250cb45f99a71e3d58539ea55c4090204c909fc0a12ae260ed15563bd437b12ef5scene21#wechat_redirect)总结下rCore使用Rust语言山寨宏内核****LinuxzCore使用Rust语言山寨微内核****Zicron注意这里说的山寨不是完全参考不同语言也全参考不了实现方式有很多不同之处。上图是王润基同学恶搞了下谷歌Fuchsia的发布改成自己的了真是新iPhone还没出来山寨就有了。总结下这些OS其实都有一个技术指向**Rust****微内核**。谷歌的Fuchsia比较难产所以逼急了又推出来一个**KataOS**见之前文章[KataOS入门-简介和代码编译](http://mp.weixin.qq.com/s?__bizMzUzMDMwNTg2Nwmid2247484228idx1sn184d2d4bed044adeb66b532168644fb6chksmfa528560cd250c76df950cc7ef82da98d74da496a967a57d5996f2bfc249234f847dfdf136a2scene21#wechat_redirect)直接用现成的**seL4微内核Rust**应用框架**Sparrow**搞了。 回归正题关于zCore基本所有的资料在下面网址https://github.com/rcore-os/zcore_tutorial_developers1. 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教程源码 https://github.com/rcore-os/zCore-Tutorial.git3. rCore整体架构zCore的设计主要有两个出发点内核对象的封装将内核对象代码封装为一个库保证可重用硬件接口的设计使硬件与内核对象的设计相对独立只向上提供统一、抽象的API接口项目设计从上到下上层更远离硬件下层更接近硬件架构如下图所示为了让 zCore 能够同时运行在内核态和用户态我们在最下面设计了一个硬件抽象层HAL将内核所依赖的底层操作封装起来在裸机环境和 Linux/macOS 环境上分别提供不同的实现。在 HAL 之上的核心是zircon-object也就是 Zircon内核对象这里面包含了所有内核机制的实现。在对象层之上是系统调用层它负责将内核对象的功能封装成 Zircon syscall ABI 暴露给用户进程。再往上就是整个 OS 的顶层模块它负责完成系统初始化和加载第一个用户进程的工作并将所有模块组装到一起生成一个可执行文件。zCore 设计的顶层是上层操作系统比如 zCore、rCore、Zircon LibOS 和 Linux LibOS。在项目架构中各版本的操作系统有部分公用代码。与 zCore 微内核设计实现相关的部分则主要是图中左侧蓝色线部分。乍一看真是**四不像**有点像**嫁接**共用一个根嫁接上不同的枝条枝条上可以结出不同的水果。感觉这就是程序的**高级玩法**殊途同归万法归一还能相互转化实在是高万能工具啊。好处是这几种OS上的应用都可以在zCore上运行跟吃了几种水果一样甜啊。4. OS界的变形金刚不仅如此它还可以作为一个普通的用户进程运行在 Linux 或 macOS 的**用户态**我们一般把这种模式称为 **LibOS** 或 User-Mode OS。你甚至无需安装 QEMU 模拟器只需装上 Rust 官方工具链就可以编译运行体验 zCoregit 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** 跑单元测试统计测试覆盖率……这在之前的内核开发中是难以想象的。zCore 作为 rCore 的继承者它并没有把前辈丢掉。事实上zCore 并不是一个独立的 OS在它的仓库里还**藏着一个小 rCore**只需使用以下命令即可快速把它召唤出来我们来运行一个原生 Linux 程序——Busyboxmake rootfs cargo run --release -p linux-loader /bin/busybox这里面的奥秘在于Zircon 作为微内核其实已经提供了内核中最关键的内存管理和进程管理的功能。我们只需在它基础上补充 Linux 作为**宏内**核的其它功能例如文件系统并对外提供 **Linux 系统调用**接口即可重新构造出一个新的 rCore。这就是微内核运行宏内核程序的关键缺的东西再加一层壳子再封装一层系统调用。5. 编程语言分析官方 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 可能是第一个吃螃蟹的人。C20 中也引入了同样的特性不过考虑到历史包袱和生态问题我比较怀疑能否真正用起来 在传统 OS 中每个内核线程需要有自己独立的**内核栈**。当线程挂起时它的状态就保存在栈上。由于内核线程可能很多因此每个线程的栈都不能太大在 Linux 中一般是两个页也就是 8KB。而在 zCore 中所有**内核线程都变成了协程**在一个 CPU 核上共享同一个内核栈。当进入用户态时内核栈不再清空因为要保留必要的信息于是内核-用户切换的风格从传统的「**用户态中断调用内核处理函数**」变成了「**内核主动调用函数切换到用户态执行**」。当任务挂起时协程的状态被包装成 Future 存储在堆上。根据计算目前每个 Future 状态机的大小约为 600B 左右大幅节省了内存空间。 无栈协程相比线程的好处除了**空间占用少**以外还有更小的**上下文切换开销**进而实现更高的并发和吞吐率。不过它的缺点在于协作式、不可抢占这可能会为系统的实时性带来挑战。关于二者之间的对比还有待进一步的测试和分析。zCore 的主要特性和创新点第一个完全山寨的 Zircon 内核使用 Rust 编写实现精简层级清晰支持用户态开发、测试和运行第一个在内核中使用 async 机制总的来说zCore 应该是目前为止我们能想到、做到的Rust 语言操作系统的集大成之作了。上面都是截取的有兴趣参考王润基同学官宣的文章https://zhuanlan.zhihu.com/p/1377336256. 代码下载体验已经运行过rCore环境的机器可以直接下载zCore的代码体验下。参考代码https://github.com/rcore-os/zCore下载命令Gitclonehttps://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这里就不介绍了目前要学的已经挺多了。“啥都懂一点啥都不精通干啥都能干干啥啥不是专业入门劝退堪称程序员杂家”。后续会继续更新纯干货分析无广告不打赏欢迎分享给朋友欢迎评论交流“那路谈OS与SoC嵌入式软件”欢迎关注个人文章汇总https://thatway1989.github.io