0%

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

进入第三阶段当然很高兴,但时间上实在太紧,我一开始的心态是按看懂源代码中的每一步来走的,但目前只是看完了所有相关的 makefile,以及看了部分 PPT 中强调部分的源代码。实验的话也是完成了第一周的内容以及 Hypervisor 的实验一。

arceos流程小结

总体执行流程:axhal的boot.rs中先引导,用于初始化内核栈,设置初始的页表,这里映射了两个 1G 的大页,分别是低地址恒等映射以及高地址的一个映射。随后要调用 axruntime 的 rust_main 来进一步完善运行时,这里会涉及到 axfeat 里面用到的 feature 条件编译并初始化一些东西,比如启用了 paging 这个 feature 就会重新映射页表这样。调用 rust_main 的时候加了一个偏移,偏移的大小其实就是高地址映射的偏移这样。随后 axruntime 做好运行时之后,调用 main 函数。随后调用结束函数,结束整个流程。

课后练习1:支持带颜色的打印输出。

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

关于转义字符的具体解析的话:颜色定义的部分可以参考 console_codes(4) — Linux manual pageECMA-48 Select Graphic Rendition 部分。在 makefile 中的 run_cmd 函数用于辅助输出同时会以颜色输出命令,参数 1 控制颜色为白色,参数 2 控制为灰色,随后执行命令。

颜色控制部分关键如下

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
param      result
0 reset all attributes to their defaults
1 set bold
2 set half-bright (simulated with color on a color display)
3 set italic (since Linux 2.6.22; simulated with color on a color display)
4 set underscore (simulated with color on a color display) (the colors
used to simulate dim or underline are set using ESC ] ...)
5 set blink
7 set reverse video
10 reset selected mapping, display control flag, and toggle meta flag
(ECMA-48 says "primary font").
11 select null mapping, set display control flag, reset toggle meta flag
(ECMA-48 says "first alternate font").
12 select null mapping, set display control flag, set toggle meta flag
(ECMA-48 says "second alternate font"). The toggle meta flag causes the
high bit of a byte to be toggled before the mapping table translation is
done.
21 set underline; before Linux 4.17, this value set normal intensity (as is
done in many other terminals)
22 set normal intensity
23 italic off (since Linux 2.6.22)
24 underline off
25 blink off
27 reverse video off
30 set black foreground
31 set red foreground
32 set green foreground
33 set brown foreground
34 set blue foreground
35 set magenta foreground
36 set cyan foreground
37 set white foreground
38 256/24-bit foreground color follows, shoehorned into 16 basic colors
(before Linux 3.16: set underscore on, set default foreground color)
39 set default foreground color (before Linux 3.16: set underscore off, set
default foreground color)
40 set black background
41 set red background
42 set green background
43 set brown background
44 set blue background
45 set magenta background
46 set cyan background
47 set white background
48 256/24-bit background color follows, shoehorned into 8 basic colors
49 set default background color
90..97 set foreground to bright versions of 30..37
100..107 set background, same as 40..47 (bright not supported)

Commands 38 and 48 require further arguments:
;5;x 256 color: values 0..15 are IBGR (black, red, green,
... white), 16..231 a 6x6x6 color cube, 232..255 a
grayscale ramp
;2;r;g;b 24-bit color, r/g/b components are in the range 0..255

ECMA-48 SGR 序列以 ESC[ parameters m 的格式控制显示的属性。parameters 用分号隔开,\033[92;1m 为例,033 为八进制,表示 ESC,92 和 1分别是 param,参考上文的 ECMA-48 Select Graphic Rendition 92 表示绿色明亮前景色。1 表示加粗,0 表示重置属性。

课后练习2:支持 HashMap

ax_api 作为下层 module 的抽象,随后 axstd 作为我们自己定义的标准库供用户程序调用。

我的想法其实也是直接看 std 的 HashMap 怎么实现,然后改一改,做到最小的满足测试案例中的那些操作。然后慢慢改一改,后面看到官方也用了 hashbrown 作为实现,然后我就改了改,把随机数用到 hashbrown 这边大概。然后就好了。

课后练习3:实现 alt_alloc

这个分配器应当是用作早期boot之后系统初始化阶段的内存分配器,所以实现上相对简单,每次分配都向后增长。dealloc的时候尝试减掉已经alloc的空间大小,如果为0,那就重新开始从头分配这样。

挑战题目:实现特定分配算法

这个算法的话,还是要感谢万能的群友,我一开始想的也是在TLSF基础上改一改这样。后面发现有取巧的地方,主要也是循环一直进行,奇数项的内容永不释放,所以就取巧了,会记录每次奇数次申请的空间,下次申请如果比上次的小,那就返回该地址。如果比上次大,那就重新申请,释放上次的内容这样。

达到的轮次是65536应该是,也是一个非常 unsigned int 的值。

思路详细描述:由于每次申请的空间大小会加1,相比上一次。例如,delta 为1,申请的空间依次是32 + 1, 32 * 2 + 1, 。delta 为 2,申请的空间依次是32 +2, 32*2 +2,。所以,第一次循环会反复替换掉分配器中的记录。

但是,从第二次开始,每次当 index 为 13 的时候,会替换上一次的内容。因为上一次的 13 比这次的 13 申请的空间小 1。但是呢,14 不是最后一次循环吗,因为 14 是偶数所以不管。奇数就很神奇,每次都是到 index 为 13 的时候重新申请一次空间。其余时候,其实大家返回的地址都是一样的。嘿嘿。而且,每次替换的时候都会把上次的给释放了,哎,就很神奇。

首先主体部分使用特定内存分配器 tlsf。包括申请,释放等操作。

其次,定制 alloc 函数。用 indicator 记录此时调用 alloc_pass 函数的 delta值。用 index 记录 alloc_pass 函数中的循环次数。

alloc 的时候需要谨慎计算,2的多少次方啊,当index = 14 的时候,重置为 0,然后indiactor需要加 1 啊,之类的。

这里要注意一点,源码里,分配器有个special变量,为bool类型。这里用它的主要原因在于有个很神奇的点:当indiactor为32, index = 1的时候,items需要申请 0x60 的空间,而恰好,下次申请向量空间也是 0x60 的大小。就,重复了。嗯。所以,作为单独判断条件,然后重置,第一次出现先不管,然后继续。然后,bug解决。

Hypervisor课后练习1

hypervisior流程分析:这里初始化阶段我们的hyper会布置好一个现场类似我们在宏内核中设置好sstatus寄存器那样,随后通过sret到GUEST中执行,GUEST中遇到无法处理的情况又会陷入Hypervisior中,通过对不同类型的陷入执行不同的代码,处理好用户的错误设置寄存器等操作,随后返回GUEST继续执行。

这里的第一个实验比较简单:只需要在处理错误函数中设置寄存器的值,然后设置sepc += 4,让GUEST去执行出错指令的下一条指令即可。

Hypervisior课后练习2

这里会涉及到虚拟化里的地址二阶段映射。主要流程:GUEST中的虚拟地址先通过 VSATP 翻译,通过 GVA 到 GPA,然后通过 HGATP 把GPA翻译到 HPA 这样。

课后练习尚未完成,嗯。

Hypervisior课后练习3

这里涉及 GUEST 的中断。主要涉及时钟中断,一种实现方式是当 GUEST 配置 RTC 的时候会陷入 Hyper,由 Hyper 来设置时钟,当时钟触发的时候,Hyper 会触发 GUEST 的时钟中断位这样。Hyper在设置完之后应该是会关中断的,待下次GUEST设置中断的时候再打开,这样保持一致。

课后练习尚未完成,嗯。

总结

这里总结的话,三阶段实在不完美,时间上太赶了,然后各种东西都想弄明白细节,这样就很来不及。原本还准备看RISCV的指令集虚拟化扩展这样,也只看了一小部分,内容上其实不算多,但要补的内容比较多,就比较费劲。