指导书地址https://rcore-os.cn/rCore-Tutorial-Book-v3/


第零章-环境配置

首先试了试了他提供的虚拟机进行操作,但是由于rust代码更新较快,虚拟机已经是1年多之前的了,也不好使,不如重新弄个ubuntu 20安装。

过程就按照他给的一步步安装环境就行,比较简单,最后clone下来仓库在main或者2022spring分支跑下测试就可以。

第一章-应用程序与基本执行环境

简单来说是介绍了操作系统的启动流程:

  1. cpu初始化,加载bootloader代码、数据
  2. bootloader初始化,加载操作系统代码、数据
  3. 进入操作系统

同时介绍了如何在qemu里编写内核指令,并且调整内存布局,使得内核对接到qemu下。

此外也简单介绍了链接脚本的语法。

例如linker.ld文件

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
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80200000;

SECTIONS
{
. = BASE_ADDRESS;
skernel = .;

stext = .;
.text : {
*(.text.entry)
*(.text .text.*)
}

. = ALIGN(4K);
etext = .;
srodata = .;
.rodata : {
*(.rodata .rodata.*)
*(.srodata .srodata.*)
}

. = ALIGN(4K);
erodata = .;
sdata = .;
.data : {
*(.data .data.*)
*(.sdata .sdata.*)
}

. = ALIGN(4K);
edata = .;
.bss : {
*(.bss.stack)
sbss = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
}

. = ALIGN(4K);
ebss = .;
ekernel = .;

/DISCARD/ : {
*(.eh_frame)
}
}

.表示当前地址,可以对.进行赋值来调整接下来段的位置。

在下面这段代码

1
2
3
.rodata : {
*(.rodata)
}

冒号代表生成段的名字,花括号内代表将哪些输入文件的短放进来,这里*表示所有文件。

此外,也通过内嵌汇编代码,实现系统调用的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
let mut ret;
unsafe {
asm!(
"ecall",
inlateout("x10") arg0 => ret,
in("x11") arg1,
in("x12") arg2,
in("x17") which,
);
}
ret
}

由此,我们能够使用系统调用和编写的宏来实现我们自己的println函数,以及其他功能,例如关机。

第二章-批处理系统

在系统我们需要能够运行多个程序,在目前这个阶段只考虑单道运行多个程序,即我们创建一个App Manager,使得在运行了一个程序后能够继续运行下一个程序,由此我们需要编写代码,复制每个程序的代码并且在内存中顺序摆放好。

这都比较简单,我们更需要仔细了解的是特权级。

为了保护我们的批处理操作系统不受到出错应用程序的影响并全程稳定工作,单凭软件实现是很难做到的,而是需要 CPU 提供一种特权级隔离机制,使 CPU 在执行应用程序和操作系统内核的指令时处于不同的特权级。本节主要介绍了特权级机制的软硬件设计思路,以及 RISC-V 的特权级架构,包括特权指令的描述。

在riscv中,设计了4种特权级:

级别 编码 名称
0 00 用户/应用模式 (U, User/Application)
1 01 监督模式 (S, Supervisor)
2 10 虚拟监督模式 (H, Hypervisor)
3 11 机器模式 (M, Machine)

越往下,有更高的权限