1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-21 23:56:18 +04:00

add OS2ATC slides. update README

This commit is contained in:
WangRunji 2018-12-16 11:47:33 +08:00
parent 9b0b0064d0
commit 70e0025c63
4 changed files with 619 additions and 1 deletions

View File

@ -8,10 +8,12 @@ Going to be the next generation teaching operating system.
Supported architectures: x86_64, RISCV32IMA(S/M), AArch64
Tested boards: QEMU, Raspberry Pi 3B+
Tested boards: QEMU, labeled-RISCV, Raspberry Pi 3B+
[Dev docs](https://rucore.gitbook.io/rust-os-docs/) (in Chinese)
![demo](./docs/2_OSLab/os2atc/demo.png)
## Summary
This is a project of THU courses:

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

View File

@ -0,0 +1,616 @@
<!-- page_number: true -->
<!-- $width:12in -->
<!-- $height: 6.75in -->
# Rust版 uCore OS 的设计与实现
## Design and implementation of uCore OS in Rust
王润基
清华大学计算机系
2018.12.16 @ OS2ATC
---
# 提纲
## 简介Rust uCore OS是什么
## 动机为什么要用Rust写OS
## 体会用Rust写OS有何好处
## 未来:接下来会做什么?
---
# 简介Rust uCore OS是什么
---
# uCore OS
清华大学教学操作系统
参考 xv6 & jos in MIT, OS161 in Harvard, Linux
用C语言编写的宏内核OS
* [ucore_os_lab](https://github.com/chyyuu/ucore_os_lab):操作系统课实验
* [ucore_os_plus](https://github.com/chyyuu/ucore_os_plus):教学科研系统
---
# uCore OS in Rust -- RustOS
2018年操作系统课大实验项目
“用Rust语言重新实现uCore”
#
之后在OS专题训练课上推广目前
支持三大平台x86_64, RISCV32, AArch64
支持硬件计算所Labeled-RISCV树莓派3B
支持多核CPU
---
## 大实验选题列举
OS
* RustOS for x86_64 SMP
* Rustable - ucore 在 arm 平台的 rust 移植
* Rucore with LKM Drivers
OS专题训练
* RustOS 上树莓派 USB 与 VideoCore IV 显卡驱动的移植
* RustOS 多核移植与基于PARD框架的线程级Label管理
* RustOS wiki完善与教学lab实验的制作
* RustOS 参考sv6的多核实现和优化
* RustOS 移植到 rv64 及llvm编译器支持
---
# 动机为什么要用Rust写OS
* C语言有何不足
* Rust解决了哪些痛点
* 条件是否成熟?
---
# C语言有何不足
---
## 简单?简陋?
C语言简单、直接为OS而生。
但从现代编程语言的角度看C语言有些简陋难以表达复杂逻辑和抽象。
![90%](./C.jpg)
*上图出自[一篇知乎回答](https://www.zhihu.com/question/25038841/answer/44396770)*
---
### 缺乏对OOP和接口的语言级支持
C中常用函数指针实现接口
```c
struct device {
size_t d_blocks;
size_t d_blocksize;
int (*d_open)(struct device *dev, uint32_t open_flags);
int (*d_close)(struct device *dev);
int (*d_io)(struct device *dev, struct iobuf *iob, bool write);
int (*d_ioctl)(struct device *dev, int op, void *data);
};
```
---
### 缺乏基础数据结构支持
OS中常用的侵入式链表摘自ucore_os_lab
```c
// 链表节点
struct list_entry {
struct list_entry *prev, *next;
};
// 在宿主类型中嵌入链表节点
struct Page {
list_entry_t page_link;
...
};
// 从list类型转化回宿主类型
#_define le2page(le, member) \
to_struct((le), struct Page, member)
#_define offsetof(type, member) \
((size_t)(&((type *)0)->member))
#_define to_struct(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
```
---
### 缺乏工程模块系统
* 编译配置复杂
* 难以复用代码
---
## SegmentFault
悬空指针,重复释放,数据竞争……
#
![60%](./pointer.png)
---
# Rust解决了哪些痛点
* 强类型内存安全线程安全——减少Bug
* 现代语言特性——提升开发体验
* 完善的模块系统——方便代码复用
* 零开销抽象——能写OS的根本保障
---
# 是时候尝试Rust了
### 社区:[Redox](https://www.redox-os.org)
全功能Rust OS微内核架构支持GUI
### 教学:[CS140e](https://web.stanford.edu/class/cs140e/)
斯坦福大学实验性OS课程2018年新开设
Rust编写OS面向ARM在树莓派3上运行
### 兴趣:[Writing an OS in Rust](https://os.phil-opp.com)
手把手带你用Rust编写OS的系列博客
面向x86_64教程极为详尽
作者为Rust编写OS提供了大量开源工具
---
## 万事俱备,只是……
# 还不会Rust怎么办
编写OS是学习Rust的高效途径
---
# 体会用Rust写OS有何好处
* 内存与线程安全减少Bug
* 包管理系统:复用已有代码
* 接口与泛型:内核模块化
* 所有权和RAII机制简化资源管理
---
# 安全!
类型系统 + 所有权机制 + 生命周期机制
=> 内存安全 + 线程安全
---
## Rust如何减少Bug
### 消除了越界访问
=> panic
### 消除了因生命周期导致的非法访存
=> 编译错误
### 消除了数据竞争
=> 死锁
### 缩小了Bug的查找范围
=> unsafe块
---
## Rust如何减少Bug
* 大部分低级错误在编译期避免
* 少数逻辑错误在运行时暴露
* 难以发现的错误被限制了范围
---
## 充分利用现成轮子
引用的外部库crate
* `alloc`: 容器
* `log`: 日志
* `spin`: 自旋锁
* `xmas-elf`: 解析ELF文件
* `linked_list_allocator`: 堆分配算法
* `uart_116500`: 串口驱动
* `x86_64`: 包装汇编指令,封装页表等数据结构
更好地专注于OS核心逻辑
---
## 制造我们自己的轮子
仿照`x86_64`库,并基于社区现有成果,
我们分别实现了`riscv`和`aarch64`库。
---
# 内核模块化
ucore_os_lab = 内存管理 + 进程管理 + 文件系统
lab1-lab8层层依赖高度耦合。
然而它们在逻辑上互不相关,理应分开。
---
# 内核模块化
每个部分作为独立的crate存在互不依赖。
内核通过实现它们的接口,把它们粘合在一起。
可以分别内部单元测试,然后放在一起集成测试。
配合泛型,可做到零开销。
---
### 内存模块
接口:页表,页表项,缺页处理函数
功能:面向进程的虚存管理(`mm_struct`
-------支持内存置换、写时复制、延迟分配等机制
### 线程模块
接口:上下文切换,新线程的构造
功能:线程调度和管理
### 文件系统
接口块设备VFS虚拟文件系统
功能:文件操作和管理
---
### 内存模块——接口
```rust
pub trait PageTable {
fn map(&mut self, addr: VirtAddr, target: PhysAddr)
-> &mut Entry;
fn unmap(&mut self, addr: VirtAddr);
fn get_entry(&mut self, addr: VirtAddr)
-> Option<&mut Entry>;
}
pub trait Entry {
fn update(&mut self); // flush TLB
fn present(&self) -> bool;
fn target(&self) -> PhysAddr;
fn set_present(&mut self, value: bool);
fn set_target(&mut self, target: PhysAddr);
...
}
```
---
### 内存模块——面向接口的上层实现
```rust
pub struct MemoryArea {
start_addr: VirtAddr,
end_addr: VirtAddr,
...
}
impl MemoryArea {
fn map(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
let target = alloc_frame();
pt.map(addr, target);
}
}
}
```
为一段连续的虚拟地址空间 映射页表项。
---
### 内存模块——接口的Mock实现
```rust
pub struct MockPageTable {
entries: [MockEntry; PAGE_COUNT],
data: [u8; PAGE_SIZE * PAGE_COUNT],
page_fault_handler: Option<PageFaultHandler>,
}
impl PageTable for MockPageTable {
fn map(...) {...}
fn unmap(...) {...}
fn get_entry(...) {...}
}
impl MockPageTable {
fn read(&mut self, addr: VirtAddr) -> u8 {...}
fn write(&mut self, addr: VirtAddr, data: u8) {...}
}
```
实现一个仿真页表,模拟地址转换的过程,从数组中存取数据。
---
### 内存模块——基于Mock的单元测试
```rust
#[test]
fn memory_area_map() {
let mut pt = MockPageTable {...};
let area = MemoryArea {...};
area.map(&mut pt);
pt.write(0x1000, 1);
assert_eq!(pt.read(0x1000), 1);
}
```
可用`cargo test`在任意环境下运行单元测试不依赖QEMU。
---
### 线程模块——接口与实现
```rust
pub trait Context {
unsafe extern "C"
fn switch_to(&mut self, target: &mut Context);
}
pub struct X86Context {
rip: usize,
... // callee-saved registers
}
impl Context for X86Context {
unsafe extern "C" // Store caller-saved registers
fn switch_to(&mut self, target: &mut Context) {
// Store callee-saved registers
// Restore callee-saved registers
} // Restore caller-saved registers
}
```
上下文切换:保存和恢复寄存器
---
### 线程模块——面向接口的上层实现
```rust
/// 管理所有线程的状态及调度,全局唯一
pub struct ProcessManager {...}
/// 线程执行者每个CPU核对应一个
pub struct Processor {
manager: Arc<ProcessManager>,
context: Box<Context>,
...
}
impl Processor {
/// 调度线程,无限循环
fn run(&mut self) -> ! { loop {
let mut process = self.manager.pop();
unsafe { self.context.switch_to(&mut process); }
self.manager.push(process);
}}
}
```
每个CPU核不断地从运行队列中取出线程-运行-放回
---
### 线程模块——兼容标准库的高层封装
```rust
// thread.rs
pub fn current() -> Thread {...}
pub fn sleep(dur: Duration) {...}
pub fn spawn<F, T>(f: F) -> JoinHandle<T> {...}
pub fn yield_now() {...}
pub fn park() {...}
```
在上页基础上进一步封装。
提供和标准库`std::thread`完全一致的上层接口。
使得依赖std的多线程代码可以方便地迁移到内核中。
---
# 所有权和RAII机制简化资源管理
OS需要管理复杂的资源
资源之间有复杂的共享和依赖关系
---
![80%](./resources.png)
---
进程的对象结构:
```rust
pub struct Process {
context: Context,
kstack: KernelStack,
memory: MemorySet,
files: BTreeMap<usize, Arc<Mutex<File>>>,
...
}
```
---
将资源封装成对象,在析构函数中释放资源。
```rust
pub struct KernelStack {
ptr: *mut u8,
layout: Layout,
}
impl Drop for KernelStack {
fn drop(&mut self) {
unsafe{ dealloc(self.ptr, self.layout); }
}
}
```
---
当对象的生命周期结束时,资源自动释放。
```rust
pub struct Process {
context: Context,
kstack: KernelStack,
memory: MemorySet,
files: BTreeMap<usize, Arc<Mutex<File>>>,
...
}
pub struct ProcessManager {
procs: BTreeMap<usize, Process>,
}
impl ProcessManager {
pub fn remove(&mut self, pid: usize) {
self.procs.remove(&pid);
// All resources have been released here
}
}
```
---
# Rust vs C
## 代码风格
||Rust|C|
|-|-|-|
|数据结构|泛型容器Vec|侵入式(链表)|
|全局变量|少量|大量|
|数据分布|倾向分散|倾向集中|
|数据类型|鼓励自定义类型|基础类型|
|思维方式|所有权+生命周期|数据+行为|
---
## 代码量
||Rust|C|
|-|-|-|
|内存管理|1600|1800|
|线程管理|1200|1200|
|文件系统|1300|3400|
|同步互斥|500|400|
|内核其它|800|1200|
|共计|5400|8000|
*使用`loc`统计代码行数基于RISCV版本粗略计算*
---
## 语言能力
在底层:
* 具有同等的底层操作能力
* 二者具有良好的互操作性
在上层:
* Rust能编写更加安全的代码减少Bug
* Rust具有更好的表达能力胜任复杂逻辑
* Rust具有更强的抽象能力有助于代码的分离和复用
——Rust更加适合编写OS
---
# Rust的问题
学习曲线过于陡峭!
所有权、生命周期等机制难以驾驭!
初学者大部分时间在与编译器作斗争。
一种可能的解决方案:
* 先用unsafe、C风格实现
* 再逐步消除unsafe、重构成Rust风格
---
# 未来:接下来会做什么?
* 真机测试HiFiveU, K210等RISCV64开发板
* 教学实验2019年操作系统课实验
* 功能完善实现POSIX接口
* 性能优化发掘Rust的潜力
* 对比借鉴其它有趣OS
* 潜力探索async异步机制
---
## 其它有趣OS
### [Tock](https://www.tockos.org)
Rust编写的嵌入式操作系统
关注Capsule内核模块设计进程的内存分配策略……
### [Biscuit](https://github.com/mit-pdos/biscuit)
Golang编写的POSIX兼容OSMIT出品
关注Go异步机制Go vs Rust
---
## 潜力探索async无栈协程应用于OS内核的探讨
async-await用户态异步编程机制
用同步的方式,编写异步的代码。
背后的实现机制和OS线程调度高度一致。
能否应用于Kernel中与传统线程机制相比有何优缺点
---
# 感谢
### 指导老师
陈渝,向勇
### 参与开发的同学们
王润基,戴臻旸,王纪霆
贾越凯,寇明阳,孔彦
刘辰屹,陈秋昊,朱书聪
---
# 欢迎试玩!
![40%](demo.png)
GitHubhttps://github.com/wangrunji0408/RustOS
---
# 感谢聆听
# Q&A

Binary file not shown.