Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2024A-stage3-arceos #662

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions source/_posts/2024A-stage3-arceos-Martin1847.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
title: 2024A-stage3-arceos-Martin1847
date: 2024-12-02 23:25:11
tags:
- author:martin1847
- repo:https://github.com/martin1847/oscamp
---

# Arceos 总结

核心学习了`arceos`作为组件化设计的理念,抽象微内核、宏内核和VVM之间的共同点。

基于这些比如调度`task`,内存空间`mmaddr`,文件系统`fs`的底层组件,可以方便的完成需求。


## lab1 内存分配挑战


通过`lab1`内存分配器的实现,对内存加深了理解,就是个大`byte[]`,物理地址就是index。

lab1核心实现就是借用操作系统的分配思想,内存空间分堆区和栈区,堆区存放不需要回收的数据(一直增长,没有内存碎片),栈区放需要回收的,包括vec中间扩容的。这部分处理掉可以达到`373`,参考实现:

https://github.com/martin1847/oscamp/blob/lab1/arceos/labs/lab_allocator/src/lib.rs


```python
# 每轮最小生存对象
>>> a = 262144 + 65536 + 16384 + 4096 + 1024 + 256 + 64
# 每轮额外需要的临时空间
>>> tmp = sum([524288, 131072, 32768, 8192, 2048, 512, 128, 32])
699040
# [PA:0x8026f000, PA:0x88000000) free memory (READ | WRITE | FREE)
>>> total = 0x88000000 - 0x8026f000
131665920
>>> (total - tmp )/a
374.7221204907526
# 考虑每轮增加还有一部分额外内存,7 * sum[1..N]
>>> (total - tmp - 7 * sum(range(1,373)) )/a
373.33259132942686
```




<!-- more -->

## unikernel

这种模式内核就是应用,共享地址空间,系统调用变成了函数调用。(不过在现有硬件下一个上下文貌似在`几个us`的级别,相比IO的10毫秒级别,感觉可以忽略不计,又有些鸡肋)

虽然理论上可以达到应用最佳性能,是服务端`serverless`的理想方案。

不过考虑到裸机成本,需要引入虚拟化。这也让我对`Hypervisor`加大了兴趣。


## 宏内核

利用`arceos`的组件化能力,较少改动就可以支持。

这里做了一个`mmap`的实验。这里做了个小优化,内容小于一页的时候,直接读取到对应地址,减少一次`内存copy`。

```rust
if size_align > PAGE_SIZE_4K {
let mut buf = alloc::vec![0; len];
// for each page to write with offset.
get_file_like(fd).and_then(|f| f.read(&mut buf));
uspace.write(addr_at, &buf);
} else {
let (paddr, _, _) = uspace.page_table().query(addr_at).unwrap();
// 开启分页,内核也是要用虚拟地址
let kernel_vaddr = phys_to_virt(paddr);
// single page, write directly
get_file_like(fd).and_then(|f| {
f.read(unsafe { from_raw_parts_mut(kernel_vaddr.as_mut_ptr(), len) })
});
}
```

## Hypervisor

据说现在的云厂商大部分都是基于`KVM`的硬件虚拟化方案,也即 `Type 1` 虚拟化。

对既能达到高性能、又能安全便捷的技术,非常感兴趣。原来硬件层面提供了一些支持、能力。

通过实验,对riscv架构下`GVA->GPA->HPA`页表转换支持、中断注入增加了了解。

对于`type 1.5`虚拟化页增加了兴趣,尤其看到`Jailhouse`这种还可以物理隔离,那么`rtos`和传统`分时os`就可以共存了,可以在智能驾驶、新能源汽车系统上发挥作用。

```txt
+-----------------------+-----------------+
| | |
| Linux | RT |
| | |
+-----------------------+-----------------+
| Jailhouse |
+-----------------------+-----------------+
| CPU 0 | CPU 1 | CPU 2 | CPU 3 |
+-------+-------+-------+-----------------+
| Root cell | Cell 0 |
+-----------------------+-----------------+
```


70 changes: 70 additions & 0 deletions source/_posts/2024A-stage4-arceos-unikernel1-Martin1847.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: 2024A-stage4-arceos-unikernel1-Martin1847
date: 2024-12-20 19:38:11
tags:
- author:martin1847
- repo:https://github.com/martin1847/arceos
---

# Arceos 训练营总结

转眼间两个多月的训练营要进入尾声了。
还记得国庆回山东的高铁上,在刷`rustlings`的算法题,小根堆的实现。

从二阶段的`rCore`到组件化的`arceos`,一路下来,对OS几大部件`CPU`虚拟化、`内存`虚拟化和文件系统虚拟化有了更深刻的理解。

下面我也从这几个方面来分别做个总结。




<!-- more -->

## CPU虚拟化

了解了`CPU`的几种特权模式,以及到OS进行系统调用进行的硬件级别(汇编指令)支持。

包括通过对时钟中断的支持,完成抢占式调度(这也解释了在用户态较难实现lock)。

在CPU眼里,没有函数、没有内存分配,有的只是指令和数据。

对于高级语言而言,一个用户态程序的最终运行,是`编译器`和`os`和CPU共同协同运作的结果。

编译器负责栈的初始化,函数上下文的处理,os负责提供硬件资源的抽象、系统调用,CPU提供特权指令。

虚拟化的目的,是为了多个程序的调度,让每个程序“独占”CPU,减少了编码的心智负担。

## 内存虚拟化

这里印象深刻的是分页,页表实现。硬件层面的`MMU`和`TLB`支持。

我们实现了彻底分页,内核态和用户态是两个页表。通过分页保障了安全,也方便了应用编写。

这一块也是非常复杂的点。

印象比较深刻的是三级页表的内存占用,以及`mmap`的实现。通过`mmap`可以从内核申请共享内存、或者映射文件,减少系统调用次数。这里也是默认`lazy init`,用到的时候通过缺页中断去真正完成映射。

通过分页`PTE`也很好了保护了内存安全,是否可执行。

![riscv-sv39-pte](https://rcore-os.cn/rCore-Tutorial-Book-v3/_images/sv39-pte.png)

另外一点就是内存分配算法,内存本质就是一个大的`byte[]`,找到一个可用的(按页不按页都可以)地址,也即`index`返回即可。

开启分页后`MMU`会进行更多安全检查。比如“数据执行保护”(Data Execution Prevention, DEP)或“不可执行位”(No-eXecute, NX),CPU碰到不可执行的代码区,会触发异常。起到防注入、溢出等的保护。



## 文件系统虚拟化

了解了ELF文件格式,静态link,动态link,以及文件inode的底层细节。

设计一个高效的文件系统是个复杂的工程,本质根内存分配一样,要减少内部碎片、外部碎片,而磁盘访问速度远远不及内存,真是一件复杂的事情。

# 总结

计算机没有魔法。通过这阵子的学习,对于CPU、内存如何协同工作加深了理解。
哪些是硬件的支持,哪些是OS的抽象、编译器的辅助,有了更深刻的认识。
比如栈的处理,编译器处理函数上下文、OS初始化栈、CPU提供栈指针寄存器,共同协作完成。
这是一次很好的练习,对于从最底层看本质非常有帮助。

感谢清华大学的主办,感谢各阶段的老师们的指导!