├── .gitignore ├── README.md ├── SUMMARY.md ├── drafts ├── FuchsiaOS和Zircon微内核简介 │ ├── Kernel Objects │ │ ├── Clock │ │ │ └── readme.md │ │ ├── Drivers │ │ │ └── readme.md │ │ ├── IPC │ │ │ ├── channel.md │ │ │ └── readme.md │ │ ├── Memory and address space │ │ │ └── readme.md │ │ ├── Scheduling │ │ │ └── readme.md │ │ ├── Signaling │ │ │ └── readme.md │ │ ├── Tasks │ │ │ └── readme.md │ │ ├── Waiting │ │ │ └── readme.md │ │ └── readme.md │ ├── Zircon内核概念.md │ └── readme.md ├── ywj_fncall相关代码分析 │ ├── GDT_Entry.png │ ├── IDT_Entry.PNG │ ├── IDT_Entry_34.PNG │ ├── IDT_Entry_Missing.PNG │ ├── IDT_Entry_other.PNG │ ├── analysis.md │ ├── fncall.md │ ├── gdt.md │ ├── htmltable.htm │ ├── htmltable2.htm │ ├── idt.md │ ├── mod.md │ └── 相关代码分析.md └── 个人材料 │ ├── vel_schedule │ └── README.md │ ├── 张文龙_Summery │ └── 个人计划.md │ ├── 方澳阳相关材料 │ ├── README.md │ ├── 目标规划.assets │ │ ├── image-20200806191621668.png │ │ ├── image-20200806191631795.png │ │ ├── image-20200806191633231.png │ │ └── image-20200806191732170.png │ ├── 目标规划.md │ └── 目标规划.pdf │ └── 荣悦同_schedule │ └── 目标.md ├── helps └── graph_analysis │ ├── call_graph_analyzer.md │ ├── control_flow_graph_analyzer.md │ └── img │ ├── control_flow_graph.png │ ├── get_rustc_cmd.png │ ├── get_the_bitcode.png │ └── zircon_loader-callgraph-part.png ├── img ├── Fuchsia 操作系统的四层结构设计.png ├── Google-Fuschia-Operating-System-logo.jpg ├── ch01-01-kernel-object.png ├── image-20200805123801306.png ├── kobject.png └── structure.svg └── src ├── 01-code ├── Cargo.lock ├── Cargo.toml ├── rust-tooltrain ├── src │ ├── lib.rs │ └── object │ │ ├── dummy_object.rs │ │ ├── mod.rs │ │ └── object.rs └── target │ └── rls │ ├── .rustc_info.json │ └── debug │ ├── .cargo-lock │ ├── .fingerprint │ ├── downcast-rs-904ea28aba046704 │ │ ├── dep-lib-downcast-rs │ │ ├── invoked.timestamp │ │ ├── lib-downcast-rs │ │ └── lib-downcast-rs.json │ ├── spin-acbc4f71625ea3b6 │ │ ├── dep-lib-spin │ │ ├── invoked.timestamp │ │ ├── lib-spin │ │ └── lib-spin.json │ ├── zcore_test-03d1a7f8dd3fa848 │ │ ├── dep-lib-zcore_test │ │ ├── invoked.timestamp │ │ ├── lib-zcore_test │ │ └── lib-zcore_test.json │ └── zcore_test-901b0ddc1b9bab15 │ │ ├── dep-test-lib-zcore_test │ │ ├── invoked.timestamp │ │ ├── test-lib-zcore_test │ │ └── test-lib-zcore_test.json │ ├── deps │ ├── downcast_rs-904ea28aba046704.d │ ├── libdowncast_rs-904ea28aba046704.rmeta │ ├── libspin-acbc4f71625ea3b6.rmeta │ ├── libzcore_test-03d1a7f8dd3fa848.rmeta │ ├── libzcore_test-901b0ddc1b9bab15.rmeta │ ├── save-analysis │ │ ├── libdowncast_rs-904ea28aba046704.json │ │ ├── libspin-acbc4f71625ea3b6.json │ │ ├── libzcore_test-03d1a7f8dd3fa848.json │ │ └── zcore_test-901b0ddc1b9bab15.json │ ├── spin-acbc4f71625ea3b6.d │ ├── zcore_test-03d1a7f8dd3fa848.d │ └── zcore_test-901b0ddc1b9bab15.d │ └── incremental │ ├── zcore_test-13cc7ji4lzg3j │ ├── s-fq07r6yih8-1h7zv3q-224luegfobocj │ │ ├── dep-graph.bin │ │ ├── query-cache.bin │ │ └── work-products.bin │ └── s-fq07r6yih8-1h7zv3q.lock │ └── zcore_test-20c6xuhgrauog │ ├── s-fq07r71re7-13gbyda-j9a298xqvikg │ ├── dep-graph.bin │ ├── query-cache.bin │ └── work-products.bin │ └── s-fq07r71re7-13gbyda.lock ├── README.md ├── SUMMARY.md ├── ch01-00-object.md ├── ch01-01-kernel-object.md ├── ch01-02-process-object.md ├── ch01-03-channel-object.md ├── ch02-00-task.md ├── ch02-01-zircon-task.md ├── ch02-02-process-job-object.md ├── ch02-03-thread-object.md ├── ch03-00-memory.md ├── ch03-01-zircon-memory.md ├── ch03-02-vmo.md ├── ch03-03-vmo-paged.md ├── ch03-04-vmar.md ├── ch04-00-userspace.md ├── ch04-01-user-program.md ├── ch04-02-load-elf.md ├── ch04-03-context-switch.md ├── ch04-04-syscall.md ├── ch05-00-signal-and-waiting.md ├── ch05-01-wait-signal.md ├── ch05-02-port-object.md ├── ch05-03-more-signal-objects.md ├── ch05-04-futex-object.md ├── fuchsia-sec.md ├── fuchsia.md ├── zcore-intro.md └── zcore-intro ├── image-20200805123801306.png └── structure.svg /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zcore_tutorial_developers 2 | zcore_tutorial文档撰写工作以及单元测试工作组 3 | ## 主要目的 4 | 建立这个仓库的主要目的为尽量减少重复的工作。由于每个人的学习程度不一样,导致前面的人遇到的坑可能后人还会碰到。为了让前人的工作能给后人一定的帮助,建立此仓库为后人提供支持。 5 | 6 | ## 主要要求 7 | 每个人尽量把自己学到的东西写成一个文档,做到低耦合、规范化,命名清晰。后人在前人的基础上迭代修改,最后项目完成的时候进一步整理一下,可以merge到zcore仓库。 8 | 9 | 10 | 11 | 12 | # 主要相关链接 13 | [2020年操作系统专题训练大实验-zCore文档WiKi页面](http://os.cs.tsinghua.edu.cn/oscourse/OsTrain2020/g2) 14 | 15 | [zCore仓库](https://github.com/rcore-os/zCore) 16 | 17 | [zCore代码文档](https://rcore-os.github.io/zCore/zircon_object) 18 | 19 | [zCore-Tutorial](https://github.com/rcore-os/zCore-Tutorial) 20 | 21 | [Zircon 官方文档](https://fuchsia.dev/fuchsia-src/reference) 22 | 23 | [wrj,Rust语言操作系统的设计与实现](https://raw.githubusercontent.com/wiki/rcore-os/zCore/files/wrj-thesis.pdf ) 24 | 25 | [pql,zCore操作系统内核的设计与实现](https://raw.githubusercontent.com/wiki/rcore-os/zCore/files/pql-thesis.pdf) 26 | 27 | [Rust中的Async /Await](https://github.com/rustcc/writing-an-os-in-rust/blob/master/12-async-await.md) 28 | 29 | # 文件仓库目录描述 30 | 31 | [初步文档仓库(本仓库)](https://github.com/rcore-os/zcore_tutorial_developers) 32 | 33 | [目标文档仓库(release版本的仓库)](https://github.com/rcore-os/zCore-Tutorial) 34 | 35 | 本仓库中的目录说明: 36 | 37 | - `src/chxx`文件夹分别对应每一章节的内容 38 | - `help`目录是方便zCore程序分析的相关文档 39 | - `drafts`是指等待被整理进入`src/chxx`文件夹中的内容 40 | - `img`存放`src/chxx`文档中的所有图片,图表等 41 | - `SUMMARY.md`是对zcore_tutorial文档中各个章节的索引目录 42 | 43 | 44 | # 现有的zcore_tutorial文档主要从这些方面展开描述 45 | 46 | [简明 zCore 教程](README.md) 47 | [zCore 整体结构和设计模式](zcore-intro.md) 48 | [Fuchsia OS 和 Zircon 微内核](src/fuchsia.md) 49 | [Fuchsia 安全原理](src/fuchsia-sec.md) 50 | 51 | - [内核对象](src/ch01-00-object.md) 52 | - [初识内核对象](src/ch01-01-kernel-object.md) 53 | - [对象管理器:Process 对象](src/ch01-02-process-object.md) 54 | - [对象传送器:Channel 对象](src/ch01-03-channel-object.md) 55 | 56 | - [任务管理](src/ch02-00-task.md) 57 | - [Zircon 任务管理体系](src/ch02-01-zircon-task.md) 58 | - [进程管理:Process 与 Job 对象](src/ch02-02-process-job-object.md) 59 | - [线程管理:Thread 对象](src/ch02-03-thread-object.md) 60 | 61 | - [内存管理](src/ch03-00-memory.md) 62 | - [Zircon 内存管理模型](src/ch03-01-zircon-memory.md) 63 | - [物理内存:VMO 对象](src/ch03-02-vmo.md) 64 | - [物理内存:按页分配的 VMO](src/ch03-03-vmo-paged.md) 65 | - [虚拟内存:VMAR 对象](src/ch03-04-vmar.md) 66 | 67 | - [用户程序](src/ch04-00-userspace.md) 68 | - [Zircon 用户程序](src/ch04-01-user-program.md) 69 | - [加载 ELF 文件](src/ch04-02-load-elf.md) 70 | - [上下文切换](drafts/ywj_fncall相关代码分析/mod.md) 71 | - [Zircon 系统调用](src/ch04-04-syscall.md) 72 | 73 | - [信号和等待](src/ch05-00-signal-and-waiting.md) 74 | - [等待内核对象的信号](src/ch05-01-wait-signal.md) 75 | - [同时等待多个信号:Port 对象](src/ch05-02-port-object.md) 76 | - [实现更多:EventPair, Timer 对象](src/ch05-03-more-signal-objects.md) 77 | - [用户态同步互斥:Futex 对象](src/ch05-04-futex-object.md) 78 | 79 | # zCore项目整理架构图 80 | ![file](http://www.nuanyun.cloud/wp-content/uploads/2020/08/5f2a17fc7d7b3.png) 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # 简明 zCore 教程 2 | 3 | [简明 zCore 教程](README.md) 4 | [zCore 整体结构和设计模式](zcore-intro.md) 5 | [Fuchsia OS 和 Zircon 微内核](src/fuchsia.md) 6 | [Fuchsia 安全原理](src/fuchsia-sec.md) 7 | 8 | - [内核对象](src/ch01-00-object.md) 9 | - [初识内核对象](src/ch01-01-kernel-object.md) 10 | - [对象管理器:Process 对象](src/ch01-02-process-object.md) 11 | - [对象传送器:Channel 对象](src/ch01-03-channel-object.md) 12 | 13 | - [任务管理](src/ch02-00-task.md) 14 | - [Zircon 任务管理体系](src/ch02-01-zircon-task.md) 15 | - [进程管理:Process 与 Job 对象](src/ch02-02-process-job-object.md) 16 | - [线程管理:Thread 对象](src/ch02-03-thread-object.md) 17 | 18 | - [内存管理](src/ch03-00-memory.md) 19 | - [Zircon 内存管理模型](src/ch03-01-zircon-memory.md) 20 | - [物理内存:VMO 对象](src/ch03-02-vmo.md) 21 | - [物理内存:按页分配的 VMO](src/ch03-03-vmo-paged.md) 22 | - [虚拟内存:VMAR 对象](src/ch03-04-vmar.md) 23 | 24 | - [用户程序](src/ch04-00-userspace.md) 25 | - [Zircon 用户程序](src/ch04-01-user-program.md) 26 | - [加载 ELF 文件](src/ch04-02-load-elf.md) 27 | - [上下文切换](drafts/ywj_fncall相关代码分析/mod.md) 28 | - [Zircon 系统调用](src/ch04-04-syscall.md) 29 | 30 | - [信号和等待](src/ch05-00-signal-and-waiting.md) 31 | - [等待内核对象的信号](src/ch05-01-wait-signal.md) 32 | - [同时等待多个信号:Port 对象](src/ch05-02-port-object.md) 33 | - [实现更多:EventPair, Timer 对象](src/ch05-03-more-signal-objects.md) 34 | - [用户态同步互斥:Futex 对象](src/ch05-04-futex-object.md) -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Clock/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Clock/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Drivers/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Drivers/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/IPC/channel.md: -------------------------------------------------------------------------------- 1 | # 通道 2 | 3 | 通道是进程间的双向通信, 要维护一个有许多消息队列, 以便在任一方向上传递由一些数据和句柄组成的消息(message)。 4 | 5 | 6 | 7 | 在zCore中, 8 | 9 | -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/IPC/readme.md: -------------------------------------------------------------------------------- 1 | > 2 | -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Memory and address space/readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## VMAR 3 | - 类似于rCore中memory_set 4 | - 树状结构 5 | - inner包含 6 | - children, VMAR的vector 7 | - mapping, VMO的映射关系 8 | - 成员函数存在递归情况(树的遍历) 9 | - 也是一个kernel object 10 | - handle 11 | - rights 12 | - 映射的对象只可能是VMO(参数传进来的只有VMO) 13 | - 成员函数大概可以分为两类 14 | - export function (pub) 15 | - 供操作系统内部使用 16 | - 经过zircon-syscall包装之后变为syscall给用户程序使用 17 | - auxiliary function (within,contains……) 18 | -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Scheduling/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Scheduling/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Signaling/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Signaling/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Tasks/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Tasks/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Waiting/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/Waiting/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/FuchsiaOS和Zircon微内核简介/Kernel Objects/readme.md -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/Zircon内核概念.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | Zircon内核管理许多不同类型的对象。本质上讲,这些对象是能够通过系统调用直接访问,并实现了Dispatcher接口的C++类。对象的实现位于[kernel object](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/objects)目录下。 4 | 5 | 接下来将会介绍一些zircon中一些常见的概念。 6 | 7 | 8 | 9 | 10 | 11 | # 内核对象ID 12 | 13 | Zircon内核为了管理这些对象,就需要给他们打上标签。 14 | 15 | 在内核中的每个对象都具有"内核对象id"或简称为“koid"。它们是64位无符号整型,用以唯一定位这些对象,并且在系统生命周期内是唯一的,这尤其意味着koid将不会被重用。 16 | 17 | 有两种特别的koid值: 18 | 19 | *ZX_KOID_INVALID*的值为0,可用做表示”null“的哨兵值。 :question::question::question:这里两个的还需解释要改进一下 20 | 21 | *ZX_KOID_KERNEL*只有一个内核,并且具有它自己的koid :question::question::question: 22 | 23 | 24 | 25 | # 句柄(Handle) 26 | 27 | Zircon是面向对象的内核, 在用户态下的代码几乎完全通过对象句柄(`object handls`)与OS资源交互。 28 | 29 | 即: `Handle`(句柄)是Zircon内核的“文件描述符”,它表示用户空间进程如何引用内核对象,通过`Channel`可以将`Handle`传递给其他进程. 30 | 31 | 对象可能有多个句柄(在一个或多个进程中)引用它们。对于所有的`Object`,当最后指向它们的`Handle`关闭时,该`Object`同时也将被销毁,或者放置到结束状态下,并且这样的操作不可回滚。 32 | 33 | 可以通过向`Channel`写入`Handle`的方式,将`Handle`从一个`Process`移动到另外一个`Process`(使用 *zx_channel_write()*函数),或通过使用*zx_process_start()*函数,作为新`Process`的第一个线程的启动参数的形式传递一个`Handle`。 34 | 35 | 在某种程度上可以将句柄理解为指针, 在对句柄或者其指向对象进行操作时受到`Right`(权限)的控制, 就好像在用户态不能执行某些特权级指令一样。并且在指向对象的数个句柄中,`Right`级别可以不一样。 36 | 37 | 38 | 39 | 40 | 41 | # 系统调用(System calls) 42 | 43 | 用户空间代码通过系统调用与内核对象进行交互,以及几乎只能通过句柄对象(`Handle`)加以访问。在用户空间中,`Handle`通过32位整型(`zx_handle_t`类型)来表示。 当系统调用被执行时,内核检查`Handle`变量指向的实际句柄是否存在于调用进程的句柄列表中。然后内核进一步检查该`Handle`是否具有正确的类型(例如传递一个Thread Handle到需要事件信号的系统调用会导致错误发生),以及`Handle`是否对请求的操作具有相应的权限(`Right`)。 44 | 45 | 46 | 47 | 从访问的角度上看,系统调动可以被细分为如下三大类: 48 | 49 | 1. 没有任何限制的调用。只有少部分调用是属于这一类,如*zx_clock_get()*和*zx_nanosleep()*可以被任意线程调用。 50 | 2. 以`Handle`作为首参数的调用,用以表示它们所操作的对象。绝大多数的调用都是这一类,例如*zx_channel_write()*和*zx_port_queue()*。 51 | 3. 创建新对象的系统调用,不需要以`Handle`作为参数。例如*zx_event_create()*和*zx_channel_create()*。这一类调用的访问是受调用`Process`进程所在的`Job`所控制的(这同时也是它们的限制)。 52 | 53 | 54 | 55 | # 运行代码:任务(Job),进程(Process)和线程(Thread) 56 | 57 | 在上面提到了`Process`进程所在的`Job`, 现在解释一下什么是`Job,Process,Thread`。 58 | 59 | 在rCore中已经有了`Process`和`Thread`的概念。`Thread`表示在拥有它们的`Process`的地址空间中线程的执行(CPU寄存器,运行栈等)。`Process`被`Job`所拥有,而后者定义了各种可用资源的上限。`Job`又被父`Job`所拥有,并一直可以追溯到根任务(`Root Job`)。根任务于内核在启动时所创建,并被传递到第一个被执行的用户进程`userboot`中。 60 | 61 | > userboot是Zircon内核启动的第一个进程。 它以与vDSO相同的方式从内核映像加载,而不是从文件系统加载。 其主要目的是从bootfs加载第二个process和bootsvc。 62 | 63 | 离开了指向`Job`的`Handle`,`Process`中的`Thread`将无法创建其他`Process`或`Job`。 64 | 65 | 66 | 67 | 68 | 69 | # 消息传递:Socket和Channel 70 | 71 | `Socket`和`Channel`都是双向和双端的进程间通信(IPC)相关的`Object`。创建`Socket`或`Channel`将返回两个不同的`Handle`,分别指向`Socket`或`Channel`的两端。 72 | 73 | > **进程间通信**(**IPC**,*Inter-Process Communication*),指至少两个进程或线程间传送数据或信号的一些技术或方法。进程是计算机系统分配资源的最小单位(进程是分配资源最小的单位,而线程是调度的最小单位,线程共用进程资源)。每个进程都有自己的一部分独立的系统资源,彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信。举一个典型的例子,使用进程间通信的两个应用可以被分类为客户端和服务器,客户端进程请求数据,服务端回复客户端的数据请求。有一些应用本身既是服务器又是客户端,这在分布式计算中,时常可以见到。这些进程可以运行在同一计算机上或网络连接的不同计算机上。 74 | 75 | `Socket`是面向流的对象,可以通过它读取或写入以一个或多个字节为单位的数据。Short writes(如果Socket的缓冲区已满)和short read(如果请求的字节数量超过缓冲区大小)也同样受到支持。 76 | 77 | `Channel`是面向数据包的对象,并限制消息的大小最多为64K(如果有改变,可能会更小),以及最多1024个`Handle`挂载到同一消息上(如果有改变,同样可能会更小)。无论消息是否满足short write或read的条件,`Channel`均不支持它们。 78 | 79 | 当`Handle`被写入到`Channel`中时,在发送端`Process`中将会移除这些`Handle`。同时携带`Handle`的消息从`Channel`中被读取时,该`Handle`也将被加入到接收端`Process`中。在这两个时间点之间时,`Handle`将同时存在于两端(以保证它们指向的`Object`继续存在而不被销毁),除非`Channel`写入方向一端被关闭,这种情况下,指向该端点的正在发送的消息将被丢弃,并且它们包含的任何句柄都将被关闭。 80 | 81 | 82 | 83 | 84 | 85 | # 对象(Object)和信号(Signal) 86 | 87 | `Object`至多可以可包含32个信号(通过`zx_signals_t`数据结构和ZX_*SIGNAL*的定义),它们是表示当前一些状态信息。 88 | 89 | 例如,`zx_channel_readable`表示这个通道的终点有消息可读。`zx_process_terminated`表示这个进程停止运行。 90 | 91 | 线程可以等待一个或多个`Object`被信号激活。 92 | 93 | 大多数对象是可以等待的, 但是`Port`是不可等待的一个例子。可以使用`zx_object_get_info()`函数查看该对象是否可等待(`waitable`) 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | # 虚拟内存地址区域(VMAR) 102 | 103 | 虚拟内存地址空间的一个连续区域 104 | 105 | -------------------------------------------------------------------------------- /drafts/FuchsiaOS和Zircon微内核简介/readme.md: -------------------------------------------------------------------------------- 1 | # 食用指南 2 | 3 | 先看Zircon内核概念, 了解整体情况 -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/GDT_Entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/ywj_fncall相关代码分析/GDT_Entry.png -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/IDT_Entry.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/ywj_fncall相关代码分析/IDT_Entry.PNG -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/IDT_Entry_34.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/ywj_fncall相关代码分析/IDT_Entry_34.PNG -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/IDT_Entry_Missing.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/ywj_fncall相关代码分析/IDT_Entry_Missing.PNG -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/IDT_Entry_other.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/ywj_fncall相关代码分析/IDT_Entry_other.PNG -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/analysis.md: -------------------------------------------------------------------------------- 1 | # 分析报告 2 | ## 概述 3 | While the kernel handles the system call, the application's CPU state is saved in a trap frame on the thread's kernel stack, and the CPU registers are available to hold kernel execution state. 4 | 5 | 当内核处理系统调用时,应用程序的CPU状态保存在线程内核栈的trap frame中,CPU寄存器就能够进入内核状态 6 | 7 | Zircon是一个可以适应多种指令集的内核,在src/arch下,有四个目录,分别对应四种不同的CPU结构,它们是: 8 | - aarch64 (ARM architecture) 9 | - mipsel (MIPS architecture) 10 | - riscv (RISC-V) 11 | - x86_64 (64 bit version of x86 instruction set) 12 | ## x86_64 13 | ### 文件 14 | file | description 15 | ---- | --- 16 | fncall.rs | 在同一个状态中,因函数调用造成的上下文切换的实现 17 | gdt.rs | 配置全局描述符表(GDT) 18 | idt.rs | 配置中断描述符表(IDT) 19 | ioport.rs | I/O端口Permission 20 | mod.rs | 公共模块? 21 | syscall.rs | 系统调用的入口(通过它进入syscall.S)(未完成) 22 | syscall.S | 汇编代码,执行系统调用处理 23 | trap.rs | 处理内核中断的入口(通过它进入trap.S)(未完成) 24 | trap.S | 汇编代码,执行中断处理 25 | 26 | ### 代码分析 27 | [mod.rs](/src/arch/x86_64/doc/mod.md) -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/fncall.md: -------------------------------------------------------------------------------- 1 | # fncall.rs 2 | 3 | #### 首先我们分析一下代码中定义的五个macro 4 | 5 | ||| 6 | | - | - | 7 | |SWITCH_TO_KERNEL_STACK | 让rsp(栈顶指针)指向kernel stack| 8 | 9 | 代码如下: 10 | ``` 11 | .macro SWITCH_TO_KERNEL_STACK 12 | mov rsp, fs:48 # rsp = kernel fsbase 13 | mov rsp, [rsp + 64] # rsp = kernel stack 14 | .endm 15 | ``` 16 | 其中,rsp为栈顶指针 17 | 在`mov rsp, fs:48`后, FS与rsp寄存器如下: 18 | ![Figure 1](/docs/riscv_doc/fncallfiles/SWITCH_TO_KERNEL_STACK.png) 19 | 在`mov rsp, [rsp + 64]`后, FS与rsp寄存器如下: 20 | ![Figure 2](/docs/riscv_doc/fncallfiles/SWITCH_TO_KERNEL_STACK_2.png) 21 | 22 | ||| 23 | |-|-| 24 | |SAVE_KERNEL_STACK|将rsp的内容存进fs:64
- fs:64 (pthread.???) = kernel stack| 25 | 26 | 代码如下: 27 | ``` 28 | .macro SAVE_KERNEL_STACK 29 | mov fs:64, rsp 30 | .endm 31 | ``` 32 | 即,将当前rsp寄存器中的内容作为kernel stack写入fs:48中 33 | 34 | ||| 35 | |-|-| 36 | |PUSH_USER_FSBASE|将fs:0(user fsbase)的内容压入栈| 37 | ``` 38 | .macro PUSH_USER_FSBASE 39 | push fs:0 40 | .endm 41 | ``` 42 | 43 | 44 | ||| 45 | |-|-| 46 | |SWITCH_TO_KERNEL_FSBASE|从ring3进入ring0,并且将fs寄存器所指向的fsbase由user fsbase切换为kernel fsbase| 47 | 代码如下: 48 | ``` 49 | .macro SWITCH_TO_KERNEL_FSBASE 50 | mov eax, 158 # SYS_arch_prctl 51 | mov edi, 0x1002 # SET_FS 52 | mov rsi, fs:48 # rsi = kernel fsbase 53 | syscall 54 | .endm 55 | ``` 56 | 其中, eax中储存了系统调用号158, 即SYS_arch_prctl, edi和rsi中储存了参数(0x1002, fs:48), 使用syscall命令执行系统调用, 作用是将fs:48中的地址(kernel fsbase)写入fs寄存器中 57 | 58 | 如图: 59 | ![Figure 3](/docs/riscv_doc/fncallfiles/SWITCH_TO_KERNEL_FSBASE.png) 60 | 61 | 62 | ||| 63 | |-|-| 64 | |POP_USER_FSBASE|还原user fsbase| 65 | 66 | ``` 67 | .macro POP_USER_FSBASE 68 | mov rsi, [rsp + 18 * 8] # rsi = user fsbase 69 | mov rdx, fs:0 # rdx = kernel fsbase 70 | test rsi, rsi # if [rsp + 18 * 8] is 0 71 | jnz 1f # if not 0, goto set 72 | 0: lea rsi, [rdx + 72] # rsi = init user fsbase 73 | mov [rsi], rsi # user_fs:0 = user fsbase 74 | # if 0, user_fs:0 = init user fsbase 75 | 76 | 1: mov eax, 158 # SYS_arch_prctl 77 | mov edi, 0x1002 # SET_FS 78 | syscall # set fsbase 79 | 80 | # if not 0, set FS to [rsp + 18 * 8] 81 | 82 | mov fs:48, rdx # user_fs:48 = kernel fsbase 83 | 84 | .endm 85 | ``` 86 | 87 | FS寄存器设置为user fsbase 88 | 89 | 如果[rsp + 18 * 8]不为空,user fsbase = [rsp + 18 * 8]; 90 | 91 | 如果[rsp + 18 * 8]为空,user fsbase为初始user fsbase;将user_fs:48设置为kernel fsbase 92 | 93 | #### 定义syscall_fn_entry及syscall_fn_return, 保存上下文 94 | 95 | 代码如下: 96 | ``` 97 | global_asm!( 98 | r#" 99 | .intel_syntax noprefix 100 | syscall_fn_entry: 101 | # save rsp 102 | lea r11, [rsp + 8] # save rsp to r11 (clobber) 103 | 104 | SWITCH_TO_KERNEL_STACK 105 | pop rsp 106 | lea rsp, [rsp + 20*8] # rsp = top of trap frame 107 | 108 | # push trap frame (struct GeneralRegs) 109 | push 0 # ignore gs_base 110 | PUSH_USER_FSBASE 111 | pushfq # push rflags 112 | push [r11 - 8] # push rip 113 | push r15 114 | push r14 115 | push r13 116 | push r12 117 | push r11 118 | push r10 119 | push r9 120 | push r8 121 | push r11 # push rsp 122 | push rbp 123 | push rdi 124 | push rsi 125 | push rdx 126 | push rcx 127 | push rbx 128 | push rax 129 | 130 | # restore callee-saved registers 131 | SWITCH_TO_KERNEL_STACK 132 | pop rbx 133 | pop rbx 134 | pop rbp 135 | pop r12 136 | pop r13 137 | pop r14 138 | pop r15 139 | 140 | SWITCH_TO_KERNEL_FSBASE 141 | 142 | # go back to Rust 143 | ret 144 | 145 | # extern "sysv64" fn syscall_fn_return(&mut UserContext) 146 | syscall_fn_return: 147 | # save callee-saved registers 148 | push r15 149 | push r14 150 | push r13 151 | push r12 152 | push rbp 153 | push rbx 154 | 155 | push rdi 156 | SAVE_KERNEL_STACK 157 | mov rsp, rdi 158 | 159 | POP_USER_FSBASE 160 | 161 | # pop trap frame (struct GeneralRegs) 162 | pop rax 163 | pop rbx 164 | pop rcx 165 | pop rdx 166 | pop rsi 167 | pop rdi 168 | pop rbp 169 | pop r8 # skip rsp 170 | pop r8 171 | pop r9 172 | pop r10 173 | pop r11 174 | pop r12 175 | pop r13 176 | pop r14 177 | pop r15 178 | pop r11 # r11 = rip. FIXME: don't overwrite r11! 179 | popfq # pop rflags 180 | mov rsp, [rsp - 8*11] # restore rsp 181 | jmp r11 # restore rip 182 | "# 183 | ); 184 | ``` 185 | 186 | 187 | #### 让我们写一个测试程序来验证 188 | 189 | 190 | 191 | 192 | 200 | 201 | 204 | 205 | 206 | 207 | 249 | 250 | 256 | 257 | 258 | 259 | 260 | 294 | 295 | 313 | 314 | 315 | 318 | 334 | 335 | 336 | 337 | 363 | 367 | 368 | 369 | 370 | 397 | 403 | 404 | 405 | 406 |
codeexplanation
193 | #[cfg(test)]
194 | mod tests {
195 |     use crate::*;
196 | 
197 |     #[cfg(target_os = "macos")]
198 |     global_asm!(".set _dump_registers, dump_registers");
199 | 
202 | 这里定义了dump_registers 203 |
208 |     // Mock user program to dump registers at stack.
209 |     global_asm!(
210 |         r#"
211 | .intel_syntax noprefix
212 | dump_registers:
213 |     push r15
214 |     push r14
215 |     push r13
216 |     push r12
217 |     push r11
218 |     push r10
219 |     push r9
220 |     push r8
221 |     push rsp
222 |     push rbp
223 |     push rdi
224 |     push rsi
225 |     push rdx
226 |     push rcx
227 |     push rbx
228 |     push rax
229 |     add rax, 10
230 |     add rbx, 10
231 |     add rcx, 10
232 |     add rdx, 10
233 |     add rsi, 10
234 |     add rdi, 10
235 |     add rbp, 10
236 |     add r8, 10
237 |     add r9, 10
238 |     add r10, 10
239 |     add r11, 10
240 |     add r12, 10
241 |     add r13, 10
242 |     add r14, 10
243 |     add r15, 10
244 |     call syscall_fn_entry
245 | "#
246 |     );
247 | 
248 | 
251 | 这里是dump_registers的代码,程序的流程功能: 252 | 1、将rax等16个通用寄存器的值压栈 253 | 2、每个通用寄存器的值加10 254 | 3、调用syscall_fn_entry 255 |
261 | #[test]
262 | fn run_fncall() {
263 |     extern "sysv64" {
264 |         fn dump_registers();
265 |     }
266 |     let mut stack = [0u8; 0x1000];
267 |     let mut cx = UserContext {
268 |         general: GeneralRegs {
269 |             rax: 0,
270 |             rbx: 1,
271 |             rcx: 2,
272 |             rdx: 3,
273 |             rsi: 4,
274 |             rdi: 5,
275 |             rbp: 6,
276 |             rsp: stack.as_mut_ptr() as usize + 0x1000,
277 |             r8: 8,
278 |             r9: 9,
279 |             r10: 10,
280 |             r11: 11,
281 |             r12: 12,
282 |             r13: 13,
283 |             r14: 14,
284 |             r15: 15,
285 |             rip: dump_registers as usize,
286 |             rflags: 0,
287 |             fsbase: 0, // don't set to non-zero garbage value
288 |             gsbase: 0,
289 |         },
290 |         trap_num: 0,
291 |         error_code: 0,
292 |     };
293 | 
296 | run_fncall的流程: 297 | 1. 定义一个数组stack,长度0x1000,内容为0 298 | 2. 定义一个UserContext结构cx,并且进行初始化,初始化之后数据如下图所示: 299 | 300 | 301 | 3. 由于rip的值为dump_register,因此此时会进入dump_register的代码: 302 | push寄存器和修改寄存器的值,stack的内容如下图所示: 303 | 304 | 305 | 此时,调用syscall_fn_entry,kernel stack的内容变化如下图所示: 306 | 307 | 308 | 309 | 310 | 【注】:代码中两次pop rbx,是否笔误? 311 | 312 |
316 | cx.run_fncall();
317 | 
319 | 4. 从dump_register返回后,调用run_fncall(&mut self),代码为: 320 |
321 | {  
322 | unsafe { syscall_fn_return(self); }
323 |           self.trap_num = 0x100; 
324 | self.error_code = 0; 
325 | }
326 | 
327 | 调用syscall_fn_return,kernel stack的内容变化如下图所示: 328 | 保存被调用者寄存器: 329 | 330 | 331 | 恢复GeneralRegs 332 | 333 |
338 | // check restored registers
339 | let general = unsafe { *(cx.general.rsp as *const GeneralRegs) };
340 | assert_eq!(
341 |     general,
342 |         GeneralRegs {
343 |             rax: 0,
344 |             rbx: 1,
345 |             rcx: 2,
346 |             rdx: 3,
347 |             rsi: 4,
348 |             rdi: 5,
349 |             rbp: 6,
350 |             // skip rsp
351 |             r8: 8,
352 |             r9: 9,
353 |             r10: 10,
354 |             // skip r11
355 |             r12: 12,
356 |             r13: 13,
357 |             r14: 14,
358 |             r15: 15,
359 |             ..general
360 |         }
361 |     );
362 | 
364 | 5. 检查恢复的寄存器: 365 | 366 |
371 | // check saved registers
372 | assert_eq!(
373 |     cx.general,
374 |     GeneralRegs {
375 |         rax: 10,
376 |         rbx: 11,
377 |         rcx: 12,
378 |         rdx: 13,
379 |         rsi: 14,
380 |         rdi: 15,
381 |         rbp: 16,
382 |         // skip rsp
383 |         r8: 18,
384 |         r9: 19,
385 |         r10: 20,
386 |         // skip r11
387 |         r12: 22,
388 |         r13: 23,
389 |         r14: 24,
390 |         r15: 25,
391 |         ..cx.general
392 |     }
393 | );
394 | assert_eq!(cx.trap_num, 0x100);
395 | assert_eq!(cx.error_code, 0);
396 | 
398 | 6. 检查保存的寄存器 399 | 400 | 401 | 【注】:除rax之外,其余寄存器都相等 402 |
-------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/gdt.md: -------------------------------------------------------------------------------- 1 | #### gdt.rs的分析 2 | #### TODO: 使用的一些macro和包,以后详细写 3 | ``` 4 | use alloc::boxed::Box; 5 | use alloc::vec::Vec; 6 | use core::mem::size_of; 7 | 8 | use x86_64::instructions::tables::{lgdt, load_tss}; 9 | use x86_64::registers::model_specific::{GsBase, Star}; 10 | use x86_64::structures::gdt::{Descriptor, SegmentSelector}; 11 | use x86_64::structures::DescriptorTablePointer; 12 | use x86_64::{PrivilegeLevel, VirtAddr}; 13 | ``` 14 | 15 | #### 定义TSS类型 16 | ``` 17 | /// 如果编译时没有参数"ioport_bitmap", 则将TSS设置为x86_64结构下的TaskStateSegment 18 | #[cfg(not(feature = "ioport_bitmap"))] 19 | type TSS = x86_64::structures::tss::TaskStateSegment; 20 | 21 | /// 如果编译时有参数"ioport_bitmap", 则将TSS设置为TSSWithPortBitmap 22 | #[cfg(feature = "ioport_bitmap")] 23 | type TSS = super::ioport::TSSWithPortBitmap; 24 | ``` 25 | 26 | #### 初始化TSS与GDT 27 | ``` 28 | pub fn init() { 29 | } 30 | ``` 31 | 在这个函数中,我们: 32 | 为trap分配栈,将栈顶设置为tss,这样一来,从ring3切换到ring0,CPU可以正确地切换栈 33 | 代码如下 34 | ``` 35 | /// 新建一个位于堆上的TSS结构,并创建一个位于栈中的指针tss指向它 36 | /// https://docs.rs/x86_64/0.1.1/x86_64/structures/tss/struct.TaskStateSegment.html 37 | 38 | let mut tss = Box::new(TSS::new()); 39 | 40 | 41 | /// 在堆中新建一个0x1000大小的数组,用于模拟栈,使用`Box::leak().as_ptr()`获取这个数组的起始地址,再加0x1000的偏移,就获得了这个模拟栈的栈顶 42 | 43 | let trap_stack_top = Box::leak(Box::new([0u8; 0x1000])).as_ptr() as u64 + 0x1000; 44 | 45 | /// 将栈顶设置为tss的privilege_stack_table 46 | tss.privilege_stack_table[0] = VirtAddr::new(trap_stack_top); 47 | 48 | /// 解开Box, 获取tss的数据 ***? 49 | let tss: &'static _ = Box::leak(tss); 50 | 51 | /// Creates a TSS system descriptor for the given TSS. 如果不能返回System Segment, 那么panic 52 | /// tss0与tss1: 53 | /// tss0: 按descriptor格式重写的栈顶地址 54 | /// 如何理解tss1? 55 | let (tss0, tss1) = match Descriptor::tss_segment(tss) { 56 | Descriptor::SystemSegment(tss0, tss1) => (tss0, tss1), 57 | _ => unreachable!(), 58 | }; 59 | 60 | // Extreme hack: the segment limit assumed by x86_64 does not include the port bitmap. 61 | #[cfg(feature = "ioport_bitmap")] 62 | let tss0 = (tss0 & !0xFFFF) | (size_of::() as u64); 63 | 64 | unsafe { 65 | // get current GDT 66 | let gdtp = sgdt(); 67 | let entry_count = (gdtp.limit + 1) as usize / size_of::(); 68 | 69 | /// old_gdt: 一个slice, 从现有的gdt的base地址开始, 取entry_count个值 70 | let old_gdt = core::slice::from_raw_parts(gdtp.base as *const u64, entry_count); 71 | 72 | // allocate new GDT with 7 more entries 73 | // 74 | // NOTICE: for fast syscall: 75 | // STAR[47:32] = K_CS = K_SS - 8 76 | // STAR[63:48] = U_CS32 = U_SS32 - 8 = U_CS - 16 77 | let mut gdt = Vec::from(old_gdt); 78 | gdt.extend([tss0, tss1, KCODE64, KDATA64, UCODE32, UDATA32, UCODE64].iter()); 79 | let gdt = Vec::leak(gdt); 80 | 81 | 82 | // load new GDT and TSS 83 | lgdt(&DescriptorTablePointer { 84 | limit: gdt.len() as u16 * 8 - 1, 85 | base: gdt.as_ptr() as _, 86 | }); 87 | 88 | /// SegmentSelector: a index to LDT or GDT table with some additional flags 89 | /// Load the task state register using the ltr instruction 90 | load_tss(SegmentSelector::new( 91 | entry_count as u16, 92 | PrivilegeLevel::Ring0, 93 | )); 94 | 95 | // for fast syscall: 96 | // store address of TSS to kernel_gsbase 97 | GsBase::MSR.write(tss as *const _ as u64); 98 | 99 | Star::write_raw( 100 | SegmentSelector::new(entry_count as u16 + 4, PrivilegeLevel::Ring3).0, 101 | SegmentSelector::new(entry_count as u16 + 2, PrivilegeLevel::Ring0).0, 102 | ); 103 | } 104 | 105 | ``` 106 | 107 | 108 | #### 获取当前GDTR内容 109 | ``` 110 | /// Get current GDT register 111 | #[inline] 112 | unsafe fn sgdt() -> DescriptorTablePointer { 113 | let mut gdt = DescriptorTablePointer { limit: 0, base: 0 }; 114 | asm!("sgdt [{}]", in(reg) &mut gdt); 115 | gdt 116 | } 117 | ``` 118 | 119 | 120 | #### 定义了一些全局描述符 121 | 全局描述符表(GDT), It contains entries telling the CPU about memory segments. A similar Interrupts Descriptor Table exists containing tasks and interrupts descriptors. 122 | 123 | ![GDT_Entry](/docs/riscv_doc/GDT_Entry.png) 124 | ``` 125 | const KCODE64: u64 = 0x00209800_00000000; // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE 126 | const UCODE64: u64 = 0x0020F800_00000000; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE 127 | const KDATA64: u64 = 0x00009200_00000000; // DATA_WRITABLE | USER_SEGMENT | PRESENT 128 | #[allow(dead_code)] 129 | const UDATA64: u64 = 0x0000F200_00000000; // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT 130 | const UCODE32: u64 = 0x00cffa00_0000ffff; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT 131 | const UDATA32: u64 = 0x00cff200_0000ffff; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT 132 | ``` 133 | 以上述代码中的KCODE64为例分析: 134 | 136 | 137 | 138 | 140 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 246 | 247 | 248 | 249 | 250 | 251 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 |
Base 139 | 0:15Limit 141 | 0:15
00000000000000000000000000000000
Base 24:31FlagsLimit 16:19Access ByteBase 16:23
00000000001000001001100000000000
Base:0
  
Limit:0
  
Access Byte:PrPrivlSEXDCRWAC
10011000
  Present bit, must be 1
  Privilege, 2 252 | bits,ring level. 00=highest(user applications)
   Descripter 260 | Type. Set 1 for code or data segments
   Executable 269 | bit. 1 for executable
   Direction 279 | bit. 0 grows up.
   Readable/Writable
       Accessed bit.
      
Flags:GrSz00
0010
-------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/htmltable.htm: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 296 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | <body> 320 | <p>&#27492;&#39029;&#38754;&#20351;&#29992;&#20102;&#26694;&#26550;&#65292;&#32780;&#24744;&#30340;&#27983;&#35272;&#22120;&#19981;&#25903;&#25345;&#26694;&#26550;&#12290;</p> 321 | </body> 322 | 323 | 324 | 325 | -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/htmltable2.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/ywj_fncall相关代码分析/htmltable2.htm -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/idt.md: -------------------------------------------------------------------------------- 1 | ``` 2 | use alloc::boxed::Box; 3 | use x86_64::structures::idt::*; 4 | use x86_64::structures::DescriptorTablePointer; 5 | use x86_64::PrivilegeLevel; 6 | ``` 7 | 8 | #### 中断描述符表的结构 9 | 10 | | Entry | description | 11 | | - | - | 12 | | `pub divide_by_zero: Entry` | A divide by zero exception (`#DE`) occurs when the denominator of a DIV instruction or an IDIV instruction is 0. A `#DE` also occurs if the result is too large to be represented in the destination. | 13 | |`pub debug: Entry` |
Instruction execution.
Instruction single stepping.
Data read.
Data write.
I/O read.
I/O write.
Task switch.
Debug-register access, or general detect fault" 14 | | `pub non_maskable_interrupt: Entry` | An non maskable interrupt exception (NMI) occurs as a result of system logic signaling a non-maskable interrupt to the processor. | 15 | | `pub breakpoint: Entry` | A breakpoint (`#BP`) exception occurs when an `INT3` instruction is executed. 16 | | `pub overflow: Entry` | An overflow exception (`#OF`) occurs as a result of executing an `INTO` instruction while the overflow bit in `RFLAGS` is set to 1. 17 | | `pub bound_range_exceeded: Entry` | A bound-range exception (`#BR`) exception can occur as a result of executing the `BOUND` instruction. 18 | | `pub invalid_opcode: Entry` | An invalid opcode exception (`#UD`) occurs when an attempt is made to execute an invalid or undefined opcode. 19 | | `pub device_not_available: Entry` | "A device not available exception (`#NM`) occurs under any of the following conditions:
- An `FWAIT`/`WAIT` instruction is executed when `CR0.MP=1` and `CR0.TS=1`.
- Any x87 instruction other than `FWAIT` is executed when `CR0.EM=1`.
- Any x87 instruction is executed when `CR0.TS=1`. The `CR0.MP` bit controls whether the `FWAIT`/`WAIT` instruction causes an `#NM` exception when `TS=1`.
- Any 128-bit or 64-bit media instruction when `CR0.TS=1`." 20 | | `pub double_fault: Entry`| A double fault (`#DF`) exception can occur when a second exception occurs during the handling of a prior (first) exception or interrupt handler. 21 | |`coprocessor_segment_overrun: Entry`| This interrupt vector is reserved. It is for a discontinued exception originally used by processors that supported external x87-instruction coprocessors. 22 | |`pub invalid_tss: Entry`| An invalid TSS exception (`#TS`) occurs only as a result of a control transfer through a gate descriptor that results in an invalid stack-segment reference using an `SS` selector in the TSS. 23 | |`pub segment_not_present: Entry`| An segment-not-present exception (`#NP`) occurs when an attempt is made to load a segment or gate with a clear present bit. 24 | | `pub stack_segment_fault: Entry`| "An stack segment exception (`#SS`) can occur in the following situations:
- Implied stack references in which the stack address is not in canonical form. Implied stack references include all push and pop instructions, and any instruction using `RSP` or `RBP` as a base register.
- Attempting to load a stack-segment selector that references a segment descriptor containing a clear present bit.
- Any stack access that fails the stack-limit check." 25 | |`pub general_protection_fault: Entry`| "A general protection fault (`#GP`) can occur in various situations. Common causes include:
- Executing a privileged instruction while `CPL > 0`.
- Writing a 1 into any register field that is reserved, must be zero (MBZ).
- Attempting to execute an SSE instruction specifying an unaligned memory operand.
- Loading a non-canonical base address into the `GDTR` or `IDTR`.
- Using WRMSR to write a read-only MSR.
- Any long-mode consistency-check violation." 26 | | `pub page_fault: Entry`| "A page fault (`#PF`) can occur during a memory access in any of the following situations:
- A page-translation-table entry or physical page involved in translating the memory access is not present in physical memory. This is indicated by a cleared present bit in the translation-table entry.
- An attempt is made by the processor to load the instruction TLB with a translation for a non-executable page.
- The memory access fails the paging-protection checks (user/supervisor, read/write, or both).
- A reserved bit in one of the page-translation-table entries is set to 1. A `#PF` occurs for this reason only when `CR4.PSE=1` or `CR4.PAE=1`." 27 | |`reserved_1: Entry`| reserved 28 | |`pub x87_floating_point: Entry`| The x87 Floating-Point Exception-Pending exception (`#MF`) is used to handle unmasked x87 floating-point exceptions. 29 | |`pub alignment_check: Entry`| An alignment check exception (`#AC`) occurs when an unaligned-memory data reference is performed while alignment checking is enabled. 30 | |`pub machine_check: Entry`| The machine check exception (`#MC`) is model specific. Processor implementations are not required to support the `#MC` exception, and those implementations that do support `#MC` can vary in how the `#MC` exception mechanism works. 31 | | `pub simd_floating_point: Entry`| "The SIMD Floating-Point Exception (`#XF`) is used to handle unmasked SSE floating-point exceptions. The SSE floating-point exceptions reported by the `#XF` exception are (including mnemonics):
- IE: Invalid-operation exception (also called #I).
- DE: Denormalized-operand exception (also called #D).
- ZE: Zero-divide exception (also called #Z).
- OE: Overflow exception (also called #O).
- UE: Underflow exception (also called #U).
- PE: Precision exception (also called #P or inexact-result exception)." 32 | | `pub virtualization: Entry` | virtualization 33 | | `reserved_2: [Entry; 9]`| reserved 34 | | `reserved_2: [Entry; 9]`| reserved 35 | | `reserved_2: [Entry; 9]`| reserved 36 | | `reserved_2: [Entry; 9]`| reserved 37 | | `reserved_2: [Entry; 9]`| reserved 38 | | `reserved_2: [Entry; 9]`| reserved 39 | | `reserved_2: [Entry; 9]`| reserved 40 | | `reserved_2: [Entry; 9]`| reserved 41 | | `reserved_2: [Entry; 9]`| reserved 42 | | `pub security_exception: Entry`| The Security Exception (`#SX`) signals security-sensitive events that occur while executing the VMM, in the form of an exception so that the VMM may take appropriate action. 43 | | `interrupts: [Entry; 256 - 32]` | interupts 44 | 45 | 46 | #### Entry 的结构 47 | ![IDT_Entry](/docs/riscv_doc/IDT_Entry.png) 48 | 49 | 50 | #### New:Creates a new IDT filled with non-present entries. 51 | ![IDT_Entry_Missing](/docs/riscv_doc/IDT_Entry_Missing.png) 52 | 53 | #### 初始化函数 54 | ``` 55 | pub fn init() { 56 | extern "C" { 57 | 58 | /// 引用汇编程序vector.S(由build.rs生成)中的中断向量表 59 | #[link_name = "__vectors"] 60 | /// 申请一个VECTOR, 由256个C函数指针组成, 函数指针指向vector.S中的中断向量表 61 | static VECTORS: [extern "C" fn(); 256]; 62 | } 63 | 64 | 65 | /// 新建中断描述符表(filled with non-present entries) 66 | let idt = Box::leak(Box::new(InterruptDescriptorTable::new())); 67 | 68 | 69 | /// 申请一个entries,然后从idt中把内容transmute_copy过来, 70 | /// transmute_copy 的说明:pub unsafe fn transmute_copy(src: &T) -> U 71 | /// Interprets src as having type &U, and then reads src without moving the contained value. 72 | 73 | let entries: &'static mut [Entry; 256] = 74 | unsafe { core::mem::transmute_copy(&idt) }; 75 | 76 | /// 将VECTORS中的函数指针写入对应的entries中, 并设置存在位 77 | /// Set the handler address for the IDT entry and sets the present bit. 78 | /// 其中, 中断3, 4与其他的区别在于优先级为最低, 见figure_3和figure_4 79 | for i in 0..256 { 80 | let opt = entries[i].set_handler_fn(unsafe { core::mem::transmute(VECTORS[i]) }); 81 | // Enable user space `int3` and `into` 82 | if i == 3 || i == 4 { 83 | opt.set_privilege_level(PrivilegeLevel::Ring3); 84 | } 85 | } 86 | 87 | /// load idt 88 | idt.load(); 89 | } 90 | ``` 91 | 92 | #### 中断3,4与其他中断 93 | 94 | 中断3,4的entrys的示意图 95 | ![Figure_3](/docs/riscv_doc/IDT_Entry_34.png) 96 | 97 | 其他中断的entrys的示意图 98 | ![Figure_4](/docs/riscv_doc/IDT_Entry_other.png) 99 | 100 | 101 | #### 获取当前IDT寄存器中的数据 102 | 103 | ``` 104 | /// Get current IDT register 105 | #[allow(dead_code)] 106 | #[inline] 107 | 108 | /// function sidt(): Get current IDT register; return: DescriptorTablePointer 109 | fn sidt() -> DescriptorTablePointer { 110 | let mut dtp = DescriptorTablePointer { limit: 0, base: 0 }; 111 | unsafe { 112 | asm!("sidt [{}]", in(reg) &mut dtp); 113 | } 114 | dtp 115 | } 116 | ``` 117 | -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/mod.md: -------------------------------------------------------------------------------- 1 | #### mod.rs 2 | #### **使用的一些macro和包,以后再详细写 3 | ``` 4 | #[cfg(any(target_os = "linux", target_os = "macos"))] 5 | mod fncall; 6 | #[cfg(any(target_os = "none", target_os = "uefi"))] 7 | mod gdt; 8 | #[cfg(any(target_os = "none", target_os = "uefi"))] 9 | mod idt; 10 | #[cfg(feature = "ioport_bitmap")] 11 | #[cfg(any(target_os = "none", target_os = "uefi"))] 12 | pub mod ioport; 13 | #[cfg(any(target_os = "none", target_os = "uefi"))] 14 | mod syscall; 15 | #[cfg(any(target_os = "none", target_os = "uefi"))] 16 | mod trap; 17 | 18 | #[cfg(any(target_os = "linux", target_os = "macos"))] 19 | pub use fncall::syscall_fn_entry; 20 | #[cfg(any(target_os = "none", target_os = "uefi"))] 21 | pub use trap::TrapFrame; 22 | ``` 23 | #### 初始化函数 24 | `pub unsafe fn init()`, 在x86_64架构下初始化中断处理 25 | 26 | 这个函数分为以下步骤: 27 | 1. 关闭x86_64中自带的中断功能 `x86_64::instructions::interrupts::disable();` 28 | 29 | 2. 初始化全局描述符表GDT(在GDT的分析中会详述它的实现) `gdt::init();` 30 | - Switch to a new [GDT], extend 7 more entries from the current one. 31 | - Switch to a new [TSS], set `GSBASE` to its base address. 32 | 33 | 34 | 35 | 3. 初始化中断描述符表IDT(在IDT的分析中会详述它的实现) `idt::init();` 36 | - Switch to a new [IDT], override the current one. 37 | 38 | 39 | 40 | 4. 使能系统调用 41 | - Enable [`syscall`] instruction. 42 | - set `EFER::SYSTEM_CALL_EXTENSIONS` 43 | 44 | [GDT]: https://wiki.osdev.org/GDT 45 | [IDT]: https://wiki.osdev.org/IDT 46 | [TSS]: https://wiki.osdev.org/Task_State_Segment 47 | [`syscall`]: https://www.felixcloutier.com/x86/syscall 48 | 49 | ##### 完整代码如下: 50 | ``` 51 | #[cfg(any(target_os = "none", target_os = "uefi"))] 52 | pub unsafe fn init() { 53 | x86_64::instructions::interrupts::disable(); 54 | gdt::init(); 55 | idt::init(); 56 | syscall::init(); 57 | } 58 | ``` 59 | 60 | #### 定义一个表示用户上下文的结构体 61 | 该结构体包含通用寄存器,陷阱号,错误代码 62 | 63 | ``` 64 | #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] 65 | #[repr(C)] 66 | pub struct UserContext { 67 | pub general: GeneralRegs, 68 | pub trap_num: usize, 69 | pub error_code: usize, 70 | } 71 | ``` 72 | 73 | 为`UserContext`添加一些必要的方法 74 | 75 | `get_syscall_num(&self)`: 从rax中获取系统调用号 76 | 77 | `get_syscall_ret(&self)`: 从rax中获取系统调用返回值 78 | 79 | `set_syscall_ret(&mut self, ret: usize)`: 将系统调用返回值写入rax 80 | 81 | `get_syscall_args(&self)`: 获取系统调用的参数 82 | 83 | `set_ip(&mut self, ip: usize)`: 将指令寄存器的值设置为参数指定的地址 84 | 85 | `set_sp(&mut self, sp: usize)`: 将栈指针寄存器的值设置为参数指定的地址 86 | 87 | `get_sp(&self)`: 获取栈指针 88 | 89 | `set_tls(&mut self, tls: usize)`: 将Thread Local Storage(TLS)写入fsbase 90 | 91 | ``` 92 | impl UserContext { 93 | /// Get number of syscall 94 | pub fn get_syscall_num(&self) -> usize { 95 | self.general.rax 96 | } 97 | 98 | /// Get return value of syscall 99 | pub fn get_syscall_ret(&self) -> usize { 100 | self.general.rax 101 | } 102 | 103 | /// Set return value of syscall 104 | pub fn set_syscall_ret(&mut self, ret: usize) { 105 | self.general.rax = ret; 106 | } 107 | 108 | /// Get syscall args 109 | pub fn get_syscall_args(&self) -> [usize; 6] { 110 | [ 111 | self.general.rdi, 112 | self.general.rsi, 113 | self.general.rdx, 114 | self.general.r10, 115 | self.general.r8, 116 | self.general.r9, 117 | ] 118 | } 119 | 120 | /// Set instruction pointer 121 | pub fn set_ip(&mut self, ip: usize) { 122 | self.general.rip = ip; 123 | } 124 | 125 | /// Set stack pointer 126 | pub fn set_sp(&mut self, sp: usize) { 127 | self.general.rsp = sp; 128 | } 129 | 130 | /// Get stack pointer 131 | pub fn get_sp(&self) -> usize { 132 | self.general.rsp 133 | } 134 | 135 | /// Set tls pointer 136 | pub fn set_tls(&mut self, tls: usize) { 137 | self.general.fsbase = tls; 138 | } 139 | } 140 | ``` 141 | 142 | #### 通用寄存器 143 | 144 | ``` 145 | #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] 146 | #[repr(C)] 147 | pub struct GeneralRegs { 148 | pub rax: usize, 149 | pub rbx: usize, 150 | pub rcx: usize, 151 | pub rdx: usize, 152 | pub rsi: usize, 153 | pub rdi: usize, 154 | pub rbp: usize, 155 | pub rsp: usize, 156 | pub r8: usize, 157 | pub r9: usize, 158 | pub r10: usize, 159 | pub r11: usize, 160 | pub r12: usize, 161 | pub r13: usize, 162 | pub r14: usize, 163 | pub r15: usize, 164 | pub rip: usize, 165 | pub rflags: usize, 166 | pub fsbase: usize, 167 | pub gsbase: usize, 168 | } 169 | ``` 170 | 171 | 寄存器|功能 172 | ---|--- 173 | rax|函数返回值 174 | rbx|用作数据存储,遵循被调用者使用规则 175 | rcx|用作函数参数,第四个参数 176 | rdx|用作函数参数,第三个参数 177 | rsi|用作函数参数,第二个参数 178 | rdi|用作函数参数,第一个参数 179 | rbp|用作数据存储,遵循被调用者使用规则 180 | rsp|栈指针寄存器,指向栈顶 181 | r8|用作函数参数,第五个参数 182 | r9|用作函数参数,第六个参数 183 | r10|用作数据存储,遵循调用者使用规则 184 | r11|用作数据存储,遵循调用者使用规则 185 | r12|用作数据存储,遵循被调用者使用规则 186 | r13|用作数据存储,遵循被调用者使用规则 187 | r14|用作数据存储,遵循被调用者使用规则 188 | r15|用作数据存储,遵循被调用者使用规则 189 | rip|指令寄存器 190 | rflags|64位标志寄存器 191 | [fsbase](https://wiki.osdev.org/SWAPGS)|Their base addresses are used to calculate effective addresses. FS is used for Thread Local Storage. 192 | [gsbase](https://wiki.osdev.org/SWAPGS)|Their base addresses are used to calculate effective addresses. The GS register often holds a base address to a structure containing per-CPU data. 193 | 194 | -------------------------------------------------------------------------------- /drafts/ywj_fncall相关代码分析/相关代码分析.md: -------------------------------------------------------------------------------- 1 | [analysis.md](analysis.md): 对zCore中trapframe的代码的整体分析 2 | 3 | [mod.md](mod.md): 对x86_64下trapframe的实现的整体分析 4 | 5 | [fncall.md](fncall.md): 对实现了上下文切换的fncall.rs的分析 6 | 7 | [gdt.md](gdt.md): 对实现了配置全局描述符表的gdt.rs的分析 8 | 9 | [idt.md](idt.md): 对实现了配置中断描述符表的idt.rs的分析 10 | -------------------------------------------------------------------------------- /drafts/个人材料/vel_schedule/README.md: -------------------------------------------------------------------------------- 1 | # 开题报告 2 | 3 | 经过一些考虑以后,我有了一些想法。 4 | 5 | 我希望的是轻量、快捷的参与方式。 6 | 7 | 目前 zCore-Tutorial 的内容还太少,我认为参与的前期准备工作较多,而且需要深度参与,这与我设想的参与方式不同,我可能没法抽出足够的时间做这件事情。 8 | 9 | 但是研究 zCore 的代码,写一些分析内容;添加注释文档和单元测试。这两项是比较轻量级的参与方式。这也是 zCore 文档与单元测试小组最开始的项目规划。 10 | 11 | 故目前的计划如下: 12 | 13 | - (20h)研究 zCore 中部分我感兴趣的代码,在增加我对 zCore 的理解的基础上,形成一些研究报告 14 | - 如果有可能的话,做一些轻量的改进,比如在zCore中添加zircon/linux的syscall 15 | - (20h)撰写注释文档,在没有足够说明的 zCore 代码段补充说明 16 | - (10h)单元测试,在测试不足的 zCore 代码段补充测试 17 | - (5h)对 zCore-Tutorial 独立性较强的章节做一些跟踪,提供轻量的PR 18 | - (15h)其它可能的参与方式 19 | - MaixPy / K210 相关的一些实验 20 | -------------------------------------------------------------------------------- /drafts/个人材料/张文龙_Summery/个人计划.md: -------------------------------------------------------------------------------- 1 | [文档仓库连接](https://github.com/rcore-os/zcore_tutorial_developers/tree/master/ch04-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F) 2 | 3 | ![file](http://www.nuanyun.cloud/wp-content/uploads/2020/08/5f2cadd2b5664.png) 4 | 5 | [DailySchedule](https://github.com/iLFTH/DailySchedule) 6 | 7 | [blogs](http://www.nuanyun.cloud) 8 | 9 | ### 第一阶段 10 | 11 | #### 小组成员 12 | 小组成员:荣悦同、卢睿博、张驰斌、张文龙、彭晓、方澳阳、姚宇飞 13 | 细分:合作者为张文龙,彭晓 14 | 15 | #### 目标实现 16 | 在理解zCore现有源程序各个模块源代码的基础上,编写解释zCore的说明书。 17 | 18 | #### 任务分工 19 | 20 | - [内核对象](ch01-00-object.md) 21 | - [任务管理](ch02-00-task.md) 22 | - [内存管理](ch03-00-memory.md) 23 | - [用户程序](ch04-00-userspace.md) 24 | - [Zircon 用户程序](ch04-01-user-program.md) 25 | - [zCore加载 ELF 文件的流程与方式(已经写了一部分)](ch04-02-load-elf.md) 26 | - [上下文切换](ch04-03-context-switch.md) 27 | - [系统调用](ch04-04-syscall.md) 28 | 29 | ![file](http://www.nuanyun.cloud/wp-content/uploads/2020/08/5f2caadd73ef5.png) 30 | 31 | ![file](http://www.nuanyun.cloud/wp-content/uploads/2020/08/5f2caa652bada.png) 32 | #### 个人负责的部分: 33 | + 用户程序ELF文件的加载流程说明(可能需要结合任务管理) 34 | + zricon_syscall系统调用的说明 35 | + 第一步 代码内注释文档编写。(预计) 36 | + 第二步 外部文档编写。 37 | + 第三步 用户态和内核态之间使用系统调用的流程。 38 | + 第四步 编写syscall的测试用例代码 39 | + 第五步 绘制syscall CallGraph 40 | 41 | > 方法一:![file](http://www.nuanyun.cloud/wp-content/uploads/2020/08/5f2cb9f437e8e.png) 42 | > 方法二:![file](http://www.nuanyun.cloud/wp-content/uploads/2020/08/5f2cba58455b6.png) 43 | 44 | ```rust 45 | sys_bti_create 46 | sys_bti_pin 47 | sys_bti_release_quarantine 48 | sys_channel_call_finish 49 | sys_channel_call_noretry 50 | sys_channel_create 51 | sys_channel_read 52 | sys_channel_write 53 | sys_channel_write_etc 54 | sys_clock_adjust 55 | sys_clock_create 56 | sys_clock_get 57 | sys_clock_read 58 | sys_clock_update 59 | sys_cprng_draw_once 60 | sys_create_exception_channel 61 | sys_debug_read 62 | sys_debug_write 63 | sys_debuglog_create 64 | sys_debuglog_read 65 | sys_debuglog_write 66 | sys_event_create 67 | sys_eventpair_create 68 | sys_exception_get_process 69 | sys_exception_get_thread 70 | sys_fifo_create 71 | sys_fifo_read 72 | sys_fifo_write 73 | sys_futex_requeue 74 | sys_futex_wait 75 | sys_futex_wake 76 | sys_futex_wake_single_owner 77 | sys_handle_close 78 | sys_handle_close_many 79 | sys_handle_duplicate 80 | sys_handle_replace 81 | sys_interrupt_ack 82 | sys_interrupt_bind 83 | sys_interrupt_create 84 | sys_interrupt_destroy 85 | sys_interrupt_trigger 86 | sys_interrupt_wait 87 | sys_iommu_create 88 | sys_job_create 89 | sys_job_set_critical 90 | sys_job_set_policy 91 | sys_nanosleep 92 | sys_object_get_child 93 | sys_object_get_info 94 | sys_object_get_property 95 | sys_object_set_property 96 | sys_object_signal 97 | sys_object_signal_peer 98 | sys_object_wait_async 99 | sys_object_wait_many 100 | sys_object_wait_one 101 | sys_pc_firmware_tables 102 | sys_pci_add_subtract_io_range 103 | sys_pci_cfg_pio_rw 104 | sys_pci_config_read 105 | sys_pci_config_write 106 | sys_pci_enable_bus_master 107 | sys_pci_get_bar 108 | sys_pci_get_nth_device 109 | sys_pci_init 110 | sys_pci_map_interrupt 111 | sys_pci_query_irq_mode 112 | sys_pci_set_irq_mode 113 | sys_pmt_unpin 114 | sys_port_create 115 | sys_port_queue 116 | sys_port_wait 117 | sys_process_create 118 | sys_process_exit 119 | sys_process_read_memory 120 | sys_process_start 121 | sys_process_write_memory 122 | sys_resource_create 123 | sys_socket_create 124 | sys_socket_read 125 | sys_socket_shutdown 126 | sys_socket_write 127 | sys_stream_create 128 | sys_stream_readv 129 | sys_stream_readv_at 130 | sys_stream_seek 131 | sys_stream_writev 132 | sys_stream_writev_at 133 | sys_system_get_event 134 | sys_task_kill 135 | sys_task_suspend_token 136 | sys_thread_create 137 | sys_thread_exit 138 | sys_thread_start 139 | sys_thread_write_state 140 | sys_timer_cancel 141 | sys_timer_create 142 | sys_timer_set 143 | sys_vmar_allocate 144 | sys_vmar_destroy 145 | sys_vmar_map 146 | sys_vmar_protect 147 | sys_vmar_unmap 148 | sys_vmo_cache_policy 149 | sys_vmo_create 150 | sys_vmo_create_child 151 | sys_vmo_create_contiguous 152 | sys_vmo_create_physical 153 | sys_vmo_get_size 154 | sys_vmo_op_range 155 | sys_vmo_read 156 | sys_vmo_replace_as_executable 157 | sys_vmo_set_size 158 | sys_vmo_write 159 | syscall 160 | ``` 161 | [fuchsia链接](fuchsiahttps://fuchsia.dev/fuchsia-src/reference/syscalls/fifo_create) -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/README.md: -------------------------------------------------------------------------------- 1 | [日志链接](https://www.notion.so/lincyawer/zcore-c95eb5df171f492282ad27da793b6fc6) 2 | 3 | -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191621668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191621668.png -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191631795.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191631795.png -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191633231.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191633231.png -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191732170.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/个人材料/方澳阳相关材料/目标规划.assets/image-20200806191732170.png -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/目标规划.md: -------------------------------------------------------------------------------- 1 | # 情况分析 2 | 3 | - 尚未学习操作系系统 4 | - 基础相对于其他参与者相对薄弱 5 | - 学校还有大作业尚未完成、开学有五门课考试 6 | 7 | 因此选择编写文档和单元测试这个任务,除了完成任务之外也可以使自己对操作系统有更加整体性的了解。 8 | 9 | 10 | 11 | # 目标定位 12 | 13 | 讨论之后定了两个阶段的目标,第一阶段为对代码进行描述分析并且添加相对应的单元测试;第二阶段为撰写相对应的zCore Tutorial, 在第一阶段的基础上进行整合,形成一个语言流畅、组织结构清晰的文档。 14 | 15 | ## 第一阶段 16 | 17 | 目前暂定为与荣悦同同学合作完成任务管理模块的内容。 18 | 19 | 1. Zircon 任务管理体系 20 | 21 | 2. 硬件抽象层与异步运行时 22 | 23 | 3. 线程管理:Thread 对象 24 | 25 | 4. 进程管理:Process 与 Job 对象 26 | 27 | 预计两周左右完成。 28 | 29 | 30 | 31 | ## 第二阶段 32 | 33 | 尚未进行讨论。 34 | 35 | > 由于需要准备考试\抽出复习时间, 考试结束之后还要参加数学建模比赛, 因此第二阶段可能会减少参与的时间。 36 | 37 | 目前个人目标为: 38 | 39 | 为自己负责的部分撰写文档,保证语言流畅;多使用结构框图使读者能有更直观的理解。 40 | 41 | 如果提前完成了任务, 就协助其他成员完成其他的任务。 42 | 43 | ![image-20200806191631795](目标规划.assets/image-20200806191631795.png) 44 | 45 | 以上是在rcore中我对这部分的一些归纳, 但是可读性还不是很好。预计后期使用如下的网络结构图,对用到的一些对象之间的关系进行描述。 46 | 47 | ![image-20200806191732170](目标规划.assets/image-20200806191732170.png) 48 | 49 | ## 总结 50 | 51 | 接下来的三周一定完成任务管理模块的代码分析及单元测试,尽量完成文档编写。 -------------------------------------------------------------------------------- /drafts/个人材料/方澳阳相关材料/目标规划.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/drafts/个人材料/方澳阳相关材料/目标规划.pdf -------------------------------------------------------------------------------- /drafts/个人材料/荣悦同_schedule/目标.md: -------------------------------------------------------------------------------- 1 | # 小组概况 2 | ## 小组成员 3 | 4 | 我们`zCore 的文档与单元测试完善`小组一共有7个成员:卢睿博、张文龙、彭晓、方澳阳、姚宇飞、荣悦同、应雯婧。 5 | 6 | 因为拥有最多的成员,所以进行合理的分工合作之后,大家积极讨论,互相协调,一个月之内完成小组的目标是非常有希望的 7 | 8 | ## 任务分工 9 | 10 | 目前zCore-Tutorial文档目录还没有更新完全,还没有完成最终的分工,暂时按照`Readme.md`来分工 11 | 12 | # 目标规划 13 | ## 第一阶段 14 | 15 | ### 小组目标 16 | 17 | 我们计划按照zCore-Tutorial文档提供的目录,一至两个人负责一个模块,以初学者写学习笔记的形式,完成这个模块对应的代码内嵌注释、知识点分析以及单元测试,目标是在理解的基础上清楚的说明知识点以及代码的调用关系,不需要简明概要。其中涉及的相关链接均共享在仓库里。同时,大家完成自己的模块之后,也可机动的阅读其他模块的文档,互相协助,进行适当的修改和补充 18 | 19 | ### 个人目标 20 | 21 | 22 | 目前暂定为与方澳阳同学合作完成`第二章 任务管理模块`的内容 23 | 24 | * Zircon 任务管理体系 25 | 26 | * 硬件抽象层与异步运行时 27 | 28 | * 线程管理:Thread 对象 29 | 30 | * 进程管理:Process 与 Job 对象 31 | 32 | 自身的情况是8月中旬有雅思考试要参加,并且8月末开学有四门考试,而且之前没有操作系统的基础,但是就像向老师说的一样,希望我可以在这次活动中有所收获并且有所贡献,月末一定会完成个人目标,以后也希望一直继续第二阶段的学习,在这个社区中和大家一起进步 33 | 34 | ## 第二阶段 35 | 36 | 还没有具体讨论,初步规划是继续完善zCore-Tutorial文档,争取能够像rCore-Tutorial文档一样,一步一步搭建起来zCore操作系统 37 | 38 | # 可能出现的问题 39 | 40 | * 大家的写作风格可能不一样,所以需要互相协调适应的部分比较多 41 | * 大家基本都有各自的考试和其他安排,所以花在zCore文档的时间可能不能像rCore第一阶段那么集中 -------------------------------------------------------------------------------- /helps/graph_analysis/call_graph_analyzer.md: -------------------------------------------------------------------------------- 1 | ### Clone zCore repo and pull prebuilt fuchsia images: 2 | ```sh 3 | $ git clone https://github.com/rcore-os/zCore --recursive 4 | $ cd zCore 5 | $ git lfs install 6 | $ git lfs pull 7 | ``` 8 | 9 | ### Run native Zircon program (shell): 10 | 原来的命令: 11 | ```sh 12 | cargo run --release -p zircon-loader prebuilt/zircon/x64 13 | ``` 14 | 现改为获得zircon-loader的LLVM-BitCode: 15 | 1. cargo 中不能直接添加 `--emit=llvm-bc` 或者是 `--emit=llvm-bc`这些参数以获得中间代码,这些额外的参数只能写到rustc命令行中 16 | 2. 因此需要获得cargo build获得最终可执行的binary:`zircon-loader`的时候的rustc 编译命令行 17 | 在cargo build 中添加 `-v` 参数便可实现 18 | ```shell 19 | $ cargo build --release -p zircon-loader -v 20 | ``` 21 | ![get_rustc_cmd](img/get_rustc_cmd.png) 22 | 23 | 3. 此时需要在rustc之后的`--emit=...`参数后追加 `llvm-bc` 或者 `llvm-ir` 24 | 4. 将上述修改后的rustc命令行在zCore目录下再次运行 25 | ```shell 26 | rustc --crate-name zircon_loader --edition=2018 zircon-loader/src/main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link,llvm-bc -C opt-level=3 -Cembed-bitcode=no --cfg 'feature="async-std"' --cfg 'feature="default"' --cfg 'feature="env_logger"' --cfg 'feature="kernel-hal-unix"' --cfg 'feature="std"' --cfg 'feature="structopt"' -C metadata=aee642b49f6df21b -C extra-filename=-aee642b49f6df21b --out-dir /home/nn/Desktop/zCore/target/release/deps -L dependency=/home/nn/Desktop/zCore/target/release/deps --extern async_std=/home/nn/Desktop/zCore/target/release/deps/libasync_std-3c0dda0c91fe99dc.rlib --extern env_logger=/home/nn/Desktop/zCore/target/release/deps/libenv_logger-a790b75524515725.rlib --extern kernel_hal=/home/nn/Desktop/zCore/target/release/deps/libkernel_hal-64775f87caa2e8c7.rlib --extern kernel_hal_unix=/home/nn/Desktop/zCore/target/release/deps/libkernel_hal_unix-69b4a18bfd96b58d.rlib --extern log=/home/nn/Desktop/zCore/target/release/deps/liblog-ef290d9b77e4b7bf.rlib --extern structopt=/home/nn/Desktop/zCore/target/release/deps/libstructopt-3e62455b61808e1e.rlib --extern xmas_elf=/home/nn/Desktop/zCore/target/release/deps/libxmas_elf-8ef2cfef9353faa8.rlib --extern zircon_loader=/home/nn/Desktop/zCore/target/release/deps/libzircon_loader-9f26292b12bedbd9.rlib --extern zircon_object=/home/nn/Desktop/zCore/target/release/deps/libzircon_object-2e7ef58f71e848aa.rlib --extern zircon_syscall=/home/nn/Desktop/zCore/target/release/deps/libzircon_syscall-61a916517403fb29.rlib 27 | ``` 28 | 29 | 5. 此时可以在 `zCore/target/release/deps`目录下获得如下bc code:`zircon_loader-aee642b49f6df21b.bc` 30 | 31 | ![get_the_bitcode](img/get_the_bitcode.png) 32 | 33 | 6. 下一步运行llvm的opt程序: 34 | ```sh 35 | $ llvm9/build/bin/opt -dot-callgraph zircon_loader-aee642b49f6df21b.bc 36 | ``` 37 | 此时会获得一个callgraph.dot的文件 38 | 39 | > 必须使用最新的llvm 9+ 版本的opt程序,不然opt程序无法分析rust-llvm 10+生成的bitcode 40 | > 从llvm 的source code编译的过程为: 41 | 42 | (以编写如下shell脚本(配合ninja),方便一键部署) 43 | 44 | ```shell 45 | #!/bin/bash 46 | #cd COMPILER_DIR 47 | #./project_init_scripts/init_llvm9.sh 48 | set e, x 49 | COMPILER_DIR=$(readlink -f `dirname $0`/..) 50 | PROJECT_ROOT_DIR=`dirname ${COMPILER_DIR}` 51 | THIS_DIR=`dirname \`readlink -f $0\`` 52 | LLVM9_DIR=${PROJECT_ROOT_DIR}/llvm9/ 53 | SYM_LINK='ln -sfn' 54 | ################################# SETUP LLVM9/CLANG9 ################################# 55 | ######################################-project llvm########################################## 56 | if [ ! -e ${LLVM9_DIR} ] 57 | then 58 | cd ${PROJECT_ROOT_DIR} 59 | git clone https://gitee.com/ilfth/llvm-project 60 | mv llvm-project llvm9 61 | bash ${PROJECT_ROOT_DIR}/compiler/analysis/def_use/setup_symlinks.sh 62 | cd llvm9 63 | mkdir build 64 | cd build 65 | cmake ../llvm \ 66 | -GNinja \ 67 | -DLLVM_BINUTILS_INCDIR=${PROJECT_ROOT_DIR}/gcc/gcc-arm-none-eabi-6-2017-q1-update/src/binutils/include \ 68 | -DLLVM_ENABLE_PROJECTS="clang;compiler-rt;lld" \ 69 | -DCMAKE_BUILD_TYPE=Debug \ 70 | -DCMAKE_C_COMPILER=clang \ 71 | -DCMAKE_CXX_COMPILER=clang++ \ 72 | -DLLVM_ENABLE_ASSERTIONS=ON \ 73 | -DLLVM_BUILD_TESTS=OFF \ 74 | -DLLVM_BUILD_EXAMPLES=OFF \ 75 | -DLLVM_INCLUDE_TESTS=OFF \ 76 | -DLLVM_INCLUDE_EXAMPLES=OFF \ 77 | -DLLVM_TARGETS_TO_BUILD="X86;ARM" \ 78 | -DBUILD_SHARED_LIBS=ON \ 79 | -DLLVM_BINUTILS_INCDIR=/usr/include \ 80 | -DCMAKE_INSTALL_PREFIX=../bin \ 81 | -DCMAKE_C_FLAGS=-fstandalone-debug \ 82 | -DCMAKE_CXX_FLAGS=-fstandalone-debug 83 | ninja 84 | fi 85 | ################################################################################ 86 | 87 | ``` 88 | 89 | 7. 这个callgraph.dot文件包含了图中所有的结点和边的信息,可以利用`dot`命令将它转变为可视化的png/pdf/svg...等格式的图片,方便阅读。 90 | 如: 91 | ```sh 92 | $ dot -Tsvg callgraph.dot -o callgraph.svg 93 | ``` 94 | 8. 在运行获得对应名称的svg图后,可以用常规的浏览器打开阅读: 95 | ![zCore-Syscall-部分](img/zircon_loader-callgraph-part.png) 96 | > 此时我们可以从图中分析得出zircon-loader中的每一个结点之间的相互调用关系。 97 | -------------------------------------------------------------------------------- /helps/graph_analysis/control_flow_graph_analyzer.md: -------------------------------------------------------------------------------- 1 | ### 这是分析zircon-loader时的到的一张示例control_flow_graph: 2 | 3 | ![control_flow_graph.png](../graph_analysis/img/control_flow_graph.png) 4 | 5 | ### 什么是CFG(control flow graph) 6 | 一个CFG是表示一个方法内的程序执行流的图,图中的节点是语句(指令),边表示执行流。例如语句A执行后的下一条语句是B,则CFG中应有一条从A到B的有向边。条件语句(if-else, while-do)之后可能执行的语句不止一个,可能执行true-branch或false-branch,所以CFG上条件语句节点的后缀会有多个,表示其后可能执行的不同branches。 7 | 8 | ### 获得CFG的方式 9 | 可以套用 10 | [call_graph_analyzer.md](call_graph_analyzer.md) 11 | 12 | 第6部以后的操作. 13 | 只需把`-dot-callgraph `更改为`-dot-cfg`即可 14 | ```sh 15 | $ llvm9/build/bin/opt -dot-callgraph zircon_loader-aee642b49f6df21b.bc 16 | ``` 17 | 18 | > 注意此时生成的所有dot图搜是隐藏的 19 | > 20 | > 我们可以单独分析每一个函数结点内部的程序流; 21 | -------------------------------------------------------------------------------- /helps/graph_analysis/img/control_flow_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/helps/graph_analysis/img/control_flow_graph.png -------------------------------------------------------------------------------- /helps/graph_analysis/img/get_rustc_cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/helps/graph_analysis/img/get_rustc_cmd.png -------------------------------------------------------------------------------- /helps/graph_analysis/img/get_the_bitcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/helps/graph_analysis/img/get_the_bitcode.png -------------------------------------------------------------------------------- /helps/graph_analysis/img/zircon_loader-callgraph-part.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/helps/graph_analysis/img/zircon_loader-callgraph-part.png -------------------------------------------------------------------------------- /img/Fuchsia 操作系统的四层结构设计.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/img/Fuchsia 操作系统的四层结构设计.png -------------------------------------------------------------------------------- /img/Google-Fuschia-Operating-System-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/img/Google-Fuschia-Operating-System-logo.jpg -------------------------------------------------------------------------------- /img/ch01-01-kernel-object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/img/ch01-01-kernel-object.png -------------------------------------------------------------------------------- /img/image-20200805123801306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/img/image-20200805123801306.png -------------------------------------------------------------------------------- /img/kobject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/img/kobject.png -------------------------------------------------------------------------------- /img/structure.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
kernel-hal
kernel-hal
zircon-object
zircon-object
linux-object
linux-object
zircon-syscall
zircon-syscall
linux-syscall
linux-syscall
kernel-hal-bare
kernel-hal-bare
kernel-hal-unix
kernel-hal-unix
zircon-loader
zircon-loader
zCore
zCore
rCore
rCore
Zircon LibOS
Zircon LibOS
Linux LibOS
Linux LibOS
linux-loader
linux-loader
ELF Program Loader
ELF Program Loader
Syscall Implementation
Syscall Implementation
Kernel Objects
Kernel Objects
Hardware Abstraction Layer
Hardware Abstraction Layer
HAL Implementation
HAL Implementation
Bare Metal
Bare Metal
Linux / macOS
Linux / macOS
-------------------------------------------------------------------------------- /src/01-code/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "downcast-rs" 5 | version = "1.2.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" 8 | 9 | [[package]] 10 | name = "spin" 11 | version = "0.5.2" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 14 | 15 | [[package]] 16 | name = "zcore_test" 17 | version = "0.1.0" 18 | dependencies = [ 19 | "downcast-rs", 20 | "spin", 21 | ] 22 | -------------------------------------------------------------------------------- /src/01-code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zcore_test" 3 | version = "0.1.0" 4 | authors = ["lincyaw"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | spin = "0.5" 11 | downcast-rs = { version = "1.2.0", default-features = false} -------------------------------------------------------------------------------- /src/01-code/rust-tooltrain: -------------------------------------------------------------------------------- 1 | nightly-2020-06-04 2 | -------------------------------------------------------------------------------- /src/01-code/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | extern crate alloc; 3 | 4 | pub mod object; 5 | // #[cfg(test)] 6 | // mod tests { 7 | // #[test] 8 | // fn dummy_object() { 9 | 10 | // } 11 | // } 12 | -------------------------------------------------------------------------------- /src/01-code/src/object/dummy_object.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use spin::Mutex; 3 | /// 空对象 4 | #[derive(Debug)] 5 | pub struct DummyObject { 6 | pub id: KoID, 7 | pub inner: Mutex, 8 | } 9 | 10 | /// DummyObject 的内部可变部分 11 | /// 采用一种内部可变性的设计模式: 12 | /// 将对象的所有可变的部分封装到一个内部对象DummyObjectInner中, 13 | /// 并在原对象中用自旋锁Mutex把它包起来, 14 | /// 因此此结构自动具有了Send+Sync的特性. 15 | #[derive(Default, Debug)] 16 | pub struct DummyObjectInner { 17 | pub name: String, 18 | } 19 | -------------------------------------------------------------------------------- /src/01-code/src/object/mod.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::String; 2 | use alloc::sync::Arc; 3 | use core::fmt::Debug; 4 | use core::sync::atomic::*; 5 | use downcast_rs::{impl_downcast, DowncastSync}; 6 | use spin::*; 7 | pub mod dummy_object; 8 | pub mod object; 9 | /// 内核对象公共接口 10 | /// 这里的 Send + Sync 是一个约束所有内核对象都要满足的前提条件, 即它必须是一个并发对象,可以安全地被多线程访问 11 | 12 | pub trait KernelObject: DowncastSync + Debug { 13 | /// 获取对象ID 14 | fn id(&self) -> KoID; 15 | /// 获取对象类型名 16 | fn type_name(&self) -> &str; 17 | /// 获取对象名称 18 | fn name(&self) -> String; 19 | /// 设置对象名称 20 | fn set_name(&self, name: &str); 21 | } 22 | impl_downcast!(sync KernelObject); 23 | /// 内核对象核心结构 24 | pub struct KObjectBase { 25 | /// 对象ID 26 | pub id: KoID, 27 | inner: Mutex, 28 | } 29 | 30 | /// KObjectBase 的内部可变部分 31 | #[derive(Default)] 32 | pub struct KObjectBaseInner { 33 | name: String, 34 | } 35 | 36 | impl Default for KObjectBase { 37 | fn default() -> Self { 38 | KObjectBase { 39 | id: Self::new_koid(), 40 | inner: Default::default(), 41 | } 42 | } 43 | } 44 | 45 | impl KObjectBase { 46 | fn new_koid() -> KoID { 47 | static NEXT_KOID: AtomicU64 = AtomicU64::new(1024); 48 | NEXT_KOID.fetch_add(1, Ordering::SeqCst) 49 | } 50 | pub fn name(&self) -> String { 51 | self.inner.lock().name.clone() 52 | } 53 | pub fn set_name(&self, name: &str) { 54 | self.inner.lock().name = String::from(name); 55 | } 56 | } 57 | /// 对象ID 类型 58 | pub type KoID = u64; 59 | 60 | #[macro_export] 61 | macro_rules! impl_kobject { 62 | ($class:ident $( $fn:tt)*) => { 63 | impl KernelObject for $class { 64 | fn id(&self) -> KoID { 65 | self.base.id 66 | } 67 | fn type_name(&self) -> &str { 68 | stringify!($class) 69 | } 70 | fn name(&self) -> alloc::string::String { 71 | self.base.name() 72 | } 73 | fn set_name(&self, name: &str){ 74 | self.base.set_name(name) 75 | } 76 | $( $fn)* 77 | } 78 | impl core::fmt::Debug for $class { 79 | fn fmt(&self, 80 | f: &mut core::fmt::Formatter<'_> 81 | ) -> core::result::Result<(), core::fmt::Error> { 82 | f.debug_tuple(&stringify!($class)) 83 | .field(&self.id()) 84 | .field(&self.name()) 85 | .finish() 86 | } 87 | } 88 | }; 89 | } 90 | 91 | pub struct DummyObjectPlus { 92 | base: KObjectBase, 93 | } 94 | 95 | impl_kobject!(DummyObjectPlus); 96 | 97 | impl DummyObjectPlus { 98 | pub fn new() -> Arc { 99 | Arc::new(DummyObjectPlus { 100 | base: KObjectBase::default(), 101 | }) 102 | } 103 | } 104 | #[test] 105 | fn downcast() { 106 | let dummy = dummy_object::DummyObject::new(); 107 | let object: Arc = dummy; 108 | let _result: Arc = 109 | object.downcast_arc::().unwrap(); 110 | } 111 | #[test] 112 | fn impl_kobject() { 113 | use alloc::format; 114 | let dummy = DummyObjectPlus::new(); 115 | let object: Arc = dummy; 116 | assert_eq!(object.type_name(), "DummyObjectPlus"); 117 | assert_eq!(object.name(), ""); 118 | object.set_name("dummy"); 119 | assert_eq!(object.name(), "dummy"); 120 | assert_eq!( 121 | format!("{:?}", object), 122 | format!("DummyObjectPlus({}, \"dummy\")", object.id()) 123 | ); 124 | let _result = object.downcast_arc::().unwrap(); 125 | } 126 | -------------------------------------------------------------------------------- /src/01-code/src/object/object.rs: -------------------------------------------------------------------------------- 1 | use super::dummy_object::DummyObject; 2 | use super::*; 3 | use alloc::sync::Arc; 4 | impl DummyObject { 5 | /// 创建一个新 DummyObject 6 | pub fn new() -> Arc { 7 | Arc::new(DummyObject { 8 | id: Self::new_koid(), 9 | inner: Default::default(), 10 | }) 11 | } 12 | 13 | /// 生成一个唯一的ID 14 | /// 每个内核对象都有唯一的ID, 因此需要实现一个全局的ID分配方法。 15 | /// 这里用一个静态变量存放下一个待分配ID值,每次分配就原子地+1。 16 | /// 在Zircon中ID从1024开始分配,1024以下保留作内核内部使用 17 | /// !!! 注意: 18 | /// 这里new函数返回类型是Arc 19 | fn new_koid() -> KoID { 20 | static NEXT_KOID: AtomicU64 = AtomicU64::new(1024); 21 | NEXT_KOID.fetch_add(1, Ordering::SeqCst) 22 | } 23 | } 24 | 25 | impl KernelObject for DummyObject { 26 | fn id(&self) -> KoID { 27 | self.id 28 | } 29 | fn type_name(&self) -> &str { 30 | "DummyObject" 31 | } 32 | fn name(&self) -> String { 33 | self.inner.lock().name.clone() 34 | } 35 | fn set_name(&self, name: &str) { 36 | self.inner.lock().name = String::from(name); 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::*; 43 | #[test] 44 | fn dummy_object() { 45 | let o1 = DummyObject::new(); 46 | let o2 = DummyObject::new(); 47 | assert_ne!(o1.id(), o2.id()); 48 | assert_eq!(o1.type_name(), "DummyObject"); 49 | assert_eq!(o1.name(), ""); 50 | o1.set_name("object1"); 51 | assert_eq!(o1.name(), "object1"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/01-code/target/rls/.rustc_info.json: -------------------------------------------------------------------------------- 1 | {"rustc_fingerprint":6411741761803963328,"outputs":{"1164083562126845933":["rustc 1.45.0 (5c1f21c3b 2020-07-13)\nbinary: rustc\ncommit-hash: 5c1f21c3b82297671ad3ae1e8c942d2ca92e84f2\ncommit-date: 2020-07-13\nhost: x86_64-unknown-linux-gnu\nrelease: 1.45.0\nLLVM version: 10.0\n",""],"4476964694761187371":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/lincyaw/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n",""],"16929990295604814582":["___\n",""]},"successes":{}} -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.cargo-lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/.cargo-lock -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/downcast-rs-904ea28aba046704/dep-lib-downcast-rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/.fingerprint/downcast-rs-904ea28aba046704/dep-lib-downcast-rs -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/downcast-rs-904ea28aba046704/invoked.timestamp: -------------------------------------------------------------------------------- 1 | This file has an mtime of when this was started. -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/downcast-rs-904ea28aba046704/lib-downcast-rs: -------------------------------------------------------------------------------- 1 | 89c6bd13a2487171 -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/downcast-rs-904ea28aba046704/lib-downcast-rs.json: -------------------------------------------------------------------------------- 1 | {"rustc":6030236523401801000,"features":"[]","target":14366446078388928085,"profile":12939370821261546320,"path":18199512961261620883,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/downcast-rs-904ea28aba046704/dep-lib-downcast-rs"}}],"rustflags":[],"metadata":14063588153147126258} -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/spin-acbc4f71625ea3b6/dep-lib-spin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/.fingerprint/spin-acbc4f71625ea3b6/dep-lib-spin -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/spin-acbc4f71625ea3b6/invoked.timestamp: -------------------------------------------------------------------------------- 1 | This file has an mtime of when this was started. -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/spin-acbc4f71625ea3b6/lib-spin: -------------------------------------------------------------------------------- 1 | 775afa8b95a6199c -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/spin-acbc4f71625ea3b6/lib-spin.json: -------------------------------------------------------------------------------- 1 | {"rustc":6030236523401801000,"features":"[]","target":8524337025134985022,"profile":12939370821261546320,"path":18423052116175064823,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/spin-acbc4f71625ea3b6/dep-lib-spin"}}],"rustflags":[],"metadata":6620005600999123125} -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-03d1a7f8dd3fa848/dep-lib-zcore_test: -------------------------------------------------------------------------------- 1 | src/lib.rssrc/object/mod.rssrc/object/dummy_object.rssrc/object/object.rs -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-03d1a7f8dd3fa848/invoked.timestamp: -------------------------------------------------------------------------------- 1 | This file has an mtime of when this was started. -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-03d1a7f8dd3fa848/lib-zcore_test: -------------------------------------------------------------------------------- 1 | b2845d276276a9cc -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-03d1a7f8dd3fa848/lib-zcore_test.json: -------------------------------------------------------------------------------- 1 | {"rustc":6030236523401801000,"features":"[]","target":6436189457279205100,"profile":2491824153796502264,"path":10872709659218687626,"deps":[[6258141844440947002,"downcast_rs",false,8174394659607266953],[9909677338687340172,"spin",false,11248204705563302519]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/zcore_test-03d1a7f8dd3fa848/dep-lib-zcore_test"}}],"rustflags":[],"metadata":4665445967946249244} -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-901b0ddc1b9bab15/dep-test-lib-zcore_test: -------------------------------------------------------------------------------- 1 | src/lib.rssrc/object/mod.rssrc/object/dummy_object.rssrc/object/object.rs -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-901b0ddc1b9bab15/invoked.timestamp: -------------------------------------------------------------------------------- 1 | This file has an mtime of when this was started. -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-901b0ddc1b9bab15/test-lib-zcore_test: -------------------------------------------------------------------------------- 1 | 5fdac689ab491970 -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/.fingerprint/zcore_test-901b0ddc1b9bab15/test-lib-zcore_test.json: -------------------------------------------------------------------------------- 1 | {"rustc":6030236523401801000,"features":"[]","target":6436189457279205100,"profile":5813434296824078385,"path":10872709659218687626,"deps":[[6258141844440947002,"downcast_rs",false,8174394659607266953],[9909677338687340172,"spin",false,11248204705563302519]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/zcore_test-901b0ddc1b9bab15/dep-test-lib-zcore_test"}}],"rustflags":[],"metadata":4665445967946249244} -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/downcast_rs-904ea28aba046704.d: -------------------------------------------------------------------------------- 1 | /home/lincyaw/zcore_test/target/rls/debug/deps/downcast_rs-904ea28aba046704.rmeta: /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/downcast-rs-1.2.0/src/lib.rs 2 | 3 | /home/lincyaw/zcore_test/target/rls/debug/deps/downcast_rs-904ea28aba046704.d: /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/downcast-rs-1.2.0/src/lib.rs 4 | 5 | /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/downcast-rs-1.2.0/src/lib.rs: 6 | -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/libdowncast_rs-904ea28aba046704.rmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/deps/libdowncast_rs-904ea28aba046704.rmeta -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/libspin-acbc4f71625ea3b6.rmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/deps/libspin-acbc4f71625ea3b6.rmeta -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/libzcore_test-03d1a7f8dd3fa848.rmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/deps/libzcore_test-03d1a7f8dd3fa848.rmeta -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/libzcore_test-901b0ddc1b9bab15.rmeta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/deps/libzcore_test-901b0ddc1b9bab15.rmeta -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/spin-acbc4f71625ea3b6.d: -------------------------------------------------------------------------------- 1 | /home/lincyaw/zcore_test/target/rls/debug/deps/spin-acbc4f71625ea3b6.rmeta: /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/lib.rs /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/mutex.rs /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/rw_lock.rs /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/once.rs 2 | 3 | /home/lincyaw/zcore_test/target/rls/debug/deps/spin-acbc4f71625ea3b6.d: /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/lib.rs /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/mutex.rs /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/rw_lock.rs /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/once.rs 4 | 5 | /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/lib.rs: 6 | /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/mutex.rs: 7 | /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/rw_lock.rs: 8 | /home/lincyaw/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/spin-0.5.2/src/once.rs: 9 | -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/zcore_test-03d1a7f8dd3fa848.d: -------------------------------------------------------------------------------- 1 | /home/lincyaw/zcore_test/target/rls/debug/deps/zcore_test-03d1a7f8dd3fa848.rmeta: src/lib.rs src/object/mod.rs src/object/dummy_object.rs src/object/object.rs 2 | 3 | /home/lincyaw/zcore_test/target/rls/debug/deps/zcore_test-03d1a7f8dd3fa848.d: src/lib.rs src/object/mod.rs src/object/dummy_object.rs src/object/object.rs 4 | 5 | src/lib.rs: 6 | src/object/mod.rs: 7 | src/object/dummy_object.rs: 8 | src/object/object.rs: 9 | -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/deps/zcore_test-901b0ddc1b9bab15.d: -------------------------------------------------------------------------------- 1 | /home/lincyaw/zcore_test/target/rls/debug/deps/zcore_test-901b0ddc1b9bab15.rmeta: src/lib.rs src/object/mod.rs src/object/dummy_object.rs src/object/object.rs 2 | 3 | /home/lincyaw/zcore_test/target/rls/debug/deps/zcore_test-901b0ddc1b9bab15.d: src/lib.rs src/object/mod.rs src/object/dummy_object.rs src/object/object.rs 4 | 5 | src/lib.rs: 6 | src/object/mod.rs: 7 | src/object/dummy_object.rs: 8 | src/object/object.rs: 9 | -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q-224luegfobocj/dep-graph.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q-224luegfobocj/dep-graph.bin -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q-224luegfobocj/query-cache.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q-224luegfobocj/query-cache.bin -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q-224luegfobocj/work-products.bin: -------------------------------------------------------------------------------- 1 | RSIC1.45.0 (5c1f21c3b 2020-07-13) -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/incremental/zcore_test-13cc7ji4lzg3j/s-fq07r6yih8-1h7zv3q.lock -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda-j9a298xqvikg/dep-graph.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda-j9a298xqvikg/dep-graph.bin -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda-j9a298xqvikg/query-cache.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda-j9a298xqvikg/query-cache.bin -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda-j9a298xqvikg/work-products.bin: -------------------------------------------------------------------------------- 1 | RSIC1.45.0 (5c1f21c3b 2020-07-13) -------------------------------------------------------------------------------- /src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/01-code/target/rls/debug/incremental/zcore_test-20c6xuhgrauog/s-fq07r71re7-13gbyda.lock -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # 简明 zCore 教程 2 | 3 | ## 自己动手山寨操作系统:自顶向下方法 4 | 5 | zCore 是用 Rust 语言重写的 Zircon 微内核,它是 Google 正在开发的 Fuchsia OS 中的底层内核。 6 | 7 | 本教程基于 zCore 的真实开发历史,还原其开发过程。带领读者一步一步用 Rust 实现自己的 Zircon 内核,最终能够运行原生的 shell 程序。 8 | 在此过程中我们将体会 Zircon 微内核的设计理念,感受如何用 Rust 语言以一种现代的方式编写系统软件,在项目中实现理论与实践的融合。 9 | 10 | 与传统操作系统开发不同的是,zCore 使用一种自顶向下的方法:首先基于宿主系统已有的功能,在用户态实现一个能够工作的 libOS,然后再逐步替换底层实现, 11 | "移植"回裸机环境中运行。因此我们更关注系统的整体设计,从高层视角看待 OS 如何为用户提供服务,而不纠结于底层硬件细节。 12 | 13 | 鉴于此,本教程假设读者了解操作系统基本概念和原理,具有常用的 Linux 系统使用经验,并且会使用 Rust 语言编写简单程序。 14 | 如果读者不熟悉操作系统和 Rust 语言,希望以自底向上方法从零构建操作系统,[rCore Tutorial] 可能是更好的选择。 15 | 16 | 如果你准备好了,让我们开始吧! 17 | 18 | [rCore Tutorial]: https://rcore-os.github.io/rCore-Tutorial-deploy/ 19 | -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # 简明 zCore 教程 2 | 3 | [简明 zCore 教程](README.md) 4 | [🚧 zCore 整体结构和设计模式](zcore-intro.md) 5 | [🚧 Fuchsia OS 和 Zircon 微内核](fuchsia.md) 6 | 7 | - [内核对象](ch01-00-object.md) 8 | - [✅ 初识内核对象](ch01-01-kernel-object.md) 9 | - [🚧 对象管理器:Process 对象](ch01-02-process-object.md) 10 | - [🚧 对象传送器:Channel 对象](ch01-03-channel-object.md) 11 | 12 | - [任务管理](ch02-00-task.md) 13 | - [🚧 Zircon 任务管理体系](ch02-01-zircon-task.md) 14 | - [🚧 进程管理:Process 与 Job 对象](ch02-02-process-job-object.md) 15 | - [🚧 线程管理:Thread 对象](ch02-03-thread-object.md) 16 | 17 | - [内存管理](ch03-00-memory.md) 18 | - [🚧 Zircon 内存管理模型](ch03-01-zircon-memory.md) 19 | - [🚧 物理内存:VMO 对象](ch03-02-vmo.md) 20 | - [🚧 物理内存:按页分配的 VMO](ch03-03-vmo-paged.md) 21 | - [🚧 虚拟内存:VMAR 对象](ch03-04-vmar.md) 22 | 23 | - [用户程序](ch04-00-userspace.md) 24 | - [🚧 Zircon 用户程序](ch04-01-user-program.md) 25 | - [🚧 上下文切换](ch04-02-context-switch.md) 26 | - [🚧 系统调用](ch04-03-syscall.md) 27 | 28 | - [信号和等待](ch05-00-signal-and-waiting.md) 29 | - [🚧 等待内核对象的信号](ch05-01-wait-signal.md) 30 | - [🚧 同时等待多个信号:Port 对象](ch05-02-port-object.md) 31 | - [🚧 实现更多:EventPair, Timer 对象](ch05-03-more-signal-objects.md) 32 | - [🚧 用户态同步互斥:Futex 对象](ch05-04-futex-object.md) 33 | -------------------------------------------------------------------------------- /src/ch01-00-object.md: -------------------------------------------------------------------------------- 1 | # 内核对象 2 | 3 | Zircon 是一个基于内核对象的系统。系统的功能被划分到若干组内核对象中。 4 | 5 | 作为一切的开始,本章首先构造了一个内核对象框架,作为后面实现的基础。 6 | 然后我们实现第一个内核对象 —— `Process`,它是所有对象的容器,也是将来我们操作对象的入口点。 7 | 最后会实现一个稍微复杂但是极其重要的对象 `Channel`,它是进程间通信(IPC)的基础设施,也是传送对象的唯一管道。 8 | -------------------------------------------------------------------------------- /src/ch01-01-kernel-object.md: -------------------------------------------------------------------------------- 1 | # 初识内核对象 2 | 3 | ## 内核对象简介 4 | 5 | 在动手编写我们的代码之前,需要首先进行调研和学习,对目标对象有一个全面系统的了解。 6 | 而了解一个项目设计的最好方式就是阅读官方提供的手册和文档。 7 | 8 | 让我们先来阅读一下 Fuchsia 官方文档:[内核对象]。这个链接是社区翻译的中文版,已经有些年头了。如果读者能够科学上网,推荐直接阅读[官方英文版]。 9 | 10 | [内核对象]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/objects.md 11 | [官方英文版]: https://fuchsia.dev/fuchsia-src/reference/kernel_objects/objects 12 | 13 | 通过阅读文档,我们了解到与内核对象相关的三个重要概念:**对象(Object),句柄(Handle),权限(Rights)**。它们在 Zircon 内核中的角色和关系如下图所示: 14 | 15 | ![](../img/ch01-01-kernel-object.png) 16 | 17 | 简单来说: 18 | 19 | * Zircon是一个基于对象的内核,内核资源被抽象封装在不同的 **对象** 中。 20 | * 用户程序通过 **句柄** 与内核交互。句柄是对某一对象的引用,并且附加了特定的 **权限**。 21 | * 对象通过 **引用计数** 管理生命周期。对于大多数对象,当指向它的最后一个句柄关闭时,对象随之销毁,或[进入无法挽回的最终状态](https://fuchsia.dev/fuchsia-src/concepts/kernel/concepts#handles_and_rights )。 22 | 23 | 此外在内核对象的文档中,还列举了一些[常用对象]。点击链接进去就能查看到这个对象的[具体描述],在页面最下方还列举了与这个对象相关的[全部系统调用]。 24 | 进一步查看系统调用的 [API 定义],以及它的[行为描述],我们就能更深入地了解用户程序操作内核对象的一些细节: 25 | 26 | [常用对象]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/objects.md#应用程序可用的内核对象 27 | [具体描述]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/objects/channel.md 28 | [全部系统调用]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/objects/channel.md#系统调用 29 | [API 定义]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/syscalls/channel_read.md#概要 30 | [行为描述]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/syscalls/channel_read.md#描述 31 | 32 | * 创建:每一种内核对象都存在一个系统调用来创建它,例如 [`zx_channel_create`]。 33 | 创建对象时一般需要传入一个参数选项 `options`,若创建成功则内核会将一个新句柄写入用户指定的内存中。 34 | 35 | * 使用:获得对象句柄后可以通过若干系统调用对它进行操作,例如 [`zx_channel_write`]。 36 | 这类系统调用一般需要传入句柄 `handle` 作为第一个参数,内核首先对其进行检查,如果句柄非法或者对象类型与系统调用不匹配就会报错。 37 | 接下来内核会检查句柄的权限是否满足操作的要求,例如 `write` 操作一般要求句柄具有 `WRITE` 权限,如果权限不满足就会继续报错。 38 | 39 | * 关闭:当用户程序不再使用对象时,会调用 [`zx_handle_close`] 关闭句柄。当用户进程退出时,仍处于打开状态的句柄也都会自动关闭。 40 | 41 | [`zx_channel_create`]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/syscalls/channel_create.md 42 | [`zx_channel_write`]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/syscalls/channel_write.md 43 | [`zx_handle_close`]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/syscalls/handle_close.md 44 | 45 | 我们还发现,有一类 Object 系统调用是对所有内核对象都适用的。 46 | 这表明所有内核对象都有一些公共属性,例如 ID、名称等等。每一种内核对象也会有自己特有的属性。 47 | 48 | 其中一些 Object 系统调用和信号相关。Zircon 每个内核对象都附带有 32 个 **[信号(Signals)]**,它们代表了不同类型的事件。 49 | 与传统 Unix 系统的信号不同,它不能异步地打断用户程序运行,而只能由用户程序主动地阻塞等待在某个对象的某些信号上面。 50 | 信号是 Zircon 内核中很重要的机制,不过这部分在前期不会涉及,我们留到第五章再具体实现。 51 | 52 | [信号(Signals)]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/signals.md 53 | 54 | 以上我们了解了 Zircon 内核对象的相关概念和使用方式。接下来在这一节中,我们将用 Rust 实现内核对象的基本框架,以方便后续快速实现各种具体类型的内核对象。 55 | 从传统面向对象语言的视角看,我们只是在实现一个基类。但由于 Rust 语言模型的限制,这件事情需要用到一些特殊的技巧。 56 | 57 | ## 建立项目 58 | 59 | 首先我们需要安装 Rust 工具链。在 Linux 或 macOS 系统下,只需要用一个命令下载安装 rustup 即可: 60 | 61 | ```sh 62 | $ curl https://sh.rustup.rs -sSf | sh 63 | ``` 64 | 65 | 具体安装方法可以参考[官方文档]。 66 | 67 | [官方文档]: https://kaisery.github.io/trpl-zh-cn/ch01-01-installation.html 68 | 69 | 接下来我们用 cargo 创建一个 Rust 库项目: 70 | 71 | ```sh 72 | $ cargo new --lib zcore 73 | $ cd zcore 74 | ``` 75 | 76 | 我们将在这个 crate 中实现所有的内核对象,以库(lib)而不是可执行文件(bin)的形式组织代码,后面我们会依赖单元测试保证代码的正确性。 77 | 78 | 由于我们会用到一些不稳定(unstable)的语言特性,需要使用 nightly 版本的工具链。在项目根目录下创建一个 `rust-toolchain` 文件,指明使用的工具链版本: 79 | 80 | ```sh 81 | {{#include ../../zcore/rust-toolchain}} 82 | ``` 83 | 84 | 这个程序库目前是在你的 Linux 或 macOS 上运行,但有朝一日它会成为一个真正的 OS 在裸机上运行。 85 | 为此我们需要移除对标准库的依赖,使其成为一个不依赖当前 OS 功能的库。在 `lib.rs` 的第一行添加声明: 86 | 87 | ```rust,noplaypen 88 | // src/lib.rs 89 | #![no_std] 90 | extern crate alloc; 91 | ``` 92 | 93 | 现在我们可以尝试运行一下自带的单元测试,编译器可能会自动下载并安装工具链: 94 | 95 | ```sh 96 | $ cargo test 97 | Finished test [unoptimized + debuginfo] target(s) in 0.52s 98 | Running target/debug/deps/zcore-dc6d43637bc5df7a 99 | 100 | running 1 test 101 | test tests::it_works ... ok 102 | 103 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out 104 | ``` 105 | 106 | ## 实现 KernelObject 接口 107 | 108 | 所有的内核对象有一系列共同的属性和方法,我们称这些方法为对象的公共**接口(Interface)**。 109 | 同一种方法在不同类型的对象中可能会有不同的行为,在面向对象语言中我们称其为**多态(Polymorphism)**。 110 | 111 | Rust 是一门部分面向对象的语言,我们通常用它的 trait 实现接口和多态。 112 | 113 | 首先创建一个 `KernelObject` trait 作为内核对象的公共接口: 114 | 115 | ```rust,noplaypen 116 | use alloc::string::String; 117 | // src/object/mod.rs 118 | /// 内核对象公共接口 119 | pub trait KernelObject: Send + Sync { 120 | {{#include ../../zcore/src/object/mod.rs:object}} 121 | 122 | {{#include ../../zcore/src/object/mod.rs:koid}} 123 | ``` 124 | 125 | 这里的 [`Send + Sync`] 是一个约束所有 `KernelObject` 都要满足的前提条件,即它必须是一个**并发对象**。 126 | 所谓并发对象指的是**可以安全地被多线程共享访问**。事实上我们的内核本身就是一个共享地址空间的多线程程序,在裸机上每个 CPU 核都可以被视为一个并发执行的线程。 127 | 由于内核对象可能被多个线程同时访问,因此它必须是并发对象。 128 | 129 | [`Send + Sync`]: https://kaisery.github.io/trpl-zh-cn/ch16-04-extensible-concurrency-sync-and-send.html 130 | 131 | ## 实现一个空对象 132 | 133 | 接下来我们实现一个最简单的空对象 `DummyObject`,并为它实现 `KernelObject` 接口: 134 | 135 | ```rust,noplaypen 136 | // src/object/object.rs 137 | {{#include ../../zcore/src/object/object_v1.rs:dummy_def}} 138 | ``` 139 | 140 | 这里我们采用一种[**内部可变性**]的设计模式:将对象的所有可变的部分封装到一个内部对象 `DummyObjectInner` 中,并在原对象中用自旋锁 [`Mutex`] 把它包起来,剩下的其它字段都是不可变的。 141 | `Mutex` 会用最简单的方式帮我们处理好并发访问问题:如果有其他人正在访问,我就在这里死等。 142 | 数据被 `Mutex` 包起来之后需要首先使用 [`lock()`] 拿到锁之后才能访问。此时并发访问已经安全,因此被包起来的结构自动具有了 `Send + Sync` 特性。 143 | 144 | [`Mutex`]: https://docs.rs/spin/0.5.2/spin/struct.Mutex.html 145 | [`lock()`]: https://docs.rs/spin/0.5.2/spin/struct.Mutex.html#method.lock 146 | [**内部可变性**]: https://kaisery.github.io/trpl-zh-cn/ch15-05-interior-mutability.html 147 | 148 | 使用自旋锁引入了新的依赖库 [`spin`] ,需要在 `Cargo.toml` 中加入以下声明: 149 | 150 | [`spin`]: https://docs.rs/spin/0.5.2/spin/index.html 151 | 152 | ```toml 153 | [dependencies] 154 | {{#include ../../zcore/Cargo.toml:spin}} 155 | ``` 156 | 157 | 然后我们为新对象实现构造函数: 158 | 159 | ```rust,noplaypen 160 | // src/object/object.rs 161 | {{#include ../../zcore/src/object/object_v1.rs:dummy_new}} 162 | ``` 163 | 164 | 根据文档描述,每个内核对象都有唯一的 ID。为此我们需要实现一个全局的 ID 分配方法。这里采用的方法是用一个静态变量存放下一个待分配 ID 值,每次分配就原子地 +1。 165 | ID 类型使用 `u64`,保证了数值空间足够大,在有生之年都不用担心溢出问题。在 Zircon 中 ID 从 1024 开始分配,1024 以下保留作内核内部使用。 166 | 167 | 另外注意这里 `new` 函数返回类型不是 `Self` 而是 `Arc`,这是为了以后方便而做的统一约定。 168 | 169 | 最后我们为它实现 `KernelObject` 接口: 170 | 171 | ```rust,noplaypen 172 | // src/object/object.rs 173 | {{#include ../../zcore/src/object/object_v1.rs:dummy_impl}} 174 | ``` 175 | 176 | 到此为止,我们已经迈出了万里长征第一步,实现了一个最简单的功能。有实现,就要有测试!即使最简单的代码也要保证它的行为符合我们预期。 177 | 只有对现有代码进行充分测试,在未来做添加和修改的时候,我们才有信心不会把事情搞砸。俗话讲"万丈高楼平地起",把地基打好才能盖摩天大楼。 178 | 179 | 为了证明上面代码的正确性,我们写一个简单的单元测试,替换掉自带的 `it_works` 函数: 180 | 181 | ```rust,noplaypen 182 | // src/object/object.rs 183 | {{#include ../../zcore/src/object/object_v1.rs:dummy_test}} 184 | ``` 185 | 186 | ```sh 187 | $ cargo test 188 | Finished test [unoptimized + debuginfo] target(s) in 0.53s 189 | Running target/debug/deps/zcore-ae1be84852989b13 190 | 191 | running 1 test 192 | test tests::dummy_object ... ok 193 | ``` 194 | 195 | 大功告成!让我们用 `cargo fmt` 命令格式化一下代码,然后记得 `git commit` 及时保存进展。 196 | 197 | ## 实现接口到具体类型的向下转换 198 | 199 | 在系统调用中,用户进程会传入一个内核对象的句柄,然后内核会根据系统调用的类型,尝试将其转换成特定类型的对象。 200 | 于是这里产生了一个很重要的需求:将接口 `Arc` 转换成具体类型的结构 `Arc where T: KernelObject`。 201 | 这种操作在面向对象语言中称为**向下转换(downcast)**。 202 | 203 | 在大部分编程语言中,向下转换都是一件非常轻松的事情。例如在 C/C++ 中,我们可以这样写: 204 | 205 | ```c++ 206 | struct KernelObject {...}; 207 | struct DummyObject: KernelObject {...}; 208 | 209 | KernelObject *base = ...; 210 | // C 风格:强制类型转换 211 | DummyObject *dummy = (DummyObject*)(base); 212 | // C++ 风格:动态类型转换 213 | DummyObject *dummy = dynamic_cast(base); 214 | ``` 215 | 216 | 但在 Rust 中,由于其 trait 模型的限制,向下转换并不是一件容易的事情。 217 | 虽然标准库中提供了 [`Any`] trait,部分实现了动态类型的功能,但实际操作起来却困难重重。 218 | 不信邪的同学可以自己折腾一下: 219 | 220 | [`Any`]: https://doc.rust-lang.org/std/any/ 221 | 222 | ```rust,editable 223 | # use std::any::Any; 224 | # use std::sync::Arc; 225 | # fn main() {} 226 | 227 | trait KernelObject: Any + Send + Sync {} 228 | fn downcast_v1(object: Arc) -> Arc { 229 | object.downcast::().unwrap() 230 | } 231 | fn downcast_v2(object: Arc) -> Arc { 232 | let object: Arc = object; 233 | object.downcast::().unwrap() 234 | } 235 | ``` 236 | 237 | 当然这个问题也困扰了 Rust 社区中的很多人。目前已经有人提出了一套不错的解决方案,就是我们接下来要引入的 [`downcast-rs`] 库: 238 | 239 | [`downcast-rs`]: https://docs.rs/downcast-rs/1.2.0/downcast_rs/index.html 240 | 241 | ```toml 242 | [dependencies] 243 | {{#include ../../zcore/Cargo.toml:downcast}} 244 | ``` 245 | 246 | (题外话:这个库原来是不支持 `no_std` 的,zCore 有这个需求,于是就顺便帮他实现了一把) 247 | 248 | 按照它文档的描述,我们要为自己的接口实现向下转换,只需以下修改: 249 | 250 | ```rust,noplaypen 251 | // src/object/mod.rs 252 | use core::fmt::Debug; 253 | use downcast_rs::{impl_downcast, DowncastSync}; 254 | 255 | pub trait KernelObject: DowncastSync + Debug {...} 256 | impl_downcast!(sync KernelObject); 257 | ``` 258 | 259 | 其中 `DowncastSync` 代替了原来的 `Send + Sync`,`Debug` 用于出错时输出调试信息。 260 | `impl_downcast!` 宏用来帮我们自动生成转换函数,然后就可以用 `downcast_arc` 来对 `Arc` 做向下转换了。我们直接来测试一把: 261 | 262 | ```rust,noplaypen 263 | // src/object/object.rs 264 | {{#include ../../zcore/src/object/object_v1.rs:downcast_test}} 265 | ``` 266 | 267 | ```sh 268 | $ cargo test 269 | Finished test [unoptimized + debuginfo] target(s) in 0.47s 270 | Running target/debug/deps/zcore-ae1be84852989b13 271 | 272 | running 2 tests 273 | test object::downcast ... ok 274 | test object::tests::dummy_object ... ok 275 | ``` 276 | 277 | ## 模拟继承:用宏自动生成接口实现代码 278 | 279 | 上面我们已经完整实现了一个内核对象,代码看起来很简洁。但当我们要实现更多对象的时候,就会发现一个问题: 280 | 这些对象拥有一些公共属性,接口方法也有共同的实现。 281 | 在传统 OOP 语言中,我们通常使用 **继承(inheritance)** 来复用这些公共代码:子类 B 可以继承父类 A,然后自动拥有父类的所有字段和方法。 282 | 283 | 继承是一个很强大的功能,但在长期实践中人们也逐渐发现了它的弊端。有兴趣的读者可以看一看知乎上的探讨:[*面向对象编程的弊端是什么?*]。 284 | 经典著作《设计模式》中就鼓励大家**使用组合代替继承**。而一些现代的编程语言,如 Go 和 Rust,甚至直接抛弃了继承。在 Rust 中,通常使用组合结构和 [`Deref`] trait 来部分模拟继承。 285 | 286 | [*面向对象编程的弊端是什么?*]: https://www.zhihu.com/question/20275578/answer/26577791 287 | [`Deref`]: https://kaisery.github.io/trpl-zh-cn/ch15-02-deref.html 288 | 289 | > 继承野蛮,trait 文明。 —— 某 Rust 爱好者 290 | 291 | 接下来我们模仿 `downcast-rs` 库的做法,使用一种基于宏的代码生成方案,来实现 `KernelObject` 的继承。 292 | 当然这只是抛砖引玉,如果读者自己实现了,或者了解到社区中有更好的解决方案,也欢迎指出。 293 | 294 | 具体做法是这样的: 295 | 296 | - 使用一个 struct 来提供所有的公共属性和方法,作为所有子类的第一个成员。 297 | - 为子类实现 trait 接口,所有方法直接委托给内部 struct 完成。这部分使用宏来自动生成模板代码。 298 | 299 | 而所谓的内部 struct,其实就是我们上面实现的 `DummyObject`。为了更好地体现它的功能,我们给他改个名叫 `KObjectBase`: 300 | 301 | ```rust,noplaypen 302 | // src/object/mod.rs 303 | {{#include ../../zcore/src/object/mod.rs:base_def}} 304 | ``` 305 | 306 | 接下来我们把它的构造函数改为实现 `Default` trait,并且公共属性和方法都指定为 `pub`: 307 | 308 | ```rust,noplaypen 309 | // src/object/mod.rs 310 | {{#include ../../zcore/src/object/mod.rs:base_default}} 311 | impl KObjectBase { 312 | /// 生成一个唯一的 ID 313 | fn new_koid() -> KoID {...} 314 | /// 获取对象名称 315 | pub fn name(&self) -> String {...} 316 | /// 设置对象名称 317 | pub fn set_name(&self, name: &str) {...} 318 | } 319 | ``` 320 | 321 | 最后来写一个魔法的宏! 322 | 323 | ```rust,noplaypen 324 | // src/object/mod.rs 325 | {{#include ../../zcore/src/object/mod.rs:impl_kobject}} 326 | ``` 327 | 328 | 轮子已经造好了!让我们看看如何用它方便地实现一个内核对象,仍以 `DummyObject` 为例: 329 | 330 | ```rust,noplaypen 331 | // src/object/mod.rs 332 | {{#include ../../zcore/src/object/mod.rs:dummy}} 333 | ``` 334 | 335 | 是不是方便了很多?最后按照惯例,用单元测试检验实现的正确性: 336 | 337 | ```rust,noplaypen 338 | // src/object/mod.rs 339 | {{#include ../../zcore/src/object/mod.rs:dummy_test}} 340 | ``` 341 | 342 | 有兴趣的读者可以继续探索使用功能更强大的 [**过程宏(proc_macro)**],进一步简化实现新内核对象所需的模板代码。 343 | 如果能把上面的代码块缩小成下面这两行,就更加完美了: 344 | 345 | [**过程宏(proc_macro)**]: https://doc.rust-lang.org/proc_macro/index.html 346 | 347 | ```rust,noplaypen 348 | #[KernelObject] 349 | pub struct DummyObject; 350 | ``` 351 | 352 | ![](../img/kobject.png) 353 | 354 | ## 总结 355 | 356 | 在这一节中我们用 Rust 语言实现了 Zircon 最核心的**内核对象**概念。在此过程中涉及到 Rust 的一系列语言特性和设计模式: 357 | 358 | - 使用 **trait** 实现接口 359 | - 使用 **内部可变性** 模式实现并发对象 360 | - 基于社区解决方案实现 trait 到 struct 的 **向下转换** 361 | - 使用组合模拟继承,并使用 **宏** 实现模板代码的自动生成 362 | 363 | 由于 Rust 独特的[面向对象编程特性],我们在实现内核对象的过程中遇到了一定的挑战。 364 | 不过万事开头难,解决这些问题为整个项目打下了坚实基础,后面实现新的内核对象就会变得简单很多。 365 | 366 | [面向对象编程特性]: https://kaisery.github.io/trpl-zh-cn/ch17-00-oop.html 367 | 368 | 在下一节中,我们将介绍内核对象相关的另外两个概念:句柄和权限,并实现内核对象的存储和访问。 369 | -------------------------------------------------------------------------------- /src/ch01-02-process-object.md: -------------------------------------------------------------------------------- 1 | # 对象管理器:Process 对象 2 | 3 | Zircon的进程是传统意义上程序的实例:由一个或多个线程执行的一组指令以及相关的资源集合组成。 4 | 5 | 进程对象是以下资源的容器集合: 6 | * [句柄(Handles)](https://fuchsia.dev/fuchsia-src/concepts/kernel/handles) 7 | * [虚拟内存地址区域(VMAR)](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/vm_address_region) 8 | * [线程(Threads)](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/thread) 9 | 10 | 通常,它与正在执行的代码相关联,直到强制终止或程序退出为止。 11 | 进程由[作业(Jobs)](https://fuchsia.dev/fuchsia-src/reference/kernel_objects/job)所拥有。每个进程属于一个作业,并且从资源和权限限制以及生命周期的控制的角度上看,由多个进程组成的应用程序被视为单个实体。 12 | 13 | 进程的定义如下: 14 | ```rust 15 | // zircon-object/src/task/process.rs 16 | // 进程 17 | #[allow(dead_code)] 18 | pub struct Process { 19 | /// 内核对象核心结构,定义于 zircon-object/src/object/mod.rs 20 | base: KObjectBase, 21 | /// 引用计数,定义于 zircon-object/src/object/mod.rs 22 | _counter: CountHelper, 23 | /// 属于的作业,定义于 zircon-object/src/task/job.rs 24 | job: Arc, 25 | /// policy,定义于 zircon-object/src/task/job_policy.rs 26 | policy: JobPolicy, 27 | /// VMAR,定义于 zircon-object/src/vm/vmar.rs 28 | vmar: Arc, 29 | ext: Box, 30 | /// Exceptionate(Kernel-owned exception channel endpoint),定义于 zircon-object/src/task/exception.rs 31 | exceptionate: Arc, 32 | debug_exceptionate: Arc, 33 | /// 进程的内部可变部分 34 | inner: Mutex, 35 | } 36 | 37 | // 进程的内部可变部分 38 | #[derive(Default)] 39 | struct ProcessInner { 40 | /// 进程的状态 41 | status: Status, 42 | max_handle_id: u32, 43 | /// 句柄(Handle),定义于 zircon-object/src/object/handle.rs 44 | handles: HashMap>)>, 45 | /// Futex(A primitive for creating userspace synchronization tools),定义于 46 | futexes: HashMap>, 47 | threads: Vec>, 48 | 49 | // special info 50 | debug_addr: usize, 51 | dyn_break_on_load: usize, 52 | critical_to_job: Option<(Arc, bool)>, 53 | } 54 | 55 | // 进程的状态 56 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 57 | pub enum Status { 58 | Init, 59 | Running, 60 | Exited(i64), 61 | } 62 | ``` 63 | 64 | 65 | ## 句柄和权限 66 | 67 | [句柄]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/handles.md 68 | [权限]: https://github.com/zhangpf/fuchsia-docs-zh-CN/blob/master/zircon/docs/rights.md 69 | 70 | > 介绍并实现 Handle,Rights 71 | 72 | `Handle`(句柄)是内核的“文件描述符”,它表示用户空间进程如何引用内核对象,通过`Channel`可以将`Handle`传递给其他进程. 73 | 74 | 对象可能有多个句柄(在一个或多个进程中)引用它们。对于所有的`Object`,当最后指向它们的`Handle`关闭时,该`Object`同时也将被销毁,或者放置到结束状态下,并且这样的操作不可回滚。 75 | 76 | 在某种程度上可以将句柄理解为指针, 在对句柄或者其指向对象进行操作时受到`Right`(权限)的控制, 就好像在用户态不能执行某些特权级指令一样。并且在指向对象的数个句柄中,`Right`级别可以不一样。 77 | 78 | ## 实现第一个内核对象 79 | 80 | > 使用上一节的方法,实现一个空的 Process 对象 81 | 82 | ## 存储内核对象句柄 83 | 84 | > 添加成员变量 handles: BTreeMap 85 | > 86 | > 实现 create,add_handle,remove_handle 函数 87 | 88 | 89 | 90 | ## 根据句柄查找内核对象 91 | 92 | > 实现 get_object_with_rights 等其它相关函数 93 | > 94 | > 实现 handle 单元测试 95 | 96 | -------------------------------------------------------------------------------- /src/ch01-03-channel-object.md: -------------------------------------------------------------------------------- 1 | # 对象传送器:Channel 对象 2 | 3 | ## 创建一对内核对象 4 | 5 | > 实现 Channel::create 6 | > 7 | > 讲一下互相持有对方 Weak 指针的目的,这里有不可避免的 unsafe 8 | 9 | ## 实现数据传输 10 | 11 | > 实现 read, write 函数,read_write 单元测试 12 | -------------------------------------------------------------------------------- /src/ch02-00-task.md: -------------------------------------------------------------------------------- 1 | # 任务管理 2 | 3 | 本章我们来实现第一类内核对象:任务管理(Tasks)。 4 | 5 | 任务对象主要包括:线程 `Thread`,进程 `Process`,作业 `Job`。以及一些辅助性的对象,例如负责暂停任务执行的 `SuspendToken` 和负责处理异常的 `Exception`。 6 | 7 | 为了能够真实表现线程对象的行为,我们使用 Rust async 运行时 [`async_std`] 中的**用户态协程**来模拟**内核线程**。 8 | 这样就可以在用户态的单元测试中检验实现的正确性。 9 | 考虑到未来这个 OS 会跑在裸机环境中,将会有不同的内核线程的实现,我们创建一个特殊的**硬件抽象层(Hardware Abstraction Layer,HAL)**,来屏蔽底层平台的差异,对上提供一个统一的接口。 10 | 这个 HAL 的接口未来会根据需要进行扩充。 11 | 12 | 本章中我们只会实现运行一个程序所必需的最小功能子集,剩下的部分则留到跑起用户程序之后再按需实现。 13 | 14 | [`async_std`]: https://docs.rs/async-std/1.6.2/async_std/index.html 15 | -------------------------------------------------------------------------------- /src/ch02-01-zircon-task.md: -------------------------------------------------------------------------------- 1 | # Zircon 任务管理体系 2 | -------------------------------------------------------------------------------- /src/ch02-02-process-job-object.md: -------------------------------------------------------------------------------- 1 | # 进程管理:Process 与 Job 对象 2 | 3 | ## Process 与 Job 4 | 5 | > 介绍 Process 与 Job 的整体设计 6 | > 7 | > 实现 Process 和 Job 对象的基本框架,支持树状结构 8 | 9 | ## Job Policy 策略 10 | 11 | > 实现 JobPolicy 12 | -------------------------------------------------------------------------------- /src/ch02-03-thread-object.md: -------------------------------------------------------------------------------- 1 | # 线程管理:Thread 对象 2 | 3 | ## 线程状态 4 | 5 | > 状态转移:创建 -> 运行 -> 暂停 -> 退出,最好有个状态机的图 6 | > 7 | > 实现 ThreadState,最好能加一个单元测试来验证转移过程 8 | 9 | ## 线程寄存器上下文 10 | 11 | > 定义 ThreadState,实现 read_state,write_state 12 | 13 | ## Async 运行时和 HAL 硬件抽象层 14 | 15 | > 简单介绍 async-std 的异步机制 16 | > 17 | > 介绍 HAL 的实现方法:弱链接 18 | > 19 | > 实现 hal_thread_spawn 20 | 21 | ## 线程启动 22 | 23 | > 将 HAL 接入 Thread::start,编写单元测试验证能启动多线程 24 | -------------------------------------------------------------------------------- /src/ch03-00-memory.md: -------------------------------------------------------------------------------- 1 | # 内存管理 2 | -------------------------------------------------------------------------------- /src/ch03-01-zircon-memory.md: -------------------------------------------------------------------------------- 1 | # Zircon 内存管理模型 2 | 3 | ## Zircon内存使用的3种方式: 4 | A process can use memory 3 ways: 5 | + 以堆、线程栈、可执行代码+数据的形式映射内存。这个内存由`VMARs`表示,而`VMARs`又持有一个对`VMOs`的引用。程序员通常通过内存地址与内存进行交互 6 | + 独立的`VMOs`。这些是没有通过`VMAR`映射的内存页集。程序员通过句柄与内存进行交互(通常利用`vmo_read`和`vmo_write`的API) 7 | + 以内核对象句柄形式存在的内核内存 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/ch03-02-vmo.md: -------------------------------------------------------------------------------- 1 | # 物理内存:VMO 对象 2 | 3 | ## 虚拟内存对象(Virtual Memory Object,VMO) 4 | `VMO`表示虚拟内存的一个连续区域,可以映射到多个地址空间中。 5 | `VMO`在内核和用户空间中用于表示分页内存和物理内存。它们是进程之间以及内核和用户空间之间共享内存的标准方法。 6 | 7 | > 根据文档梳理 VMO 的主要特性 8 | 9 | ## 实现 VMO 对象框架 10 | 11 | > 实现 VmObject 结构,其中定义 VmObjectTrait 接口,并提供三个具体实现 Paged, Physical, Slice 12 | 13 | ## HAL:用文件模拟物理内存 14 | 15 | > 初步介绍 mmap,引出用文件模拟物理内存的思想 16 | > 17 | > 创建文件并用 mmap 线性映射到进程地址空间 18 | > 19 | > 实现 pmem_read, pmem_write 20 | 21 | ## 实现物理内存 VMO 22 | 23 | > 用 HAL 实现 VmObjectPhysical 的方法,并做单元测试 24 | 25 | ## 实现切片 VMO 26 | 27 | > 实现 VmObjectSlice,并做单元测试 28 | -------------------------------------------------------------------------------- /src/ch03-03-vmo-paged.md: -------------------------------------------------------------------------------- 1 | # 物理内存:按页分配的 VMO 2 | 3 | ## 简介 4 | 5 | > 说明一下:Zircon 的官方实现中为了高效支持写时复制,使用了复杂精巧的树状数据结构,但它同时也引入了复杂性和各种 Bug。 6 | > 我们在这里只实现一个简单版本,完整实现留给读者自行探索。 7 | > 8 | > 介绍 commit 操作的意义和作用 9 | 10 | ## HAL:物理内存管理 11 | 12 | > 在 HAL 中实现 PhysFrame 和最简单的分配器 13 | 14 | ## 辅助结构:BlockRange 迭代器 15 | 16 | > 实现 BlockRange 17 | 18 | ## 实现按页分配的 VMO 19 | 20 | > 实现 for_each_page, commit, read, write 函数 21 | 22 | ## VMO 复制 23 | 24 | > 实现 create_child 函数 25 | -------------------------------------------------------------------------------- /src/ch03-04-vmar.md: -------------------------------------------------------------------------------- 1 | # 虚拟内存:VMAR 对象 2 | 3 | ## VMAR 简介 4 | 5 | ## 实现 VMAR 对象框架 6 | 7 | > 定义 VmAddressRange,VmMapping 8 | > 9 | > 实现 create_child, map, unmap, destroy 函数,并做单元测试验证地址空间分配 10 | 11 | ## HAL:用 mmap 模拟页表 12 | 13 | > 实现页表接口 map, unmap, protect 14 | 15 | ## 实现内存映射 16 | 17 | > 用 HAL 实现上面 VMAR 留空的部分,并做单元测试验证内存映射 18 | -------------------------------------------------------------------------------- /src/ch04-00-userspace.md: -------------------------------------------------------------------------------- 1 | # 用户程序 2 | 3 | zCore采用的是微内核的设计风格。微内核设计的一个复杂问题是”如何引导初始用户空间进程“。通常这是通过让内核实现最小版本的文件系统读取和程序加载来实现的引导。 4 | 5 | + userprogram 6 | + load-elf 7 | + context-switch 8 | + syscall 9 | 10 | -------------------------------------------------------------------------------- /src/ch04-01-user-program.md: -------------------------------------------------------------------------------- 1 | # Zircon 用户程序 2 | 3 | ## 用户态启动流程 4 | 5 | ### 流程概要 6 | kernel 7 | -> userboot (decompress bootsvc LZ4 format) 8 | -> bootsvc (可执行文件bin/component_manager) 9 | -> component_manager 10 | -> sh / device_manager 11 | 12 | ### ZBI(Zircon Boot Image) 13 | ZBI是一种简单的容器格式,它内嵌了许多可由引导加载程序 `BootLoader`传递的项目内容,包括硬件特定的信息、提供引导选项的内核“命令行”以及RAM磁盘映像(通常是被压缩的)。`ZBI`中包含了初始文件系统 `bootfs`,内核将 `ZBI` 完整传递给 `userboot`,由它负责解析并对其它进程提供文件服务。 14 | 15 | 16 | ### bootfs 17 | 18 | 基本的`bootfs`映像可满足用户空间程序运行需要的所有依赖: 19 | + 可执行文件 20 | + 共享库 21 | + 数据文件 22 | 23 | 以上列出的内容还可实现设备驱动或更高级的文件系统,从而能够从存储设备或网络设备上访问读取更多的代码和数据。 24 | 25 | 在系统自引导结束后,`bootfs`中的文件就会成为一个挂载在根目录`/boot`上的只读文件系统树(并由bootsvc提供服务)。随后`userboot`将从`bootfs`加载第一个真正意义上的用户程序。 26 | 27 | 28 | 29 | ### USERBOOT 30 | 31 | #### 使用userboot的原因 32 | 33 | 在Zircon中,内嵌在ZBI中的`RAM磁盘映像`通常采用[LZ4](https://github.com/lz4/lz4)格式压缩。解压后将继续得到`bootfs`格式的磁盘镜像。这是一种简单的只读文件系统格式,它只列出文件名。且对于每个文件,可分别列出它们在BOOTFS映像中的偏移量和大小(这两个值都必须是页面对齐的,并且限制在32位)。 34 | 35 | 由于kernel中没有包含任何可用于解压缩[LZ4](https://github.com/lz4/lz4)格式的代码,也没有任何用于解析BOOTFS格式的代码。所有这些工作都是由称为`userboot`的第一个用户空间进程完成的。 36 | 37 | 38 | > zCore中未找到解压缩bootfs的相关实现, 39 | > 但是能够在scripts/gen-prebuilt.sh中找到ZBI中确实有bootfs的内容 40 | > 且现有的zCore实现中有关所载入的ZBI方式如下: 41 | 42 | > zircon-loader/src/lib.rs 43 | ```rust 44 | // zbi 45 | let zbi_vmo = { 46 | let vmo = VmObject::new_paged(images.zbi.as_ref().len() / PAGE_SIZE + 1); 47 | vmo.write(0, images.zbi.as_ref()).unwrap(); 48 | vmo.set_name("zbi"); 49 | vmo 50 | }; 51 | ``` 52 | #### userboot是什么 53 | userboot是一个普通的用户空间进程。它只能像任何其他进程一样通过vDSO执行标准的系统调用,并受完整vDSO执行制度的约束。 54 | 55 | > 唯一一个由内核态“不规范地”创建的用户进程 56 | > 57 | > userboot具体实现的功能有: 58 | > 59 | > + 读取channel中的cmdline、handles 60 | > 61 | > + 解析zbi 62 | > 63 | > + 解压BOOTFS 64 | > 65 | > + 选定下一个程序启动 自己充当loader,然后“死亡” 66 | > 67 | > + 用“规范的方式”启动下一个程序 68 | 69 | 70 | userboot被构建为一个ELF动态共享对象(DSO,dynamic shared object),使用了与vDSO相同的布局。与vDSO一样,userboot的ELF映像在编译时就被嵌入到内核中。其简单的布局意味着加载它不需要内核在引导时解析ELF的文件头。内核只需要知道三件事: 71 | 1. 只读段`segment`的大小 72 | 2. 可执行段`segment`的大小 73 | 3. `userboot`入口点的地址。 74 | 75 | 这些值在编译时便可从userboot ELF映像中提取,并在内核代码中用作常量。 76 | 77 | #### kernel如何启用userboot 78 | 79 | 与任何其他进程一样,userboot必须从已经映射到其地址空间的vDSO开始,这样它才能进行系统调用。内核将userboot和vDSO映射到第一个用户进程,然后在userboot的入口处启动它。 80 | 81 | 83 | 84 | #### userboot如何在vDSO中取得系统调用 85 | 当内核将`userboot`映射到第一个用户进程时,会像正常程序那样,在内存中选择一个随机地址进行加载。而在映射`userboot`的vDSO时,并不采用上述随机的方式,而是将vDSO映像直接放在内存中`userboot`的映像之后。这样一来,vDSO代码与`userboot`的偏移量总是固定的。 86 | 87 | 在编译阶段中,系统调用的入口点符号表会从vDSO ELF映像中提取出来,随后写入到链接脚本的符号定义中。利用每个符号在vDSO映像中相对固定的偏移地址,可在链接脚本提供的`_end`符号的固定偏移量处,定义该符号。通过这种方式,userboot代码可以直接调用到放在内存中,其映像本身之后的,每个确切位置上的vDSO入口点。 88 | 89 | 相关代码: 90 | > zircon-loader/src/lib.rs 91 | ```rust 92 | pub fn run_userboot(images: &Images>, cmdline: &str) -> Arc { 93 | ... 94 | // vdso 95 | let vdso_vmo = { 96 | let elf = ElfFile::new(images.vdso.as_ref()).unwrap(); 97 | let vdso_vmo = VmObject::new_paged(images.vdso.as_ref().len() / PAGE_SIZE + 1); 98 | vdso_vmo.write(0, images.vdso.as_ref()).unwrap(); 99 | let size = elf.load_segment_size(); 100 | let vmar = vmar 101 | .allocate_at( 102 | userboot_size, 103 | size, 104 | VmarFlags::CAN_MAP_RXW | VmarFlags::SPECIFIC, 105 | PAGE_SIZE, 106 | ) 107 | .unwrap(); 108 | vmar.map_from_elf(&elf, vdso_vmo.clone()).unwrap(); 109 | #[cfg(feature = "std")] 110 | { 111 | let offset = elf 112 | .get_symbol_address("zcore_syscall_entry") 113 | .expect("failed to locate syscall entry") as usize; 114 | let syscall_entry = &(kernel_hal_unix::syscall_entry as usize).to_ne_bytes(); 115 | // fill syscall entry x3 116 | vdso_vmo.write(offset, syscall_entry).unwrap(); 117 | vdso_vmo.write(offset + 8, syscall_entry).unwrap(); 118 | vdso_vmo.write(offset + 16, syscall_entry).unwrap(); 119 | } 120 | vdso_vmo 121 | }; 122 | ... 123 | 124 | } 125 | ``` 126 | 127 | ### bootsvc 128 | bootsvc 通常是usermode加载的第一个程序(与userboot不同,userboot是由内核加载的)。bootsvc提供了几种系统服务: 129 | + 包含bootfs(/boot)内容的文件系统服务(初始的bootfs映像包含用户空间系统需要运行的所有内容: 130 | - 可执行文件 131 | - 共享库和数据文件(包括设备驱动程序或更高级的文件系统的实现) 132 | + 从bootfs加载的加载程序服务 133 | 134 | 135 | + bin/component_manager 136 | + sh / device_manager 137 | 138 | 139 | 140 | 141 | 142 | 143 | ## 用户程序的组成 144 | 145 | > 内核不直接参与用户程序的加载工作(第一个进程除外) 146 | > 147 | > 用户程序强制使用 PIC 和 PIE(位置无关代码) 148 | > 149 | > 内存地址空间组成:Program, Stack, vDSO, Dylibs 150 | > 151 | > 通过 Channel 传递启动信息和句柄 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | ## 系统调用的跳板:vDSO 164 | 165 | #### 介绍 vDSO 的作用 166 | 167 | vDSO(virtual Dynamic Shared Object),Zircon vDSO 是 Zircon 内核访问系统调用的唯一方法(作为系统调用的跳板)。它之所以是虚拟的,是因为它不是从文件系统中的ELF文件加载的,而是由内核直接提供的vDSO镜像。 168 | 169 | 170 | 171 | > zCore/src/main.rs 172 | ```rust 173 | #[cfg(feature = "zircon")] 174 | fn main(ramfs_data: &[u8], cmdline: &str) { 175 | use zircon_loader::{run_userboot, Images}; 176 | let images = Images::<&[u8]> { 177 | userboot: include_bytes!("../../prebuilt/zircon/x64/userboot.so"), 178 | vdso: include_bytes!("../../prebuilt/zircon/x64/libzircon.so"), 179 | zbi: ramfs_data, 180 | }; 181 | let _proc = run_userboot(&images, cmdline); 182 | run(); 183 | } 184 | ``` 185 | 186 | 它是一个用户态运行的代码,被封装成`prebuilt/zircon/x64/libzircon.so`文件。这个.so 文件装载不是放在文件系统中,而是由内核提供。它被整合在内核image中。 187 | 188 | vDSO映像在编译时嵌入到内核中。内核将它作为只读VMO公开给用户空间。内核启动时,会通过计算得到它所在的物理页。当`program loader`设置了一个新进程后,使该进程能够进行系统调用的唯一方法是:`program loader`在新进程的第一个线程开始运行之前,将vDSO映射到新进程的虚拟地址空间(地址随机)。因此,在启动其他能够进行系统调用的进程的每个进程自己本身都必须能够访问vDSO的VMO。 189 | 190 | > zircon-loader/src/lib.rs#line167 191 | 192 | ```rust 193 | proc.start(&thread, entry, sp, Some(handle), 0, thread_fn) 194 | .expect("failed to start main thread"); 195 | proc 196 | ``` 197 | > zircon-object/src/task/process.rs#line189 198 | 199 | ```rust 200 | thread.start(entry, stack, handle_value as usize, arg2, thread_fn) 201 | ``` 202 | 203 | vDSO被映射到新进程的同时会将映像的`base address`通过`arg2`参数传递给新进程中的第一个线程。通过这个地址,可以在内存中找到ELF的文件头,该文件头指向可用于查找系统调用符号名的其他ELF程序模块。 204 | 205 | #### 如何修改 vDSO 源码(libzircon)将 syscall 改为函数调用 206 | 207 | ##### 有关代码 208 | + 参考仓库[README.MD](https://github.com/PanQL/zircon/blob/master/README.md) 209 | > ···解析代码依赖的compile_commands.json将会随build过程生成到**out**文件夹··· 210 | 211 | ##### 如何生成imgs(VDSO,ZBI) 212 | 1. clone Zircon代码仓库(从fuchsia官方目录中分离出来的zircon代码): 213 | ```shell 214 | $ git clone https://github.com/PanQL/zircon.git 215 | ``` 216 | 2. 关于Zircon的编译运行 217 | 为了减小仓库体积,我们将prebuilt目录进行了大幅调整;因此运行之前请下载google预编译好的clang,解压后放到某个权限合适的位置,然后在代码的[这个位置](https://github.com/PanQL/zircon/blob/master/public/gn/toolchain/clang.gni#L16)将**绝对目录**修改为对应位置。 218 | clang下载链接: 219 | * [云盘下载链接](https://cloud.tsinghua.edu.cn/d/7ab1d87feecd4b2cb3d8/) 220 | * 官方CIPD包下载链接如下 221 | * [Linux](https://chrome-infra-packages.appspot.com/p/fuchsia/clang/linux-amd64/+/oEsFSe99FkcDKVxZkAY0MKi6C-yYOan1m-QL45N33W8C) 222 | * [Mac](https://chrome-infra-packages.appspot.com/p/fuchsia/clang/mac-amd64/+/Lc64-GTi4kihzkCnW8Vaa80TWTnMpZY0Fy6AqChmqvcC) 223 | 224 | 225 | 3. 当前只支持在Mac OS及Linux x64上进行编译。 226 | 默认的`make run`和`make build`是针对x64架构的,如果希望编译运行arm架构的zircon,那么需要: 227 | * 修改out/args.gn中的`legacy-image-x64`为`legacy-image-arm64` 228 | * 重新`make build` 229 | * `make runarm` 230 | 231 | 232 | 233 | 234 | 235 | 4. 配合zCore中的有关脚本与补丁文件 236 | - scripts/gen-prebuilt.sh 237 | - scripts/zircon-libos.patch 238 | + https://github.com/PanQL/zircon/blob/master/system/ulib/zircon/syscall-entry.h 239 | + https://github.com/PanQL/zircon/blob/master/system/ulib/zircon/syscalls-x86-64.S 240 | + zircon-loader/src/lib.rs#line 83-93 241 | ```rust 242 | #[cfg(feature = "std")] 243 | { 244 | let offset = elf 245 | .get_symbol_address("zcore_syscall_entry") 246 | .expect("failed to locate syscall entry") as usize; 247 | let syscall_entry = &(kernel_hal_unix::syscall_entry as usize).to_ne_bytes(); 248 | // fill syscall entry x3 249 | vdso_vmo.write(offset, syscall_entry).unwrap(); 250 | vdso_vmo.write(offset + 8, syscall_entry).unwrap(); 251 | vdso_vmo.write(offset + 16, syscall_entry).unwrap(); 252 | } 253 | 254 | ``` 255 | 256 | 259 | 260 | #### 加载 vDSO 时修改 vDSO 代码段,填入跳转地址 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | ## 第一个用户程序:userboot 269 | 270 | > 实现 zircon-loader 中的 run_userboot 函数 271 | > 272 | > 能够进入用户态并在第一个系统调用时跳转回来 273 | 274 | 275 | #### 从`bootfs`加载第一个真正意义上的用户程序。 276 | 主要相关代码: 277 | > zircon-loader/src/lib.rs 278 | > zircon-object/src/util/elf_loader.rs 279 | 280 | 当`userboot`解压完毕`ZBI`中的`bootfs`后,`userboot`将继续从`bootfs`载入程序文件运行。 281 | 282 | Zircon中具体的实现流程如下: 283 | 1. `userboot`检查从内核接收到的环境字符串,这些字符串代表了一定的内核命令行。 284 | > zircon-loader/src/main.rs 285 | ```rust 286 | #[async_std::main] 287 | async fn main() { 288 | kernel_hal_unix::init(); 289 | init_logger(); 290 | 291 | let opt = Opt::from_args(); 292 | let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 293 | 294 | let proc: Arc = run_userboot(&images, &opt.cmdline); 295 | drop(images); 296 | 297 | proc.wait_signal(Signal::USER_SIGNAL_0).await; 298 | } 299 | ``` 300 | 在Zircon中: 301 | + 若该字符串内容为```userboot=file```,那么该`file`将作为第一个真正的用户进程加载。 302 | + 若没有这样的选项,则`userboot`将选择的默认文为`bin/bootsvc`。该文件可在`bootfs`中找到。 303 | 304 | 而在zCore的实现中: 305 | + .. 306 | 2. 为了加载上述文件,userboot实现了一个功能齐全的ELF程序加载器 307 | `zircon_object::util::elf_loader::load_from_elf` 308 | ```rust 309 | // userboot 310 | let (entry, userboot_size) = { 311 | let elf = ElfFile::new(images.userboot.as_ref()).unwrap(); 312 | let size = elf.load_segment_size(); 313 | let vmar = vmar 314 | .allocate(None, size, VmarFlags::CAN_MAP_RXW, PAGE_SIZE) 315 | .unwrap(); 316 | vmar.load_from_elf(&elf).unwrap(); 317 | (vmar.addr() + elf.header.pt2.entry_point() as usize, size) 318 | }; 319 | ``` 320 | 3. 然后userboot以随机地址加载vDSO。它使用标准约定启动新进程,并给它传递一个channel句柄和vDSO基址。 321 | `zircon_object::util::elf_loader::map_from_elf` 322 | -------------------------------------------------------------------------------- /src/ch04-02-load-elf.md: -------------------------------------------------------------------------------- 1 | # [zCore程序(ELF加载与动态链接)](https://fuchsia.dev/fuchsia-src/concepts/booting/program_loading) 2 | 3 | zCore内核不直接参与正常程序的加载,而是提供了一些用户态程序加载时可用的模块。如虚拟内存对象(VMO)、进程(processes)、虚拟地址空间(VMAR)和线程(threads)。 4 | 5 | 6 | ### ELF 格式以及系统应用程序二进制接口(system ABI) 7 | 8 | 9 | 标准的zCore用户空间环境提供了动态链接器以及基于ELF的执行环境,能够运行ELF格式的格式机器码可执行文件。zCore进程只能通过zCore vDSO使用系统调用。内核采用基于ELF系统常见的程序二进制接口(ABI)提供了vDSO。 10 | 11 | 具备适当功能的用户空间代码可通过系统调用直接创建进程和加载程序,而不用ELF。但是zCore的标准ABI使用了这里所述的ELF。有关ELF文件格式的背景知识如下: 12 | 13 | ### ELF文件类型 14 | 15 | “ET_REL”代表此ELF文件为可重定位文件 16 | 17 | “ET_EXEC“代表ELF文件为可执行文件 18 | 19 | “ET_DYN”代表此ELF文件为动态链接库 20 | 21 | “ET_CORE”代表此ELF文件是核心转储文件 22 | 23 | 24 | ### 传统ELF程序文件加载 25 | 26 | 可执行链接格式(Executable and Linking Format, ELF)最初由 UNIX 系统实验室开发并发布,并成为大多数类Unix系统的通用标准可执行文件格式。在这些系统中,内核使用```POSIX```(可移植操作系统接口)```execve API```将程序加载与文件系统访问集成在一起。该类系统加载ELF程序的方式会有一些不同,但大多遵循以下模式: 27 | 28 | 29 | 1. 内核按照名称加载文件,并检查它是ELF还是系统支持的其他类型的文件。 30 | 31 | 32 | 2. 内核根据ELF文件的```PT_LOAD```程序头来映射ELF映像。对于```ET_EXEC```文件,系统会将程序中的各段(Section)放到```p_vaddr```中所指定内存中的固定地址。对于```ET_DYN```文件,系统将加载程序第一个```PT_LOAD```的基地址,然后根据它们的```p_vaddr```相对于第一个section的```p_vaddr```放置后面的section。 通常来说该基地址是通过地址随机化(ASLR)来产生的。 33 | 34 | 35 | 3. 若ELF文件中有一个```PT_INTERP```(Program interpreter)程序头, 它的部分内容(ELF文件中```p_offset```和```p_filesz```给出的一些字节)被当做为一个文件名,改文件名用于寻找另一个称为“ELF解释器”的ELF文件。上述这种ELF文件是```ET_DYN```文件。内核采用同样的方式将该类ELF文件加载,但是所加载的地址是自定的。该ELF“解释器”通常指的是被命名为```/lib/ld.so.1``` 或者是 ```/lib/ld-linux.so.2```的ELF动态链接器。 36 | 37 | 38 | 39 | 4. 内核为初始的线程设置了寄存器和堆栈的内容,并在PC寄存器已指向特定程序入口处(Entry Point)的情况下启动线程。 40 | + 程序入口处(Entry Point)指的是ELF文件头中 ```e_entry```的值,它会根据程序基地址(base address)做相应的调整。如果这是一个带有```PT_INTERP```的ELF文件,则它的入口点不在它本身,而是被设置在动态链接器中。 41 | + 内核通过设置寄存器和堆栈来使得程序能够接收特定的参数,环境变量以及其它有实际用途的辅助向量。寄存器和堆栈的设置方法遵循了一种汇编级别的协议方式。若ELF文件运行时依赖动态链接,即带有```PT_INTERP```。则寄存器和堆栈中将包括来自该可执行文件的ELF文件头中的基地址、入口点和程序头部表地址信息,这些信息可允许动态链接器在内存中找到该可执行文件的ELF动态链接元数据,以实现动态链接。当动态链接启动完成后,动态链接器将跳转到该可执行文件的入口点地址。 42 | 43 | ```rust 44 | pub fn sys_process_start( 45 | &self, 46 | proc_handle: HandleValue, 47 | thread_handle: HandleValue, 48 | entry: usize, 49 | stack: usize, 50 | arg1_handle: HandleValue, 51 | arg2: usize, 52 | ) -> ZxResult { 53 | info!("process.start: proc_handle={:?}, thread_handle={:?}, entry={:?}, stack={:?}, arg1_handle={:?}, arg2={:?}", 54 | proc_handle, thread_handle, entry, stack, arg1_handle, arg2 55 | ); 56 | let proc = self.thread.proc(); 57 | let process = proc.get_object_with_rights::(proc_handle, Rights::WRITE)?; 58 | let thread = proc.get_object_with_rights::(thread_handle, Rights::WRITE)?; 59 | if !Arc::ptr_eq(&thread.proc(), &process) { 60 | return Err(ZxError::ACCESS_DENIED); 61 | } 62 | let arg1 = if arg1_handle != INVALID_HANDLE { 63 | let arg1 = proc.remove_handle(arg1_handle)?; 64 | if !arg1.rights.contains(Rights::TRANSFER) { 65 | return Err(ZxError::ACCESS_DENIED); 66 | } 67 | Some(arg1) 68 | } else { 69 | None 70 | }; 71 | process.start(&thread, entry, stack, arg1, arg2, self.spawn_fn)?; 72 | Ok(()) 73 | } 74 | ``` 75 | zCore的程序加载受到了传统方式的启发,但是有一些不同。在传统模式中,需要在加载动态链接器之前加载可执行文件的一个关键原因是,动态链接器随机化选择的基地址(base address)不能与```ET_EXEC```可执行文件使用的固定地址相交。zCore从根本上并不支持```ET_EXEC```格式ELF文件的固定地址程序加载,它只支持位置无关的可执行文件或[PIE](https://patchwork.kernel.org/patch/9807325/)(```ET_DYN```格式的ELF文件) 76 | 77 | 78 | ### VmarExt trait实现 79 | 80 | zCore底层的API不支持文件系统。zCore程序文件的加载通过虚拟内存对象(VMO)以及```channel```使用的进程间通信机制来完成。 81 | 82 | 程序的加载基于如下一些前提: 83 | + 获得一个包含可执行文件的虚拟内存对象(VMO)的句柄。 84 | 85 | > zircon-object\src\util\elf_loader.rs 86 | ```shell 87 | fn make_vmo(elf: &ElfFile, ph: ProgramHeader) -> ZxResult> { 88 | assert_eq!(ph.get_type().unwrap(), Type::Load); 89 | let page_offset = ph.virtual_addr() as usize % PAGE_SIZE; 90 | let pages = pages(ph.mem_size() as usize + page_offset); 91 | let vmo = VmObject::new_paged(pages); 92 | let data = match ph.get_data(&elf).unwrap() { 93 | SegmentData::Undefined(data) => data, 94 | _ => return Err(ZxError::INVALID_ARGS), 95 | }; 96 | vmo.write(page_offset, data)?; 97 | Ok(vmo) 98 | } 99 | ``` 100 | + 程序执行参数列表。 101 | + 程序执行环境变量列表。 102 | + 存在一个初始的句柄列表,每个句柄都有一个句柄信息项。 103 | 104 | 105 | ### zCore所支持的三种 106 | 107 | 108 | ### 标准zCore ELF动态链接器 109 | 110 | -------------------------------------------------------------------------------- /src/ch04-03-context-switch.md: -------------------------------------------------------------------------------- 1 | # 上下文切换 2 | 3 | > 本节介绍 trapframe-rs 中 [fncall.rs] 的魔法实现 4 | 5 | [fncall.rs]: https://github.com/rcore-os/trapframe-rs/blob/master/src/arch/x86_64/fncall.rs 6 | 7 | ## 保存和恢复通用寄存器 8 | 9 | > 定义 UserContext 结构体 10 | > 11 | > 保存 callee-saved 寄存器到栈上,恢复 UserContext 寄存器,进入用户态,反之亦然 12 | 13 | ## 找回内核上下文:线程局部存储 与 FS 寄存器 14 | 15 | > 在用户程序跳转回内核代码的那一刻,如何在不破坏用户寄存器的情况下切换回内核栈? 16 | > 17 | > 进入用户态前,将内核栈指针保存在内核 glibc 的 TLS 区域中。为此我们需要查看 glibc 源码,找到一个空闲位置。 18 | > 19 | > Linux 和 macOS 下如何分别通过系统调用设置 fsbase / gsbase 20 | 21 | ## 测试 22 | 23 | > 编写单元测试验证上述过程 24 | 25 | ## macOS 的麻烦:动态二进制修改 26 | 27 | > 由于 macOS 用户程序无法修改 fs 寄存器,当运行相关指令时会访问非法内存地址触发段错误。 28 | > 29 | > 我们需要实现段错误信号处理函数,并在其中动态修改用户程序指令,将 fs 改为 gs。 30 | -------------------------------------------------------------------------------- /src/ch04-04-syscall.md: -------------------------------------------------------------------------------- 1 | # Zircon 系统调用 2 | > 目录位于`zCore/zircon-syscall` 3 | 4 | 从userboot运行起来到实现调用syscall的简要函数调用流程如下: 5 | 6 | 1. run_userboot -> 7 | 2. proc.start -> 8 | 3. thread_fn -> 9 | 4. new_thread -> 10 | 5. handle_syscall -> 11 | 6. syscall -> 12 | 7. sys_handle_close() (举例某一具体的syscall运行,该syscall可用于实现`close a handle`的功能) 13 | 14 | ## 获取系统调用参数 15 | 从寄存器中获取参数 16 | > 不同的计算机体系结构获得参数的方式不同 17 | > 18 | > 以下区分`x86_64`以及`aarch64` 19 | 20 | 调用syscall需要从寄存器收集两种参数: 21 | + `num` : 系统调用号 22 | + `args` : 具体某一系统调用的参数 23 | 24 | ```rust 25 | async fn handle_syscall(thread: &CurrentThread, regs: &mut GeneralRegs) { 26 | #[cfg(target_arch = "x86_64")] 27 | let num = regs.rax as u32; 28 | #[cfg(target_arch = "aarch64")] 29 | let num = regs.x16 as u32; 30 | // LibOS: Function call ABI 31 | #[cfg(feature = "std")] 32 | #[cfg(target_arch = "x86_64")] 33 | let args = unsafe { 34 | let a6 = (regs.rsp as *const usize).read(); 35 | let a7 = (regs.rsp as *const usize).add(1).read(); 36 | [ 37 | regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9, a6, a7, 38 | ] 39 | }; 40 | // RealOS: Zircon syscall ABI 41 | #[cfg(not(feature = "std"))] 42 | #[cfg(target_arch = "x86_64")] 43 | let args = [ 44 | regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9, regs.r12, regs.r13, 45 | ]; 46 | // ARM64 47 | #[cfg(target_arch = "aarch64")] 48 | let args = [ 49 | regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5, regs.x6, regs.x7, 50 | ]; 51 | let mut syscall = Syscall { 52 | regs, 53 | thread, 54 | thread_fn, 55 | }; 56 | let ret = syscall.syscall(num, args).await as usize; 57 | #[cfg(target_arch = "x86_64")] 58 | { 59 | syscall.regs.rax = ret; 60 | } 61 | #[cfg(target_arch = "aarch64")] 62 | { 63 | syscall.regs.x0 = ret; 64 | } 65 | } 66 | 67 | ``` 68 | 69 | 70 | 71 | ## 系统调用上下文与处理函数 72 | 73 | ### 定义 Syscall 结构体 74 | 75 | 保存上下文信息 76 | 77 | > zCore/zircon-syscall/src/lib.rs#L52 78 | 79 | ```rust 80 | /// 系统调用的结构(存储关于创建系统调用的信息) 81 | pub struct Syscall<'a> { 82 | /// store the regs statues 83 | pub regs: &'a mut GeneralRegs, 84 | /// the thread making a syscall 85 | pub thread: &'a CurrentThread, 86 | /// new thread function 87 | pub thread_fn: ThreadFn, 88 | } 89 | ``` 90 | 91 | ### 实现 syscall 函数 92 | 93 | > zCore/zircon-syscall/src/lib.rs#L59 94 | 95 | 1. 检查系统调用号`sys_type`是否合法 96 | 2. 获取传递给具体某一系统调用的参数`args` 97 | 3. 若syscall函数输入的系统调用号合法,则进一步根据系统调用号匹配具体系统调用处理函数 98 | 4. 传入对应系统调用所需的参数,并运行之 99 | 5. 检查系统调用的返回值`ret`是否符合预期 100 | 101 | ```rust 102 | pub async fn syscall(&mut self, num: u32, args: [usize; 8]) -> isize { 103 | 104 | ... 105 | 106 | // 1. 检查系统调用号`sys_type`是否合法 107 | let sys_type = match Sys::try_from(num) { 108 | Ok(t) => t, 109 | Err(_) => { 110 | error!("invalid syscall number: {}", num); 111 | return ZxError::INVALID_ARGS as _; 112 | } 113 | }; 114 | 115 | ... 116 | 117 | // 2. 获取传递给具体系统调用参数 118 | let [a0, a1, a2, a3, a4, a5, a6, a7] = args; 119 | 120 | // 3. 若syscall函数输入的系统调用号合法 121 | // 则进一步根据系统调用号匹配具体系统调用处理函数 122 | 123 | let ret = match sys_type { 124 | 125 | // 4. 传入对应系统调用所需的参数,并运行之 126 | Sys::HANDLE_CLOSE => self.sys_handle_close(a0 as _), 127 | Sys::HANDLE_CLOSE_MANY => self.sys_handle_close_many(a0.into(), a1 as _), 128 | Sys::HANDLE_DUPLICATE => self.sys_handle_duplicate(a0 as _, a1 as _, a2.into()), 129 | Sys::HANDLE_REPLACE => self.sys_handle_replace(a0 as _, a1 as _, a2.into()), 130 | 131 | ... 132 | // 更多系统调用匹配的分支 133 | Sys::CLOCK_GET => self.sys_clock_get(a0 as _, a1.into()), 134 | Sys::CLOCK_READ => self.sys_clock_read(a0 as _, a1.into()), 135 | Sys::CLOCK_ADJUST => self.sys_clock_adjust(a0 as _, a1 as _, a2 as _), 136 | Sys::CLOCK_UPDATE => self.sys_clock_update(a0 as _, a1 as _, a2.into()), 137 | Sys::TIMER_CREATE => self.sys_timer_create(a0 as _, a1 as _, a2.into()), 138 | 139 | ... 140 | }; 141 | 142 | ... 143 | 144 | // 5. 检查系统调用的返回值`ret`是否符合预期 145 | match ret { 146 | Ok(_) => 0, 147 | Err(err) => err as isize, 148 | } 149 | } 150 | ``` 151 | 152 | 153 | 系统调用号匹配信息位于 154 | > zCore/zircon-syscall/src/consts.rs#L8 155 | ```rust 156 | pub enum SyscallType { 157 | BTI_CREATE = 0, 158 | BTI_PIN = 1, 159 | BTI_RELEASE_QUARANTINE = 2, 160 | CHANNEL_CREATE = 3, 161 | CHANNEL_READ = 4, 162 | CHANNEL_READ_ETC = 5, 163 | CHANNEL_WRITE = 6, 164 | CHANNEL_WRITE_ETC = 7, 165 | CHANNEL_CALL_NORETRY = 8, 166 | CHANNEL_CALL_FINISH = 9, 167 | CLOCK_GET = 10, 168 | CLOCK_ADJUST = 11, 169 | CLOCK_GET_MONOTONIC_VIA_KERNEL = 12, 170 | 171 | ... 172 | 173 | VMO_CREATE_CONTIGUOUS = 165, 174 | VMO_CREATE_PHYSICAL = 166, 175 | COUNT = 167, 176 | FUTEX_WAKE_HANDLE_CLOSE_THREAD_EXIT = 200, 177 | VMAR_UNMAP_HANDLE_CLOSE_THREAD_EXIT = 201, 178 | } 179 | ``` 180 | 181 | 182 | 183 | ### 简单实现一个系统调用处理函数(`sys_clock_adjust`为例) 184 | 185 | ```rust 186 | pub fn sys_clock_adjust(&self, resource: HandleValue, clock_id: u32, offset: u64) -> ZxResult { 187 | 188 | // 1. 记录log信息:info!() 189 | info!( 190 | "clock.adjust: resource={:#x?}, id={:#x}, offset={:#x}", 191 | resource, clock_id, offset 192 | ); 193 | 194 | // 2. 检查参数合法性(需要归纳出每个系统调用的参数值的范围) 195 | // missing now 196 | 197 | // 3. 获取当前进程对象 198 | let proc = self.thread.proc(); 199 | 200 | // 4. 根据句柄从进程中获取对象 201 | proc.get_object::(resource)? 202 | .validate(ResourceKind::ROOT)?; 203 | match clock_id { 204 | ZX_CLOCK_MONOTONIC => Err(ZxError::ACCESS_DENIED), 205 | 206 | // 5. 调用内河对象API执行具体功能 207 | ZX_CLOCK_UTC => { 208 | UTC_OFFSET.store(offset, Ordering::Relaxed); 209 | Ok(()) 210 | } 211 | _ => Err(ZxError::INVALID_ARGS), 212 | } 213 | } 214 | ``` 215 | 216 | 217 | > 一个现有不完全的系统调用实现`sys_clock_get` 218 | 219 | ```rust 220 | /// Acquire the current time. 221 | /// 222 | /// + Returns the current time of clock_id via `time`. 223 | /// + Returns whether `clock_id` was valid. 224 | pub fn sys_clock_get(&self, clock_id: u32, mut time: UserOutPtr) -> ZxResult { 225 | // 记录log信息:info!() 226 | info!("clock.get: id={}", clock_id); 227 | // 检查参数合法性 228 | // miss 229 | 230 | match clock_id { 231 | ZX_CLOCK_MONOTONIC => { 232 | time.write(timer_now().as_nanos() as u64)?; 233 | Ok(()) 234 | } 235 | ZX_CLOCK_UTC => { 236 | time.write(timer_now().as_nanos() as u64 + UTC_OFFSET.load(Ordering::Relaxed))?; 237 | Ok(()) 238 | } 239 | ZX_CLOCK_THREAD => { 240 | time.write(self.thread.get_time())?; 241 | Ok(()) 242 | } 243 | _ => Err(ZxError::NOT_SUPPORTED), 244 | } 245 | } 246 | ``` 247 | -------------------------------------------------------------------------------- /src/ch05-00-signal-and-waiting.md: -------------------------------------------------------------------------------- 1 | # 信号和等待 2 | -------------------------------------------------------------------------------- /src/ch05-01-wait-signal.md: -------------------------------------------------------------------------------- 1 | # 等待内核对象的信号 2 | 3 | ## 信号与等待机制简介 4 | 5 | ## 在内核对象中加入信号 6 | 7 | > 定义 Signal 结构体 8 | > 9 | > 在 KObjectBase 中加入 signal 和 callbacks 变量,实现 signal 系列函数,并做单元测试 10 | 11 | ## 实现信号等待 Future 12 | 13 | > 实现 wait_signal 函数,并做单元测试 14 | 15 | ## 利用 select 组合子实现多对象等待 16 | 17 | > 实现 wait_signal_many 函数,并做单元测试 18 | -------------------------------------------------------------------------------- /src/ch05-02-port-object.md: -------------------------------------------------------------------------------- 1 | # 同时等待多个信号:Port 对象 2 | 3 | ## Port 对象简介 4 | 5 | > 同时提及一下 Linux 的 epoll 机制作为对比 6 | 7 | ## 实现 Port 对象框架 8 | 9 | > 定义 Port 和 PortPacket 结构体 10 | 11 | ## 实现事件推送和等待 12 | 13 | > 实现 KernelObject::send_signal_to_port 和 Port::wait 函数,并做单元测试 14 | -------------------------------------------------------------------------------- /src/ch05-03-more-signal-objects.md: -------------------------------------------------------------------------------- 1 | # 实现更多:EventPair, Timer 对象 2 | 3 | ## Event 对象 4 | 5 | ## EventPair 对象 6 | 7 | ## HAL:定时器 8 | 9 | > 实现 timer_now, timer_set,在此基础上实现 SleepFuture 10 | 11 | ## Timer 对象 12 | -------------------------------------------------------------------------------- /src/ch05-04-futex-object.md: -------------------------------------------------------------------------------- 1 | # 用户态同步互斥:Futex 对象 2 | 3 | ## Futex 机制简介 4 | 5 | > Futex 是现代 OS 中用户态同步互斥的唯一底层设施 6 | > 7 | > 为什么快:利用共享内存中的原子变量,避免进入内核 8 | 9 | ## 实现基础元语:wait 和 wake 10 | 11 | > 实现 wait 和 wake 函数,并做单元测试 12 | 13 | ## 实现高级操作 14 | 15 | > 实现 Zircon 中定义的复杂 API 16 | -------------------------------------------------------------------------------- /src/fuchsia-sec.md: -------------------------------------------------------------------------------- 1 | # Fuchsia OS 安全性 2 | 3 | ### 1. a “safe stack" and an "unsafe stack"? 4 | 5 | ### 2. random number generator 6 | -------------------------------------------------------------------------------- /src/fuchsia.md: -------------------------------------------------------------------------------- 1 | # Fuchsia OS 和 Zircon 微内核 2 | 3 | ![logo](../img/Google-Fuschia-Operating-System-logo.jpg) 4 | 5 | ## Fuchsia 6 | 7 | [开发 Fuchsia 的目的](https://www.digitaltrends.com/mobile/google-fuchsia-os-news/) 8 | 9 | Fuchsia 是谷歌试图使用单一操作系统去统一整个生态圈的一种尝试。Fuchsia 的目标是能够在谷歌的技术保护伞下,运行于智能手机、智能音响、笔记本电脑等任何合适的设备之上,同时为关键业务应用的生产设备和产品提供动力,因此Fuchsia并不是一个简单意义上实验操作系统概念研究的小试验场。据某消息人士透露,谷歌计划在未来三年内,先让 Fuchsia 在智能音响和其他智能家具设备上运行起来,然后再转移到笔记本电脑等更大的设备上,并最终取代 Android 成为世界上最大的移动操作系统。 10 | 11 | 12 | ## Fuchsia OS 13 | 14 | [Fuchsia 操作系统的四层结构设计:](https://fuchsia-china.com/the-4-layers-of-fuchsia/) 15 | ![Fuchsia 操作系统的四层结构设计](../img/Fuchsia%20操作系统的四层结构设计.png) 16 | 17 | Fuchsia作为一款为性能而生的开源操作系统,它的安全性和可更新性都得到了充分的考虑。 18 | 19 | #### Fuchsia的性能优化设计 20 | 21 | 1. Fuchsia大量使用了异步通信(asynchronous communication),通过让发送方在不等待接收方的情况下继续运行,从而减少了延迟。 22 | 2. 通过避免核心操作系统中的垃圾收集(garbage collection,GC),Fuchsia优化了内存使用,这有助于在实现同等的性能的情况下,最小化内存需求。 23 | 24 | #### Fuchsia的安全性 25 | 26 | Fuchsia主推安全和隐私。运行在Fuchsia上的应用程序没有环境权限:应用程序只能与它们被显式授予访问权限的对象进行交互。且Fuchsia中的软件是在封闭的组件包中交付的,所有的东西都基于沙箱(Sandbox)。这意味着该系统上运行的所有软件,包括应用程序和系统组件,都能获得执行其工作所需的最低权限,并且只能访问它需要知道的信息。 27 | 28 | #### Fuchsia的可更新性 29 | Fuchsia的运行基于所提供的各组件包/软件包(packaged components)。 30 | 1. Fuchsia软件包被设计为独立更新,甚至是临时交付的形式。这意味着Fuchsia软件运行所需要的依赖包可以即时获得,就像一个网页,总是最新的。 31 | 2. Fuchsia目标为驱动程序提供稳定的二进制接口。在未来,为旧版本Fuchsia编译的驱动程序在后续推出的新版本Fuchsia中将继续工作,而不需要修改甚至重新编译。这意味着Fuchsia设备将能够在保持现有驱动程序的同时无缝地更新到最新版本的Fuchsia。 32 | 33 | 34 | ## Fuchsia:Zircon Kernel 35 | Fuchsia不使用Linux内核。相反,Fuchsia有自己的内核,即Zircon。Zircon由一个微内核以及一组用户空间服务、驱动程序和库组成。Fuchsia将POSIX规范的一部分(不是全部)作为底层内核原语之上库的实现,这些原语侧重于安全消息传递和内存管理。许多核心系统服务,比如文件系统和网络,这些服务在内核之外运行时尽量满足最小特权原则,如提供了沙箱隔离机制... 36 | 37 | Zircon内核提供系统调用来管理进程、线程、虚拟内存、进程间通信、等待对象状态变化和锁定(通过futexes)。 38 | 39 | > 目前,有一些临时的系统调用已经用于早期的升级工作,随着长期`syscall API`和`ABI surface`的最终完善,这些临时系统调用将在未来被删除。 40 | 41 | 如下仓库链接中,这是由参与[2019年操作系统专题训练大实验-Fuchsia OS调研](http://os.cs.tsinghua.edu.cn/oscourse/OsTrain2019/g1)的成员整理出的一版可独立存在的zircon代码,并可能减小仓库体积。[[仓库链接]](https://github.com/PanQL/zircon) 42 | 43 | > 一些典型Zircon内核模块提供的功能 44 | #### 运行代码: Jobs, Processes 和 Threads. 45 | 线程代表在一个地址空间中执行的线程(CPU寄存器、堆栈等),这个地址空间是由它们存在的进程所拥有的。进程由作业(Job)所拥有,作业定义了各种资源限制。Job属于父Job,一直到根Job,根Job是由内核在引导时创建的,并被传递到userboot(第一个开始执行的用户空间进程)。程序的加载则是由内核层之上的用户空间工具和协议提供的。 46 | 47 | > 如果没有Job句柄,进程中的线程就不可能创建另一个进程或另一个Job。 48 | 49 | #### 信息传递机制:Sockets and Channels 50 | 51 | `Socket`和`Channel`都是两端点间双向的IPC对象。创建`Socket`或`Channel`将返回两个句柄 52 | 53 | + `Socket`是面向流的,数据可以从中以一个或多个字节的单位写入或读出 54 | 55 | + `Channel`是面向数据报文的,其最大消息大小由`ZX_CHANNEL_MAX_MSG_BYTES`给出,并且还可能有多达`ZX_CHANNEL_MAX_MSG_HANDLES`个附加到消息的句柄。 56 | 57 | #### 虚拟内存对象:VMOs 58 | 59 | 虚拟内存对象(VMO)表示内存的一组物理页面,或者潜在的页面(这些页面将按需迟滞性地被创建或填充)。VMOs也可以通过`sys_vmo_read()`和`sys_vmo_write()`直接读取和写入。因此可以避免类似“创建VMO,将数据集写入其中,并将其交给另一个进程使用”这样的一次性操作,从而增加运行时的开销。 60 | 61 | #### 内存管理机制:Address Space Management 62 | 63 | 虚拟地址空间(VMARs)提供了一个管理进程地址空间的抽象。在进程创建时,可实现向进程创建者提供根VMAR的句柄。该句柄引用了一个`VMAR`,它跨越了整个地址空间。这个空间可以通过`zx_vmar_map()`和`zx_vmar_allocate()`系统调用接口进行划分。`zx_vmar_allocate()`可用于生成新的`VMARs`(称为子区域),这些子VMARs可将部分地址空间继续组合。 64 | 65 | 66 | 67 | ## 参考资料: 68 | 1. Fuchsia Overview: 69 | https://fuchsia.dev/fuchsia-src/concepts 70 | 71 | 2. 开发 Fuchsia 的目的是什么? 72 | https://www.digitaltrends.com/mobile/google-fuchsia-os-news/ 73 | 74 | 3. Fuchsia 操作系统的四层结构设计: 75 | https://fuchsia-china.com/the-4-layers-of-fuchsia/ 76 | 77 | 78 | ## Fuchsia Partner 79 | 80 | + ARM 81 | + GlobalEdge Software 82 | + Huawei 83 | + Imagination Technologies 84 | + MediaTek 85 | + Oppo 86 | + Qualcomm 87 | + Samsung 88 | + Sharp 89 | + Sony 90 | + STMicro 91 | + Unisoc 92 | + Xiaomi -------------------------------------------------------------------------------- /src/zcore-intro.md: -------------------------------------------------------------------------------- 1 | # zCore 整体结构和设计模式 2 | 3 | 首先,从 [Rust语言操作系统的设计与实现,王润基本科毕设论文,2019](https://github.com/rcore-os/zCore/wiki/files/wrj-thesis.pdf) 和 [zCore操作系统内核的设计与实现,潘庆霖本科毕设论文,2020](https://github.com/rcore-os/zCore/wiki/files/pql-thesis.pdf) 可以了解到从 rCore 的设计到 zCore 的设计过程的全貌。 4 | 5 | ## zCore 的整体结构 6 | 7 | [zCore](https://github.com/rcore-os/zCore) 的整体结构/项目设计图如下: 8 | 9 | ![img](zcore-intro/structure.svg) 10 | 11 | zCore的设计主要有两个出发点: 12 | 13 | - 内核对象的封装:将内核对象代码封装为一个库,保证可重用 14 | - 硬件接口的设计:使硬件与内核对象的设计相对独立,只向上提供统一、抽象的API接口 15 | 16 | 项目设计从上到下,上层更远离硬件,下层更接近硬件。 17 | 18 | zCore 设计的顶层是上层操作系统,比如 zCore、rCore、Zircon LibOS 和 Linux LibOS。在项目架构中,各版本的操作系统有部分公用代码。与 zCore 微内核设计实现相关的部分则主要是图中左侧蓝色线部分。 19 | 20 | 第二层,是 ELF 程序加载层(ELF Program Loader),包括 zircon-loader 和 linux-loader,其中封装了初始化内核对象、部分硬件相关的初始化、设定系统调用接口、运行首个用户态程序等逻辑,并形成一个库函数。zCore 在顶层通过调用 zircon-loader 库中的初始化逻辑,进入第一个用户态程序执行。 21 | 22 | 第三层,是系统调用实现层(Syscall Implementation),包括 zircon-syscall 和 linux-syscall,这一层将所有的系统调用处理例程封装为一个系统调用库,供上方操作系统使用。 23 | 24 | 第四层,利用硬件抽象层提供的虚拟硬件 API 进行内核对象(Kernel Objects)的实现,并且基于实现的各类内核对象,实现第三层各个系统调用接口所需要的具体处理例程。 25 | 26 | 第五层,是硬件抽象层(HAL,Hardware Abstraction Layer),这里对应的是 kernel-hal 模块。kernel-hal 将向上提供所有操作硬件需要的接口,从而使得硬件环境对上层操作系统透明化。 27 | 28 | 第六层,是对直接操作硬件的代码进行一层封装,对应模块为 kernel-hal-bare 和 kernel-hal-unix。kernel-hal 系列库仅仅负责接口定义,即将底层硬件/宿主操作系统的操作翻译为上层操作系统可以使用的形式。在这里,kernel-hal-bare 负责翻译裸机的硬件功能,而 kernel-hal-unix 则负责翻译类 Unix 系统的系统调用。 29 | 30 | 最底层是底层运行环境,包括 Bare Metal(裸机),Linux / macOS 操作系统。Bare Metal可以认为是硬件架构上的寄存器等硬件接口。 31 | 32 | ## zCore 内核组件 33 | 34 | zCore 内核运行时组件层次概况如下: 35 | 36 | ![image-20200805123801306](zcore-intro/image-20200805123801306.png) 37 | 38 | 在zCore启动过程中,会初始化物理页帧分配器、堆分配器、线程调度器等各个组成部分。并委托 zircon-­loader 进行内核对象的初始化创建过程,然后进入用户态的启动过程开始执行。每当用户态触发系统调用进入内核态,系统调用处理例程将会通过已实现的内核对象的功能来对服务请求进行处理;而对应的内核对象的内部实现所需要的各种底层操作,则是通过 HAL 层接口由各个内核组件负责提供。 39 | 40 | 其中,VDSO(Virtual dynamic shared object)是一个映射到用户空间的 so 文件,可以在不陷入内核的情况下执行一些简单的系统调用。在设计中,所有中断都需要经过 VDSO 拦截进行处理,因此重写 VDSO 便可以实现自定义的对下层系统调用(syscall)的支持。Executor 是 zCore 中基于 Rust 的 `async` 机制的协程调度器。 41 | 42 | 在HAL接口层的设计上,还借助了 Rust 的能够指定函数链接过程的特性。即,在 kernel-­hal 中规定了所有可供 zircon­-object 库及 zircon-­syscall 库调用的虚拟硬件接口,以函数 API 的形式给出,但是内部均为未实现状态,并设置函数为弱引用链接状态。在 kernel­-hal-­bare 中才给出裸机环境下的硬件接口具体实现,编译 zCore 项目时、链接的过程中将会替换/覆盖 kernel-­hal 中未实现的同名接口,从而达到能够在编译时灵活选择 HAL 层的效果。 -------------------------------------------------------------------------------- /src/zcore-intro/image-20200805123801306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zcore_tutorial_developers/0c35b105fe09626b12d239eca331bdd4f9b9b272/src/zcore-intro/image-20200805123801306.png -------------------------------------------------------------------------------- /src/zcore-intro/structure.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
kernel-hal
kernel-hal
zircon-object
zircon-object
linux-object
linux-object
zircon-syscall
zircon-syscall
linux-syscall
linux-syscall
kernel-hal-bare
kernel-hal-bare
kernel-hal-unix
kernel-hal-unix
zircon-loader
zircon-loader
zCore
zCore
rCore
rCore
Zircon LibOS
Zircon LibOS
Linux LibOS
Linux LibOS
linux-loader
linux-loader
ELF Program Loader
ELF Program Loader
Syscall Implementation
Syscall Implementation
Kernel Objects
Kernel Objects
Hardware Abstraction Layer
Hardware Abstraction Layer
HAL Implementation
HAL Implementation
Bare Metal
Bare Metal
Linux / macOS
Linux / macOS
--------------------------------------------------------------------------------