0%

2024 秋冬季开源操作系统训练营第三阶段总结报告-戴志强

2024 秋冬季开源操作系统训练营 项目基础阶段


进度情况:

由于忙于区域赛和大创申请书,三阶段的时间并不充足,作业仅仅做到hypervisor前的部分,仅阅读了部分源码。

Unikernel基础与框架

题1

只需要将

println!("[WithColor]: !");

改为
println!("\x1b[33m[WithColor]: Hello, Arceos!\x1b[0m");

可以打出黄色字体。

题2

要求实现HashMap,并且提供随机数,我还没办法理解随机数和HashMap的关系,所以写了一个简单的HashMap

1
2
3
4
5
6
7
8
9
10
11
struct KeyValue<K, V> {
key: K,
value: V,
}
pub struct HashMap<K, V> {
buckets: Vec<Vec<Option<KeyValue<K, V>>>>,
}
fn hash(&self, key: &K) -> usize {
let key_ptr = key as *const _ as usize;
key_ptr % self.buckets.len()
}

Unikernel地址空间与分页、多任务支持(协作式)

题目要求:

只能修改modules/bump_allocator组件的实现,支持bump内存分配算法。不能改其它部分。

Bumpallocator 结构体

1
2
3
4
5
6
7
pub struct EarlyAllocator<const PAGE_SIZE: usize> {
heap_start: usize,
heap_end: usize,
next: usize,
allocations: usize,
page_pos: usize,
}

Base allocator需要的init 与 add_memory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

impl<const PAGE_SIZE: usize> BaseAllocator for EarlyAllocator<PAGE_SIZE> {
fn add_memory(&mut self, start: usize, size: usize) -> AllocResult {

self.heap_end = start + size;
Ok(())
}

fn init(&mut self, start: usize, size: usize) {
self.heap_start = start;
self.heap_end = size + self.heap_start;
self.next = self.heap_start;
}

}

PageAllocator因没有dealloc所以未实现

1
2
3
4
5
6
7
8
fn alloc_pages(&mut self, num_pages: usize, align_pow2: usize) -> AllocResult<usize> {
let align_mask = (1 << align_pow2) - 1;
let required_size = num_pages * PAGE_SIZE;
let aligned_pos = (self.page_pos + align_mask) & !align_mask;
let allocated_pages = aligned_pos;
self.page_pos = aligned_pos + required_size;
Ok(allocated_pages)
}

ByteAllocator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
impl<const PAGE_SIZE:usize> ByteAllocator for EarlyAllocator<PAGE_SIZE>{
fn alloc(&mut self, layout: Layout) -> AllocResult<NonNull<u8>> {
let alloc_start = self.next;
self.next = alloc_start + layout.size();
self.allocations += 1;
Ok(unsafe { NonNull::new_unchecked(alloc_start as *mut u8) })

}
fn dealloc(&mut self, pos: NonNull<u8>, layout: Layout) {
self.allocations -= 1;
if self.allocations == 0 {
self.next = self.heap_start;
}
}

从Unikernel到宏内核

题目要求:

需要补全缺页加载代码。

观察m1.0.0 task中代码,发现用 current().task_ext()可以得到TaskExt,然后TaskExt中包含一个AddSpace 结构体,该结构体实现了处理缺页加载的方法。于是按照该思路需要补充的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use axhal::{mem::VirtAddr,paging::MappingFlags};
use axhal::trap::{register_trap_handler,PAGE_FAULT};
#[register_trap_handler(PAGE_FAULT)]
fn handle_page_fault(vaddr: VirtAddr, access_flags: MappingFlags, is_user: bool) -> bool {
if is_user {
if !axtask::current()
.task_ext()
.aspace
.lock()
.handle_page_fault(vaddr, access_flags)
{
ax_println!("handle_page_fault failed, vaddr={:#x}", vaddr);
axtask::exit(-1);
} else {
true
}

}
else{
false
}

}

感想:与 Rcore 相比,似乎 ArceOS显得更加复杂,因其为了实现模块之间的兼容性,采用了多层的封装、抽象和隔离机制。然而,从我的编程体验来看,从某个特定模块的视角来看,阅读 ArceOS 的代码反而比 Rcore 更加清晰。降低了局部代码阅读难度,是值得学习的编码习惯。同时,ArceOS 的课程内容十分丰富,极大地拓宽了我的操作系统视野。