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 的课程内容十分丰富,极大地拓宽了我的操作系统视野。