├── .github └── workflows │ ├── deploy.yml │ └── main.yml ├── .gitignore ├── README.md ├── code ├── .gitignore ├── Cargo.toml ├── ch01-01 │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── object │ │ ├── mod.rs │ │ └── object_v1.rs ├── ch01-02 │ ├── Cargo.toml │ └── src │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ └── task │ │ ├── mod.rs │ │ └── process.rs ├── ch01-03 │ ├── Cargo.toml │ └── src │ │ ├── error.rs │ │ ├── ipc │ │ ├── channel.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ └── task │ │ ├── mod.rs │ │ └── process.rs ├── ch02-02 │ ├── Cargo.toml │ └── src │ │ ├── error.rs │ │ ├── ipc │ │ ├── channel.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ ├── task │ │ ├── job.rs │ │ ├── job_policy.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ └── thread.rs │ │ └── vm │ │ ├── mod.rs │ │ └── vmar.rs ├── ch02-03 │ ├── Cargo.toml │ ├── kernel-hal-unix │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── kernel-hal │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── object │ │ ├── Cargo.toml │ │ └── src │ │ ├── error.rs │ │ ├── ipc │ │ ├── channel.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ ├── task │ │ ├── job.rs │ │ ├── job_policy.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ ├── thread.rs │ │ └── thread │ │ │ └── thread_state.rs │ │ └── vm │ │ ├── mod.rs │ │ └── vmar.rs ├── ch03-02 │ ├── Cargo.toml │ ├── kernel-hal-unix │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── kernel-hal │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── object │ │ ├── Cargo.toml │ │ └── src │ │ ├── error.rs │ │ ├── ipc │ │ ├── channel.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ ├── task │ │ ├── job.rs │ │ ├── job_policy.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ ├── thread.rs │ │ └── thread │ │ │ └── thread_state.rs │ │ ├── util.rs │ │ └── vm │ │ ├── mod.rs │ │ ├── vmar.rs │ │ └── vmo │ │ ├── mod.rs │ │ ├── paged.rs │ │ ├── physical.rs │ │ └── slice.rs ├── ch03-04 │ ├── Cargo.toml │ ├── kernel-hal-unix │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── kernel-hal │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── object │ │ ├── Cargo.toml │ │ └── src │ │ ├── error.rs │ │ ├── ipc │ │ ├── channel.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ ├── task │ │ ├── job.rs │ │ ├── job_policy.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ ├── thread.rs │ │ └── thread │ │ │ └── thread_state.rs │ │ ├── util.rs │ │ └── vm │ │ ├── mod.rs │ │ ├── vmar.rs │ │ └── vmo │ │ ├── mod.rs │ │ ├── paged.rs │ │ ├── physical.rs │ │ └── slice.rs ├── ch04-01 │ ├── Cargo.toml │ ├── kernel-hal-unix │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── kernel-hal │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── dummy.rs │ │ │ ├── lib.rs │ │ │ └── vdso.rs │ ├── prebuilt │ │ └── zircon │ │ │ └── x64 │ │ │ ├── Scrt1.o │ │ │ ├── bringup.zbi │ │ │ ├── core-tests.zbi │ │ │ ├── libc.so │ │ │ ├── libfdio.so │ │ │ ├── libunwind.so │ │ │ ├── libzircon-libos.so │ │ │ ├── libzircon.so │ │ │ ├── userboot-libos.so │ │ │ ├── userboot.so │ │ │ ├── zbi-linux │ │ │ └── zbi-macos │ ├── zircon-loader │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── kcounter.rs │ │ │ ├── lib.rs │ │ │ └── main.rs │ └── zircon-object │ │ ├── Cargo.toml │ │ └── src │ │ ├── dev │ │ ├── mod.rs │ │ └── resource.rs │ │ ├── error.rs │ │ ├── ipc │ │ ├── channel.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── object │ │ ├── handle.rs │ │ ├── mod.rs │ │ └── rights.rs │ │ ├── task │ │ ├── job.rs │ │ ├── job_policy.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ ├── thread.rs │ │ └── thread │ │ │ └── thread_state.rs │ │ ├── util │ │ ├── block_range.rs │ │ ├── elf_loader.rs │ │ └── mod.rs │ │ └── vm │ │ ├── mod.rs │ │ ├── vmar.rs │ │ └── vmo │ │ ├── mod.rs │ │ ├── paged.rs │ │ ├── physical.rs │ │ └── slice.rs ├── ch04-03 │ ├── Cargo.toml │ ├── kernel-hal-unix │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── kernel-hal │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── dummy.rs │ │ │ ├── lib.rs │ │ │ ├── user.rs │ │ │ └── vdso.rs │ ├── prebuilt │ │ └── zircon │ │ │ └── x64 │ │ │ ├── Scrt1.o │ │ │ ├── bringup.zbi │ │ │ ├── core-tests.zbi │ │ │ ├── libc.so │ │ │ ├── libfdio.so │ │ │ ├── libunwind.so │ │ │ ├── libzircon-libos.so │ │ │ ├── libzircon.so │ │ │ ├── userboot-libos.so │ │ │ ├── userboot.so │ │ │ ├── zbi-linux │ │ │ └── zbi-macos │ ├── zircon-loader │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── kcounter.rs │ │ │ ├── lib.rs │ │ │ └── main.rs │ ├── zircon-object │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── debuglog.rs │ │ │ ├── dev │ │ │ ├── mod.rs │ │ │ └── resource.rs │ │ │ ├── error.rs │ │ │ ├── ipc │ │ │ ├── channel.rs │ │ │ └── mod.rs │ │ │ ├── lib.rs │ │ │ ├── object │ │ │ ├── handle.rs │ │ │ ├── mod.rs │ │ │ └── rights.rs │ │ │ ├── task │ │ │ ├── job.rs │ │ │ ├── job_policy.rs │ │ │ ├── mod.rs │ │ │ ├── process.rs │ │ │ ├── thread.rs │ │ │ └── thread │ │ │ │ └── thread_state.rs │ │ │ ├── util │ │ │ ├── block_range.rs │ │ │ ├── elf_loader.rs │ │ │ └── mod.rs │ │ │ └── vm │ │ │ ├── mod.rs │ │ │ ├── vmar.rs │ │ │ └── vmo │ │ │ ├── mod.rs │ │ │ ├── paged.rs │ │ │ ├── physical.rs │ │ │ └── slice.rs │ └── zircon-syscall │ │ ├── Cargo.toml │ │ ├── build.rs │ │ └── src │ │ ├── channel.rs │ │ ├── consts.rs │ │ ├── debuglog.rs │ │ ├── lib.rs │ │ └── zx-syscall-numbers.h └── rust-toolchain └── docs ├── .gitignore ├── book.toml └── src ├── 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-context-switch.md ├── ch04-03-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 ├── ch06-00-hal.md ├── ch06-01-zcore-hal-unix.md ├── fuchsia.md ├── img ├── ch01-01-kernel-object.png └── mmap.png ├── zcore-intro.md └── zcore-intro ├── image-20200805123801306.png └── structure.svg /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Setup mdBook 14 | uses: peaceiris/actions-mdbook@v1 15 | with: 16 | mdbook-version: 'latest' 17 | - name: Build mdbook 18 | run: mdbook build docs 19 | - name: Deploy 20 | uses: peaceiris/actions-gh-pages@v3 21 | with: 22 | github_token: ${{ secrets.GITHUB_TOKEN }} 23 | publish_dir: ./docs/book 24 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | check: 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions-rs/toolchain@v1 14 | with: 15 | profile: minimal 16 | toolchain: nightly-2021-07-27 17 | override: true 18 | components: rustfmt, clippy 19 | - name: Check code format 20 | run: | 21 | cd code 22 | cargo fmt --all -- --check 23 | cd ch02-03 24 | cargo fmt --all -- --check 25 | cd ../ch03-02 26 | cargo fmt --all -- --check 27 | cd ../ch03-04 28 | cargo fmt --all -- --check 29 | cd ../ch04-01 30 | cargo fmt --all -- --check 31 | cd ../ch04-03 32 | cargo fmt --all -- --check 33 | # uses: actions-rs/cargo@v1 34 | # with: 35 | # command: fmt 36 | # args: --all -- --check 37 | - name: Clippy 38 | run: | 39 | cd code 40 | cargo clippy 41 | cd ch02-03 42 | cargo clippy 43 | cd ../ch03-02 44 | cargo clippy 45 | cd ../ch03-04 46 | cargo clippy 47 | cd ../ch04-01 48 | cargo clippy 49 | cd ../ch04-03 50 | cargo clippy 51 | # uses: actions-rs/cargo@v1 52 | # with: 53 | # command: clippy 54 | build: 55 | runs-on: ${{ matrix.os }} 56 | strategy: 57 | matrix: 58 | os: [ubuntu-20.04] 59 | # os: [ubuntu-20.04, macos-latest] 60 | steps: 61 | - uses: actions/checkout@v2 62 | with: 63 | submodules: 'recursive' 64 | - uses: actions-rs/toolchain@v1 65 | with: 66 | profile: minimal 67 | toolchain: nightly-2021-07-27 68 | components: rust-src 69 | - name: Build 70 | run: | 71 | cd code 72 | cargo build 73 | cd ch02-03 74 | cargo build 75 | cd ../ch03-02 76 | cargo build 77 | cd ../ch03-04 78 | cargo build 79 | cd ../ch04-01 80 | cargo build 81 | cd ../ch04-03 82 | cargo build 83 | # uses: actions-rs/cargo@v1 84 | # with: 85 | # command: build 86 | test: 87 | runs-on: ${{ matrix.os }} 88 | strategy: 89 | matrix: 90 | os: [ubuntu-20.04] 91 | # os: [ubuntu-20.04, macos-latest] 92 | steps: 93 | - uses: actions/checkout@v2 94 | with: 95 | submodules: 'recursive' 96 | - uses: actions-rs/toolchain@v1 97 | with: 98 | profile: minimal 99 | toolchain: nightly-2021-07-27 100 | components: rust-src 101 | - name: Test 102 | run: | 103 | cd code 104 | cargo test 105 | cd ch02-03 106 | cargo test 107 | cd ../ch03-02 108 | cargo test 109 | cd ../ch03-04 110 | cargo test 111 | cd ../ch04-01 112 | cargo test 113 | cd ../ch04-03 114 | cargo test 115 | doc: 116 | runs-on: ${{ matrix.os }} 117 | strategy: 118 | matrix: 119 | os: [ubuntu-20.04] 120 | # os: [ubuntu-20.04, macos-latest] 121 | steps: 122 | - uses: actions/checkout@v2 123 | with: 124 | submodules: 'recursive' 125 | - uses: actions-rs/toolchain@v1 126 | with: 127 | profile: minimal 128 | toolchain: nightly-2021-07-27 129 | components: rust-src 130 | - name: Build docs 131 | run: | 132 | cd code 133 | cargo doc --no-deps --all-features 134 | cd ch02-03 135 | cargo doc --no-deps --all-features 136 | cd ../ch03-02 137 | cargo doc --no-deps --all-features 138 | cd ../ch03-04 139 | cargo doc --no-deps --all-features 140 | cd ../ch04-01 141 | cargo doc --no-deps --all-features 142 | cd ../ch04-03 143 | cargo doc --no-deps --all-features 144 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Editor 2 | *.swp 3 | *.swo 4 | Session.vim 5 | .cproject 6 | .idea 7 | *.iml 8 | .vscode 9 | .project 10 | .favorites.json 11 | .settings/ 12 | # Generated by Cargo 13 | # will have compiled files and executables 14 | debug/ 15 | target/ 16 | 17 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 18 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 19 | Cargo.lock 20 | 21 | # These are backup files generated by rustfmt 22 | **/*.rs.bk 23 | 24 | # MSVC Windows builds of rustc generate these, which store debugging information 25 | *.pdb 26 | 27 | ## File system 28 | .DS_Store 29 | desktop.ini 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zCore Tutorial 2 | 3 | [![CI](https://github.com/rcore-os/zCore-Tutorial/workflows/CI/badge.svg?branch=master)](https://github.com/rcore-os/zCore-Tutorial/actions) 4 | [![Docs](https://img.shields.io/badge/docs-alpha-blue)](https://rcore-os.github.io/zCore-Tutorial/) 5 | 6 | zCore Toturial 的目标是通过`step by step`地建立一个简化的zCore kernel的过程来学习和掌握zCore Kernel的核心概念和对应实现,从而为进一步分析掌握zCore的完整内核打下基础。 7 | 8 | zCore Toturial 的特点是所有的code都在用户态运行,便于调试和分析。 9 | 10 | ## 仓库目录 11 | 12 | * `docs/`: 教学实验指导 13 | * `code`: 操作系统代码 14 | 15 | ## 实验指导 16 | 17 | 基于 mdBook,目前目前已经部署到了 [GitHub Pages](https://rcore-os.github.io/zCore-Tutorial/) 上面。 18 | 19 | ### 文档本地使用方法 20 | 21 | ```bash 22 | git clone https://github.com/rcore-os/zCore-Tutorial.git 23 | cd zCore-Tutorial 24 | cargo install mdbook 25 | mdbook serve docs 26 | ``` 27 | 28 | ## code 29 | `code`目录下的`rust-toolchain`内容为`nightly-2021-07-27`。原则上,我们会采用`rustc`最新的版本。目前的版本信息如下: 30 | ``` 31 | rustc 1.56.0-nightly (08095fc1f 2021-07-26) 32 | ``` 33 | 34 | ## 学习顺序建议 35 | 36 | ### 初步了解 37 | 38 | 1. 阅读有关fuchsia/zircon的概述/简介文章,如 https://zh.wikipedia.org/zh-hans/Google_Fuchsia 39 | 40 | 2. 阅读 https://fuchsia.dev/fuchsia-src/concepts/kernel 了解zircon基本思想 41 | 42 | 3. 阅读潘庆霖毕设论文前两章,了解zCore的基本思想 43 | 44 | ### 逐渐深入 45 | 1. 阅读 https://fuchsia.dev/fuchsia-src/reference/syscalls 了解应用程序对Kernel的需求 46 | 2. 阅读 https://fuchsia.dev/fuchsia-src/reference/kernel_objects/objects 了解Kernel中各种object的含义和行为 47 | 48 | ### 理解设计实现 49 | 50 | 1. 阅读&分析本项目中的文档和代码,并对照上面的kernel概念,了解kernel概念和设计实现的对应关系 51 | 52 | ### 动手实践 53 | 54 | 1. 在分析和理解的基础上,改进本项目对应章节的文档 55 | 56 | 2. 在分析和理解的基础上,改进/优化本项目的代码,增加测试用例,增加功能 57 | 58 | 3. 在大致掌握本项目后,通过进一步理解和改进zCore,对zCore等新型操作系统有很好的感悟,提升自身实践能力 59 | 60 | 61 | 62 | #### code/ch04-xx的相关提示 63 | - 推荐运行方式: 在 `ch04-0x` 目录下: `RUST_LOG=info cargo run -p zircon-loader -- /prebuilt/zircon/x64` 64 | - ch4 会执行 zircon prebuilt 中的 userboot 程序,详见[userboot源码](https://github.com/vsrinivas/fuchsia/tree/master/zircon/kernel/lib/userabi/userboot),[fuchsia启动流程](https://fuchsia.dev/fuchsia-src/concepts/booting/userboot?hl=en)。 65 | - `ch04-01` 并未实现任何 syscall。因此进入 userboot 后会在第一次 syscall 返回到内核态时 panic 退出。 66 | - `ch04-03` 实现了与 `channel` 和 `debuglog` 有关的部分 syscall,会执行 3 次 syscall 之后由于不支持 process_exit 而退出。 67 | 68 | 69 | 70 | ## 参考 71 | 72 | - https://fuchsia.dev/ 73 | - https://fuchsia.dev/fuchsia-src/concepts/kernel 74 | - https://fuchsia.dev/fuchsia-src/reference/kernel_objects/objects 75 | - https://fuchsia.dev/fuchsia-src/reference/syscalls 76 | - https://github.com/zhangpf/fuchsia-docs-zh-CN/tree/master/zircon 77 | - [许中兴博士演讲:Fuchsia OS 简介](https://xuzhongxing.github.io/201806fuchsia.pdf) 78 | 79 | - 毕设论文 80 | - [Rust语言操作系统的设计与实现,王润基本科毕设论文,2019](https://github.com/rcore-os/zCore/wiki/files/wrj-thesis.pdf) 81 | - [zCore操作系统内核的设计与实现,潘庆霖本科毕设论文,2020](https://github.com/rcore-os/zCore/wiki/files/pql-thesis.pdf) 82 | 83 | - 开发文档 84 | - https://github.com/rcore-os/zCore/wiki/documents-of-zcore 85 | 86 | - 更简单和基础的[rCore-Tutorial v3](https://rcore-os.github.io/rCore-Tutorial-Book-v3/):如果看不懂上面的内容,可以先看看这个教程。 87 | -------------------------------------------------------------------------------- /code/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .idea 4 | -------------------------------------------------------------------------------- /code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "ch01-01", 4 | "ch01-02", 5 | "ch01-03", 6 | "ch02-02", 7 | # "ch02-03", 8 | # "ch03-02", 9 | ] 10 | -------------------------------------------------------------------------------- /code/ch01-01/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ch01-01" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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 | # ANCHOR: spin 11 | spin = "0.7" 12 | # ANCHOR_END: spin 13 | # ANCHOR: downcast 14 | downcast-rs = { version = "1.2.0", default-features = false } 15 | # ANCHOR_END: downcast 16 | -------------------------------------------------------------------------------- /code/ch01-01/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | 5 | mod object; 6 | -------------------------------------------------------------------------------- /code/ch01-01/src/object/object_v1.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use super::{KernelObject, KoID, String}; 3 | 4 | // ANCHOR: dummy_def 5 | use spin::Mutex; 6 | 7 | /// 空对象 8 | #[derive(Debug)] 9 | pub struct DummyObject { 10 | id: KoID, 11 | inner: Mutex, 12 | } 13 | 14 | /// `DummyObject` 的内部可变部分 15 | #[derive(Default, Debug)] 16 | struct DummyObjectInner { 17 | name: String, 18 | } 19 | // ANCHOR_END: dummy_def 20 | 21 | // ANCHOR: dummy_new 22 | use alloc::sync::Arc; 23 | use core::sync::atomic::*; 24 | 25 | impl DummyObject { 26 | /// 创建一个新 `DummyObject` 27 | pub fn new() -> Arc { 28 | Arc::new(DummyObject { 29 | id: Self::new_koid(), 30 | inner: Default::default(), 31 | }) 32 | } 33 | 34 | /// 生成一个唯一的 ID 35 | fn new_koid() -> KoID { 36 | static NEXT_KOID: AtomicU64 = AtomicU64::new(1024); 37 | NEXT_KOID.fetch_add(1, Ordering::SeqCst) 38 | } 39 | } 40 | // ANCHOR_END: dummy_new 41 | 42 | // ANCHOR: dummy_impl 43 | impl KernelObject for DummyObject { 44 | fn id(&self) -> KoID { 45 | self.id 46 | } 47 | fn type_name(&self) -> &str { 48 | "DummyObject" 49 | } 50 | fn name(&self) -> String { 51 | self.inner.lock().name.clone() 52 | } 53 | fn set_name(&self, name: &str) { 54 | self.inner.lock().name = String::from(name); 55 | } 56 | } 57 | // ANCHOR_END: dummy_impl 58 | 59 | // ANCHOR: dummy_test 60 | #[cfg(test)] 61 | mod tests { 62 | use super::*; 63 | #[test] 64 | fn dummy_object() { 65 | let o1 = DummyObject::new(); 66 | let o2 = DummyObject::new(); 67 | assert_ne!(o1.id(), o2.id()); 68 | assert_eq!(o1.type_name(), "DummyObject"); 69 | assert_eq!(o1.name(), ""); 70 | o1.set_name("object1"); 71 | assert_eq!(o1.name(), "object1"); 72 | } 73 | } 74 | // ANCHOR_END: dummy_test 75 | 76 | #[cfg(test)] 77 | // ANCHOR: downcast_test 78 | #[test] 79 | fn downcast() { 80 | let dummy = DummyObject::new(); 81 | let object: Arc = dummy; 82 | let _result: Arc = object.downcast_arc::().unwrap(); 83 | } 84 | // ANCHOR_END: downcast_test 85 | -------------------------------------------------------------------------------- /code/ch01-02/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ch01-02" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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.7" 11 | downcast-rs = { version = "1.2.0", default-features = false } 12 | # ANCHOR: bitflags 13 | bitflags = "1.2" 14 | # ANCHOR_END: bitflags 15 | -------------------------------------------------------------------------------- /code/ch01-02/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | 5 | mod error; 6 | mod object; 7 | mod task; 8 | -------------------------------------------------------------------------------- /code/ch01-02/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | /// 内核对象句柄 6 | #[derive(Clone)] 7 | pub struct Handle { 8 | pub object: Arc, 9 | pub rights: Rights, 10 | } 11 | 12 | impl Handle { 13 | /// 创建一个新句柄 14 | pub fn new(object: Arc, rights: Rights) -> Self { 15 | Handle { object, rights } 16 | } 17 | } 18 | // ANCHOR_END: handle 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | use crate::object::DummyObject; 24 | #[test] 25 | fn new_obj_handle() { 26 | let obj = DummyObject::new(); 27 | let handle1 = Handle::new(obj.clone(), Rights::BASIC); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/ch01-02/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::Mutex; 7 | 8 | // ANCHOR: mod 9 | mod handle; 10 | mod rights; 11 | 12 | pub use self::handle::*; 13 | pub use self::rights::*; 14 | // ANCHOR_END: mod 15 | 16 | /// 内核对象公共接口 17 | pub trait KernelObject: DowncastSync + Debug { 18 | /// 获取对象 ID 19 | fn id(&self) -> KoID; 20 | /// 获取对象类型名 21 | fn type_name(&self) -> &str; 22 | /// 获取对象名称 23 | fn name(&self) -> String; 24 | /// 设置对象名称 25 | fn set_name(&self, name: &str); 26 | } 27 | 28 | impl_downcast!(sync KernelObject); 29 | 30 | /// 对象 ID 类型 31 | pub type KoID = u64; 32 | 33 | /// 内核对象核心结构 34 | pub struct KObjectBase { 35 | /// 对象 ID 36 | pub id: KoID, 37 | inner: Mutex, 38 | } 39 | 40 | /// `KObjectBase` 的内部可变部分 41 | #[derive(Default)] 42 | struct KObjectBaseInner { 43 | name: String, 44 | } 45 | 46 | impl Default for KObjectBase { 47 | /// 创建一个新 `KObjectBase` 48 | fn default() -> Self { 49 | KObjectBase { 50 | id: Self::new_koid(), 51 | inner: Default::default(), 52 | } 53 | } 54 | } 55 | 56 | impl KObjectBase { 57 | /// 生成一个唯一的 ID 58 | fn new_koid() -> KoID { 59 | static NEXT_KOID: AtomicU64 = AtomicU64::new(1024); 60 | NEXT_KOID.fetch_add(1, Ordering::SeqCst) 61 | } 62 | /// 获取对象名称 63 | pub fn name(&self) -> String { 64 | self.inner.lock().name.clone() 65 | } 66 | /// 设置对象名称 67 | pub fn set_name(&self, name: &str) { 68 | self.inner.lock().name = String::from(name); 69 | } 70 | } 71 | 72 | /// 为内核对象 struct 自动实现 `KernelObject` trait 的宏。 73 | #[macro_export] // 导出宏,可在 crate 外部使用 74 | macro_rules! impl_kobject { 75 | // 匹配类型名,并可以提供函数覆盖默认实现 76 | ($class:ident $( $fn:tt )*) => { 77 | // 为对象实现 KernelObject trait,方法直接转发到内部 struct 78 | impl KernelObject for $class { 79 | fn id(&self) -> KoID { 80 | // 直接访问内部的 pub 属性 81 | self.base.id 82 | } 83 | fn type_name(&self) -> &str { 84 | // 用 stringify! 宏将输入转成字符串 85 | stringify!($class) 86 | } 87 | // 注意宏里面的类型要写完整路径,例如:alloc::string::String 88 | fn name(&self) -> alloc::string::String { 89 | self.base.name() 90 | } 91 | fn set_name(&self, name: &str){ 92 | // 直接访问内部的 pub 方法 93 | self.base.set_name(name) 94 | } 95 | // 可以传入任意数量的函数,覆盖 trait 的默认实现 96 | $( $fn )* 97 | } 98 | // 为对象实现 Debug trait 99 | impl core::fmt::Debug for $class { 100 | fn fmt( 101 | &self, 102 | f: &mut core::fmt::Formatter<'_>, 103 | ) -> core::result::Result<(), core::fmt::Error> { 104 | // 输出对象类型、ID 和名称 105 | f.debug_tuple(&stringify!($class)) 106 | .field(&self.id()) 107 | .field(&self.name()) 108 | .finish() 109 | } 110 | } 111 | }; 112 | } 113 | 114 | /// 空对象 115 | pub struct DummyObject { 116 | // 其中必须包含一个名为 `base` 的 `KObjectBase` 117 | base: KObjectBase, 118 | } 119 | 120 | // 使用刚才的宏,声明其为内核对象,自动生成必要的代码 121 | impl_kobject!(DummyObject); 122 | 123 | impl DummyObject { 124 | /// 创建一个新 `DummyObject` 125 | pub fn new() -> Arc { 126 | Arc::new(DummyObject { 127 | base: KObjectBase::default(), 128 | }) 129 | } 130 | } 131 | 132 | #[cfg(test)] 133 | #[test] 134 | fn impl_kobject() { 135 | use alloc::format; 136 | let dummy = DummyObject::new(); 137 | let object: Arc = dummy; 138 | assert_eq!(object.type_name(), "DummyObject"); 139 | assert_eq!(object.name(), ""); 140 | object.set_name("dummy"); 141 | assert_eq!(object.name(), "dummy"); 142 | assert_eq!( 143 | format!("{:?}", object), 144 | format!("DummyObject({}, \"dummy\")", object.id()) 145 | ); 146 | let _result: Arc = object.downcast_arc::().unwrap(); 147 | } 148 | -------------------------------------------------------------------------------- /code/ch01-02/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | pub struct Rights: u32 { 7 | const DUPLICATE = 1 << 0; 8 | const TRANSFER = 1 << 1; 9 | const READ = 1 << 2; 10 | const WRITE = 1 << 3; 11 | const EXECUTE = 1 << 4; 12 | const MAP = 1 << 5; 13 | const GET_PROPERTY = 1 << 6; 14 | const SET_PROPERTY = 1 << 7; 15 | const ENUMERATE = 1 << 8; 16 | const DESTROY = 1 << 9; 17 | const SET_POLICY = 1 << 10; 18 | const GET_POLICY = 1 << 11; 19 | const SIGNAL = 1 << 12; 20 | const SIGNAL_PEER = 1 << 13; 21 | const WAIT = 1 << 14; 22 | const INSPECT = 1 << 15; 23 | const MANAGE_JOB = 1 << 16; 24 | const MANAGE_PROCESS = 1 << 17; 25 | const MANAGE_THREAD = 1 << 18; 26 | const APPLY_PROFILE = 1 << 19; 27 | const SAME_RIGHTS = 1 << 31; 28 | 29 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 30 | const IO = Self::READ.bits | Self::WRITE.bits; 31 | 32 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 33 | /// GET_PROPERTY | SET_PROPERTY 34 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 35 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 36 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 37 | } 38 | } 39 | // ANCHOR_END: rights 40 | -------------------------------------------------------------------------------- /code/ch01-02/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod process; 4 | -------------------------------------------------------------------------------- /code/ch01-02/src/task/process.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::error::*; 3 | use crate::object::*; 4 | use alloc::collections::BTreeMap; 5 | use alloc::sync::Arc; 6 | use spin::Mutex; 7 | 8 | // ANCHOR: process 9 | /// 进程对象 10 | pub struct Process { 11 | base: KObjectBase, 12 | inner: Mutex, 13 | } 14 | 15 | impl_kobject!(Process); 16 | 17 | struct ProcessInner { 18 | handles: BTreeMap, 19 | } 20 | 21 | pub type HandleValue = u32; 22 | 23 | impl Process { 24 | /// 创建一个新的进程对象 25 | pub fn new() -> Arc { 26 | Arc::new(Process { 27 | base: KObjectBase::default(), 28 | inner: Mutex::new(ProcessInner { 29 | handles: BTreeMap::default(), 30 | }), 31 | }) 32 | } 33 | // ANCHOR_END: process 34 | 35 | // ANCHOR: add_remove_handle 36 | /// 添加一个新的对象句柄 37 | pub fn add_handle(&self, handle: Handle) -> HandleValue { 38 | let mut inner = self.inner.lock(); 39 | let value = (0 as HandleValue..) 40 | .find(|idx| !inner.handles.contains_key(idx)) 41 | .unwrap(); 42 | inner.handles.insert(value, handle); 43 | value 44 | } 45 | 46 | /// 删除一个对象句柄 47 | pub fn remove_handle(&self, handle_value: HandleValue) { 48 | self.inner.lock().handles.remove(&handle_value); 49 | } 50 | // ANCHOR_END: add_remove_handle 51 | 52 | // ANCHOR: get_object_with_rights 53 | /// 根据句柄值查找内核对象,并检查权限 54 | pub fn get_object_with_rights( 55 | &self, 56 | handle_value: HandleValue, 57 | desired_rights: Rights, 58 | ) -> ZxResult> { 59 | let handle = self 60 | .inner 61 | .lock() 62 | .handles 63 | .get(&handle_value) 64 | .ok_or(ZxError::BAD_HANDLE)? 65 | .clone(); 66 | // check type before rights 67 | let object = handle 68 | .object 69 | .downcast_arc::() 70 | .map_err(|_| ZxError::WRONG_TYPE)?; 71 | if !handle.rights.contains(desired_rights) { 72 | return Err(ZxError::ACCESS_DENIED); 73 | } 74 | Ok(object) 75 | } 76 | // ANCHOR_END: get_object_with_rights 77 | } 78 | 79 | #[cfg(test)] 80 | mod tests { 81 | use super::*; 82 | use alloc::format; 83 | 84 | #[test] 85 | fn new_proc() { 86 | let proc = Process::new(); 87 | assert_eq!(proc.type_name(), "Process"); 88 | assert_eq!(proc.name(), ""); 89 | proc.set_name("proc1"); 90 | assert_eq!(proc.name(), "proc1"); 91 | assert_eq!( 92 | format!("{:?}", proc), 93 | format!("Process({}, \"proc1\")", proc.id()) 94 | ); 95 | 96 | let obj: Arc = proc; 97 | assert_eq!(obj.type_name(), "Process"); 98 | assert_eq!(obj.name(), "proc1"); 99 | obj.set_name("proc2"); 100 | assert_eq!(obj.name(), "proc2"); 101 | assert_eq!( 102 | format!("{:?}", obj), 103 | format!("Process({}, \"proc2\")", obj.id()) 104 | ); 105 | } 106 | 107 | fn proc_handle() { 108 | let proc = Process::new(); 109 | let handle = Handle::new(proc.clone(), Rights::DEFAULT_PROCESS); 110 | let handle_value = proc.add_handle(handle); 111 | 112 | let object1: Arc = proc 113 | .get_object_with_rights(handle_value, Rights::DEFAULT_PROCESS) 114 | .expect("failed to get object"); 115 | assert!(Arc::ptr_eq(&object1, &proc)); 116 | 117 | proc.remove_handle(handle_value); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /code/ch01-03/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ch01-03" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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.7" 11 | downcast-rs = { version = "1.2.0", default-features = false } 12 | bitflags = "1.2" 13 | -------------------------------------------------------------------------------- /code/ch01-03/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch01-03/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![feature(get_mut_unchecked)] 4 | 5 | extern crate alloc; 6 | 7 | mod error; 8 | mod ipc; 9 | mod object; 10 | mod task; 11 | -------------------------------------------------------------------------------- /code/ch01-03/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | /// 内核对象句柄 6 | #[derive(Clone)] 7 | pub struct Handle { 8 | pub object: Arc, 9 | pub rights: Rights, 10 | } 11 | 12 | impl Handle { 13 | /// 创建一个新句柄 14 | pub fn new(object: Arc, rights: Rights) -> Self { 15 | Handle { object, rights } 16 | } 17 | } 18 | // ANCHOR_END: handle 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | use crate::object::DummyObject; 24 | #[test] 25 | fn new_obj_handle() { 26 | let obj = DummyObject::new(); 27 | let handle1 = Handle::new(obj.clone(), Rights::BASIC); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/ch01-03/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | pub struct Rights: u32 { 7 | const DUPLICATE = 1 << 0; 8 | const TRANSFER = 1 << 1; 9 | const READ = 1 << 2; 10 | const WRITE = 1 << 3; 11 | const EXECUTE = 1 << 4; 12 | const MAP = 1 << 5; 13 | const GET_PROPERTY = 1 << 6; 14 | const SET_PROPERTY = 1 << 7; 15 | const ENUMERATE = 1 << 8; 16 | const DESTROY = 1 << 9; 17 | const SET_POLICY = 1 << 10; 18 | const GET_POLICY = 1 << 11; 19 | const SIGNAL = 1 << 12; 20 | const SIGNAL_PEER = 1 << 13; 21 | const WAIT = 1 << 14; 22 | const INSPECT = 1 << 15; 23 | const MANAGE_JOB = 1 << 16; 24 | const MANAGE_PROCESS = 1 << 17; 25 | const MANAGE_THREAD = 1 << 18; 26 | const APPLY_PROFILE = 1 << 19; 27 | const SAME_RIGHTS = 1 << 31; 28 | 29 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 30 | const IO = Self::READ.bits | Self::WRITE.bits; 31 | 32 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 33 | /// GET_PROPERTY | SET_PROPERTY 34 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 35 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 36 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 37 | } 38 | } 39 | // ANCHOR_END: rights 40 | -------------------------------------------------------------------------------- /code/ch01-03/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod process; 4 | -------------------------------------------------------------------------------- /code/ch01-03/src/task/process.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::error::*; 3 | use crate::object::*; 4 | use alloc::collections::BTreeMap; 5 | use alloc::sync::Arc; 6 | use spin::Mutex; 7 | 8 | // ANCHOR: process 9 | /// 进程对象 10 | pub struct Process { 11 | base: KObjectBase, 12 | inner: Mutex, 13 | } 14 | 15 | impl_kobject!(Process); 16 | 17 | struct ProcessInner { 18 | handles: BTreeMap, 19 | } 20 | 21 | pub type HandleValue = u32; 22 | 23 | impl Process { 24 | /// 创建一个新的进程对象 25 | pub fn new() -> Arc { 26 | Arc::new(Process { 27 | base: KObjectBase::default(), 28 | inner: Mutex::new(ProcessInner { 29 | handles: BTreeMap::default(), 30 | }), 31 | }) 32 | } 33 | // ANCHOR_END: process 34 | 35 | // ANCHOR: add_remove_handle 36 | /// 添加一个新的对象句柄 37 | pub fn add_handle(&self, handle: Handle) -> HandleValue { 38 | let mut inner = self.inner.lock(); 39 | let value = (0 as HandleValue..) 40 | .find(|idx| !inner.handles.contains_key(idx)) 41 | .unwrap(); 42 | inner.handles.insert(value, handle); 43 | value 44 | } 45 | 46 | /// 删除一个对象句柄 47 | pub fn remove_handle(&self, handle_value: HandleValue) { 48 | self.inner.lock().handles.remove(&handle_value); 49 | } 50 | // ANCHOR_END: add_remove_handle 51 | 52 | // ANCHOR: get_object_with_rights 53 | /// 根据句柄值查找内核对象,并检查权限 54 | pub fn get_object_with_rights( 55 | &self, 56 | handle_value: HandleValue, 57 | desired_rights: Rights, 58 | ) -> ZxResult> { 59 | let handle = self 60 | .inner 61 | .lock() 62 | .handles 63 | .get(&handle_value) 64 | .ok_or(ZxError::BAD_HANDLE)? 65 | .clone(); 66 | // check type before rights 67 | let object = handle 68 | .object 69 | .downcast_arc::() 70 | .map_err(|_| ZxError::WRONG_TYPE)?; 71 | if !handle.rights.contains(desired_rights) { 72 | return Err(ZxError::ACCESS_DENIED); 73 | } 74 | Ok(object) 75 | } 76 | // ANCHOR_END: get_object_with_rights 77 | } 78 | 79 | #[cfg(test)] 80 | mod tests { 81 | use super::*; 82 | use alloc::format; 83 | 84 | #[test] 85 | fn new_proc() { 86 | let proc = Process::new(); 87 | assert_eq!(proc.type_name(), "Process"); 88 | assert_eq!(proc.name(), ""); 89 | proc.set_name("proc1"); 90 | assert_eq!(proc.name(), "proc1"); 91 | assert_eq!( 92 | format!("{:?}", proc), 93 | format!("Process({}, \"proc1\")", proc.id()) 94 | ); 95 | 96 | let obj: Arc = proc; 97 | assert_eq!(obj.type_name(), "Process"); 98 | assert_eq!(obj.name(), "proc1"); 99 | obj.set_name("proc2"); 100 | assert_eq!(obj.name(), "proc2"); 101 | assert_eq!( 102 | format!("{:?}", obj), 103 | format!("Process({}, \"proc2\")", obj.id()) 104 | ); 105 | } 106 | 107 | fn proc_handle() { 108 | let proc = Process::new(); 109 | let handle = Handle::new(proc.clone(), Rights::DEFAULT_PROCESS); 110 | let handle_value = proc.add_handle(handle); 111 | 112 | let object1: Arc = proc 113 | .get_object_with_rights(handle_value, Rights::DEFAULT_PROCESS) 114 | .expect("failed to get object"); 115 | assert!(Arc::ptr_eq(&object1, &proc)); 116 | 117 | proc.remove_handle(handle_value); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /code/ch02-02/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ch02-02" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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.7" 11 | downcast-rs = { version = "1.2.0", default-features = false } 12 | bitflags = "1.2" 13 | hashbrown = "0.9" -------------------------------------------------------------------------------- /code/ch02-02/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch02-02/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![allow(dead_code)] 4 | #![feature(get_mut_unchecked)] 5 | 6 | extern crate alloc; 7 | 8 | #[cfg(test)] 9 | #[macro_use] 10 | extern crate std; 11 | 12 | mod error; 13 | mod ipc; 14 | mod object; 15 | mod task; 16 | mod vm; 17 | 18 | pub use self::error::*; 19 | -------------------------------------------------------------------------------- /code/ch02-02/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | pub type HandleValue = u32; 6 | 7 | /// 内核对象句柄 8 | #[derive(Clone)] 9 | pub struct Handle { 10 | pub object: Arc, 11 | pub rights: Rights, 12 | } 13 | 14 | impl Handle { 15 | /// 创建一个新句柄 16 | pub fn new(object: Arc, rights: Rights) -> Self { 17 | Handle { object, rights } 18 | } 19 | } 20 | // ANCHOR_END: handle 21 | -------------------------------------------------------------------------------- /code/ch02-02/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | pub struct Rights: u32 { 7 | const DUPLICATE = 1 << 0; 8 | const TRANSFER = 1 << 1; 9 | const READ = 1 << 2; 10 | const WRITE = 1 << 3; 11 | const EXECUTE = 1 << 4; 12 | const MAP = 1 << 5; 13 | const GET_PROPERTY = 1 << 6; 14 | const SET_PROPERTY = 1 << 7; 15 | const ENUMERATE = 1 << 8; 16 | const DESTROY = 1 << 9; 17 | const SET_POLICY = 1 << 10; 18 | const GET_POLICY = 1 << 11; 19 | const SIGNAL = 1 << 12; 20 | const SIGNAL_PEER = 1 << 13; 21 | const WAIT = 1 << 14; 22 | const INSPECT = 1 << 15; 23 | const MANAGE_JOB = 1 << 16; 24 | const MANAGE_PROCESS = 1 << 17; 25 | const MANAGE_THREAD = 1 << 18; 26 | const APPLY_PROFILE = 1 << 19; 27 | const SAME_RIGHTS = 1 << 31; 28 | 29 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 30 | const IO = Self::READ.bits | Self::WRITE.bits; 31 | 32 | /// GET_PROPERTY | SET_PROPERTY 33 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 34 | 35 | /// GET_POLICY | SET_POLICY 36 | const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; 37 | 38 | /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER 39 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 40 | 41 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 42 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits 43 | | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 44 | 45 | /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD 46 | const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; 47 | 48 | /// BASIC | WAIT 49 | const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; 50 | 51 | /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD 52 | const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits 53 | | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 54 | 55 | } 56 | } 57 | // ANCHOR_END: rights 58 | -------------------------------------------------------------------------------- /code/ch02-02/src/task/job_policy.rs: -------------------------------------------------------------------------------- 1 | /// Security and resource policies of a job. 2 | #[derive(Default, Copy, Clone)] 3 | pub struct JobPolicy { 4 | // TODO: use bitset 5 | action: [Option; 15], 6 | } 7 | 8 | impl JobPolicy { 9 | /// Get the action of a policy `condition`. 10 | pub fn get_action(&self, condition: PolicyCondition) -> Option { 11 | self.action[condition as usize] 12 | } 13 | 14 | /// Apply a basic policy. 15 | pub fn apply(&mut self, policy: BasicPolicy) { 16 | self.action[policy.condition as usize] = Some(policy.action); 17 | } 18 | 19 | /// Merge the policy with `parent`'s. 20 | pub fn merge(&self, parent: &Self) -> Self { 21 | let mut new = *self; 22 | for i in 0..15 { 23 | if parent.action[i].is_some() { 24 | new.action[i] = parent.action[i]; 25 | } 26 | } 27 | new 28 | } 29 | } 30 | 31 | /// Control the effect in the case of conflict between 32 | /// the existing policies and the new policies when setting new policies. 33 | #[derive(Debug, Copy, Clone)] 34 | pub enum SetPolicyOptions { 35 | /// Policy is applied for all conditions in policy or the call fails. 36 | Absolute, 37 | /// Policy is applied for the conditions not specifically overridden by the parent policy. 38 | Relative, 39 | } 40 | 41 | /// The policy type. 42 | #[repr(C)] 43 | #[derive(Debug, Copy, Clone)] 44 | pub struct BasicPolicy { 45 | /// Condition when the policy is applied. 46 | pub condition: PolicyCondition, 47 | /// 48 | pub action: PolicyAction, 49 | } 50 | 51 | /// The condition when a policy is applied. 52 | #[repr(u32)] 53 | #[derive(Debug, Copy, Clone)] 54 | pub enum PolicyCondition { 55 | /// A process under this job is attempting to issue a syscall with an invalid handle. 56 | /// In this case, `PolicyAction::Allow` and `PolicyAction::Deny` are equivalent: 57 | /// if the syscall returns, it will always return the error ZX_ERR_BAD_HANDLE. 58 | BadHandle = 0, 59 | /// A process under this job is attempting to issue a syscall with a handle that does not support such operation. 60 | WrongObject = 1, 61 | /// A process under this job is attempting to map an address region with write-execute access. 62 | VmarWx = 2, 63 | /// A special condition that stands for all of the above ZX_NEW conditions 64 | /// such as NEW_VMO, NEW_CHANNEL, NEW_EVENT, NEW_EVENTPAIR, NEW_PORT, NEW_SOCKET, NEW_FIFO, 65 | /// And any future ZX_NEW policy. 66 | /// This will include any new kernel objects which do not require a parent object for creation. 67 | NewAny = 3, 68 | /// A process under this job is attempting to create a new vm object. 69 | NewVMO = 4, 70 | /// A process under this job is attempting to create a new channel. 71 | NewChannel = 5, 72 | /// A process under this job is attempting to create a new event. 73 | NewEvent = 6, 74 | /// A process under this job is attempting to create a new event pair. 75 | NewEventPair = 7, 76 | /// A process under this job is attempting to create a new port. 77 | NewPort = 8, 78 | /// A process under this job is attempting to create a new socket. 79 | NewSocket = 9, 80 | /// A process under this job is attempting to create a new fifo. 81 | NewFIFO = 10, 82 | /// A process under this job is attempting to create a new timer. 83 | NewTimer = 11, 84 | /// A process under this job is attempting to create a new process. 85 | NewProcess = 12, 86 | /// A process under this job is attempting to create a new profile. 87 | NewProfile = 13, 88 | /// A process under this job is attempting to use zx_vmo_replace_as_executable() 89 | /// with a ZX_HANDLE_INVALID as the second argument rather than a valid ZX_RSRC_KIND_VMEX. 90 | AmbientMarkVMOExec = 14, 91 | } 92 | 93 | /// The action taken when the condition happens specified by a policy. 94 | #[repr(u32)] 95 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 96 | pub enum PolicyAction { 97 | /// Allow condition. 98 | Allow = 0, 99 | /// Prevent condition. 100 | Deny = 1, 101 | /// Generate an exception via the debug port. An exception generated this 102 | /// way acts as a breakpoint. The thread may be resumed after the exception. 103 | AllowException = 2, 104 | /// Just like `AllowException`, but after resuming condition is denied. 105 | DenyException = 3, 106 | /// Terminate the process. 107 | Kill = 4, 108 | } 109 | -------------------------------------------------------------------------------- /code/ch02-02/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod job; 4 | mod job_policy; 5 | mod process; 6 | mod thread; 7 | 8 | pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; 9 | 10 | /// Task (Thread, Process, or Job) 11 | pub trait Task: Sync + Send { 12 | /// Kill the task. The task do not terminate immediately when killed. 13 | /// It will terminate after all its children are terminated or some cleanups are finished. 14 | fn kill(&self); 15 | 16 | /// Suspend the task. Currently only thread or process handles may be suspended. 17 | fn suspend(&self); 18 | 19 | /// Resume the task 20 | fn resume(&self); 21 | } 22 | 23 | /// The return code set when a task is killed via zx_task_kill(). 24 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 25 | -------------------------------------------------------------------------------- /code/ch02-02/src/task/thread.rs: -------------------------------------------------------------------------------- 1 | use {super::process::Process, super::*, crate::object::*, alloc::sync::Arc}; 2 | 3 | pub struct Thread { 4 | base: KObjectBase, 5 | proc: Arc, 6 | } 7 | 8 | impl_kobject!(Thread 9 | fn related_koid(&self) -> KoID { 10 | self.proc.id() 11 | } 12 | ); 13 | 14 | impl Thread { 15 | /// Create a new thread. 16 | pub fn create(proc: &Arc, name: &str) -> ZxResult> { 17 | let thread = Arc::new(Thread { 18 | base: KObjectBase::with_name(name), 19 | proc: proc.clone(), 20 | }); 21 | proc.add_thread(thread.clone())?; 22 | Ok(thread) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/ch02-02/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | use super::*; 3 | 4 | mod vmar; 5 | 6 | pub use self::vmar::*; 7 | -------------------------------------------------------------------------------- /code/ch02-02/src/vm/vmar.rs: -------------------------------------------------------------------------------- 1 | use {super::*, crate::object::*, alloc::sync::Arc}; 2 | 3 | /// Virtual Memory Address Regions 4 | pub struct VmAddressRegion { 5 | base: KObjectBase, 6 | } 7 | 8 | impl_kobject!(VmAddressRegion); 9 | 10 | impl VmAddressRegion { 11 | /// Create a new root VMAR. 12 | pub fn new_root() -> Arc { 13 | Arc::new(VmAddressRegion { 14 | base: KObjectBase::new(), 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/ch02-03/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "object", 4 | "kernel-hal-unix", 5 | "kernel-hal", 6 | ] 7 | -------------------------------------------------------------------------------- /code/ch02-03/kernel-hal-unix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-unix" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation on Linux and macOS." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | kernel-hal = { path = "../kernel-hal" } 12 | async-std = "1.9" 13 | trapframe = "0.8.0" 14 | -------------------------------------------------------------------------------- /code/ch02-03/kernel-hal-unix/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(asm)] 2 | #![feature(linkage)] 3 | #![deny(warnings)] 4 | 5 | extern crate alloc; 6 | 7 | use { 8 | alloc::boxed::Box, 9 | core::time::Duration, 10 | core::{future::Future, pin::Pin}, 11 | std::time::SystemTime, 12 | }; 13 | 14 | pub use trapframe::{GeneralRegs, UserContext}; 15 | 16 | #[repr(C)] 17 | pub struct Thread { 18 | thread: usize, 19 | } 20 | 21 | impl Thread { 22 | #[export_name = "hal_thread_spawn"] 23 | pub fn spawn( 24 | future: Pin + Send + 'static>>, 25 | _vmtoken: usize, 26 | ) -> Self { 27 | async_std::task::spawn(future); 28 | Thread { thread: 0 } 29 | } 30 | } 31 | 32 | /// Get current time. 33 | #[export_name = "hal_timer_now"] 34 | pub fn timer_now() -> Duration { 35 | SystemTime::now() 36 | .duration_since(SystemTime::UNIX_EPOCH) 37 | .unwrap() 38 | } 39 | 40 | /// Initialize the HAL. 41 | /// 42 | /// This function must be called at the beginning. 43 | pub fn init() { 44 | #[cfg(target_os = "macos")] 45 | unimplemented!() 46 | } 47 | -------------------------------------------------------------------------------- /code/ch02-03/kernel-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL interface definations." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | trapframe = "0.8.0" 12 | -------------------------------------------------------------------------------- /code/ch02-03/kernel-hal/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(linkage)] 3 | #![deny(warnings)] 4 | 5 | extern crate alloc; 6 | 7 | pub use trapframe::{GeneralRegs, UserContext}; 8 | 9 | use { 10 | alloc::boxed::Box, 11 | core::{future::Future, pin::Pin, time::Duration}, 12 | }; 13 | 14 | #[repr(C)] 15 | pub struct Thread { 16 | id: usize, 17 | } 18 | 19 | impl Thread { 20 | /// Spawn a new thread. 21 | #[linkage = "weak"] 22 | #[export_name = "hal_thread_spawn"] 23 | pub fn spawn( 24 | _future: Pin + Send + 'static>>, 25 | _vmtoken: usize, 26 | ) -> Self { 27 | unimplemented!() 28 | } 29 | } 30 | 31 | #[linkage = "weak"] 32 | #[export_name = "hal_timer_now"] 33 | pub fn timer_now() -> Duration { 34 | unimplemented!() 35 | } 36 | -------------------------------------------------------------------------------- /code/ch02-03/object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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.7" 11 | downcast-rs = { version = "1.2.0", default-features = false } 12 | bitflags = "1.2" 13 | hashbrown = "0.9" 14 | trapframe = "0.8.0" 15 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 16 | async-std = { version = "1.9", features = ["attributes", "unstable"] } 17 | numeric-enum-macro = "0.2" 18 | kernel-hal = { path = "../kernel-hal" } 19 | kernel-hal-unix = { path = "../kernel-hal-unix" } -------------------------------------------------------------------------------- /code/ch02-03/object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![allow(dead_code)] 4 | #![feature(get_mut_unchecked)] 5 | 6 | extern crate alloc; 7 | 8 | #[cfg(test)] 9 | #[macro_use] 10 | extern crate std; 11 | 12 | mod error; 13 | mod ipc; 14 | mod object; 15 | mod task; 16 | mod vm; 17 | 18 | pub use self::error::*; 19 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | pub type HandleValue = u32; 6 | pub const INVALID_HANDLE: HandleValue = 0; 7 | 8 | /// 内核对象句柄 9 | #[derive(Clone)] 10 | pub struct Handle { 11 | pub object: Arc, 12 | pub rights: Rights, 13 | } 14 | 15 | impl Handle { 16 | /// 创建一个新句柄 17 | pub fn new(object: Arc, rights: Rights) -> Self { 18 | Handle { object, rights } 19 | } 20 | } 21 | // ANCHOR_END: handle 22 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | pub struct Rights: u32 { 7 | const DUPLICATE = 1 << 0; 8 | const TRANSFER = 1 << 1; 9 | const READ = 1 << 2; 10 | const WRITE = 1 << 3; 11 | const EXECUTE = 1 << 4; 12 | const MAP = 1 << 5; 13 | const GET_PROPERTY = 1 << 6; 14 | const SET_PROPERTY = 1 << 7; 15 | const ENUMERATE = 1 << 8; 16 | const DESTROY = 1 << 9; 17 | const SET_POLICY = 1 << 10; 18 | const GET_POLICY = 1 << 11; 19 | const SIGNAL = 1 << 12; 20 | const SIGNAL_PEER = 1 << 13; 21 | const WAIT = 1 << 14; 22 | const INSPECT = 1 << 15; 23 | const MANAGE_JOB = 1 << 16; 24 | const MANAGE_PROCESS = 1 << 17; 25 | const MANAGE_THREAD = 1 << 18; 26 | const APPLY_PROFILE = 1 << 19; 27 | const SAME_RIGHTS = 1 << 31; 28 | 29 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 30 | const IO = Self::READ.bits | Self::WRITE.bits; 31 | 32 | /// GET_PROPERTY | SET_PROPERTY 33 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 34 | 35 | /// GET_POLICY | SET_POLICY 36 | const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; 37 | 38 | /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER 39 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 40 | 41 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 42 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits 43 | | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 44 | 45 | /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD 46 | const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; 47 | 48 | /// BASIC | WAIT 49 | const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; 50 | 51 | /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD 52 | const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits 53 | | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 54 | 55 | } 56 | } 57 | // ANCHOR_END: rights 58 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/task/job_policy.rs: -------------------------------------------------------------------------------- 1 | /// Security and resource policies of a job. 2 | #[derive(Default, Copy, Clone)] 3 | pub struct JobPolicy { 4 | // TODO: use bitset 5 | action: [Option; 15], 6 | } 7 | 8 | impl JobPolicy { 9 | /// Get the action of a policy `condition`. 10 | pub fn get_action(&self, condition: PolicyCondition) -> Option { 11 | self.action[condition as usize] 12 | } 13 | 14 | /// Apply a basic policy. 15 | pub fn apply(&mut self, policy: BasicPolicy) { 16 | self.action[policy.condition as usize] = Some(policy.action); 17 | } 18 | 19 | /// Merge the policy with `parent`'s. 20 | pub fn merge(&self, parent: &Self) -> Self { 21 | let mut new = *self; 22 | for i in 0..15 { 23 | if parent.action[i].is_some() { 24 | new.action[i] = parent.action[i]; 25 | } 26 | } 27 | new 28 | } 29 | } 30 | 31 | /// Control the effect in the case of conflict between 32 | /// the existing policies and the new policies when setting new policies. 33 | #[derive(Debug, Copy, Clone)] 34 | pub enum SetPolicyOptions { 35 | /// Policy is applied for all conditions in policy or the call fails. 36 | Absolute, 37 | /// Policy is applied for the conditions not specifically overridden by the parent policy. 38 | Relative, 39 | } 40 | 41 | /// The policy type. 42 | #[repr(C)] 43 | #[derive(Debug, Copy, Clone)] 44 | pub struct BasicPolicy { 45 | /// Condition when the policy is applied. 46 | pub condition: PolicyCondition, 47 | /// 48 | pub action: PolicyAction, 49 | } 50 | 51 | /// The condition when a policy is applied. 52 | #[repr(u32)] 53 | #[derive(Debug, Copy, Clone)] 54 | pub enum PolicyCondition { 55 | /// A process under this job is attempting to issue a syscall with an invalid handle. 56 | /// In this case, `PolicyAction::Allow` and `PolicyAction::Deny` are equivalent: 57 | /// if the syscall returns, it will always return the error ZX_ERR_BAD_HANDLE. 58 | BadHandle = 0, 59 | /// A process under this job is attempting to issue a syscall with a handle that does not support such operation. 60 | WrongObject = 1, 61 | /// A process under this job is attempting to map an address region with write-execute access. 62 | VmarWx = 2, 63 | /// A special condition that stands for all of the above ZX_NEW conditions 64 | /// such as NEW_VMO, NEW_CHANNEL, NEW_EVENT, NEW_EVENTPAIR, NEW_PORT, NEW_SOCKET, NEW_FIFO, 65 | /// And any future ZX_NEW policy. 66 | /// This will include any new kernel objects which do not require a parent object for creation. 67 | NewAny = 3, 68 | /// A process under this job is attempting to create a new vm object. 69 | NewVMO = 4, 70 | /// A process under this job is attempting to create a new channel. 71 | NewChannel = 5, 72 | /// A process under this job is attempting to create a new event. 73 | NewEvent = 6, 74 | /// A process under this job is attempting to create a new event pair. 75 | NewEventPair = 7, 76 | /// A process under this job is attempting to create a new port. 77 | NewPort = 8, 78 | /// A process under this job is attempting to create a new socket. 79 | NewSocket = 9, 80 | /// A process under this job is attempting to create a new fifo. 81 | NewFIFO = 10, 82 | /// A process under this job is attempting to create a new timer. 83 | NewTimer = 11, 84 | /// A process under this job is attempting to create a new process. 85 | NewProcess = 12, 86 | /// A process under this job is attempting to create a new profile. 87 | NewProfile = 13, 88 | /// A process under this job is attempting to use zx_vmo_replace_as_executable() 89 | /// with a ZX_HANDLE_INVALID as the second argument rather than a valid ZX_RSRC_KIND_VMEX. 90 | AmbientMarkVMOExec = 14, 91 | } 92 | 93 | /// The action taken when the condition happens specified by a policy. 94 | #[repr(u32)] 95 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 96 | pub enum PolicyAction { 97 | /// Allow condition. 98 | Allow = 0, 99 | /// Prevent condition. 100 | Deny = 1, 101 | /// Generate an exception via the debug port. An exception generated this 102 | /// way acts as a breakpoint. The thread may be resumed after the exception. 103 | AllowException = 2, 104 | /// Just like `AllowException`, but after resuming condition is denied. 105 | DenyException = 3, 106 | /// Terminate the process. 107 | Kill = 4, 108 | } 109 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod job; 4 | mod job_policy; 5 | mod process; 6 | mod thread; 7 | 8 | pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; 9 | 10 | /// Task (Thread, Process, or Job) 11 | pub trait Task: Sync + Send { 12 | /// Kill the task. The task do not terminate immediately when killed. 13 | /// It will terminate after all its children are terminated or some cleanups are finished. 14 | fn kill(&self); 15 | 16 | /// Suspend the task. Currently only thread or process handles may be suspended. 17 | fn suspend(&self); 18 | 19 | /// Resume the task 20 | fn resume(&self); 21 | } 22 | 23 | /// The return code set when a task is killed via zx_task_kill(). 24 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 25 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | /// Possible values for "kind" in zx_thread_read_state and zx_thread_write_state. 8 | #[allow(missing_docs)] 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum ThreadStateKind { 11 | General = 0, 12 | FS = 6, 13 | GS = 7, 14 | } 15 | } 16 | 17 | pub(super) trait ContextExt { 18 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 19 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 20 | } 21 | 22 | impl ContextExt for UserContext { 23 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 24 | match kind { 25 | ThreadStateKind::General => buf.write_struct(&self.general), 26 | ThreadStateKind::FS => buf.write_struct(&self.general.fsbase), 27 | ThreadStateKind::GS => buf.write_struct(&self.general.gsbase), 28 | } 29 | } 30 | 31 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 32 | match kind { 33 | ThreadStateKind::General => self.general = buf.read_struct()?, 34 | ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?, 35 | ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?, 36 | } 37 | Ok(()) 38 | } 39 | } 40 | 41 | trait BufExt { 42 | fn read_struct(&self) -> ZxResult; 43 | fn write_struct(&mut self, value: &T) -> ZxResult; 44 | } 45 | 46 | #[allow(unsafe_code)] 47 | impl BufExt for [u8] { 48 | fn read_struct(&self) -> ZxResult { 49 | if self.len() < core::mem::size_of::() { 50 | return Err(ZxError::BUFFER_TOO_SMALL); 51 | } 52 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 53 | } 54 | 55 | fn write_struct(&mut self, value: &T) -> ZxResult { 56 | if self.len() < core::mem::size_of::() { 57 | return Err(ZxError::BUFFER_TOO_SMALL); 58 | } 59 | unsafe { 60 | *(self.as_mut_ptr() as *mut T) = *value; 61 | } 62 | Ok(core::mem::size_of::()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | use super::*; 3 | 4 | mod vmar; 5 | 6 | pub use self::vmar::*; 7 | -------------------------------------------------------------------------------- /code/ch02-03/object/src/vm/vmar.rs: -------------------------------------------------------------------------------- 1 | use {super::*, crate::object::*, alloc::sync::Arc}; 2 | 3 | /// Virtual Memory Address Regions 4 | pub struct VmAddressRegion { 5 | base: KObjectBase, 6 | } 7 | 8 | impl_kobject!(VmAddressRegion); 9 | 10 | impl VmAddressRegion { 11 | /// Create a new root VMAR. 12 | pub fn new_root() -> Arc { 13 | Arc::new(VmAddressRegion { 14 | base: KObjectBase::new(), 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/ch03-02/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "object", 4 | "kernel-hal-unix", 5 | "kernel-hal", 6 | ] 7 | -------------------------------------------------------------------------------- /code/ch03-02/kernel-hal-unix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-unix" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation on Linux and macOS." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | libc = "0.2" 13 | tempfile = "3" 14 | bitflags = "1.2" 15 | lazy_static = "1.4" 16 | kernel-hal = { path = "../kernel-hal" } 17 | async-std = "1.9" 18 | trapframe = "0.8.0" 19 | -------------------------------------------------------------------------------- /code/ch03-02/kernel-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL interface definations." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | bitflags = "1.2" 12 | trapframe = "0.8.0" 13 | numeric-enum-macro = "0.2" 14 | -------------------------------------------------------------------------------- /code/ch03-02/object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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 | log = "0.4" 11 | spin = "0.7" 12 | downcast-rs = { version = "1.2.0", default-features = false } 13 | bitflags = "1.2" 14 | hashbrown = "0.9" 15 | trapframe = "0.8.0" 16 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 17 | async-std = { version = "1.9", features = ["attributes", "unstable"] } 18 | numeric-enum-macro = "0.2" 19 | kernel-hal = { path = "../kernel-hal" } 20 | kernel-hal-unix = { path = "../kernel-hal-unix" } -------------------------------------------------------------------------------- /code/ch03-02/object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![allow(dead_code)] 4 | #![feature(get_mut_unchecked)] 5 | #![feature(drain_filter)] 6 | 7 | extern crate alloc; 8 | 9 | #[cfg(test)] 10 | #[macro_use] 11 | extern crate std; 12 | 13 | #[macro_use] 14 | extern crate log; 15 | 16 | mod error; 17 | mod ipc; 18 | mod object; 19 | mod task; 20 | mod util; 21 | mod vm; 22 | 23 | pub use self::error::*; 24 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | pub type HandleValue = u32; 6 | pub const INVALID_HANDLE: HandleValue = 0; 7 | 8 | /// 内核对象句柄 9 | #[derive(Clone)] 10 | pub struct Handle { 11 | pub object: Arc, 12 | pub rights: Rights, 13 | } 14 | 15 | impl Handle { 16 | /// 创建一个新句柄 17 | pub fn new(object: Arc, rights: Rights) -> Self { 18 | Handle { object, rights } 19 | } 20 | } 21 | // ANCHOR_END: handle 22 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | #[derive(Default)] 7 | pub struct Rights: u32 { 8 | const DUPLICATE = 1 << 0; 9 | const TRANSFER = 1 << 1; 10 | const READ = 1 << 2; 11 | const WRITE = 1 << 3; 12 | const EXECUTE = 1 << 4; 13 | const MAP = 1 << 5; 14 | const GET_PROPERTY = 1 << 6; 15 | const SET_PROPERTY = 1 << 7; 16 | const ENUMERATE = 1 << 8; 17 | const DESTROY = 1 << 9; 18 | const SET_POLICY = 1 << 10; 19 | const GET_POLICY = 1 << 11; 20 | const SIGNAL = 1 << 12; 21 | const SIGNAL_PEER = 1 << 13; 22 | const WAIT = 1 << 14; 23 | const INSPECT = 1 << 15; 24 | const MANAGE_JOB = 1 << 16; 25 | const MANAGE_PROCESS = 1 << 17; 26 | const MANAGE_THREAD = 1 << 18; 27 | const APPLY_PROFILE = 1 << 19; 28 | const SAME_RIGHTS = 1 << 31; 29 | 30 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 31 | const IO = Self::READ.bits | Self::WRITE.bits; 32 | 33 | /// GET_PROPERTY | SET_PROPERTY 34 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 35 | 36 | /// GET_POLICY | SET_POLICY 37 | const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; 38 | 39 | /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER 40 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 41 | 42 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 43 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits 44 | | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 45 | 46 | /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD 47 | const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; 48 | 49 | /// BASIC | WAIT 50 | const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; 51 | 52 | /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD 53 | const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits 54 | | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 55 | 56 | } 57 | } 58 | // ANCHOR_END: rights 59 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/task/job_policy.rs: -------------------------------------------------------------------------------- 1 | /// Security and resource policies of a job. 2 | #[derive(Default, Copy, Clone)] 3 | pub struct JobPolicy { 4 | // TODO: use bitset 5 | action: [Option; 15], 6 | } 7 | 8 | impl JobPolicy { 9 | /// Get the action of a policy `condition`. 10 | pub fn get_action(&self, condition: PolicyCondition) -> Option { 11 | self.action[condition as usize] 12 | } 13 | 14 | /// Apply a basic policy. 15 | pub fn apply(&mut self, policy: BasicPolicy) { 16 | self.action[policy.condition as usize] = Some(policy.action); 17 | } 18 | 19 | /// Merge the policy with `parent`'s. 20 | pub fn merge(&self, parent: &Self) -> Self { 21 | let mut new = *self; 22 | for i in 0..15 { 23 | if parent.action[i].is_some() { 24 | new.action[i] = parent.action[i]; 25 | } 26 | } 27 | new 28 | } 29 | } 30 | 31 | /// Control the effect in the case of conflict between 32 | /// the existing policies and the new policies when setting new policies. 33 | #[derive(Debug, Copy, Clone)] 34 | pub enum SetPolicyOptions { 35 | /// Policy is applied for all conditions in policy or the call fails. 36 | Absolute, 37 | /// Policy is applied for the conditions not specifically overridden by the parent policy. 38 | Relative, 39 | } 40 | 41 | /// The policy type. 42 | #[repr(C)] 43 | #[derive(Debug, Copy, Clone)] 44 | pub struct BasicPolicy { 45 | /// Condition when the policy is applied. 46 | pub condition: PolicyCondition, 47 | /// 48 | pub action: PolicyAction, 49 | } 50 | 51 | /// The condition when a policy is applied. 52 | #[repr(u32)] 53 | #[derive(Debug, Copy, Clone)] 54 | pub enum PolicyCondition { 55 | /// A process under this job is attempting to issue a syscall with an invalid handle. 56 | /// In this case, `PolicyAction::Allow` and `PolicyAction::Deny` are equivalent: 57 | /// if the syscall returns, it will always return the error ZX_ERR_BAD_HANDLE. 58 | BadHandle = 0, 59 | /// A process under this job is attempting to issue a syscall with a handle that does not support such operation. 60 | WrongObject = 1, 61 | /// A process under this job is attempting to map an address region with write-execute access. 62 | VmarWx = 2, 63 | /// A special condition that stands for all of the above ZX_NEW conditions 64 | /// such as NEW_VMO, NEW_CHANNEL, NEW_EVENT, NEW_EVENTPAIR, NEW_PORT, NEW_SOCKET, NEW_FIFO, 65 | /// And any future ZX_NEW policy. 66 | /// This will include any new kernel objects which do not require a parent object for creation. 67 | NewAny = 3, 68 | /// A process under this job is attempting to create a new vm object. 69 | NewVMO = 4, 70 | /// A process under this job is attempting to create a new channel. 71 | NewChannel = 5, 72 | /// A process under this job is attempting to create a new event. 73 | NewEvent = 6, 74 | /// A process under this job is attempting to create a new event pair. 75 | NewEventPair = 7, 76 | /// A process under this job is attempting to create a new port. 77 | NewPort = 8, 78 | /// A process under this job is attempting to create a new socket. 79 | NewSocket = 9, 80 | /// A process under this job is attempting to create a new fifo. 81 | NewFIFO = 10, 82 | /// A process under this job is attempting to create a new timer. 83 | NewTimer = 11, 84 | /// A process under this job is attempting to create a new process. 85 | NewProcess = 12, 86 | /// A process under this job is attempting to create a new profile. 87 | NewProfile = 13, 88 | /// A process under this job is attempting to use zx_vmo_replace_as_executable() 89 | /// with a ZX_HANDLE_INVALID as the second argument rather than a valid ZX_RSRC_KIND_VMEX. 90 | AmbientMarkVMOExec = 14, 91 | } 92 | 93 | /// The action taken when the condition happens specified by a policy. 94 | #[repr(u32)] 95 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 96 | pub enum PolicyAction { 97 | /// Allow condition. 98 | Allow = 0, 99 | /// Prevent condition. 100 | Deny = 1, 101 | /// Generate an exception via the debug port. An exception generated this 102 | /// way acts as a breakpoint. The thread may be resumed after the exception. 103 | AllowException = 2, 104 | /// Just like `AllowException`, but after resuming condition is denied. 105 | DenyException = 3, 106 | /// Terminate the process. 107 | Kill = 4, 108 | } 109 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod job; 4 | mod job_policy; 5 | mod process; 6 | mod thread; 7 | 8 | pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; 9 | 10 | /// Task (Thread, Process, or Job) 11 | pub trait Task: Sync + Send { 12 | /// Kill the task. The task do not terminate immediately when killed. 13 | /// It will terminate after all its children are terminated or some cleanups are finished. 14 | fn kill(&self); 15 | 16 | /// Suspend the task. Currently only thread or process handles may be suspended. 17 | fn suspend(&self); 18 | 19 | /// Resume the task 20 | fn resume(&self); 21 | } 22 | 23 | /// The return code set when a task is killed via zx_task_kill(). 24 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 25 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | /// Possible values for "kind" in zx_thread_read_state and zx_thread_write_state. 8 | #[allow(missing_docs)] 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum ThreadStateKind { 11 | General = 0, 12 | FS = 6, 13 | GS = 7, 14 | } 15 | } 16 | 17 | pub(super) trait ContextExt { 18 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 19 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 20 | } 21 | 22 | impl ContextExt for UserContext { 23 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 24 | match kind { 25 | ThreadStateKind::General => buf.write_struct(&self.general), 26 | ThreadStateKind::FS => buf.write_struct(&self.general.fsbase), 27 | ThreadStateKind::GS => buf.write_struct(&self.general.gsbase), 28 | } 29 | } 30 | 31 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 32 | match kind { 33 | ThreadStateKind::General => self.general = buf.read_struct()?, 34 | ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?, 35 | ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?, 36 | } 37 | Ok(()) 38 | } 39 | } 40 | 41 | trait BufExt { 42 | fn read_struct(&self) -> ZxResult; 43 | fn write_struct(&mut self, value: &T) -> ZxResult; 44 | } 45 | 46 | #[allow(unsafe_code)] 47 | impl BufExt for [u8] { 48 | fn read_struct(&self) -> ZxResult { 49 | if self.len() < core::mem::size_of::() { 50 | return Err(ZxError::BUFFER_TOO_SMALL); 51 | } 52 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 53 | } 54 | 55 | fn write_struct(&mut self, value: &T) -> ZxResult { 56 | if self.len() < core::mem::size_of::() { 57 | return Err(ZxError::BUFFER_TOO_SMALL); 58 | } 59 | unsafe { 60 | *(self.as_mut_ptr() as *mut T) = *value; 61 | } 62 | Ok(core::mem::size_of::()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/util.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /// Given a range and iterate sub-range for each block 4 | pub struct BlockIter { 5 | pub begin: usize, 6 | pub end: usize, 7 | pub block_size_log2: u8, 8 | } 9 | 10 | #[derive(Debug, Eq, PartialEq)] 11 | pub struct BlockRange { 12 | pub block: usize, 13 | pub begin: usize, 14 | pub end: usize, 15 | pub block_size_log2: u8, 16 | } 17 | 18 | impl BlockRange { 19 | pub fn len(&self) -> usize { 20 | self.end - self.begin 21 | } 22 | pub fn is_full(&self) -> bool { 23 | self.len() == (1usize << self.block_size_log2) 24 | } 25 | pub fn is_empty(&self) -> bool { 26 | self.len() == 0 27 | } 28 | pub fn origin_begin(&self) -> usize { 29 | (self.block << self.block_size_log2) + self.begin 30 | } 31 | pub fn origin_end(&self) -> usize { 32 | (self.block << self.block_size_log2) + self.end 33 | } 34 | } 35 | 36 | impl Iterator for BlockIter { 37 | type Item = BlockRange; 38 | 39 | fn next(&mut self) -> Option<::Item> { 40 | if self.begin >= self.end { 41 | return None; 42 | } 43 | let block_size_log2 = self.block_size_log2; 44 | let block_size = 1usize << self.block_size_log2; 45 | let block = self.begin / block_size; 46 | let begin = self.begin % block_size; 47 | let end = if block == self.end / block_size { 48 | self.end % block_size 49 | } else { 50 | block_size 51 | }; 52 | self.begin += end - begin; 53 | Some(BlockRange { 54 | block, 55 | begin, 56 | end, 57 | block_size_log2, 58 | }) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod test { 64 | use super::*; 65 | 66 | #[test] 67 | fn block_iter() { 68 | let mut iter = BlockIter { 69 | begin: 0x123, 70 | end: 0x2018, 71 | block_size_log2: 12, 72 | }; 73 | assert_eq!( 74 | iter.next(), 75 | Some(BlockRange { 76 | block: 0, 77 | begin: 0x123, 78 | end: 0x1000, 79 | block_size_log2: 12 80 | }) 81 | ); 82 | assert_eq!( 83 | iter.next(), 84 | Some(BlockRange { 85 | block: 1, 86 | begin: 0, 87 | end: 0x1000, 88 | block_size_log2: 12 89 | }) 90 | ); 91 | assert_eq!( 92 | iter.next(), 93 | Some(BlockRange { 94 | block: 2, 95 | begin: 0, 96 | end: 0x18, 97 | block_size_log2: 12 98 | }) 99 | ); 100 | assert_eq!(iter.next(), None); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | 3 | mod vmar; 4 | mod vmo; 5 | 6 | pub use self::{vmar::*, vmo::*}; 7 | 8 | /// Physical Address 9 | pub type PhysAddr = usize; 10 | 11 | /// Virtual Address 12 | pub type VirtAddr = usize; 13 | 14 | /// Device Address 15 | pub type DevVAddr = usize; 16 | 17 | /// Size of a page 18 | pub const PAGE_SIZE: usize = 0x1000; 19 | 20 | /// log2(PAGE_SIZE) 21 | pub const PAGE_SIZE_LOG2: usize = 12; 22 | 23 | /// Check whether `x` is a multiple of `PAGE_SIZE`. 24 | pub fn page_aligned(x: usize) -> bool { 25 | check_aligned(x, PAGE_SIZE) 26 | } 27 | 28 | /// Check whether `x` is a multiple of `align`. 29 | pub fn check_aligned(x: usize, align: usize) -> bool { 30 | x % align == 0 31 | } 32 | 33 | /// How many pages the `size` needs. 34 | /// To avoid overflow and pass more unit tests, use wrapping add 35 | pub fn pages(size: usize) -> usize { 36 | ceil(size, PAGE_SIZE) 37 | } 38 | 39 | /// How many `align` the `x` needs. 40 | pub fn ceil(x: usize, align: usize) -> usize { 41 | x.wrapping_add(align - 1) / align 42 | } 43 | 44 | /// Round up `size` to a multiple of `PAGE_SIZE`. 45 | pub fn roundup_pages(size: usize) -> usize { 46 | pages(size) * PAGE_SIZE 47 | } 48 | 49 | /// Round down `size` to a multiple of `PAGE_SIZE`. 50 | pub fn round_down_pages(size: usize) -> usize { 51 | size / PAGE_SIZE * PAGE_SIZE 52 | } 53 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/vm/vmar.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, crate::object::*, alloc::sync::Arc, alloc::vec::Vec, kernel_hal::MMUFlags, 3 | spin::Mutex, 4 | }; 5 | 6 | /// Virtual Memory Address Regions 7 | pub struct VmAddressRegion { 8 | base: KObjectBase, 9 | } 10 | 11 | impl_kobject!(VmAddressRegion); 12 | 13 | impl VmAddressRegion { 14 | /// Create a new root VMAR. 15 | pub fn new_root() -> Arc { 16 | Arc::new(VmAddressRegion { 17 | base: KObjectBase::new(), 18 | }) 19 | } 20 | } 21 | 22 | /// Virtual Memory Mapping 23 | pub struct VmMapping { 24 | /// The permission limitation of the vmar 25 | permissions: MMUFlags, 26 | vmo: Arc, 27 | // page_table: Arc>, 28 | inner: Mutex, 29 | } 30 | 31 | #[derive(Debug, Clone)] 32 | struct VmMappingInner { 33 | /// The actual flags used in the mapping of each page 34 | flags: Vec, 35 | addr: VirtAddr, 36 | size: usize, 37 | vmo_offset: usize, 38 | } 39 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/vm/vmo/physical.rs: -------------------------------------------------------------------------------- 1 | use {super::*, alloc::sync::Arc, kernel_hal::MMUFlags, spin::Mutex}; 2 | 3 | /// VMO representing a physical range of memory. 4 | pub struct VMObjectPhysical { 5 | paddr: PhysAddr, 6 | pages: usize, 7 | /// Lock this when access physical memory. 8 | data_lock: Mutex<()>, 9 | inner: Mutex, 10 | } 11 | 12 | struct VMObjectPhysicalInner { 13 | cache_policy: CachePolicy, 14 | } 15 | 16 | impl VMObjectPhysicalInner { 17 | pub fn new() -> VMObjectPhysicalInner { 18 | VMObjectPhysicalInner { 19 | cache_policy: CachePolicy::Uncached, 20 | } 21 | } 22 | } 23 | 24 | impl VMObjectPhysical { 25 | /// Create a new VMO representing a piece of contiguous physical memory. 26 | /// You must ensure nobody has the ownership of this piece of memory yet. 27 | pub fn new(paddr: PhysAddr, pages: usize) -> Arc { 28 | assert!(page_aligned(paddr)); 29 | Arc::new(VMObjectPhysical { 30 | paddr, 31 | pages, 32 | data_lock: Mutex::default(), 33 | inner: Mutex::new(VMObjectPhysicalInner::new()), 34 | }) 35 | } 36 | } 37 | 38 | impl VMObjectTrait for VMObjectPhysical { 39 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 40 | let _ = self.data_lock.lock(); 41 | assert!(offset + buf.len() <= self.len()); 42 | kernel_hal::pmem_read(self.paddr + offset, buf); 43 | Ok(()) 44 | } 45 | 46 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 47 | let _ = self.data_lock.lock(); 48 | assert!(offset + buf.len() <= self.len()); 49 | kernel_hal::pmem_write(self.paddr + offset, buf); 50 | Ok(()) 51 | } 52 | 53 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 54 | let _ = self.data_lock.lock(); 55 | assert!(offset + len <= self.len()); 56 | kernel_hal::pmem_zero(self.paddr + offset, len); 57 | Ok(()) 58 | } 59 | 60 | fn len(&self) -> usize { 61 | self.pages * PAGE_SIZE 62 | } 63 | 64 | fn set_len(&self, _len: usize) -> ZxResult { 65 | unimplemented!() 66 | } 67 | 68 | fn commit_page(&self, page_idx: usize, _flags: MMUFlags) -> ZxResult { 69 | Ok(self.paddr + page_idx * PAGE_SIZE) 70 | } 71 | 72 | fn commit_pages_with( 73 | &self, 74 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 75 | ) -> ZxResult { 76 | f(&mut |page_idx, _flags| Ok(self.paddr + page_idx * PAGE_SIZE)) 77 | } 78 | 79 | fn commit(&self, _offset: usize, _len: usize) -> ZxResult { 80 | // do nothing 81 | Ok(()) 82 | } 83 | 84 | fn decommit(&self, _offset: usize, _len: usize) -> ZxResult { 85 | // do nothing 86 | Ok(()) 87 | } 88 | 89 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 90 | Err(ZxError::NOT_SUPPORTED) 91 | } 92 | 93 | fn complete_info(&self, _info: &mut VmoInfo) { 94 | warn!("VmoInfo for physical is unimplemented"); 95 | } 96 | 97 | fn cache_policy(&self) -> CachePolicy { 98 | let inner = self.inner.lock(); 99 | inner.cache_policy 100 | } 101 | 102 | fn set_cache_policy(&self, policy: CachePolicy) -> ZxResult { 103 | let mut inner = self.inner.lock(); 104 | inner.cache_policy = policy; 105 | Ok(()) 106 | } 107 | 108 | fn committed_pages_in_range(&self, _start_idx: usize, _end_idx: usize) -> usize { 109 | 0 110 | } 111 | 112 | fn is_contiguous(&self) -> bool { 113 | true 114 | } 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | #![allow(unsafe_code)] 120 | use super::*; 121 | use kernel_hal::CachePolicy; 122 | 123 | #[test] 124 | fn read_write() { 125 | let vmo = VmObject::new_physical(0x1000, 2); 126 | assert_eq!(vmo.cache_policy(), CachePolicy::Uncached); 127 | super::super::tests::read_write(&vmo); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /code/ch03-02/object/src/vm/vmo/slice.rs: -------------------------------------------------------------------------------- 1 | use {super::*, kernel_hal::MMUFlags}; 2 | 3 | pub struct VMObjectSlice { 4 | /// Parent node. 5 | parent: Arc, 6 | /// The offset from parent. 7 | offset: usize, 8 | /// The size in bytes. 9 | size: usize, 10 | } 11 | 12 | impl VMObjectSlice { 13 | pub fn new(parent: Arc, offset: usize, size: usize) -> Arc { 14 | Arc::new(VMObjectSlice { 15 | parent, 16 | offset, 17 | size, 18 | }) 19 | } 20 | 21 | fn check_range(&self, offset: usize, len: usize) -> ZxResult { 22 | if offset + len >= self.size { 23 | return Err(ZxError::OUT_OF_RANGE); 24 | } 25 | Ok(()) 26 | } 27 | } 28 | 29 | impl VMObjectTrait for VMObjectSlice { 30 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 31 | self.check_range(offset, buf.len())?; 32 | self.parent.read(offset + self.offset, buf) 33 | } 34 | 35 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 36 | self.check_range(offset, buf.len())?; 37 | self.parent.write(offset + self.offset, buf) 38 | } 39 | 40 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 41 | self.check_range(offset, len)?; 42 | self.parent.zero(offset + self.offset, len) 43 | } 44 | 45 | fn len(&self) -> usize { 46 | self.size 47 | } 48 | 49 | fn set_len(&self, _len: usize) -> ZxResult { 50 | unimplemented!() 51 | } 52 | 53 | fn commit_page(&self, page_idx: usize, flags: MMUFlags) -> ZxResult { 54 | self.parent 55 | .commit_page(page_idx + self.offset / PAGE_SIZE, flags) 56 | } 57 | 58 | fn commit_pages_with( 59 | &self, 60 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 61 | ) -> ZxResult { 62 | self.parent.commit_pages_with(f) 63 | } 64 | 65 | fn commit(&self, offset: usize, len: usize) -> ZxResult { 66 | self.parent.commit(offset + self.offset, len) 67 | } 68 | 69 | fn decommit(&self, offset: usize, len: usize) -> ZxResult { 70 | self.parent.decommit(offset + self.offset, len) 71 | } 72 | 73 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 74 | Err(ZxError::NOT_SUPPORTED) 75 | } 76 | 77 | fn complete_info(&self, info: &mut VmoInfo) { 78 | self.parent.complete_info(info); 79 | } 80 | 81 | fn cache_policy(&self) -> CachePolicy { 82 | self.parent.cache_policy() 83 | } 84 | 85 | fn set_cache_policy(&self, _policy: CachePolicy) -> ZxResult { 86 | Ok(()) 87 | } 88 | 89 | fn committed_pages_in_range(&self, start_idx: usize, end_idx: usize) -> usize { 90 | let po = pages(self.offset); 91 | self.parent 92 | .committed_pages_in_range(start_idx + po, end_idx + po) 93 | } 94 | 95 | fn pin(&self, offset: usize, len: usize) -> ZxResult { 96 | self.check_range(offset, len)?; 97 | self.parent.pin(offset + self.offset, len) 98 | } 99 | 100 | fn unpin(&self, offset: usize, len: usize) -> ZxResult { 101 | self.check_range(offset, len)?; 102 | self.parent.unpin(offset + self.offset, len) 103 | } 104 | 105 | fn is_contiguous(&self) -> bool { 106 | self.parent.is_contiguous() 107 | } 108 | 109 | fn is_paged(&self) -> bool { 110 | self.parent.is_paged() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /code/ch03-04/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "object", 4 | "kernel-hal-unix", 5 | "kernel-hal", 6 | ] 7 | -------------------------------------------------------------------------------- /code/ch03-04/kernel-hal-unix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-unix" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation on Linux and macOS." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | libc = "0.2" 13 | tempfile = "3" 14 | bitflags = "1.2" 15 | lazy_static = "1.4" 16 | kernel-hal = { path = "../kernel-hal" } 17 | async-std = "1.9" 18 | trapframe = "0.8.0" 19 | -------------------------------------------------------------------------------- /code/ch03-04/kernel-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL interface definations." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | bitflags = "1.2" 12 | trapframe = "0.8.0" 13 | numeric-enum-macro = "0.2" 14 | -------------------------------------------------------------------------------- /code/ch03-04/object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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 | log = "0.4" 11 | spin = "0.7" 12 | downcast-rs = { version = "1.2.0", default-features = false } 13 | bitflags = "1.2" 14 | hashbrown = "0.9" 15 | trapframe = "0.8.0" 16 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 17 | async-std = { version = "1.9", features = ["attributes", "unstable"] } 18 | numeric-enum-macro = "0.2" 19 | kernel-hal = { path = "../kernel-hal" } 20 | kernel-hal-unix = { path = "../kernel-hal-unix" } 21 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![allow(dead_code)] 4 | #![feature(get_mut_unchecked)] 5 | #![feature(drain_filter)] 6 | 7 | extern crate alloc; 8 | 9 | #[cfg(test)] 10 | #[macro_use] 11 | extern crate std; 12 | 13 | #[macro_use] 14 | extern crate log; 15 | 16 | mod error; 17 | mod ipc; 18 | mod object; 19 | mod task; 20 | mod util; 21 | mod vm; 22 | 23 | pub use self::error::*; 24 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | pub type HandleValue = u32; 6 | pub const INVALID_HANDLE: HandleValue = 0; 7 | 8 | /// 内核对象句柄 9 | #[derive(Clone)] 10 | pub struct Handle { 11 | pub object: Arc, 12 | pub rights: Rights, 13 | } 14 | 15 | impl Handle { 16 | /// 创建一个新句柄 17 | pub fn new(object: Arc, rights: Rights) -> Self { 18 | Handle { object, rights } 19 | } 20 | } 21 | // ANCHOR_END: handle 22 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | #[derive(Default)] 7 | pub struct Rights: u32 { 8 | const DUPLICATE = 1 << 0; 9 | const TRANSFER = 1 << 1; 10 | const READ = 1 << 2; 11 | const WRITE = 1 << 3; 12 | const EXECUTE = 1 << 4; 13 | const MAP = 1 << 5; 14 | const GET_PROPERTY = 1 << 6; 15 | const SET_PROPERTY = 1 << 7; 16 | const ENUMERATE = 1 << 8; 17 | const DESTROY = 1 << 9; 18 | const SET_POLICY = 1 << 10; 19 | const GET_POLICY = 1 << 11; 20 | const SIGNAL = 1 << 12; 21 | const SIGNAL_PEER = 1 << 13; 22 | const WAIT = 1 << 14; 23 | const INSPECT = 1 << 15; 24 | const MANAGE_JOB = 1 << 16; 25 | const MANAGE_PROCESS = 1 << 17; 26 | const MANAGE_THREAD = 1 << 18; 27 | const APPLY_PROFILE = 1 << 19; 28 | const SAME_RIGHTS = 1 << 31; 29 | 30 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 31 | const IO = Self::READ.bits | Self::WRITE.bits; 32 | 33 | /// GET_PROPERTY | SET_PROPERTY 34 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 35 | 36 | /// GET_POLICY | SET_POLICY 37 | const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; 38 | 39 | /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER 40 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 41 | 42 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 43 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits 44 | | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 45 | 46 | /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD 47 | const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; 48 | 49 | /// BASIC | WAIT 50 | const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; 51 | 52 | /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD 53 | const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits 54 | | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 55 | 56 | } 57 | } 58 | // ANCHOR_END: rights 59 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/task/job_policy.rs: -------------------------------------------------------------------------------- 1 | /// Security and resource policies of a job. 2 | #[derive(Default, Copy, Clone)] 3 | pub struct JobPolicy { 4 | // TODO: use bitset 5 | action: [Option; 15], 6 | } 7 | 8 | impl JobPolicy { 9 | /// Get the action of a policy `condition`. 10 | pub fn get_action(&self, condition: PolicyCondition) -> Option { 11 | self.action[condition as usize] 12 | } 13 | 14 | /// Apply a basic policy. 15 | pub fn apply(&mut self, policy: BasicPolicy) { 16 | self.action[policy.condition as usize] = Some(policy.action); 17 | } 18 | 19 | /// Merge the policy with `parent`'s. 20 | pub fn merge(&self, parent: &Self) -> Self { 21 | let mut new = *self; 22 | for i in 0..15 { 23 | if parent.action[i].is_some() { 24 | new.action[i] = parent.action[i]; 25 | } 26 | } 27 | new 28 | } 29 | } 30 | 31 | /// Control the effect in the case of conflict between 32 | /// the existing policies and the new policies when setting new policies. 33 | #[derive(Debug, Copy, Clone)] 34 | pub enum SetPolicyOptions { 35 | /// Policy is applied for all conditions in policy or the call fails. 36 | Absolute, 37 | /// Policy is applied for the conditions not specifically overridden by the parent policy. 38 | Relative, 39 | } 40 | 41 | /// The policy type. 42 | #[repr(C)] 43 | #[derive(Debug, Copy, Clone)] 44 | pub struct BasicPolicy { 45 | /// Condition when the policy is applied. 46 | pub condition: PolicyCondition, 47 | /// 48 | pub action: PolicyAction, 49 | } 50 | 51 | /// The condition when a policy is applied. 52 | #[repr(u32)] 53 | #[derive(Debug, Copy, Clone)] 54 | pub enum PolicyCondition { 55 | /// A process under this job is attempting to issue a syscall with an invalid handle. 56 | /// In this case, `PolicyAction::Allow` and `PolicyAction::Deny` are equivalent: 57 | /// if the syscall returns, it will always return the error ZX_ERR_BAD_HANDLE. 58 | BadHandle = 0, 59 | /// A process under this job is attempting to issue a syscall with a handle that does not support such operation. 60 | WrongObject = 1, 61 | /// A process under this job is attempting to map an address region with write-execute access. 62 | VmarWx = 2, 63 | /// A special condition that stands for all of the above ZX_NEW conditions 64 | /// such as NEW_VMO, NEW_CHANNEL, NEW_EVENT, NEW_EVENTPAIR, NEW_PORT, NEW_SOCKET, NEW_FIFO, 65 | /// And any future ZX_NEW policy. 66 | /// This will include any new kernel objects which do not require a parent object for creation. 67 | NewAny = 3, 68 | /// A process under this job is attempting to create a new vm object. 69 | NewVMO = 4, 70 | /// A process under this job is attempting to create a new channel. 71 | NewChannel = 5, 72 | /// A process under this job is attempting to create a new event. 73 | NewEvent = 6, 74 | /// A process under this job is attempting to create a new event pair. 75 | NewEventPair = 7, 76 | /// A process under this job is attempting to create a new port. 77 | NewPort = 8, 78 | /// A process under this job is attempting to create a new socket. 79 | NewSocket = 9, 80 | /// A process under this job is attempting to create a new fifo. 81 | NewFIFO = 10, 82 | /// A process under this job is attempting to create a new timer. 83 | NewTimer = 11, 84 | /// A process under this job is attempting to create a new process. 85 | NewProcess = 12, 86 | /// A process under this job is attempting to create a new profile. 87 | NewProfile = 13, 88 | /// A process under this job is attempting to use zx_vmo_replace_as_executable() 89 | /// with a ZX_HANDLE_INVALID as the second argument rather than a valid ZX_RSRC_KIND_VMEX. 90 | AmbientMarkVMOExec = 14, 91 | } 92 | 93 | /// The action taken when the condition happens specified by a policy. 94 | #[repr(u32)] 95 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 96 | pub enum PolicyAction { 97 | /// Allow condition. 98 | Allow = 0, 99 | /// Prevent condition. 100 | Deny = 1, 101 | /// Generate an exception via the debug port. An exception generated this 102 | /// way acts as a breakpoint. The thread may be resumed after the exception. 103 | AllowException = 2, 104 | /// Just like `AllowException`, but after resuming condition is denied. 105 | DenyException = 3, 106 | /// Terminate the process. 107 | Kill = 4, 108 | } 109 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod job; 4 | mod job_policy; 5 | mod process; 6 | mod thread; 7 | 8 | pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; 9 | 10 | /// Task (Thread, Process, or Job) 11 | pub trait Task: Sync + Send { 12 | /// Kill the task. The task do not terminate immediately when killed. 13 | /// It will terminate after all its children are terminated or some cleanups are finished. 14 | fn kill(&self); 15 | 16 | /// Suspend the task. Currently only thread or process handles may be suspended. 17 | fn suspend(&self); 18 | 19 | /// Resume the task 20 | fn resume(&self); 21 | } 22 | 23 | /// The return code set when a task is killed via zx_task_kill(). 24 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 25 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | /// Possible values for "kind" in zx_thread_read_state and zx_thread_write_state. 8 | #[allow(missing_docs)] 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum ThreadStateKind { 11 | General = 0, 12 | FS = 6, 13 | GS = 7, 14 | } 15 | } 16 | 17 | pub(super) trait ContextExt { 18 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 19 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 20 | } 21 | 22 | impl ContextExt for UserContext { 23 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 24 | match kind { 25 | ThreadStateKind::General => buf.write_struct(&self.general), 26 | ThreadStateKind::FS => buf.write_struct(&self.general.fsbase), 27 | ThreadStateKind::GS => buf.write_struct(&self.general.gsbase), 28 | } 29 | } 30 | 31 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 32 | match kind { 33 | ThreadStateKind::General => self.general = buf.read_struct()?, 34 | ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?, 35 | ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?, 36 | } 37 | Ok(()) 38 | } 39 | } 40 | 41 | trait BufExt { 42 | fn read_struct(&self) -> ZxResult; 43 | fn write_struct(&mut self, value: &T) -> ZxResult; 44 | } 45 | 46 | #[allow(unsafe_code)] 47 | impl BufExt for [u8] { 48 | fn read_struct(&self) -> ZxResult { 49 | if self.len() < core::mem::size_of::() { 50 | return Err(ZxError::BUFFER_TOO_SMALL); 51 | } 52 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 53 | } 54 | 55 | fn write_struct(&mut self, value: &T) -> ZxResult { 56 | if self.len() < core::mem::size_of::() { 57 | return Err(ZxError::BUFFER_TOO_SMALL); 58 | } 59 | unsafe { 60 | *(self.as_mut_ptr() as *mut T) = *value; 61 | } 62 | Ok(core::mem::size_of::()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/util.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /// Given a range and iterate sub-range for each block 4 | pub struct BlockIter { 5 | pub begin: usize, 6 | pub end: usize, 7 | pub block_size_log2: u8, 8 | } 9 | 10 | #[derive(Debug, Eq, PartialEq)] 11 | pub struct BlockRange { 12 | pub block: usize, 13 | pub begin: usize, 14 | pub end: usize, 15 | pub block_size_log2: u8, 16 | } 17 | 18 | impl BlockRange { 19 | pub fn len(&self) -> usize { 20 | self.end - self.begin 21 | } 22 | pub fn is_full(&self) -> bool { 23 | self.len() == (1usize << self.block_size_log2) 24 | } 25 | pub fn is_empty(&self) -> bool { 26 | self.len() == 0 27 | } 28 | pub fn origin_begin(&self) -> usize { 29 | (self.block << self.block_size_log2) + self.begin 30 | } 31 | pub fn origin_end(&self) -> usize { 32 | (self.block << self.block_size_log2) + self.end 33 | } 34 | } 35 | 36 | impl Iterator for BlockIter { 37 | type Item = BlockRange; 38 | 39 | fn next(&mut self) -> Option<::Item> { 40 | if self.begin >= self.end { 41 | return None; 42 | } 43 | let block_size_log2 = self.block_size_log2; 44 | let block_size = 1usize << self.block_size_log2; 45 | let block = self.begin / block_size; 46 | let begin = self.begin % block_size; 47 | let end = if block == self.end / block_size { 48 | self.end % block_size 49 | } else { 50 | block_size 51 | }; 52 | self.begin += end - begin; 53 | Some(BlockRange { 54 | block, 55 | begin, 56 | end, 57 | block_size_log2, 58 | }) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod test { 64 | use super::*; 65 | 66 | #[test] 67 | fn block_iter() { 68 | let mut iter = BlockIter { 69 | begin: 0x123, 70 | end: 0x2018, 71 | block_size_log2: 12, 72 | }; 73 | assert_eq!( 74 | iter.next(), 75 | Some(BlockRange { 76 | block: 0, 77 | begin: 0x123, 78 | end: 0x1000, 79 | block_size_log2: 12 80 | }) 81 | ); 82 | assert_eq!( 83 | iter.next(), 84 | Some(BlockRange { 85 | block: 1, 86 | begin: 0, 87 | end: 0x1000, 88 | block_size_log2: 12 89 | }) 90 | ); 91 | assert_eq!( 92 | iter.next(), 93 | Some(BlockRange { 94 | block: 2, 95 | begin: 0, 96 | end: 0x18, 97 | block_size_log2: 12 98 | }) 99 | ); 100 | assert_eq!(iter.next(), None); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | 3 | mod vmar; 4 | mod vmo; 5 | 6 | pub use self::{vmar::*, vmo::*}; 7 | 8 | /// Physical Address 9 | pub type PhysAddr = usize; 10 | 11 | /// Virtual Address 12 | pub type VirtAddr = usize; 13 | 14 | /// Device Address 15 | pub type DevVAddr = usize; 16 | 17 | /// Size of a page 18 | pub const PAGE_SIZE: usize = 0x1000; 19 | 20 | /// log2(PAGE_SIZE) 21 | pub const PAGE_SIZE_LOG2: usize = 12; 22 | 23 | /// Check whether `x` is a multiple of `PAGE_SIZE`. 24 | pub fn page_aligned(x: usize) -> bool { 25 | check_aligned(x, PAGE_SIZE) 26 | } 27 | 28 | /// Check whether `x` is a multiple of `align`. 29 | pub fn check_aligned(x: usize, align: usize) -> bool { 30 | x % align == 0 31 | } 32 | 33 | /// How many pages the `size` needs. 34 | /// To avoid overflow and pass more unit tests, use wrapping add 35 | pub fn pages(size: usize) -> usize { 36 | ceil(size, PAGE_SIZE) 37 | } 38 | 39 | /// How many `align` the `x` needs. 40 | pub fn ceil(x: usize, align: usize) -> usize { 41 | x.wrapping_add(align - 1) / align 42 | } 43 | 44 | /// Round up `size` to a multiple of `PAGE_SIZE`. 45 | pub fn roundup_pages(size: usize) -> usize { 46 | pages(size) * PAGE_SIZE 47 | } 48 | 49 | /// Round down `size` to a multiple of `PAGE_SIZE`. 50 | pub fn round_down_pages(size: usize) -> usize { 51 | size / PAGE_SIZE * PAGE_SIZE 52 | } 53 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/vm/vmo/physical.rs: -------------------------------------------------------------------------------- 1 | use {super::*, alloc::sync::Arc, kernel_hal::MMUFlags, spin::Mutex}; 2 | 3 | /// VMO representing a physical range of memory. 4 | pub struct VMObjectPhysical { 5 | paddr: PhysAddr, 6 | pages: usize, 7 | /// Lock this when access physical memory. 8 | data_lock: Mutex<()>, 9 | inner: Mutex, 10 | } 11 | 12 | struct VMObjectPhysicalInner { 13 | cache_policy: CachePolicy, 14 | } 15 | 16 | impl VMObjectPhysicalInner { 17 | pub fn new() -> VMObjectPhysicalInner { 18 | VMObjectPhysicalInner { 19 | cache_policy: CachePolicy::Uncached, 20 | } 21 | } 22 | } 23 | 24 | impl VMObjectPhysical { 25 | /// Create a new VMO representing a piece of contiguous physical memory. 26 | /// You must ensure nobody has the ownership of this piece of memory yet. 27 | pub fn new(paddr: PhysAddr, pages: usize) -> Arc { 28 | assert!(page_aligned(paddr)); 29 | Arc::new(VMObjectPhysical { 30 | paddr, 31 | pages, 32 | data_lock: Mutex::default(), 33 | inner: Mutex::new(VMObjectPhysicalInner::new()), 34 | }) 35 | } 36 | } 37 | 38 | impl VMObjectTrait for VMObjectPhysical { 39 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 40 | let _ = self.data_lock.lock(); 41 | assert!(offset + buf.len() <= self.len()); 42 | kernel_hal::pmem_read(self.paddr + offset, buf); 43 | Ok(()) 44 | } 45 | 46 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 47 | let _ = self.data_lock.lock(); 48 | assert!(offset + buf.len() <= self.len()); 49 | kernel_hal::pmem_write(self.paddr + offset, buf); 50 | Ok(()) 51 | } 52 | 53 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 54 | let _ = self.data_lock.lock(); 55 | assert!(offset + len <= self.len()); 56 | kernel_hal::pmem_zero(self.paddr + offset, len); 57 | Ok(()) 58 | } 59 | 60 | fn len(&self) -> usize { 61 | self.pages * PAGE_SIZE 62 | } 63 | 64 | fn set_len(&self, _len: usize) -> ZxResult { 65 | unimplemented!() 66 | } 67 | 68 | fn commit_page(&self, page_idx: usize, _flags: MMUFlags) -> ZxResult { 69 | Ok(self.paddr + page_idx * PAGE_SIZE) 70 | } 71 | 72 | fn commit_pages_with( 73 | &self, 74 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 75 | ) -> ZxResult { 76 | f(&mut |page_idx, _flags| Ok(self.paddr + page_idx * PAGE_SIZE)) 77 | } 78 | 79 | fn commit(&self, _offset: usize, _len: usize) -> ZxResult { 80 | // do nothing 81 | Ok(()) 82 | } 83 | 84 | fn decommit(&self, _offset: usize, _len: usize) -> ZxResult { 85 | // do nothing 86 | Ok(()) 87 | } 88 | 89 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 90 | Err(ZxError::NOT_SUPPORTED) 91 | } 92 | 93 | fn complete_info(&self, _info: &mut VmoInfo) { 94 | warn!("VmoInfo for physical is unimplemented"); 95 | } 96 | 97 | fn cache_policy(&self) -> CachePolicy { 98 | let inner = self.inner.lock(); 99 | inner.cache_policy 100 | } 101 | 102 | fn set_cache_policy(&self, policy: CachePolicy) -> ZxResult { 103 | let mut inner = self.inner.lock(); 104 | inner.cache_policy = policy; 105 | Ok(()) 106 | } 107 | 108 | fn committed_pages_in_range(&self, _start_idx: usize, _end_idx: usize) -> usize { 109 | 0 110 | } 111 | 112 | fn is_contiguous(&self) -> bool { 113 | true 114 | } 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | #![allow(unsafe_code)] 120 | use super::*; 121 | use kernel_hal::CachePolicy; 122 | 123 | #[test] 124 | fn read_write() { 125 | let vmo = VmObject::new_physical(0x1000, 2); 126 | assert_eq!(vmo.cache_policy(), CachePolicy::Uncached); 127 | super::super::tests::read_write(&vmo); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /code/ch03-04/object/src/vm/vmo/slice.rs: -------------------------------------------------------------------------------- 1 | use {super::*, kernel_hal::MMUFlags}; 2 | 3 | pub struct VMObjectSlice { 4 | /// Parent node. 5 | parent: Arc, 6 | /// The offset from parent. 7 | offset: usize, 8 | /// The size in bytes. 9 | size: usize, 10 | } 11 | 12 | impl VMObjectSlice { 13 | pub fn new(parent: Arc, offset: usize, size: usize) -> Arc { 14 | Arc::new(VMObjectSlice { 15 | parent, 16 | offset, 17 | size, 18 | }) 19 | } 20 | 21 | fn check_range(&self, offset: usize, len: usize) -> ZxResult { 22 | if offset + len >= self.size { 23 | return Err(ZxError::OUT_OF_RANGE); 24 | } 25 | Ok(()) 26 | } 27 | } 28 | 29 | impl VMObjectTrait for VMObjectSlice { 30 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 31 | self.check_range(offset, buf.len())?; 32 | self.parent.read(offset + self.offset, buf) 33 | } 34 | 35 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 36 | self.check_range(offset, buf.len())?; 37 | self.parent.write(offset + self.offset, buf) 38 | } 39 | 40 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 41 | self.check_range(offset, len)?; 42 | self.parent.zero(offset + self.offset, len) 43 | } 44 | 45 | fn len(&self) -> usize { 46 | self.size 47 | } 48 | 49 | fn set_len(&self, _len: usize) -> ZxResult { 50 | unimplemented!() 51 | } 52 | 53 | fn commit_page(&self, page_idx: usize, flags: MMUFlags) -> ZxResult { 54 | self.parent 55 | .commit_page(page_idx + self.offset / PAGE_SIZE, flags) 56 | } 57 | 58 | fn commit_pages_with( 59 | &self, 60 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 61 | ) -> ZxResult { 62 | self.parent.commit_pages_with(f) 63 | } 64 | 65 | fn commit(&self, offset: usize, len: usize) -> ZxResult { 66 | self.parent.commit(offset + self.offset, len) 67 | } 68 | 69 | fn decommit(&self, offset: usize, len: usize) -> ZxResult { 70 | self.parent.decommit(offset + self.offset, len) 71 | } 72 | 73 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 74 | Err(ZxError::NOT_SUPPORTED) 75 | } 76 | 77 | fn complete_info(&self, info: &mut VmoInfo) { 78 | self.parent.complete_info(info); 79 | } 80 | 81 | fn cache_policy(&self) -> CachePolicy { 82 | self.parent.cache_policy() 83 | } 84 | 85 | fn set_cache_policy(&self, _policy: CachePolicy) -> ZxResult { 86 | Ok(()) 87 | } 88 | 89 | fn committed_pages_in_range(&self, start_idx: usize, end_idx: usize) -> usize { 90 | let po = pages(self.offset); 91 | self.parent 92 | .committed_pages_in_range(start_idx + po, end_idx + po) 93 | } 94 | 95 | fn pin(&self, offset: usize, len: usize) -> ZxResult { 96 | self.check_range(offset, len)?; 97 | self.parent.pin(offset + self.offset, len) 98 | } 99 | 100 | fn unpin(&self, offset: usize, len: usize) -> ZxResult { 101 | self.check_range(offset, len)?; 102 | self.parent.unpin(offset + self.offset, len) 103 | } 104 | 105 | fn is_contiguous(&self) -> bool { 106 | self.parent.is_contiguous() 107 | } 108 | 109 | fn is_paged(&self) -> bool { 110 | self.parent.is_paged() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /code/ch04-01/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "zircon-loader", 4 | "zircon-object", 5 | "kernel-hal-unix", 6 | "kernel-hal", 7 | ] 8 | -------------------------------------------------------------------------------- /code/ch04-01/kernel-hal-unix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-unix" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation on Linux and macOS." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | libc = "0.2" 13 | tempfile = "3" 14 | bitflags = "1.2" 15 | lazy_static = "1.4" 16 | kernel-hal = { path = "../kernel-hal" } 17 | async-std = "1.9" 18 | trapframe = "0.8.0" 19 | git-version = "0.3" -------------------------------------------------------------------------------- /code/ch04-01/kernel-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL interface definations." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | bitflags = "1.2" 12 | trapframe = "0.8.0" 13 | numeric-enum-macro = "0.2" 14 | -------------------------------------------------------------------------------- /code/ch04-01/kernel-hal/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Hardware Abstraction Layer 2 | 3 | #![no_std] 4 | #![feature(linkage)] 5 | #![deny(warnings)] 6 | 7 | extern crate alloc; 8 | 9 | pub mod defs { 10 | use bitflags::bitflags; 11 | use numeric_enum_macro::numeric_enum; 12 | 13 | bitflags! { 14 | pub struct MMUFlags: usize { 15 | #[allow(clippy::identity_op)] 16 | const CACHE_1 = 1 << 0; 17 | const CACHE_2 = 1 << 1; 18 | const READ = 1 << 2; 19 | const WRITE = 1 << 3; 20 | const EXECUTE = 1 << 4; 21 | const USER = 1 << 5; 22 | const RXW = Self::READ.bits | Self::WRITE.bits | Self::EXECUTE.bits; 23 | } 24 | } 25 | numeric_enum! { 26 | #[repr(u32)] 27 | #[derive(Debug, PartialEq, Clone, Copy)] 28 | pub enum CachePolicy { 29 | Cached = 0, 30 | Uncached = 1, 31 | UncachedDevice = 2, 32 | WriteCombining = 3, 33 | } 34 | } 35 | 36 | impl Default for CachePolicy { 37 | fn default() -> Self { 38 | CachePolicy::Cached 39 | } 40 | } 41 | 42 | pub const CACHE_POLICY_MASK: u32 = 3; 43 | 44 | pub type PhysAddr = usize; 45 | pub type VirtAddr = usize; 46 | pub type DevVAddr = usize; 47 | pub const PAGE_SIZE: usize = 0x1000; 48 | } 49 | 50 | mod dummy; 51 | pub mod vdso; 52 | 53 | pub use self::defs::*; 54 | pub use self::dummy::*; 55 | pub use trapframe::{GeneralRegs, UserContext}; 56 | -------------------------------------------------------------------------------- /code/ch04-01/kernel-hal/src/vdso.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Debug, Error, Formatter}; 2 | 3 | /// This struct contains constants that are initialized by the kernel 4 | /// once at boot time. From the vDSO code's perspective, they are 5 | /// read-only data that can never change. Hence, no synchronization is 6 | /// required to read them. 7 | #[repr(C)] 8 | #[derive(Debug)] 9 | pub struct VdsoConstants { 10 | /// Maximum number of CPUs that might be online during the lifetime 11 | /// of the booted system. 12 | pub max_num_cpus: u32, 13 | /// Bit map indicating features. 14 | pub features: Features, 15 | /// Number of bytes in a data cache line. 16 | pub dcache_line_size: u32, 17 | /// Number of bytes in an instruction cache line. 18 | pub icache_line_size: u32, 19 | /// Conversion factor for zx_ticks_get return values to seconds. 20 | pub ticks_per_second: u64, 21 | /// Ratio which relates ticks (zx_ticks_get) to clock monotonic. 22 | /// 23 | /// Specifically: ClockMono(ticks) = (ticks * N) / D 24 | pub ticks_to_mono_numerator: u32, 25 | pub ticks_to_mono_denominator: u32, 26 | /// Total amount of physical memory in the system, in bytes. 27 | pub physmem: u64, 28 | /// Actual length of `version_string`, not including the NUL terminator. 29 | pub version_string_len: u64, 30 | /// A NUL-terminated UTF-8 string returned by `zx_system_get_version_string`. 31 | pub version_string: VersionString, 32 | } 33 | 34 | /// Bit map indicating features. 35 | /// 36 | /// For specific feature bits, see zircon/features.h. 37 | #[repr(C)] 38 | #[derive(Debug)] 39 | pub struct Features { 40 | pub cpu: u32, 41 | /// Total amount of debug registers available in the system. 42 | pub hw_breakpoint_count: u32, 43 | pub hw_watchpoint_count: u32, 44 | } 45 | 46 | impl VdsoConstants { 47 | /// Set version string. 48 | pub fn set_version_string(&mut self, s: &str) { 49 | let len = s.len().min(64); 50 | self.version_string_len = len as u64; 51 | self.version_string.0[..len].copy_from_slice(s.as_bytes()); 52 | } 53 | } 54 | 55 | #[repr(C)] 56 | pub struct VersionString([u8; 64]); 57 | 58 | impl Default for VersionString { 59 | fn default() -> Self { 60 | VersionString([0; 64]) 61 | } 62 | } 63 | 64 | impl Debug for VersionString { 65 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 66 | for &c in self.0.iter().take_while(|&&c| c != 0) { 67 | write!(f, "{}", c as char)?; 68 | } 69 | Ok(()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/Scrt1.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/Scrt1.o -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/bringup.zbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/bringup.zbi -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/core-tests.zbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/core-tests.zbi -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/libc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/libc.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/libfdio.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/libfdio.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/libunwind.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/libunwind.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/libzircon-libos.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/libzircon-libos.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/libzircon.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/libzircon.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/userboot-libos.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/userboot-libos.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/userboot.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/userboot.so -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/zbi-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/zbi-linux -------------------------------------------------------------------------------- /code/ch04-01/prebuilt/zircon/x64/zbi-macos: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-01/prebuilt/zircon/x64/zbi-macos -------------------------------------------------------------------------------- /code/ch04-01/zircon-loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-loader" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Zircon user program (userboot) loader" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | xmas-elf = "0.7" 13 | zircon-object = { path = "../zircon-object" } 14 | kernel-hal = { path = "../kernel-hal" } 15 | env_logger = { version = "0.8", optional = true } 16 | structopt = { version = "0.3", default-features = false, optional = true } 17 | kernel-hal-unix = { path = "../kernel-hal-unix" } 18 | async-std = { version = "1.9", features = ["attributes"], optional = true } 19 | 20 | [features] 21 | default = ["std"] 22 | std = ["env_logger", "structopt", "async-std"] 23 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-loader/src/kcounter.rs: -------------------------------------------------------------------------------- 1 | use { 2 | alloc::sync::Arc, 3 | core::mem::size_of, 4 | zircon_object::{object::KernelObject, vm::*}, 5 | }; 6 | 7 | pub fn create_kcounter_vmo() -> (Arc, Arc) { 8 | const HEADER_SIZE: usize = size_of::(); 9 | let counter_name_vmo = VmObject::new_paged(1); 10 | let header = KCounterVmoHeader { 11 | magic: KCOUNTER_MAGIC, 12 | max_cpu: 1, 13 | counter_table_size: 0, 14 | }; 15 | let serde_header: [u8; HEADER_SIZE] = unsafe { core::mem::transmute(header) }; 16 | counter_name_vmo.write(0, &serde_header).unwrap(); 17 | counter_name_vmo.set_name("counters/desc"); 18 | 19 | let kcounters_vmo = VmObject::new_paged(1); 20 | kcounters_vmo.set_name("counters/arena"); 21 | (counter_name_vmo, kcounters_vmo) 22 | } 23 | 24 | // #[repr(C)] 25 | // struct KCounterDescItem { 26 | // name: [u8; 56], 27 | // type_: KCounterType, 28 | // } 29 | 30 | // #[repr(u64)] 31 | // enum KCounterType { 32 | // Sum = 1, 33 | // } 34 | 35 | // impl From<&KCounterDescriptor> for KCounterDescItem { 36 | // fn from(desc: &KCounterDescriptor) -> Self { 37 | // let mut name = [0u8; 56]; 38 | // let length = desc.name.len().min(56); 39 | // name[..length].copy_from_slice(&desc.name.as_bytes()[..length]); 40 | // KCounterDescItem { 41 | // name, 42 | // type_: KCounterType::Sum, 43 | // } 44 | // } 45 | // } 46 | 47 | #[repr(C)] 48 | struct KCounterVmoHeader { 49 | magic: u64, 50 | max_cpu: u64, 51 | counter_table_size: usize, 52 | } 53 | 54 | const KCOUNTER_MAGIC: u64 = 1_547_273_975; 55 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-loader/src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, unused_must_use)] 2 | 3 | extern crate log; 4 | 5 | use std::path::{Path, PathBuf}; 6 | use std::sync::Arc; 7 | use structopt::StructOpt; 8 | use zircon_loader::*; 9 | use zircon_object::object::*; 10 | use zircon_object::task::Process; 11 | 12 | #[derive(Debug, StructOpt)] 13 | #[structopt()] 14 | struct Opt { 15 | #[structopt(parse(from_os_str))] 16 | prebuilt_path: PathBuf, 17 | #[structopt(default_value = "")] 18 | cmdline: String, 19 | } 20 | 21 | #[async_std::main] 22 | async fn main() { 23 | kernel_hal_unix::init(); 24 | init_logger(); 25 | let opt = Opt::from_args(); 26 | let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 27 | let proc: Arc = run_userboot(&images, &opt.cmdline); 28 | drop(images); 29 | let proc = proc.downcast_arc::().unwrap(); 30 | proc.wait_for_end().await; 31 | } 32 | 33 | fn open_images(path: &Path) -> std::io::Result>> { 34 | Ok(Images { 35 | userboot: std::fs::read(path.join("userboot-libos.so"))?, 36 | vdso: std::fs::read(path.join("libzircon-libos.so"))?, 37 | zbi: std::fs::read(path.join("bringup.zbi"))?, 38 | }) 39 | } 40 | 41 | fn init_logger() { 42 | env_logger::builder() 43 | .format(|buf, record| { 44 | use env_logger::fmt::Color; 45 | use log::Level; 46 | use std::io::Write; 47 | 48 | let (tid, pid) = kernel_hal::Thread::get_tid(); 49 | let mut style = buf.style(); 50 | match record.level() { 51 | Level::Trace => style.set_color(Color::Black).set_intense(true), 52 | Level::Debug => style.set_color(Color::White), 53 | Level::Info => style.set_color(Color::Green), 54 | Level::Warn => style.set_color(Color::Yellow), 55 | Level::Error => style.set_color(Color::Red).set_bold(true), 56 | }; 57 | let now = kernel_hal_unix::timer_now(); 58 | let level = style.value(record.level()); 59 | let args = record.args(); 60 | writeln!(buf, "[{:?} {:>5} {}:{}] {}", now, level, pid, tid, args) 61 | }) 62 | .init(); 63 | } 64 | 65 | // #[cfg(test)] 66 | // mod tests { 67 | // use super::*; 68 | 69 | // #[async_std::test] 70 | // async fn userboot() { 71 | // kernel_hal_unix::init(); 72 | 73 | // let opt = Opt { 74 | // prebuilt_path: PathBuf::from("../prebuilt/zircon/x64"), 75 | // cmdline: String::from(""), 76 | // }; 77 | // let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 78 | 79 | // let proc: Arc = run_userboot(&images, &opt.cmdline); 80 | // drop(images); 81 | 82 | // proc.wait_for_end().await; 83 | // } 84 | // } 85 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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 | log = "0.4" 11 | spin = "0.7" 12 | downcast-rs = { version = "1.2.0", default-features = false } 13 | bitflags = "1.2" 14 | hashbrown = "0.9" 15 | trapframe = "0.8.0" 16 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 17 | async-std = { version = "1.9", features = ["attributes", "unstable"] } 18 | numeric-enum-macro = "0.2" 19 | xmas-elf = { version = "0.7"} 20 | kernel-hal = { path = "../kernel-hal" } 21 | kernel-hal-unix = { path = "../kernel-hal-unix" } 22 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/dev/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Device Drivers. 2 | 3 | mod resource; 4 | 5 | pub use self::resource::*; 6 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/dev/resource.rs: -------------------------------------------------------------------------------- 1 | use {crate::object::*, alloc::sync::Arc, bitflags::bitflags, numeric_enum_macro::numeric_enum}; 2 | 3 | numeric_enum! { 4 | #[repr(u32)] 5 | /// ResourceKind definition from fuchsia/zircon/system/public/zircon/syscalls/resource.h 6 | #[allow(missing_docs)] 7 | #[allow(clippy::upper_case_acronyms)] 8 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 9 | pub enum ResourceKind { 10 | MMIO = 0, 11 | IRQ = 1, 12 | IOPORT = 2, 13 | HYPERVISOR = 3, 14 | ROOT = 4, 15 | VMEX = 5, 16 | SMC = 6, 17 | COUNT = 7, 18 | } 19 | } 20 | 21 | bitflags! { 22 | /// Bits for Resource.flags. 23 | pub struct ResourceFlags: u32 { 24 | #[allow(clippy::identity_op)] 25 | /// Exclusive resource. 26 | const EXCLUSIVE = 1 << 16; 27 | } 28 | } 29 | 30 | /// Address space rights and accounting. 31 | pub struct Resource { 32 | base: KObjectBase, 33 | kind: ResourceKind, 34 | addr: usize, 35 | len: usize, 36 | flags: ResourceFlags, 37 | } 38 | 39 | impl_kobject!(Resource); 40 | 41 | impl Resource { 42 | /// Create a new `Resource`. 43 | pub fn create( 44 | name: &str, 45 | kind: ResourceKind, 46 | addr: usize, 47 | len: usize, 48 | flags: ResourceFlags, 49 | ) -> Arc { 50 | Arc::new(Resource { 51 | base: KObjectBase::with_name(name), 52 | kind, 53 | addr, 54 | len, 55 | flags, 56 | }) 57 | } 58 | 59 | /// Validate the resource is the given kind or it is the root resource. 60 | pub fn validate(&self, kind: ResourceKind) -> ZxResult { 61 | if self.kind == kind || self.kind == ResourceKind::ROOT { 62 | Ok(()) 63 | } else { 64 | Err(ZxError::WRONG_TYPE) 65 | } 66 | } 67 | 68 | /// Validate the resource is the given kind or it is the root resource, 69 | /// and [addr, addr+len] is within the range of the resource. 70 | pub fn validate_ranged_resource( 71 | &self, 72 | kind: ResourceKind, 73 | addr: usize, 74 | len: usize, 75 | ) -> ZxResult { 76 | self.validate(kind)?; 77 | if addr >= self.addr && (addr + len) <= (self.addr + self.len) { 78 | Ok(()) 79 | } else { 80 | Err(ZxError::OUT_OF_RANGE) 81 | } 82 | } 83 | 84 | /// Returns `Err(ZxError::INVALID_ARGS)` if the resource is not the root resource, and 85 | /// either it's flags or parameter `flags` contains `ResourceFlags::EXCLUSIVE`. 86 | pub fn check_exclusive(&self, flags: ResourceFlags) -> ZxResult { 87 | if self.kind != ResourceKind::ROOT 88 | && (self.flags.contains(ResourceFlags::EXCLUSIVE) 89 | || flags.contains(ResourceFlags::EXCLUSIVE)) 90 | { 91 | Err(ZxError::INVALID_ARGS) 92 | } else { 93 | Ok(()) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![allow(dead_code)] 4 | #![feature(get_mut_unchecked)] 5 | #![feature(drain_filter)] 6 | 7 | extern crate alloc; 8 | 9 | #[cfg(test)] 10 | #[macro_use] 11 | extern crate std; 12 | 13 | #[macro_use] 14 | extern crate log; 15 | 16 | pub mod dev; 17 | pub mod error; 18 | pub mod ipc; 19 | pub mod object; 20 | pub mod task; 21 | pub mod util; 22 | pub mod vm; 23 | 24 | pub use self::error::*; 25 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | pub type HandleValue = u32; 6 | pub const INVALID_HANDLE: HandleValue = 0; 7 | 8 | /// 内核对象句柄 9 | #[derive(Clone)] 10 | pub struct Handle { 11 | pub object: Arc, 12 | pub rights: Rights, 13 | } 14 | 15 | impl Handle { 16 | /// 创建一个新句柄 17 | pub fn new(object: Arc, rights: Rights) -> Self { 18 | Handle { object, rights } 19 | } 20 | } 21 | // ANCHOR_END: handle 22 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | #[derive(Default)] 7 | pub struct Rights: u32 { 8 | const DUPLICATE = 1 << 0; 9 | const TRANSFER = 1 << 1; 10 | const READ = 1 << 2; 11 | const WRITE = 1 << 3; 12 | const EXECUTE = 1 << 4; 13 | const MAP = 1 << 5; 14 | const GET_PROPERTY = 1 << 6; 15 | const SET_PROPERTY = 1 << 7; 16 | const ENUMERATE = 1 << 8; 17 | const DESTROY = 1 << 9; 18 | const SET_POLICY = 1 << 10; 19 | const GET_POLICY = 1 << 11; 20 | const SIGNAL = 1 << 12; 21 | const SIGNAL_PEER = 1 << 13; 22 | const WAIT = 1 << 14; 23 | const INSPECT = 1 << 15; 24 | const MANAGE_JOB = 1 << 16; 25 | const MANAGE_PROCESS = 1 << 17; 26 | const MANAGE_THREAD = 1 << 18; 27 | const APPLY_PROFILE = 1 << 19; 28 | const SAME_RIGHTS = 1 << 31; 29 | 30 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 31 | const IO = Self::READ.bits | Self::WRITE.bits; 32 | 33 | /// GET_PROPERTY | SET_PROPERTY 34 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 35 | 36 | /// GET_POLICY | SET_POLICY 37 | const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; 38 | 39 | /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER 40 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 41 | 42 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 43 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits 44 | | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 45 | 46 | /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD 47 | const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; 48 | 49 | /// BASIC | WAIT 50 | const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; 51 | 52 | /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD 53 | const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits 54 | | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 55 | 56 | /// BASIC | IO | PROPERTY | MAP | SIGNAL 57 | const DEFAULT_VMO = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::MAP.bits | Self::SIGNAL.bits; 58 | 59 | /// TRANSFER | DUPLICATE | WRITE | INSPECT 60 | const DEFAULT_RESOURCE = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WRITE.bits | Self::INSPECT.bits; 61 | } 62 | } 63 | // ANCHOR_END: rights 64 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod job; 4 | mod job_policy; 5 | mod process; 6 | mod thread; 7 | 8 | pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; 9 | 10 | /// Task (Thread, Process, or Job) 11 | pub trait Task: Sync + Send { 12 | /// Kill the task. The task do not terminate immediately when killed. 13 | /// It will terminate after all its children are terminated or some cleanups are finished. 14 | fn kill(&self); 15 | 16 | /// Suspend the task. Currently only thread or process handles may be suspended. 17 | fn suspend(&self); 18 | 19 | /// Resume the task 20 | fn resume(&self); 21 | } 22 | 23 | /// The return code set when a task is killed via zx_task_kill(). 24 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 25 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | /// Possible values for "kind" in zx_thread_read_state and zx_thread_write_state. 8 | #[allow(missing_docs)] 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum ThreadStateKind { 11 | General = 0, 12 | FS = 6, 13 | GS = 7, 14 | } 15 | } 16 | 17 | pub(super) trait ContextExt { 18 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 19 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 20 | } 21 | 22 | impl ContextExt for UserContext { 23 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 24 | match kind { 25 | ThreadStateKind::General => buf.write_struct(&self.general), 26 | ThreadStateKind::FS => buf.write_struct(&self.general.fsbase), 27 | ThreadStateKind::GS => buf.write_struct(&self.general.gsbase), 28 | } 29 | } 30 | 31 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 32 | match kind { 33 | ThreadStateKind::General => self.general = buf.read_struct()?, 34 | ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?, 35 | ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?, 36 | } 37 | Ok(()) 38 | } 39 | } 40 | 41 | trait BufExt { 42 | fn read_struct(&self) -> ZxResult; 43 | fn write_struct(&mut self, value: &T) -> ZxResult; 44 | } 45 | 46 | #[allow(unsafe_code)] 47 | impl BufExt for [u8] { 48 | fn read_struct(&self) -> ZxResult { 49 | if self.len() < core::mem::size_of::() { 50 | return Err(ZxError::BUFFER_TOO_SMALL); 51 | } 52 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 53 | } 54 | 55 | fn write_struct(&mut self, value: &T) -> ZxResult { 56 | if self.len() < core::mem::size_of::() { 57 | return Err(ZxError::BUFFER_TOO_SMALL); 58 | } 59 | unsafe { 60 | *(self.as_mut_ptr() as *mut T) = *value; 61 | } 62 | Ok(core::mem::size_of::()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/util/block_range.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /// Given a range and iterate sub-range for each block 4 | pub struct BlockIter { 5 | pub begin: usize, 6 | pub end: usize, 7 | pub block_size_log2: u8, 8 | } 9 | 10 | #[derive(Debug, Eq, PartialEq)] 11 | pub struct BlockRange { 12 | pub block: usize, 13 | pub begin: usize, 14 | pub end: usize, 15 | pub block_size_log2: u8, 16 | } 17 | 18 | impl BlockRange { 19 | pub fn len(&self) -> usize { 20 | self.end - self.begin 21 | } 22 | pub fn is_full(&self) -> bool { 23 | self.len() == (1usize << self.block_size_log2) 24 | } 25 | pub fn is_empty(&self) -> bool { 26 | self.len() == 0 27 | } 28 | pub fn origin_begin(&self) -> usize { 29 | (self.block << self.block_size_log2) + self.begin 30 | } 31 | pub fn origin_end(&self) -> usize { 32 | (self.block << self.block_size_log2) + self.end 33 | } 34 | } 35 | 36 | impl Iterator for BlockIter { 37 | type Item = BlockRange; 38 | 39 | fn next(&mut self) -> Option<::Item> { 40 | if self.begin >= self.end { 41 | return None; 42 | } 43 | let block_size_log2 = self.block_size_log2; 44 | let block_size = 1usize << self.block_size_log2; 45 | let block = self.begin / block_size; 46 | let begin = self.begin % block_size; 47 | let end = if block == self.end / block_size { 48 | self.end % block_size 49 | } else { 50 | block_size 51 | }; 52 | self.begin += end - begin; 53 | Some(BlockRange { 54 | block, 55 | begin, 56 | end, 57 | block_size_log2, 58 | }) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod test { 64 | use super::*; 65 | 66 | #[test] 67 | fn block_iter() { 68 | let mut iter = BlockIter { 69 | begin: 0x123, 70 | end: 0x2018, 71 | block_size_log2: 12, 72 | }; 73 | assert_eq!( 74 | iter.next(), 75 | Some(BlockRange { 76 | block: 0, 77 | begin: 0x123, 78 | end: 0x1000, 79 | block_size_log2: 12 80 | }) 81 | ); 82 | assert_eq!( 83 | iter.next(), 84 | Some(BlockRange { 85 | block: 1, 86 | begin: 0, 87 | end: 0x1000, 88 | block_size_log2: 12 89 | }) 90 | ); 91 | assert_eq!( 92 | iter.next(), 93 | Some(BlockRange { 94 | block: 2, 95 | begin: 0, 96 | end: 0x18, 97 | block_size_log2: 12 98 | }) 99 | ); 100 | assert_eq!(iter.next(), None); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utilities. 2 | 3 | pub(crate) mod block_range; 4 | pub mod elf_loader; 5 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | 3 | mod vmar; 4 | mod vmo; 5 | 6 | pub use self::{vmar::*, vmo::*}; 7 | 8 | /// Physical Address 9 | pub type PhysAddr = usize; 10 | 11 | /// Virtual Address 12 | pub type VirtAddr = usize; 13 | 14 | /// Device Address 15 | pub type DevVAddr = usize; 16 | 17 | /// Size of a page 18 | pub const PAGE_SIZE: usize = 0x1000; 19 | 20 | /// log2(PAGE_SIZE) 21 | pub const PAGE_SIZE_LOG2: usize = 12; 22 | 23 | /// Check whether `x` is a multiple of `PAGE_SIZE`. 24 | pub fn page_aligned(x: usize) -> bool { 25 | check_aligned(x, PAGE_SIZE) 26 | } 27 | 28 | /// Check whether `x` is a multiple of `align`. 29 | pub fn check_aligned(x: usize, align: usize) -> bool { 30 | x % align == 0 31 | } 32 | 33 | /// How many pages the `size` needs. 34 | /// To avoid overflow and pass more unit tests, use wrapping add 35 | pub fn pages(size: usize) -> usize { 36 | ceil(size, PAGE_SIZE) 37 | } 38 | 39 | /// How many `align` the `x` needs. 40 | pub fn ceil(x: usize, align: usize) -> usize { 41 | x.wrapping_add(align - 1) / align 42 | } 43 | 44 | /// Round up `size` to a multiple of `PAGE_SIZE`. 45 | pub fn roundup_pages(size: usize) -> usize { 46 | pages(size) * PAGE_SIZE 47 | } 48 | 49 | /// Round down `size` to a multiple of `PAGE_SIZE`. 50 | pub fn round_down_pages(size: usize) -> usize { 51 | size / PAGE_SIZE * PAGE_SIZE 52 | } 53 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/vm/vmo/physical.rs: -------------------------------------------------------------------------------- 1 | use {super::*, alloc::sync::Arc, kernel_hal::MMUFlags, spin::Mutex}; 2 | 3 | /// VMO representing a physical range of memory. 4 | pub struct VMObjectPhysical { 5 | paddr: PhysAddr, 6 | pages: usize, 7 | /// Lock this when access physical memory. 8 | data_lock: Mutex<()>, 9 | inner: Mutex, 10 | } 11 | 12 | struct VMObjectPhysicalInner { 13 | cache_policy: CachePolicy, 14 | } 15 | 16 | impl VMObjectPhysicalInner { 17 | pub fn new() -> VMObjectPhysicalInner { 18 | VMObjectPhysicalInner { 19 | cache_policy: CachePolicy::Uncached, 20 | } 21 | } 22 | } 23 | 24 | impl VMObjectPhysical { 25 | /// Create a new VMO representing a piece of contiguous physical memory. 26 | /// You must ensure nobody has the ownership of this piece of memory yet. 27 | pub fn new(paddr: PhysAddr, pages: usize) -> Arc { 28 | assert!(page_aligned(paddr)); 29 | Arc::new(VMObjectPhysical { 30 | paddr, 31 | pages, 32 | data_lock: Mutex::default(), 33 | inner: Mutex::new(VMObjectPhysicalInner::new()), 34 | }) 35 | } 36 | } 37 | 38 | impl VMObjectTrait for VMObjectPhysical { 39 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 40 | let _ = self.data_lock.lock(); 41 | assert!(offset + buf.len() <= self.len()); 42 | kernel_hal::pmem_read(self.paddr + offset, buf); 43 | Ok(()) 44 | } 45 | 46 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 47 | let _ = self.data_lock.lock(); 48 | assert!(offset + buf.len() <= self.len()); 49 | kernel_hal::pmem_write(self.paddr + offset, buf); 50 | Ok(()) 51 | } 52 | 53 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 54 | let _ = self.data_lock.lock(); 55 | assert!(offset + len <= self.len()); 56 | kernel_hal::pmem_zero(self.paddr + offset, len); 57 | Ok(()) 58 | } 59 | 60 | fn len(&self) -> usize { 61 | self.pages * PAGE_SIZE 62 | } 63 | 64 | fn set_len(&self, _len: usize) -> ZxResult { 65 | unimplemented!() 66 | } 67 | 68 | fn commit_page(&self, page_idx: usize, _flags: MMUFlags) -> ZxResult { 69 | Ok(self.paddr + page_idx * PAGE_SIZE) 70 | } 71 | 72 | fn commit_pages_with( 73 | &self, 74 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 75 | ) -> ZxResult { 76 | f(&mut |page_idx, _flags| Ok(self.paddr + page_idx * PAGE_SIZE)) 77 | } 78 | 79 | fn commit(&self, _offset: usize, _len: usize) -> ZxResult { 80 | // do nothing 81 | Ok(()) 82 | } 83 | 84 | fn decommit(&self, _offset: usize, _len: usize) -> ZxResult { 85 | // do nothing 86 | Ok(()) 87 | } 88 | 89 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 90 | Err(ZxError::NOT_SUPPORTED) 91 | } 92 | 93 | fn complete_info(&self, _info: &mut VmoInfo) { 94 | warn!("VmoInfo for physical is unimplemented"); 95 | } 96 | 97 | fn cache_policy(&self) -> CachePolicy { 98 | let inner = self.inner.lock(); 99 | inner.cache_policy 100 | } 101 | 102 | fn set_cache_policy(&self, policy: CachePolicy) -> ZxResult { 103 | let mut inner = self.inner.lock(); 104 | inner.cache_policy = policy; 105 | Ok(()) 106 | } 107 | 108 | fn committed_pages_in_range(&self, _start_idx: usize, _end_idx: usize) -> usize { 109 | 0 110 | } 111 | 112 | fn is_contiguous(&self) -> bool { 113 | true 114 | } 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | #![allow(unsafe_code)] 120 | use super::*; 121 | use kernel_hal::CachePolicy; 122 | 123 | #[test] 124 | fn read_write() { 125 | let vmo = VmObject::new_physical(0x1000, 2); 126 | assert_eq!(vmo.cache_policy(), CachePolicy::Uncached); 127 | super::super::tests::read_write(&vmo); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /code/ch04-01/zircon-object/src/vm/vmo/slice.rs: -------------------------------------------------------------------------------- 1 | use {super::*, kernel_hal::MMUFlags}; 2 | 3 | pub struct VMObjectSlice { 4 | /// Parent node. 5 | parent: Arc, 6 | /// The offset from parent. 7 | offset: usize, 8 | /// The size in bytes. 9 | size: usize, 10 | } 11 | 12 | impl VMObjectSlice { 13 | pub fn new(parent: Arc, offset: usize, size: usize) -> Arc { 14 | Arc::new(VMObjectSlice { 15 | parent, 16 | offset, 17 | size, 18 | }) 19 | } 20 | 21 | fn check_range(&self, offset: usize, len: usize) -> ZxResult { 22 | if offset + len >= self.size { 23 | return Err(ZxError::OUT_OF_RANGE); 24 | } 25 | Ok(()) 26 | } 27 | } 28 | 29 | impl VMObjectTrait for VMObjectSlice { 30 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 31 | self.check_range(offset, buf.len())?; 32 | self.parent.read(offset + self.offset, buf) 33 | } 34 | 35 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 36 | self.check_range(offset, buf.len())?; 37 | self.parent.write(offset + self.offset, buf) 38 | } 39 | 40 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 41 | self.check_range(offset, len)?; 42 | self.parent.zero(offset + self.offset, len) 43 | } 44 | 45 | fn len(&self) -> usize { 46 | self.size 47 | } 48 | 49 | fn set_len(&self, _len: usize) -> ZxResult { 50 | unimplemented!() 51 | } 52 | 53 | fn commit_page(&self, page_idx: usize, flags: MMUFlags) -> ZxResult { 54 | self.parent 55 | .commit_page(page_idx + self.offset / PAGE_SIZE, flags) 56 | } 57 | 58 | fn commit_pages_with( 59 | &self, 60 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 61 | ) -> ZxResult { 62 | self.parent.commit_pages_with(f) 63 | } 64 | 65 | fn commit(&self, offset: usize, len: usize) -> ZxResult { 66 | self.parent.commit(offset + self.offset, len) 67 | } 68 | 69 | fn decommit(&self, offset: usize, len: usize) -> ZxResult { 70 | self.parent.decommit(offset + self.offset, len) 71 | } 72 | 73 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 74 | Err(ZxError::NOT_SUPPORTED) 75 | } 76 | 77 | fn complete_info(&self, info: &mut VmoInfo) { 78 | self.parent.complete_info(info); 79 | } 80 | 81 | fn cache_policy(&self) -> CachePolicy { 82 | self.parent.cache_policy() 83 | } 84 | 85 | fn set_cache_policy(&self, _policy: CachePolicy) -> ZxResult { 86 | Ok(()) 87 | } 88 | 89 | fn committed_pages_in_range(&self, start_idx: usize, end_idx: usize) -> usize { 90 | let po = pages(self.offset); 91 | self.parent 92 | .committed_pages_in_range(start_idx + po, end_idx + po) 93 | } 94 | 95 | fn pin(&self, offset: usize, len: usize) -> ZxResult { 96 | self.check_range(offset, len)?; 97 | self.parent.pin(offset + self.offset, len) 98 | } 99 | 100 | fn unpin(&self, offset: usize, len: usize) -> ZxResult { 101 | self.check_range(offset, len)?; 102 | self.parent.unpin(offset + self.offset, len) 103 | } 104 | 105 | fn is_contiguous(&self) -> bool { 106 | self.parent.is_contiguous() 107 | } 108 | 109 | fn is_paged(&self) -> bool { 110 | self.parent.is_paged() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /code/ch04-03/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "zircon-loader", 4 | "zircon-object", 5 | "zircon-syscall", 6 | "kernel-hal-unix", 7 | "kernel-hal", 8 | ] 9 | -------------------------------------------------------------------------------- /code/ch04-03/kernel-hal-unix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal-unix" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL implementation on Linux and macOS." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | libc = "0.2" 13 | tempfile = "3" 14 | bitflags = "1.2" 15 | lazy_static = "1.4" 16 | kernel-hal = { path = "../kernel-hal" } 17 | async-std = "1.9" 18 | trapframe = "0.8.0" 19 | git-version = "0.3" -------------------------------------------------------------------------------- /code/ch04-03/kernel-hal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel-hal" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Kernel HAL interface definations." 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | bitflags = "1.2" 12 | trapframe = "0.8.0" 13 | numeric-enum-macro = "0.2" 14 | -------------------------------------------------------------------------------- /code/ch04-03/kernel-hal/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Hardware Abstraction Layer 2 | 3 | #![no_std] 4 | #![feature(linkage)] 5 | #![deny(warnings)] 6 | 7 | extern crate alloc; 8 | 9 | pub mod defs { 10 | use bitflags::bitflags; 11 | use numeric_enum_macro::numeric_enum; 12 | 13 | bitflags! { 14 | pub struct MMUFlags: usize { 15 | #[allow(clippy::identity_op)] 16 | const CACHE_1 = 1 << 0; 17 | const CACHE_2 = 1 << 1; 18 | const READ = 1 << 2; 19 | const WRITE = 1 << 3; 20 | const EXECUTE = 1 << 4; 21 | const USER = 1 << 5; 22 | const RXW = Self::READ.bits | Self::WRITE.bits | Self::EXECUTE.bits; 23 | } 24 | } 25 | numeric_enum! { 26 | #[repr(u32)] 27 | #[derive(Debug, PartialEq, Clone, Copy)] 28 | pub enum CachePolicy { 29 | Cached = 0, 30 | Uncached = 1, 31 | UncachedDevice = 2, 32 | WriteCombining = 3, 33 | } 34 | } 35 | 36 | impl Default for CachePolicy { 37 | fn default() -> Self { 38 | CachePolicy::Cached 39 | } 40 | } 41 | 42 | pub const CACHE_POLICY_MASK: u32 = 3; 43 | 44 | pub type PhysAddr = usize; 45 | pub type VirtAddr = usize; 46 | pub type DevVAddr = usize; 47 | pub const PAGE_SIZE: usize = 0x1000; 48 | } 49 | 50 | mod dummy; 51 | pub mod user; 52 | pub mod vdso; 53 | 54 | pub use self::defs::*; 55 | pub use self::dummy::*; 56 | pub use trapframe::{GeneralRegs, UserContext}; 57 | -------------------------------------------------------------------------------- /code/ch04-03/kernel-hal/src/vdso.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{Debug, Error, Formatter}; 2 | 3 | /// This struct contains constants that are initialized by the kernel 4 | /// once at boot time. From the vDSO code's perspective, they are 5 | /// read-only data that can never change. Hence, no synchronization is 6 | /// required to read them. 7 | #[repr(C)] 8 | #[derive(Debug)] 9 | pub struct VdsoConstants { 10 | /// Maximum number of CPUs that might be online during the lifetime 11 | /// of the booted system. 12 | pub max_num_cpus: u32, 13 | /// Bit map indicating features. 14 | pub features: Features, 15 | /// Number of bytes in a data cache line. 16 | pub dcache_line_size: u32, 17 | /// Number of bytes in an instruction cache line. 18 | pub icache_line_size: u32, 19 | /// Conversion factor for zx_ticks_get return values to seconds. 20 | pub ticks_per_second: u64, 21 | /// Ratio which relates ticks (zx_ticks_get) to clock monotonic. 22 | /// 23 | /// Specifically: ClockMono(ticks) = (ticks * N) / D 24 | pub ticks_to_mono_numerator: u32, 25 | pub ticks_to_mono_denominator: u32, 26 | /// Total amount of physical memory in the system, in bytes. 27 | pub physmem: u64, 28 | /// Actual length of `version_string`, not including the NUL terminator. 29 | pub version_string_len: u64, 30 | /// A NUL-terminated UTF-8 string returned by `zx_system_get_version_string`. 31 | pub version_string: VersionString, 32 | } 33 | 34 | /// Bit map indicating features. 35 | /// 36 | /// For specific feature bits, see zircon/features.h. 37 | #[repr(C)] 38 | #[derive(Debug)] 39 | pub struct Features { 40 | pub cpu: u32, 41 | /// Total amount of debug registers available in the system. 42 | pub hw_breakpoint_count: u32, 43 | pub hw_watchpoint_count: u32, 44 | } 45 | 46 | impl VdsoConstants { 47 | /// Set version string. 48 | pub fn set_version_string(&mut self, s: &str) { 49 | let len = s.len().min(64); 50 | self.version_string_len = len as u64; 51 | self.version_string.0[..len].copy_from_slice(s.as_bytes()); 52 | } 53 | } 54 | 55 | #[repr(C)] 56 | pub struct VersionString([u8; 64]); 57 | 58 | impl Default for VersionString { 59 | fn default() -> Self { 60 | VersionString([0; 64]) 61 | } 62 | } 63 | 64 | impl Debug for VersionString { 65 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { 66 | for &c in self.0.iter().take_while(|&&c| c != 0) { 67 | write!(f, "{}", c as char)?; 68 | } 69 | Ok(()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/Scrt1.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/Scrt1.o -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/bringup.zbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/bringup.zbi -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/core-tests.zbi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/core-tests.zbi -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/libc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/libc.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/libfdio.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/libfdio.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/libunwind.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/libunwind.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/libzircon-libos.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/libzircon-libos.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/libzircon.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/libzircon.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/userboot-libos.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/userboot-libos.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/userboot.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/userboot.so -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/zbi-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/zbi-linux -------------------------------------------------------------------------------- /code/ch04-03/prebuilt/zircon/x64/zbi-macos: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/code/ch04-03/prebuilt/zircon/x64/zbi-macos -------------------------------------------------------------------------------- /code/ch04-03/zircon-loader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-loader" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Zircon user program (userboot) loader" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | xmas-elf = "0.7" 13 | zircon-object = { path = "../zircon-object" } 14 | zircon-syscall = { path = "../zircon-syscall" } 15 | kernel-hal = { path = "../kernel-hal" } 16 | env_logger = { version = "0.8", optional = true } 17 | structopt = { version = "0.3", default-features = false, optional = true } 18 | kernel-hal-unix = { path = "../kernel-hal-unix" } 19 | async-std = { version = "1.9", features = ["attributes"], optional = true } 20 | 21 | [features] 22 | default = ["std"] 23 | std = ["env_logger", "structopt", "async-std"] 24 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-loader/src/kcounter.rs: -------------------------------------------------------------------------------- 1 | use { 2 | alloc::sync::Arc, 3 | core::mem::size_of, 4 | zircon_object::{object::KernelObject, vm::*}, 5 | }; 6 | 7 | pub fn create_kcounter_vmo() -> (Arc, Arc) { 8 | const HEADER_SIZE: usize = size_of::(); 9 | let counter_name_vmo = VmObject::new_paged(1); 10 | let header = KCounterVmoHeader { 11 | magic: KCOUNTER_MAGIC, 12 | max_cpu: 1, 13 | counter_table_size: 0, 14 | }; 15 | let serde_header: [u8; HEADER_SIZE] = unsafe { core::mem::transmute(header) }; 16 | counter_name_vmo.write(0, &serde_header).unwrap(); 17 | counter_name_vmo.set_name("counters/desc"); 18 | 19 | let kcounters_vmo = VmObject::new_paged(1); 20 | kcounters_vmo.set_name("counters/arena"); 21 | (counter_name_vmo, kcounters_vmo) 22 | } 23 | 24 | // #[repr(C)] 25 | // struct KCounterDescItem { 26 | // name: [u8; 56], 27 | // type_: KCounterType, 28 | // } 29 | 30 | // #[repr(u64)] 31 | // enum KCounterType { 32 | // Sum = 1, 33 | // } 34 | 35 | // impl From<&KCounterDescriptor> for KCounterDescItem { 36 | // fn from(desc: &KCounterDescriptor) -> Self { 37 | // let mut name = [0u8; 56]; 38 | // let length = desc.name.len().min(56); 39 | // name[..length].copy_from_slice(&desc.name.as_bytes()[..length]); 40 | // KCounterDescItem { 41 | // name, 42 | // type_: KCounterType::Sum, 43 | // } 44 | // } 45 | // } 46 | 47 | #[repr(C)] 48 | struct KCounterVmoHeader { 49 | magic: u64, 50 | max_cpu: u64, 51 | counter_table_size: usize, 52 | } 53 | 54 | const KCOUNTER_MAGIC: u64 = 1_547_273_975; 55 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-loader/src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings, unused_must_use)] 2 | 3 | extern crate log; 4 | 5 | use std::path::{Path, PathBuf}; 6 | use std::sync::Arc; 7 | use structopt::StructOpt; 8 | use zircon_loader::*; 9 | use zircon_object::object::*; 10 | use zircon_object::task::Process; 11 | 12 | #[derive(Debug, StructOpt)] 13 | #[structopt()] 14 | struct Opt { 15 | #[structopt(parse(from_os_str))] 16 | prebuilt_path: PathBuf, 17 | #[structopt(default_value = "")] 18 | cmdline: String, 19 | } 20 | 21 | #[async_std::main] 22 | async fn main() { 23 | kernel_hal_unix::init(); 24 | init_logger(); 25 | let opt = Opt::from_args(); 26 | let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 27 | let proc: Arc = run_userboot(&images, &opt.cmdline); 28 | drop(images); 29 | let proc = proc.downcast_arc::().unwrap(); 30 | proc.wait_for_end().await; 31 | } 32 | 33 | fn open_images(path: &Path) -> std::io::Result>> { 34 | Ok(Images { 35 | userboot: std::fs::read(path.join("userboot-libos.so"))?, 36 | vdso: std::fs::read(path.join("libzircon-libos.so"))?, 37 | zbi: std::fs::read(path.join("bringup.zbi"))?, 38 | }) 39 | } 40 | 41 | fn init_logger() { 42 | env_logger::builder() 43 | .format(|buf, record| { 44 | use env_logger::fmt::Color; 45 | use log::Level; 46 | use std::io::Write; 47 | 48 | let (tid, pid) = kernel_hal::Thread::get_tid(); 49 | let mut style = buf.style(); 50 | match record.level() { 51 | Level::Trace => style.set_color(Color::Black).set_intense(true), 52 | Level::Debug => style.set_color(Color::White), 53 | Level::Info => style.set_color(Color::Green), 54 | Level::Warn => style.set_color(Color::Yellow), 55 | Level::Error => style.set_color(Color::Red).set_bold(true), 56 | }; 57 | let now = kernel_hal_unix::timer_now(); 58 | let level = style.value(record.level()); 59 | let args = record.args(); 60 | writeln!(buf, "[{:?} {:>5} {}:{}] {}", now, level, pid, tid, args) 61 | }) 62 | .init(); 63 | } 64 | 65 | // #[cfg(test)] 66 | // mod tests { 67 | // use super::*; 68 | 69 | // #[async_std::test] 70 | // async fn userboot() { 71 | // kernel_hal_unix::init(); 72 | 73 | // let opt = Opt { 74 | // prebuilt_path: PathBuf::from("../prebuilt/zircon/x64"), 75 | // cmdline: String::from(""), 76 | // }; 77 | // let images = open_images(&opt.prebuilt_path).expect("failed to read file"); 78 | 79 | // let proc: Arc = run_userboot(&images, &opt.cmdline); 80 | // drop(images); 81 | 82 | // let proc = proc.downcast_arc::().unwrap(); 83 | // proc.wait_for_end().await; 84 | // } 85 | // } 86 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-object" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 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 | log = "0.4" 11 | spin = "0.7" 12 | downcast-rs = { version = "1.2.0", default-features = false } 13 | bitflags = "1.2" 14 | hashbrown = "0.9" 15 | trapframe = "0.8.0" 16 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } 17 | async-std = { version = "1.9", features = ["attributes", "unstable"] } 18 | numeric-enum-macro = "0.2" 19 | xmas-elf = { version = "0.7"} 20 | kernel-hal = { path = "../kernel-hal" } 21 | kernel-hal-unix = { path = "../kernel-hal-unix" } 22 | lazy_static = "1.4" 23 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/debuglog.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Kernel Debuglog. 2 | use { 3 | super::*, 4 | crate::object::*, 5 | alloc::{sync::Arc, vec::Vec}, 6 | kernel_hal::timer_now, 7 | lazy_static::lazy_static, 8 | spin::Mutex, 9 | }; 10 | 11 | lazy_static! { 12 | static ref DLOG: Mutex = Mutex::new(DlogBuffer { 13 | buf: Vec::with_capacity(0x1000), 14 | }); 15 | } 16 | 17 | /// Debuglog - Kernel debuglog 18 | /// 19 | /// ## SYNOPSIS 20 | /// 21 | /// Debuglog objects allow userspace to read and write to kernel debug logs. 22 | pub struct DebugLog { 23 | base: KObjectBase, 24 | flags: u32, 25 | read_offset: Mutex, 26 | } 27 | 28 | struct DlogBuffer { 29 | /// Append only buffer 30 | buf: Vec, 31 | } 32 | 33 | impl_kobject!(DebugLog); 34 | 35 | impl DebugLog { 36 | /// Create a new `DebugLog`. 37 | pub fn create(flags: u32) -> Arc { 38 | Arc::new(DebugLog { 39 | base: KObjectBase::new(), 40 | flags, 41 | read_offset: Default::default(), 42 | }) 43 | } 44 | 45 | /// Read a log, return the actual read size. 46 | pub fn read(&self, buf: &mut [u8]) -> usize { 47 | let mut offset = self.read_offset.lock(); 48 | let len = DLOG.lock().read_at(*offset, buf); 49 | *offset += len; 50 | len 51 | } 52 | 53 | /// Write a log. 54 | pub fn write(&self, severity: Severity, flags: u32, tid: u64, pid: u64, data: &str) { 55 | DLOG.lock() 56 | .write(severity, flags | self.flags, tid, pid, data.as_bytes()); 57 | } 58 | } 59 | 60 | #[repr(C)] 61 | #[derive(Debug)] 62 | struct DlogHeader { 63 | rollout: u32, 64 | datalen: u16, 65 | severity: Severity, 66 | flags: u8, 67 | timestamp: u64, 68 | pid: u64, 69 | tid: u64, 70 | } 71 | 72 | /// Log entry severity. Used for coarse filtering of log messages. 73 | #[allow(missing_docs)] 74 | #[repr(u8)] 75 | #[derive(Debug)] 76 | pub enum Severity { 77 | Trace = 0x10, 78 | Debug = 0x20, 79 | Info = 0x30, 80 | Warning = 0x40, 81 | Error = 0x50, 82 | Fatal = 0x60, 83 | } 84 | 85 | const HEADER_SIZE: usize = core::mem::size_of::(); 86 | /// Max length of Dlog read buffer. 87 | pub const DLOG_MAX_LEN: usize = 256; 88 | 89 | #[allow(unsafe_code)] 90 | impl DlogBuffer { 91 | /// Read one record at offset. 92 | #[allow(clippy::cast_ptr_alignment)] 93 | fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> usize { 94 | assert!(buf.len() >= DLOG_MAX_LEN); 95 | if offset == self.buf.len() { 96 | return 0; 97 | } 98 | let header_buf = &self.buf[offset..offset + HEADER_SIZE]; 99 | buf[..HEADER_SIZE].copy_from_slice(header_buf); 100 | let header = unsafe { &*(header_buf.as_ptr() as *const DlogHeader) }; 101 | let len = (header.rollout & 0xFFF) as usize; 102 | buf[HEADER_SIZE..len].copy_from_slice(&self.buf[offset + HEADER_SIZE..offset + len]); 103 | len 104 | } 105 | 106 | fn write(&mut self, severity: Severity, flags: u32, tid: u64, pid: u64, data: &[u8]) { 107 | let wire_size = HEADER_SIZE + align_up_4(data.len()); 108 | let size = HEADER_SIZE + data.len(); 109 | let header = DlogHeader { 110 | rollout: ((size as u32) << 12) | (wire_size as u32), 111 | datalen: data.len() as u16, 112 | severity, 113 | flags: flags as u8, 114 | timestamp: timer_now().as_nanos() as u64, 115 | pid, 116 | tid, 117 | }; 118 | let header_buf: [u8; HEADER_SIZE] = unsafe { core::mem::transmute(header) }; 119 | self.buf.extend(header_buf.iter()); 120 | self.buf.extend(data); 121 | self.buf.extend(&[0u8; 4][..wire_size - size]); 122 | } 123 | } 124 | 125 | fn align_up_4(x: usize) -> usize { 126 | (x + 3) & !3 127 | } 128 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/dev/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Device Drivers. 2 | 3 | mod resource; 4 | 5 | pub use self::resource::*; 6 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/dev/resource.rs: -------------------------------------------------------------------------------- 1 | use {crate::object::*, alloc::sync::Arc, bitflags::bitflags, numeric_enum_macro::numeric_enum}; 2 | 3 | numeric_enum! { 4 | #[repr(u32)] 5 | /// ResourceKind definition from fuchsia/zircon/system/public/zircon/syscalls/resource.h 6 | #[allow(missing_docs)] 7 | #[allow(clippy::upper_case_acronyms)] 8 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 9 | pub enum ResourceKind { 10 | MMIO = 0, 11 | IRQ = 1, 12 | IOPORT = 2, 13 | HYPERVISOR = 3, 14 | ROOT = 4, 15 | VMEX = 5, 16 | SMC = 6, 17 | COUNT = 7, 18 | } 19 | } 20 | 21 | bitflags! { 22 | /// Bits for Resource.flags. 23 | pub struct ResourceFlags: u32 { 24 | #[allow(clippy::identity_op)] 25 | /// Exclusive resource. 26 | const EXCLUSIVE = 1 << 16; 27 | } 28 | } 29 | 30 | /// Address space rights and accounting. 31 | pub struct Resource { 32 | base: KObjectBase, 33 | kind: ResourceKind, 34 | addr: usize, 35 | len: usize, 36 | flags: ResourceFlags, 37 | } 38 | 39 | impl_kobject!(Resource); 40 | 41 | impl Resource { 42 | /// Create a new `Resource`. 43 | pub fn create( 44 | name: &str, 45 | kind: ResourceKind, 46 | addr: usize, 47 | len: usize, 48 | flags: ResourceFlags, 49 | ) -> Arc { 50 | Arc::new(Resource { 51 | base: KObjectBase::with_name(name), 52 | kind, 53 | addr, 54 | len, 55 | flags, 56 | }) 57 | } 58 | 59 | /// Validate the resource is the given kind or it is the root resource. 60 | pub fn validate(&self, kind: ResourceKind) -> ZxResult { 61 | if self.kind == kind || self.kind == ResourceKind::ROOT { 62 | Ok(()) 63 | } else { 64 | Err(ZxError::WRONG_TYPE) 65 | } 66 | } 67 | 68 | /// Validate the resource is the given kind or it is the root resource, 69 | /// and [addr, addr+len] is within the range of the resource. 70 | pub fn validate_ranged_resource( 71 | &self, 72 | kind: ResourceKind, 73 | addr: usize, 74 | len: usize, 75 | ) -> ZxResult { 76 | self.validate(kind)?; 77 | if addr >= self.addr && (addr + len) <= (self.addr + self.len) { 78 | Ok(()) 79 | } else { 80 | Err(ZxError::OUT_OF_RANGE) 81 | } 82 | } 83 | 84 | /// Returns `Err(ZxError::INVALID_ARGS)` if the resource is not the root resource, and 85 | /// either it's flags or parameter `flags` contains `ResourceFlags::EXCLUSIVE`. 86 | pub fn check_exclusive(&self, flags: ResourceFlags) -> ZxResult { 87 | if self.kind != ResourceKind::ROOT 88 | && (self.flags.contains(ResourceFlags::EXCLUSIVE) 89 | || flags.contains(ResourceFlags::EXCLUSIVE)) 90 | { 91 | Err(ZxError::INVALID_ARGS) 92 | } else { 93 | Ok(()) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod channel; 4 | pub use self::channel::*; 5 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![deny(unused_imports)] 3 | #![allow(dead_code)] 4 | #![feature(get_mut_unchecked)] 5 | #![feature(drain_filter)] 6 | 7 | extern crate alloc; 8 | 9 | #[cfg(test)] 10 | #[macro_use] 11 | extern crate std; 12 | 13 | #[macro_use] 14 | extern crate log; 15 | 16 | pub mod debuglog; 17 | pub mod dev; 18 | pub mod error; 19 | pub mod ipc; 20 | pub mod object; 21 | pub mod task; 22 | pub mod util; 23 | pub mod vm; 24 | 25 | pub use self::error::*; 26 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/object/handle.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: handle 2 | use super::{KernelObject, Rights}; 3 | use alloc::sync::Arc; 4 | 5 | pub type HandleValue = u32; 6 | pub const INVALID_HANDLE: HandleValue = 0; 7 | 8 | /// 内核对象句柄 9 | #[derive(Clone)] 10 | pub struct Handle { 11 | pub object: Arc, 12 | pub rights: Rights, 13 | } 14 | 15 | impl Handle { 16 | /// 创建一个新句柄 17 | pub fn new(object: Arc, rights: Rights) -> Self { 18 | Handle { object, rights } 19 | } 20 | } 21 | // ANCHOR_END: handle 22 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/object/rights.rs: -------------------------------------------------------------------------------- 1 | // ANCHOR: rights 2 | use bitflags::bitflags; 3 | 4 | bitflags! { 5 | /// 句柄权限 6 | #[derive(Default)] 7 | pub struct Rights: u32 { 8 | const DUPLICATE = 1 << 0; 9 | const TRANSFER = 1 << 1; 10 | const READ = 1 << 2; 11 | const WRITE = 1 << 3; 12 | const EXECUTE = 1 << 4; 13 | const MAP = 1 << 5; 14 | const GET_PROPERTY = 1 << 6; 15 | const SET_PROPERTY = 1 << 7; 16 | const ENUMERATE = 1 << 8; 17 | const DESTROY = 1 << 9; 18 | const SET_POLICY = 1 << 10; 19 | const GET_POLICY = 1 << 11; 20 | const SIGNAL = 1 << 12; 21 | const SIGNAL_PEER = 1 << 13; 22 | const WAIT = 1 << 14; 23 | const INSPECT = 1 << 15; 24 | const MANAGE_JOB = 1 << 16; 25 | const MANAGE_PROCESS = 1 << 17; 26 | const MANAGE_THREAD = 1 << 18; 27 | const APPLY_PROFILE = 1 << 19; 28 | const SAME_RIGHTS = 1 << 31; 29 | 30 | const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; 31 | const IO = Self::READ.bits | Self::WRITE.bits; 32 | 33 | /// GET_PROPERTY | SET_PROPERTY 34 | const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; 35 | 36 | /// GET_POLICY | SET_POLICY 37 | const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; 38 | 39 | /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER 40 | const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; 41 | 42 | /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD 43 | const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits 44 | | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 45 | 46 | /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD 47 | const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; 48 | 49 | /// BASIC | WAIT 50 | const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; 51 | 52 | /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD 53 | const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits 54 | | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; 55 | 56 | /// BASIC | IO | PROPERTY | MAP | SIGNAL 57 | const DEFAULT_VMO = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::MAP.bits | Self::SIGNAL.bits; 58 | 59 | /// TRANSFER | DUPLICATE | WRITE | INSPECT 60 | const DEFAULT_RESOURCE = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WRITE.bits | Self::INSPECT.bits; 61 | 62 | /// BASIC | WRITE | SIGNAL 63 | const DEFAULT_DEBUGLOG = Self::BASIC.bits | Self::WRITE.bits | Self::SIGNAL.bits; 64 | } 65 | } 66 | // ANCHOR_END: rights 67 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/task/mod.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | mod job; 4 | mod job_policy; 5 | mod process; 6 | mod thread; 7 | 8 | pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; 9 | 10 | /// Task (Thread, Process, or Job) 11 | pub trait Task: Sync + Send { 12 | /// Kill the task. The task do not terminate immediately when killed. 13 | /// It will terminate after all its children are terminated or some cleanups are finished. 14 | fn kill(&self); 15 | 16 | /// Suspend the task. Currently only thread or process handles may be suspended. 17 | fn suspend(&self); 18 | 19 | /// Resume the task 20 | fn resume(&self); 21 | } 22 | 23 | /// The return code set when a task is killed via zx_task_kill(). 24 | pub const TASK_RETCODE_SYSCALL_KILL: i64 = -1028; 25 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/task/thread/thread_state.rs: -------------------------------------------------------------------------------- 1 | use crate::{ZxError, ZxResult}; 2 | use kernel_hal::UserContext; 3 | use numeric_enum_macro::numeric_enum; 4 | 5 | numeric_enum! { 6 | #[repr(u32)] 7 | /// Possible values for "kind" in zx_thread_read_state and zx_thread_write_state. 8 | #[allow(missing_docs)] 9 | #[derive(Debug, Copy, Clone)] 10 | pub enum ThreadStateKind { 11 | General = 0, 12 | FS = 6, 13 | GS = 7, 14 | } 15 | } 16 | 17 | pub(super) trait ContextExt { 18 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult; 19 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult; 20 | } 21 | 22 | impl ContextExt for UserContext { 23 | fn read_state(&self, kind: ThreadStateKind, buf: &mut [u8]) -> ZxResult { 24 | match kind { 25 | ThreadStateKind::General => buf.write_struct(&self.general), 26 | ThreadStateKind::FS => buf.write_struct(&self.general.fsbase), 27 | ThreadStateKind::GS => buf.write_struct(&self.general.gsbase), 28 | } 29 | } 30 | 31 | fn write_state(&mut self, kind: ThreadStateKind, buf: &[u8]) -> ZxResult { 32 | match kind { 33 | ThreadStateKind::General => self.general = buf.read_struct()?, 34 | ThreadStateKind::FS => self.general.fsbase = buf.read_struct()?, 35 | ThreadStateKind::GS => self.general.gsbase = buf.read_struct()?, 36 | } 37 | Ok(()) 38 | } 39 | } 40 | 41 | trait BufExt { 42 | fn read_struct(&self) -> ZxResult; 43 | fn write_struct(&mut self, value: &T) -> ZxResult; 44 | } 45 | 46 | #[allow(unsafe_code)] 47 | impl BufExt for [u8] { 48 | fn read_struct(&self) -> ZxResult { 49 | if self.len() < core::mem::size_of::() { 50 | return Err(ZxError::BUFFER_TOO_SMALL); 51 | } 52 | Ok(unsafe { (self.as_ptr() as *const T).read() }) 53 | } 54 | 55 | fn write_struct(&mut self, value: &T) -> ZxResult { 56 | if self.len() < core::mem::size_of::() { 57 | return Err(ZxError::BUFFER_TOO_SMALL); 58 | } 59 | unsafe { 60 | *(self.as_mut_ptr() as *mut T) = *value; 61 | } 62 | Ok(core::mem::size_of::()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/util/block_range.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | /// Given a range and iterate sub-range for each block 4 | pub struct BlockIter { 5 | pub begin: usize, 6 | pub end: usize, 7 | pub block_size_log2: u8, 8 | } 9 | 10 | #[derive(Debug, Eq, PartialEq)] 11 | pub struct BlockRange { 12 | pub block: usize, 13 | pub begin: usize, 14 | pub end: usize, 15 | pub block_size_log2: u8, 16 | } 17 | 18 | impl BlockRange { 19 | pub fn len(&self) -> usize { 20 | self.end - self.begin 21 | } 22 | pub fn is_full(&self) -> bool { 23 | self.len() == (1usize << self.block_size_log2) 24 | } 25 | pub fn is_empty(&self) -> bool { 26 | self.len() == 0 27 | } 28 | pub fn origin_begin(&self) -> usize { 29 | (self.block << self.block_size_log2) + self.begin 30 | } 31 | pub fn origin_end(&self) -> usize { 32 | (self.block << self.block_size_log2) + self.end 33 | } 34 | } 35 | 36 | impl Iterator for BlockIter { 37 | type Item = BlockRange; 38 | 39 | fn next(&mut self) -> Option<::Item> { 40 | if self.begin >= self.end { 41 | return None; 42 | } 43 | let block_size_log2 = self.block_size_log2; 44 | let block_size = 1usize << self.block_size_log2; 45 | let block = self.begin / block_size; 46 | let begin = self.begin % block_size; 47 | let end = if block == self.end / block_size { 48 | self.end % block_size 49 | } else { 50 | block_size 51 | }; 52 | self.begin += end - begin; 53 | Some(BlockRange { 54 | block, 55 | begin, 56 | end, 57 | block_size_log2, 58 | }) 59 | } 60 | } 61 | 62 | #[cfg(test)] 63 | mod test { 64 | use super::*; 65 | 66 | #[test] 67 | fn block_iter() { 68 | let mut iter = BlockIter { 69 | begin: 0x123, 70 | end: 0x2018, 71 | block_size_log2: 12, 72 | }; 73 | assert_eq!( 74 | iter.next(), 75 | Some(BlockRange { 76 | block: 0, 77 | begin: 0x123, 78 | end: 0x1000, 79 | block_size_log2: 12 80 | }) 81 | ); 82 | assert_eq!( 83 | iter.next(), 84 | Some(BlockRange { 85 | block: 1, 86 | begin: 0, 87 | end: 0x1000, 88 | block_size_log2: 12 89 | }) 90 | ); 91 | assert_eq!( 92 | iter.next(), 93 | Some(BlockRange { 94 | block: 2, 95 | begin: 0, 96 | end: 0x18, 97 | block_size_log2: 12 98 | }) 99 | ); 100 | assert_eq!(iter.next(), None); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utilities. 2 | 3 | pub(crate) mod block_range; 4 | pub mod elf_loader; 5 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Objects for Virtual Memory Management. 2 | 3 | mod vmar; 4 | mod vmo; 5 | 6 | pub use self::{vmar::*, vmo::*}; 7 | 8 | /// Physical Address 9 | pub type PhysAddr = usize; 10 | 11 | /// Virtual Address 12 | pub type VirtAddr = usize; 13 | 14 | /// Device Address 15 | pub type DevVAddr = usize; 16 | 17 | /// Size of a page 18 | pub const PAGE_SIZE: usize = 0x1000; 19 | 20 | /// log2(PAGE_SIZE) 21 | pub const PAGE_SIZE_LOG2: usize = 12; 22 | 23 | /// Check whether `x` is a multiple of `PAGE_SIZE`. 24 | pub fn page_aligned(x: usize) -> bool { 25 | check_aligned(x, PAGE_SIZE) 26 | } 27 | 28 | /// Check whether `x` is a multiple of `align`. 29 | pub fn check_aligned(x: usize, align: usize) -> bool { 30 | x % align == 0 31 | } 32 | 33 | /// How many pages the `size` needs. 34 | /// To avoid overflow and pass more unit tests, use wrapping add 35 | pub fn pages(size: usize) -> usize { 36 | ceil(size, PAGE_SIZE) 37 | } 38 | 39 | /// How many `align` the `x` needs. 40 | pub fn ceil(x: usize, align: usize) -> usize { 41 | x.wrapping_add(align - 1) / align 42 | } 43 | 44 | /// Round up `size` to a multiple of `PAGE_SIZE`. 45 | pub fn roundup_pages(size: usize) -> usize { 46 | pages(size) * PAGE_SIZE 47 | } 48 | 49 | /// Round down `size` to a multiple of `PAGE_SIZE`. 50 | pub fn round_down_pages(size: usize) -> usize { 51 | size / PAGE_SIZE * PAGE_SIZE 52 | } 53 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/vm/vmo/physical.rs: -------------------------------------------------------------------------------- 1 | use {super::*, alloc::sync::Arc, kernel_hal::MMUFlags, spin::Mutex}; 2 | 3 | /// VMO representing a physical range of memory. 4 | pub struct VMObjectPhysical { 5 | paddr: PhysAddr, 6 | pages: usize, 7 | /// Lock this when access physical memory. 8 | data_lock: Mutex<()>, 9 | inner: Mutex, 10 | } 11 | 12 | struct VMObjectPhysicalInner { 13 | cache_policy: CachePolicy, 14 | } 15 | 16 | impl VMObjectPhysicalInner { 17 | pub fn new() -> VMObjectPhysicalInner { 18 | VMObjectPhysicalInner { 19 | cache_policy: CachePolicy::Uncached, 20 | } 21 | } 22 | } 23 | 24 | impl VMObjectPhysical { 25 | /// Create a new VMO representing a piece of contiguous physical memory. 26 | /// You must ensure nobody has the ownership of this piece of memory yet. 27 | pub fn new(paddr: PhysAddr, pages: usize) -> Arc { 28 | assert!(page_aligned(paddr)); 29 | Arc::new(VMObjectPhysical { 30 | paddr, 31 | pages, 32 | data_lock: Mutex::default(), 33 | inner: Mutex::new(VMObjectPhysicalInner::new()), 34 | }) 35 | } 36 | } 37 | 38 | impl VMObjectTrait for VMObjectPhysical { 39 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 40 | let _ = self.data_lock.lock(); 41 | assert!(offset + buf.len() <= self.len()); 42 | kernel_hal::pmem_read(self.paddr + offset, buf); 43 | Ok(()) 44 | } 45 | 46 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 47 | let _ = self.data_lock.lock(); 48 | assert!(offset + buf.len() <= self.len()); 49 | kernel_hal::pmem_write(self.paddr + offset, buf); 50 | Ok(()) 51 | } 52 | 53 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 54 | let _ = self.data_lock.lock(); 55 | assert!(offset + len <= self.len()); 56 | kernel_hal::pmem_zero(self.paddr + offset, len); 57 | Ok(()) 58 | } 59 | 60 | fn len(&self) -> usize { 61 | self.pages * PAGE_SIZE 62 | } 63 | 64 | fn set_len(&self, _len: usize) -> ZxResult { 65 | unimplemented!() 66 | } 67 | 68 | fn commit_page(&self, page_idx: usize, _flags: MMUFlags) -> ZxResult { 69 | Ok(self.paddr + page_idx * PAGE_SIZE) 70 | } 71 | 72 | fn commit_pages_with( 73 | &self, 74 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 75 | ) -> ZxResult { 76 | f(&mut |page_idx, _flags| Ok(self.paddr + page_idx * PAGE_SIZE)) 77 | } 78 | 79 | fn commit(&self, _offset: usize, _len: usize) -> ZxResult { 80 | // do nothing 81 | Ok(()) 82 | } 83 | 84 | fn decommit(&self, _offset: usize, _len: usize) -> ZxResult { 85 | // do nothing 86 | Ok(()) 87 | } 88 | 89 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 90 | Err(ZxError::NOT_SUPPORTED) 91 | } 92 | 93 | fn complete_info(&self, _info: &mut VmoInfo) { 94 | warn!("VmoInfo for physical is unimplemented"); 95 | } 96 | 97 | fn cache_policy(&self) -> CachePolicy { 98 | let inner = self.inner.lock(); 99 | inner.cache_policy 100 | } 101 | 102 | fn set_cache_policy(&self, policy: CachePolicy) -> ZxResult { 103 | let mut inner = self.inner.lock(); 104 | inner.cache_policy = policy; 105 | Ok(()) 106 | } 107 | 108 | fn committed_pages_in_range(&self, _start_idx: usize, _end_idx: usize) -> usize { 109 | 0 110 | } 111 | 112 | fn is_contiguous(&self) -> bool { 113 | true 114 | } 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | #![allow(unsafe_code)] 120 | use super::*; 121 | use kernel_hal::CachePolicy; 122 | 123 | #[test] 124 | fn read_write() { 125 | let vmo = VmObject::new_physical(0x1000, 2); 126 | assert_eq!(vmo.cache_policy(), CachePolicy::Uncached); 127 | super::super::tests::read_write(&vmo); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-object/src/vm/vmo/slice.rs: -------------------------------------------------------------------------------- 1 | use {super::*, kernel_hal::MMUFlags}; 2 | 3 | pub struct VMObjectSlice { 4 | /// Parent node. 5 | parent: Arc, 6 | /// The offset from parent. 7 | offset: usize, 8 | /// The size in bytes. 9 | size: usize, 10 | } 11 | 12 | impl VMObjectSlice { 13 | pub fn new(parent: Arc, offset: usize, size: usize) -> Arc { 14 | Arc::new(VMObjectSlice { 15 | parent, 16 | offset, 17 | size, 18 | }) 19 | } 20 | 21 | fn check_range(&self, offset: usize, len: usize) -> ZxResult { 22 | if offset + len >= self.size { 23 | return Err(ZxError::OUT_OF_RANGE); 24 | } 25 | Ok(()) 26 | } 27 | } 28 | 29 | impl VMObjectTrait for VMObjectSlice { 30 | fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { 31 | self.check_range(offset, buf.len())?; 32 | self.parent.read(offset + self.offset, buf) 33 | } 34 | 35 | fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { 36 | self.check_range(offset, buf.len())?; 37 | self.parent.write(offset + self.offset, buf) 38 | } 39 | 40 | fn zero(&self, offset: usize, len: usize) -> ZxResult { 41 | self.check_range(offset, len)?; 42 | self.parent.zero(offset + self.offset, len) 43 | } 44 | 45 | fn len(&self) -> usize { 46 | self.size 47 | } 48 | 49 | fn set_len(&self, _len: usize) -> ZxResult { 50 | unimplemented!() 51 | } 52 | 53 | fn commit_page(&self, page_idx: usize, flags: MMUFlags) -> ZxResult { 54 | self.parent 55 | .commit_page(page_idx + self.offset / PAGE_SIZE, flags) 56 | } 57 | 58 | fn commit_pages_with( 59 | &self, 60 | f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult) -> ZxResult, 61 | ) -> ZxResult { 62 | self.parent.commit_pages_with(f) 63 | } 64 | 65 | fn commit(&self, offset: usize, len: usize) -> ZxResult { 66 | self.parent.commit(offset + self.offset, len) 67 | } 68 | 69 | fn decommit(&self, offset: usize, len: usize) -> ZxResult { 70 | self.parent.decommit(offset + self.offset, len) 71 | } 72 | 73 | fn create_child(&self, _offset: usize, _len: usize) -> ZxResult> { 74 | Err(ZxError::NOT_SUPPORTED) 75 | } 76 | 77 | fn complete_info(&self, info: &mut VmoInfo) { 78 | self.parent.complete_info(info); 79 | } 80 | 81 | fn cache_policy(&self) -> CachePolicy { 82 | self.parent.cache_policy() 83 | } 84 | 85 | fn set_cache_policy(&self, _policy: CachePolicy) -> ZxResult { 86 | Ok(()) 87 | } 88 | 89 | fn committed_pages_in_range(&self, start_idx: usize, end_idx: usize) -> usize { 90 | let po = pages(self.offset); 91 | self.parent 92 | .committed_pages_in_range(start_idx + po, end_idx + po) 93 | } 94 | 95 | fn pin(&self, offset: usize, len: usize) -> ZxResult { 96 | self.check_range(offset, len)?; 97 | self.parent.pin(offset + self.offset, len) 98 | } 99 | 100 | fn unpin(&self, offset: usize, len: usize) -> ZxResult { 101 | self.check_range(offset, len)?; 102 | self.parent.unpin(offset + self.offset, len) 103 | } 104 | 105 | fn is_contiguous(&self) -> bool { 106 | self.parent.is_contiguous() 107 | } 108 | 109 | fn is_paged(&self) -> bool { 110 | self.parent.is_paged() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-syscall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zircon-syscall" 3 | version = "0.1.0" 4 | authors = ["Runji Wang "] 5 | edition = "2018" 6 | description = "Zircon syscalls implementation" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | log = "0.4" 12 | spin = "0.7" 13 | bitflags = "1.2" 14 | numeric-enum-macro = "0.2" 15 | zircon-object = { path = "../zircon-object" } 16 | kernel-hal = { path = "../kernel-hal" } 17 | futures = { version = "0.3", default-features = false, features = ["alloc", "async-await"] } -------------------------------------------------------------------------------- /code/ch04-03/zircon-syscall/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | fn main() { 4 | println!("cargo:rerun-if-changed=src/zx-syscall-numbers.h"); 5 | 6 | let mut fout = std::fs::File::create("src/consts.rs").unwrap(); 7 | writeln!(fout, "// Generated by build.rs. DO NOT EDIT.").unwrap(); 8 | writeln!(fout, "use numeric_enum_macro::numeric_enum;\n").unwrap(); 9 | writeln!(fout, "numeric_enum! {{").unwrap(); 10 | writeln!(fout, "#[repr(u32)]").unwrap(); 11 | writeln!(fout, "#[derive(Debug, Eq, PartialEq)]").unwrap(); 12 | writeln!(fout, "#[allow(non_camel_case_types)]").unwrap(); 13 | writeln!(fout, "#[allow(clippy::upper_case_acronyms)]").unwrap(); 14 | writeln!(fout, "pub enum SyscallType {{").unwrap(); 15 | 16 | let data = std::fs::read_to_string("src/zx-syscall-numbers.h").unwrap(); 17 | for line in data.lines() { 18 | if !line.starts_with("#define") { 19 | continue; 20 | } 21 | let mut iter = line.split(' '); 22 | let _ = iter.next().unwrap(); 23 | let name = iter.next().unwrap(); 24 | let id = iter.next().unwrap(); 25 | 26 | let name = &name[7..].to_uppercase(); 27 | writeln!(fout, " {} = {},", name, id).unwrap(); 28 | } 29 | writeln!(fout, "}}").unwrap(); 30 | writeln!(fout, "}}").unwrap(); 31 | } 32 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-syscall/src/debuglog.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::*, 3 | zircon_object::{debuglog::*, dev::*}, 4 | }; 5 | 6 | impl Syscall<'_> { 7 | /// Create a kernel managed debuglog reader or writer. 8 | pub fn sys_debuglog_create( 9 | &self, 10 | rsrc: HandleValue, 11 | options: u32, 12 | mut target: UserOutPtr, 13 | ) -> ZxResult { 14 | info!( 15 | "debuglog.create: resource_handle={:#x?}, options={:#x?}", 16 | rsrc, options, 17 | ); 18 | let proc = self.thread.proc(); 19 | if rsrc != 0 { 20 | proc.get_object::(rsrc)? 21 | .validate(ResourceKind::ROOT)?; 22 | } 23 | let dlog = DebugLog::create(options); 24 | // FIX ME: 25 | const FLAG_READABLE: u32 = 0x4000_0000u32; 26 | let dlog_right = if options & FLAG_READABLE == 0 { 27 | Rights::DEFAULT_DEBUGLOG 28 | } else { 29 | Rights::DEFAULT_DEBUGLOG | Rights::READ 30 | }; 31 | let dlog_handle = proc.add_handle(Handle::new(dlog, dlog_right)); 32 | target.write(dlog_handle)?; 33 | Ok(()) 34 | } 35 | 36 | /// Write log entry to debuglog. 37 | pub fn sys_debuglog_write( 38 | &self, 39 | handle_value: HandleValue, 40 | options: u32, 41 | buf: UserInPtr, 42 | len: usize, 43 | ) -> ZxResult { 44 | info!( 45 | "debuglog.write: handle={:#x?}, options={:#x?}, buf=({:#x?}; {:#x?})", 46 | handle_value, options, buf, len, 47 | ); 48 | const LOG_FLAGS_MASK: u32 = 0x10; 49 | if options & !LOG_FLAGS_MASK != 0 { 50 | return Err(ZxError::INVALID_ARGS); 51 | } 52 | let datalen = len.min(224); 53 | let data = buf.read_string(datalen as usize)?; 54 | let proc = self.thread.proc(); 55 | let dlog = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; 56 | dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data); 57 | // print to kernel console 58 | kernel_hal::serial_write(&data); 59 | if data.as_bytes().last() != Some(&b'\n') { 60 | kernel_hal::serial_write("\n"); 61 | } 62 | Ok(()) 63 | } 64 | 65 | #[allow(unsafe_code)] 66 | /// Read log entries from debuglog. 67 | pub fn sys_debuglog_read( 68 | &self, 69 | handle_value: HandleValue, 70 | options: u32, 71 | mut buf: UserOutPtr, 72 | len: usize, 73 | ) -> ZxResult { 74 | info!( 75 | "debuglog.read: handle={:#x?}, options={:#x?}, buf=({:#x?}; {:#x?})", 76 | handle_value, options, buf, len, 77 | ); 78 | if options != 0 { 79 | return Err(ZxError::INVALID_ARGS); 80 | } 81 | let proc = self.thread.proc(); 82 | let mut buffer = [0; DLOG_MAX_LEN]; 83 | let dlog = proc.get_object_with_rights::(handle_value, Rights::READ)?; 84 | let actual_len = dlog.read(&mut buffer).min(len); 85 | if actual_len == 0 { 86 | return Err(ZxError::SHOULD_WAIT); 87 | } 88 | buf.write_array(&buffer[..actual_len])?; 89 | // special case: return actual_len as status 90 | Err(unsafe { core::mem::transmute(actual_len as u32) }) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /code/ch04-03/zircon-syscall/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Zircon syscall implementations 2 | 3 | #![no_std] 4 | #![deny(warnings, unsafe_code, unused_must_use, unreachable_patterns)] 5 | 6 | extern crate alloc; 7 | 8 | #[macro_use] 9 | extern crate log; 10 | 11 | use { 12 | core::convert::TryFrom, 13 | kernel_hal::user::*, 14 | zircon_object::object::*, 15 | zircon_object::task::{CurrentThread, ThreadFn}, 16 | }; 17 | 18 | mod channel; 19 | mod consts; 20 | mod debuglog; 21 | 22 | use consts::SyscallType as Sys; 23 | 24 | pub struct Syscall<'a> { 25 | pub thread: &'a CurrentThread, 26 | pub thread_fn: ThreadFn, 27 | } 28 | 29 | impl Syscall<'_> { 30 | pub async fn syscall(&mut self, num: u32, args: [usize; 8]) -> isize { 31 | let thread_name = self.thread.name(); 32 | let proc_name = self.thread.proc().name(); 33 | let sys_type = match Sys::try_from(num) { 34 | Ok(t) => t, 35 | Err(_) => { 36 | error!("invalid syscall number: {}", num); 37 | return ZxError::INVALID_ARGS as _; 38 | } 39 | }; 40 | info!( 41 | "{}|{} {:?} => args={:x?}", 42 | proc_name, thread_name, sys_type, args 43 | ); 44 | let [a0, a1, a2, a3, a4, a5, a6, a7] = args; 45 | let ret = match sys_type { 46 | Sys::CHANNEL_CREATE => self.sys_channel_create(a0 as _, a1.into(), a2.into()), 47 | Sys::CHANNEL_READ => self.sys_channel_read( 48 | a0 as _, 49 | a1 as _, 50 | a2.into(), 51 | a3 as _, 52 | a4 as _, 53 | a5 as _, 54 | a6.into(), 55 | a7.into(), 56 | ), 57 | Sys::CHANNEL_WRITE => { 58 | self.sys_channel_write(a0 as _, a1 as _, a2.into(), a3 as _, a4.into(), a5 as _) 59 | } 60 | Sys::DEBUGLOG_CREATE => self.sys_debuglog_create(a0 as _, a1 as _, a2.into()), 61 | Sys::DEBUGLOG_WRITE => self.sys_debuglog_write(a0 as _, a1 as _, a2.into(), a3 as _), 62 | Sys::DEBUGLOG_READ => self.sys_debuglog_read(a0 as _, a1 as _, a2.into(), a3 as _), 63 | _ => { 64 | error!("syscall unimplemented: {:?}", sys_type); 65 | Err(ZxError::NOT_SUPPORTED) 66 | } 67 | }; 68 | info!("{}|{} {:?} <= {:?}", proc_name, thread_name, sys_type, ret); 69 | match ret { 70 | Ok(_) => 0, 71 | Err(err) => err as isize, 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /code/rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2021-07-27 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | .DS_Store -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Runji Wang"] 3 | language = "cn" 4 | multilingual = false 5 | src = "src" 6 | title = "简明 zCore 教程" 7 | [rust] 8 | edition = "2018" 9 | [output.html.playpen] 10 | editable = true 11 | [output.html] 12 | git-repository-url = "https://github.com/rcore-os/zCore-Tutorial" 13 | # mathjax-support = true 14 | # [preprocessor.mathjax] 15 | # renderers = ["html"] 16 | [output.html.search] 17 | enable = true 18 | limit-results = 30 19 | teaser-word-count = 30 20 | use-boolean-and = true 21 | boost-title = 2 22 | boost-hierarchy = 1 23 | boost-paragraph = 1 24 | expand = true 25 | heading-split-level = 3 -------------------------------------------------------------------------------- /docs/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 | -------------------------------------------------------------------------------- /docs/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 | 34 | - [硬件抽象层](ch06-00-hal.md) 35 | - [✅ UNIX硬件抽象层](ch06-01-zcore-hal-unix.md) -------------------------------------------------------------------------------- /docs/src/ch01-00-object.md: -------------------------------------------------------------------------------- 1 | # 内核对象 2 | 3 | Zircon 是一个基于内核对象的系统。系统的功能被划分到若干组内核对象中。 4 | 5 | 作为一切的开始,本章首先构造了一个内核对象框架,作为后面实现的基础。 6 | 然后我们实现第一个内核对象 —— `Process`,它是所有对象的容器,也是将来我们操作对象的入口点。 7 | 最后会实现一个稍微复杂但是极其重要的对象 `Channel`,它是进程间通信(IPC)的基础设施,也是传送对象的唯一管道。 8 | -------------------------------------------------------------------------------- /docs/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 | -------------------------------------------------------------------------------- /docs/src/ch02-01-zircon-task.md: -------------------------------------------------------------------------------- 1 | # Zircon 任务管理体系 2 | 3 | 线程(Thread)表示包含进程(Proess)所拥有的地址空间中的多个执行控制流(CPU寄存器,堆栈等)。进程属于作业(Job),作业定义了各种资源限制。作业一直由父级作业(parent Jobs)拥有,一直到根作业(Root Job)为止,根作业是内核在启动时创建并传递给[`userboot`(第一个开始执行的用户进程)](https://fuchsia.dev/docs/concepts/booting/userboot)。 4 | 5 | 如果没有作业句柄(Job Handle),则进程中的线程无法创建另一个进程或另一个作业。 6 | 7 | [程序加载](https://fuchsia.dev/docs/concepts/booting/program_loading)由内核层以上的用户空间工具和协议提供。 8 | 9 | 一些相关的系统调用: 10 | 11 | [`zx_process_create()`](https://fuchsia.dev/docs/reference/syscalls/process_create), [`zx_process_start()`](https://fuchsia.dev/docs/reference/syscalls/process_start), [`zx_thread_create()`](https://fuchsia.dev/docs/reference/syscalls/thread_create), [`zx_thread_start()`](https://fuchsia.dev/docs/reference/syscalls/thread_start) -------------------------------------------------------------------------------- /docs/src/ch02-02-process-job-object.md: -------------------------------------------------------------------------------- 1 | # 进程管理:Process 与 Job 对象 2 | 3 | 4 | 5 | > 介绍 Process 与 Job 的整体设计 6 | > 7 | > 实现 Process 和 Job 对象的基本框架,支持树状结构 8 | > 9 | 10 | ## 作业Job 11 | ### 概要 12 | 作业是一组进程,可能还包括其他(子)作业。作业用于跟踪执行内核操作的特权(即使用各种选项进行各种syscall),以及跟踪和限制基本资源(例如内存,CPU)的消耗。每个进程都属于一个作业。作业也可以嵌套,并且除根作业外的每个作业都属于一个(父)作业。 13 | ### 描述 14 | 15 | 作业是包含以下内容的对象: 16 | 17 | - 对父作业的引用 18 | - 一组子作业(每个子作业的父作业既是这个作业) 19 | - 一组成员进程 20 | - 一套策略(Policy) 21 | 22 | 由多个进程组成的“应用程序”可作为单个实体,被作业基于一套策略进行控制。 23 | 24 | ### 作业策略Job Policy 25 | 26 | [策略policy](https://fuchsia.dev/fuchsia-src/concepts/settings/policy/policy_concepts?hl=en) 可在Kernel运行时动态修改系统的各种配置(setting)。作业策略主要涉及作业安全性和资源使用的条件(Condition)限制。 27 | 28 | #### 策略的行为PolicyAction 29 | 30 | 策略的行为包括: 31 | 32 | - Allow 允许条件 33 | - Deny 拒绝条件 34 | - AllowException 通过 debugt port 生成异常,异常处理完毕后可恢复执行且运行条件 35 | - DenyException 通过 debugt port 生成异常,异常处理完毕后可恢复执行 36 | - Kill 杀死进程 37 | 38 | #### 应用策略时的条件 PolicyCondition 39 | 40 | 应用策略时的条件包括: 41 | 42 | - BadHandle: 此作业下的某个进程正在尝试发出带有无效句柄的syscall。在这种情况下,`PolicyAction::Allow`并且`PolicyAction::Deny`是等效的:如果syscall返回,它将始终返回错误ZX_ERR_BAD_HANDLE。 43 | - WrongObject:此作业下的某个进程正在尝试发出带有不支持该操作的句柄的syscall。 44 | - VmarWx:此作业下的进程正在尝试映射具有写执行访问权限的地址区域。 45 | - NewAny:代表上述所有ZX_NEW条件的特殊条件,例如NEW_VMO,NEW_CHANNEL,NEW_EVENT,NEW_EVENTPAIR,NEW_PORT,NEW_SOCKET,NEW_FIFO和任何将来的ZX_NEW策略。这将包括不需要父对象来创建的所有新内核对象。 46 | - NewVMO:此作业下的某个进程正在尝试创建新的vm对象。 47 | - NewChannel:此作业下的某个进程正在尝试创建新通道。 48 | - NewEvent:此作业下的一个进程正在尝试创建一个新事件。 49 | - NewEventPair:此作业下的某个进程正在尝试创建新的事件对。 50 | - NewPort:此作业下的进程正在尝试创建新端口。 51 | - NewSocket:此作业下的进程正在尝试创建新的套接字。 52 | - NewFIFO:此工作下的一个进程正在尝试创建一个新的FIFO。 53 | - NewTimer:此作业下的某个进程正在尝试创建新的计时器。 54 | - NewProcess:此作业下的进程正在尝试创建新进程。 55 | - NewProfile:此作业下的一个进程正在尝试创建新的配置文件。 56 | - AmbientMarkVMOExec:此作业下的某个进程正在尝试使用带有ZX_HANDLE_INVALID的zx_vmo_replace_as_executable()作为第二个参数,而不是有效的ZX_RSRC_KIND_VMEX。 57 | 58 | ## 进程Process 59 | 60 | 进程是传统意义上程序的一个运行实例,包含一组指令和数据,这些指令将由一个或多个线程执行,并拥有一组资源。在具体实现上,进程包括如下内容: 61 | 62 | - Handles :大部分是进程用到的资源对象的句柄 63 | - Virtual Memory Address Regions:进程所在的内存地址空间 64 | - Threads:进程包含的线程组 65 | 66 | 67 | 68 | 进程包含在作业(Job)的管理范畴之中。从资源和权限限制以及生命周期控制的角度来看,允许将由多个进程组成的应用程序视为一个实体(即作业)。 69 | 70 | ### 生命周期(lifetime) 71 | 进程有自己的生命周期,从开始创建到直到被强制终止或程序退出为止。可通过调用`Process::create()`创建一个进程,并调用`Process::start()`开始执行 。该进程在以下情况下停止执行: 72 | 73 | - 最后一个线程终止或退出 74 | - 进程调用 `Process::exit()` 75 | - 父作业(parent job)终止了该过程 76 | - 父作业(parent job)被销毁(destroied) 77 | 78 | 注:`Process::start()`不能被调用两次。新线程不能被添加到已启动的进程。 79 | 80 | -------------------------------------------------------------------------------- /docs/src/ch02-03-thread-object.md: -------------------------------------------------------------------------------- 1 | # 线程管理:Thread 对象 2 | 3 | 线程对象是代表分时CPU的执行上下文的一种结构。线程对象与特定的进程对象相关联,该进程对象为线程对象执行中涉及的I/O和计算提供提供必要的内存和其他对象的句柄。 4 | 5 | 6 | ## 生命期 7 | 8 | 线程是通过调用Thread::create()创建的,但只有在调用Thread::create()或Process::start()时才开始执行。这两个系统调用的参数都是要执行的初始例程的入口。 9 | 10 | 传递给Process::start()的线程应该是在一个进程上开始执行的第一个线程。 11 | 12 | 13 | 下列情况都可导致一个线程终止执行: 14 | 15 | - 通过调用 `CurrentThread::exit()` 16 | - 当父进程终止时 17 | - 通过调用 `Task::kill()` 18 | - 在生成没有处理程序或处理程序决定终止线程的异常之后。 19 | 20 | 从入口例程返回并不终止执行。入口点的最后一个动作应该是调用CurrentThread::exit()。 21 | 22 | 23 | 24 | 关闭一个线程的最后一个句柄并不终止执行。为了强行杀死一个没有可用句柄的线程,可以使用KernelObject::get_child()来获得该线程的句柄。但这种方法是非常不可取的。杀死一个正在执行的线程可能会使进程处于损坏的状态。 25 | 26 | 本地线程总是分离的(*detached*)。也就是说,不需要join()操作来做一个干净的终止(clean termination)。但一些内核之上的运行系统,如C11或POSIX可能需要线程被连接(be joined)。 27 | 28 | 29 | 30 | ## 信号 31 | 32 | 线程提供以下信号: 33 | 34 | - THREAD_TERMINATED 35 | - THREAD_SUSPENDED 36 | - THREAD_RUNNING 37 | 38 | 当一个线程启动执行时,THREAD_RUNNING被设定。当它被暂停时,THREAD_RUNNING被取消,THREAD_SUSPENDED被设定。当线程恢复时,THREAD_SUSPENDED被取消,THREAD_RUNNING被设定。当线程终止时,THREAD_RUNNING和THREAD_SUSPENDED都被置位,THREAD_TERMINATED也被置位。 39 | 40 | 注意,信号经过“或”运算后进入KernelObject::wait_signal()函数系列所保持的状态 ,因此当它们返回时,你可能会看到所要求的信号的任何组合。 41 | 42 | 43 | 44 | ## 线程状态(ThreadState) 45 | 46 | > 状态转移:创建 -> 运行 -> 暂停 -> 退出,最好有个状态机的图 47 | > 48 | > 实现 ThreadState,最好能加一个单元测试来验证转移过程 49 | 50 | ```rust 51 | pub enum ThreadState { 52 | New, \\该线程已经创建,但还没有开始运行 53 | Running, \\该线程正在正常运行用户代码 54 | Suspended, \\由于zx_task_suspend()而暂停 55 | Blocked, \\在一个系统调用中或处理一个异常而阻塞 56 | Dying, \\线程正在被终止的过程中,但还没有停止运行 57 | Dead, \\该线程已停止运行 58 | BlockedException, \\该线程在一个异常中被阻塞 59 | BlockedSleeping, \\该线程在zx_nanosleep()中被阻塞 60 | BlockedFutex, \\该线程在zx_futex_wait()中被阻塞 61 | BlockedPort, \\该线程在zx_port_wait()中被被阻塞 62 | BlockedChannel, \\该线程在zx_channel_call()中被阻塞 63 | BlockedWaitOne, \\该线程在zx_object_wait_one()中被阻塞 64 | BlockedWaitMany, \\该线程在zx_object_wait_many()中被阻塞 65 | BlockedInterrupt, \\该线程在zx_interrupt_wait()中被阻塞 66 | BlockedPager, \\被Pager阻塞 (目前没用到???) 67 | } 68 | ``` 69 | 70 | 71 | 72 | ## 线程寄存器上下文 73 | 74 | > 定义 ThreadState,实现 read_state,write_state 75 | 76 | 77 | 78 | ## Async 运行时和 HAL 硬件抽象层 79 | 80 | > 简单介绍 async-std 的异步机制 81 | > 82 | > 介绍 HAL 的实现方法:弱链接 83 | > 84 | > 实现 hal_thread_spawn 85 | 86 | ## 线程启动 87 | 88 | > 将 HAL 接入 Thread::start,编写单元测试验证能启动多线程 89 | -------------------------------------------------------------------------------- /docs/src/ch03-00-memory.md: -------------------------------------------------------------------------------- 1 | # 内存管理 2 | -------------------------------------------------------------------------------- /docs/src/ch03-01-zircon-memory.md: -------------------------------------------------------------------------------- 1 | # Zircon 内存管理模型 2 | Zircon 中有两个跟内存管理有关的对象 VMO(Virtual Memory Object)和 VMAR (Virtual Memory Address Region)。VMO 主要负责管理物理内存页面,VMAR 主要负责进程虚拟内存管理。当创建一个进程的时候,需要使用到内存的时候,都需要创建一个 VMO,然后将这个 VMO map 到 VMAR上面。 3 | -------------------------------------------------------------------------------- /docs/src/ch04-00-userspace.md: -------------------------------------------------------------------------------- 1 | # 用户程序 2 | 3 | zCore采用的是微内核的设计风格。微内核设计的一个复杂问题是”如何引导初始用户空间进程“。通常这是通过让内核实现最小版本的文件系统读取和程序加载来实现的引导。 -------------------------------------------------------------------------------- /docs/src/ch05-00-signal-and-waiting.md: -------------------------------------------------------------------------------- 1 | # 信号和等待 2 | 3 | ## 信号 4 | 5 | 对象可能有多达 32 个信号(由 zx_signals *t 类型和 ZX* **SIGNAL** 定义表示),它们表示有关其当前状态的一条信息。例如,通道和套接字可能是 READABLE 或 WRITABLE 的。进程或线程可能会被终止。等等。 6 | 7 | 线程可以等待信号在一个或多个对象上变为活动状态。 8 | 9 | ## 等待 10 | 11 | 线程可用于[`zx_object_wait_one()`](https://fuchsia.dev/docs/reference/syscalls/object_wait_one) 等待单个句柄上的信号处于活动状态或 [`zx_object_wait_many()`](https://fuchsia.dev/docs/reference/syscalls/object_wait_many)等待多个句柄上的信号。两个调用都允许超时,即使没有信号挂起,它们也会返回。 12 | 13 | 超时可能会偏离指定的截止时间,具体取决于计时器的余量。 14 | 15 | 如果线程要等待大量句柄,使用端口(Port)会更有效,它是一个对象,其他对象可能会绑定到这样的对象,当信号在它们上被断言时,端口会收到一个包含信息的数据包关于未决信号。 16 | 17 | ## 事件与事件对 18 | 19 | 事件(Event)是最简单的对象,除了它的活动信号集合之外没有其他状态。 20 | 21 | 事件对(Event Pair)是可以相互发出信号的一对事件中的一个。事件对的一个有用属性是,当一对的一侧消失时(它的所有句柄都已关闭),PEER_CLOSED 信号在另一侧被断言。 22 | 23 | 见:[`zx_event_create()`](https://fuchsia.dev/docs/reference/syscalls/event_create), 和[`zx_eventpair_create()`](https://fuchsia.dev/docs/reference/syscalls/eventpair_create)。 -------------------------------------------------------------------------------- /docs/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 | -------------------------------------------------------------------------------- /docs/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 | -------------------------------------------------------------------------------- /docs/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 | -------------------------------------------------------------------------------- /docs/src/ch05-04-futex-object.md: -------------------------------------------------------------------------------- 1 | # 用户态同步互斥:Futex 对象 2 | 3 | ## Futex 机制简介 4 | 5 | > Futex 是现代 OS 中用户态同步互斥的唯一底层设施 6 | > 7 | > 为什么快:利用共享内存中的原子变量,避免进入内核 8 | 9 | Futexes 是内核原语,与用户空间原子操作一起使用以实现高效的同步原语(如Mutexes, Condition Variables等),它只需要在竞争情况(contended case)下才进行系统调用。通常它们实现在标准库中。 10 | 11 | ## 实现基础元语:wait 和 wake 12 | 13 | > 实现 wait 和 wake 函数,并做单元测试 14 | 15 | ## 实现高级操作 16 | 17 | > 实现 Zircon 中定义的复杂 API 18 | -------------------------------------------------------------------------------- /docs/src/ch06-00-hal.md: -------------------------------------------------------------------------------- 1 | # 硬件抽象层 2 | -------------------------------------------------------------------------------- /docs/src/fuchsia.md: -------------------------------------------------------------------------------- 1 | # Fuchsia OS 和 Zircon 微内核 2 | -------------------------------------------------------------------------------- /docs/src/img/ch01-01-kernel-object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/docs/src/img/ch01-01-kernel-object.png -------------------------------------------------------------------------------- /docs/src/img/mmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/docs/src/img/mmap.png -------------------------------------------------------------------------------- /docs/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 层的效果。 -------------------------------------------------------------------------------- /docs/src/zcore-intro/image-20200805123801306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcore-os/zCore-Tutorial/e41dd13f904db29b131c20afb1f1a838255bd509/docs/src/zcore-intro/image-20200805123801306.png --------------------------------------------------------------------------------