0%

2024秋冬季开源操作系统训练营第三阶段总结报告-孙海华

很高兴能够进入第三阶段,本来想着好好跟进一下,但是很遗憾与考试科目以及组里的项目冲突里,仅仅完成了前三次课程的实验,后面大体了解了一下宏内核与Hypervisor

第一次课 HelloWorld

image-20241111222207439

什么是组件化操作系统? 上面是课件里很形象的一张图。在裸机程序中,Bootloader阶段后,需要初始化寄存器、栈指针等。之后初始化串口驱动,并在此基础上打印HelloWorld,这是一套连贯的操作流程。在层次化中,可以分为Hal层和runtime层,Hal层对于对应一些基本的初始化,runtime层对应的是驱动的初始化,为上层的应用提供运行时环境。如果迭代为组件化结构,那么优势就很明显了,在hal层可以抽象出不同架构的初始化,runtime层分为了不同组件,在构建不同的裸机应用时,可以有选择的使用相关的组件,有利于系统的裁剪和定制化。

一个简单的helloword程序使用的组件大致如图所示

image-20241111223112760

课后练习

为了实现带颜色的输出,一个最简单的实现是在输出字符串前后加入相应的转义字符。

修改axstd组件中println的实现即可

1
2
3
4
5
6
7
#[macro_export]
macro_rules! println {
() => { $crate::print!("\n") };
($($arg:tt)*) => {
$crate::io::__print_impl(format_args!("\x1b[34m{}\x1b[0m\n", format_args!($($arg)*)));
}
}

image-20241111223334733

或者修改axhal中putchar的实现,在打印每一个字符时都加入相应的转义字符

1
2
3
4
5
6
7
8
9
10
11
12
13
pub fn putchar(c: u8) {
#[allow(deprecated)]
sbi_rt::legacy::console_putchar('\x1b' as usize);
sbi_rt::legacy::console_putchar('[' as usize);
sbi_rt::legacy::console_putchar('3' as usize);
sbi_rt::legacy::console_putchar('4' as usize);
sbi_rt::legacy::console_putchar('m' as usize);
sbi_rt::legacy::console_putchar(c as usize);
sbi_rt::legacy::console_putchar('\x1b' as usize);
sbi_rt::legacy::console_putchar('[' as usize);
sbi_rt::legacy::console_putchar('0' as usize);
sbi_rt::legacy::console_putchar('m' as usize);
}

image-20241111224510977

第二次课 Collections

引入了新的组件axalloc,以便于实现动态的内存分配。

课后练习

支持HashMap

使用hashbrown作为HashMap实现

image-20241115210910430

第三次课

课后练习

image-20241115211654916

实现一个简单的bump内存分配算法,比较简单,维护相应的trait即可。Page不考虑回收,回收Bytes的时候记录剩余的Bytes计数,在count为0的时候将byte_pos归零。

image-20241115212923154

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
pub struct EarlyAllocator<const PAGE_SIZE: usize> {
start: usize,
b_pos: usize,
p_pos: usize,
end: usize,
count: usize,
}

impl<const PAGE_SIZE: usize> EarlyAllocator<PAGE_SIZE> {
pub const fn new() -> Self {
Self {
start: 0,
b_pos: 0,
p_pos: 0,
end: 0,
count: 0,
}
}
}

impl<const PAGE_SIZE: usize> BaseAllocator for EarlyAllocator<PAGE_SIZE> {
fn init(&mut self, start: usize, size: usize) {
self.start = start;
self.end = start + size;
self.b_pos = start;
self.p_pos = self.end;
self.count = 0;
}
fn add_memory(&mut self, _start: usize, _size: usize) -> AllocResult {
Err(AllocError::NoMemory)
}
}

impl<const PAGE_SIZE: usize> ByteAllocator for EarlyAllocator<PAGE_SIZE> {
fn alloc(&mut self, layout: Layout) -> AllocResult<NonNull<u8>> {
let size = layout.size();
let align = layout.align();
let align_mask = align - 1;
let new_pos = (self.b_pos + align_mask) & !align_mask;
if new_pos + size > self.p_pos {
return Err(AllocError::NoMemory);
}
self.b_pos = new_pos + size;
self.count += 1;
Ok(NonNull::new(new_pos as *mut u8).unwrap())
}
fn dealloc(&mut self, _ptr: NonNull<u8>, _layout: Layout) {
if self.count > 0 {
self.count -= 1;
}
if self.count == 0 {
self.b_pos = self.start;
}
// Do nothing
}
fn total_bytes(&self) -> usize {
self.end - self.start
}
fn available_bytes(&self) -> usize {
self.p_pos - self.b_pos
}
fn used_bytes(&self) -> usize {
self.b_pos - self.start
}
}

impl<const PAGE_SIZE: usize> PageAllocator for EarlyAllocator<PAGE_SIZE> {
const PAGE_SIZE: usize = PAGE_SIZE;
fn alloc_pages(&mut self, num_pages: usize, align_pow2: usize) -> AllocResult<usize> {
if align_pow2 % Self::PAGE_SIZE != 0 {
return Err(AllocError::InvalidParam);
}
let align_pow2 = align_pow2 / Self::PAGE_SIZE;
if !align_pow2.is_power_of_two() {
return Err(AllocError::InvalidParam);
}
let p_pos = self.p_pos - num_pages * Self::PAGE_SIZE;
if p_pos < self.b_pos {
return Err(AllocError::NoMemory);
}

self.p_pos -= num_pages * Self::PAGE_SIZE;
Ok(self.p_pos)
}
fn dealloc_pages(&mut self, _pos: usize, _num_pages: usize) {
// Do nothing
}
fn total_pages(&self) -> usize {
(self.end - self.start) / Self::PAGE_SIZE
}
fn used_pages(&self) -> usize {
(self.end - self.p_pos) / Self::PAGE_SIZE
}
fn available_pages(&self) -> usize {
self.p_pos / Self::PAGE_SIZE
}
}

感悟

第三节阶段的代码相对于第二阶段清晰了不少,很后悔没有持续跟进下去,其实本人一直想学习的是基于协程异步机制的操作系统/驱动这一部分,不知道为什么没有相应的前置课程,希望第四阶段能够坚持下去,学习一下协程、异步机制以及操作系统的一些新实践。