Skip to content

Commit 32bb712

Browse files
committed
more RISC-V notes and update rcore_os_lab1_qemu_gdb.md
1 parent 558f073 commit 32bb712

11 files changed

+255
-94
lines changed

2023/08/gcc_ld_as_needed.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
gpt 让我加上 `-Wl,--no-as-needed` 参数之后居然误打误撞就能编译过了
88

99
--no-as-needed option is used to prevent the linker from discarding unused shared object files
10+
11+

2023/08/learning_os.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ OS 课缺失的 lecture7 可以看学堂在线公开课的版本
1212

1313
书籍和课程视频
1414

15-
|||
16-
|---|---|
17-
|CSAPP| ch1 |
18-
|计算机组成与设计 RISC-V edition| ch2.3.2 常数 |
19-
|OS Three easy pieces| ch4 进程抽象 |
20-
|rCore Turtorial Book| ch1.6 为内核支持函数调用 |
21-
|程序员的自我修养链接装载库| ch1.6 线程 |
22-
|os_lecture| lecture03 70min |
23-
|操作系统(RISC-V)(2020秋)| 3.4 系统调用 |
15+
||||
16+
|---|---|---|
17+
|CSAPP| ch1.5 | 高速缓存 |
18+
|计算机组成与设计 RISC-V edition| ch2.3.2 | 常数 |
19+
|OS Three easy pieces| ch4 | 进程抽象 |
20+
|rCore Turtorial Book| ch2.4 | 批处理系统 |
21+
|程序员的自我修养链接装载库| ch2 | 静态链接 |
22+
|os_lecture| lecture03 37min | 异常/中断的硬件处理 |
23+
|操作系统(RISC-V)(2020秋)| 3.4 | 系统调用 |
2424

2525
|||
2626
|---|---|

2023/08/rcore_os_lab1_qemu_gdb.md

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# [rcore lab1 qemu gdb](/2023/08/rcore_os_lab1_qemu_gdb)
1+
# [rcore lab1 qemu gdb](/2023/08/rcore_os_lab1_qemu_gdb.md)
22

33
yay -S riscv-gnu-toolchain-bin
44

@@ -55,7 +55,12 @@ qemu-system-riscv64 -machine virt -nographic \
5555

5656
我的思考是 0x802 内存地址必须紧凑排满生成出的代码块,因此就不能 debug symbol? 这里我没想明白,linux kernel 确实也有 debug symbol 相关配置
5757

58-
解答: 看本文后续 ELF section 解释以及 linker-qemu.ld 源码中都是将各个 section 位置写死装载到内存中
58+
解答: rcore 书中有解释为什么用这个地址,看本文后续 ELF section 解释以及 linker-qemu.ld 源码中都是将各个 section 位置写死装载到内存中
59+
60+
## 为什么用 0x80200000 地址
61+
qemu 源码内存布局写死的 0x80000000 是 DRAM 也就是内存的首地址
62+
63+
然后将 ROM 中的固件 RustSBI 加载到内存中占用了 200000 大小
5964

6065
## qemu gdb 初体验
6166

@@ -67,6 +72,10 @@ ubuntu 用 gdb-multiarch 亦可
6772

6873
`i r mstatus` 能看一些特殊寄存器
6974

75+
mstatus 跟 riscv 的模式有关,例如 User mode 跟 Machine mode 之间的切换就是通关修改 mstatus 寄存器实现的
76+
77+
78+
7079
结果全是 0 只有当前执行指令地址的 pc 寄存器有值 0x1000
7180

7281
```
@@ -176,16 +185,95 @@ text section 就是代码段一般在前两个位置 text section 的例子
176185
说起 ELF 文件加载想起一本必须要看的经典书《程序员的自我修养:链接、装载与库》
177186

178187
### ELF 三个核心 section
179-
180-
- text: 放代码和常量
181-
- bss: 未初始化的 static 变量
182-
- data: 已初始化的 static 变量
188+
- .text: 放代码和常量
189+
- .bss: 未初始化的 static 变量
190+
- .data: 已初始化的 static 变量
191+
- .rodata: 已初始化只读的 static 变量
192+
- .srodata: String-Read Only Data
183193

184194
## objdump 反汇编
185-
186195
rust-objdump -all target/riscv64gc-unknown-none-elf/release/os
187196

188197
可以去找下 main/_start 的汇编代码
189198

190199
## objcopy
191200
实验一中已经用熟练了
201+
202+
---
203+
204+
## linker 原理
205+
rcore 第一章好多内容都是 链接、装载与库 书中知识,再次觉得自己看的书太少了
206+
207+
linker 在汇编器后执行,算是编译的最后一步了
208+
209+
1. symbol resolution
210+
2. symbol relocation
211+
3. symbol merging
212+
4. relocation table generate
213+
5. generate executable file or dylib
214+
215+
### relocation
216+
多个编译好的 .o 格式 ELF 文件,合并所有 ELF 文件的 .text,.data 等部分
217+
218+
因此合并前源文件中 函数符号到内存地址的映射 合并后会变化,需要 relocation 重新定位一遍
219+
220+
对于动态库的符号会存一个符号表,不会在 link 阶段映射出内存地址
221+
222+
### ld script 示例讲解
223+
224+
```
225+
.rodata : {
226+
*(.rodata .rodata.*)
227+
*(.srodata .srodata.*)
228+
}
229+
```
230+
231+
首先 `*()` 是个通配符,也就是匹配所有 .o 文件中,带 .rodata 或者带 .rodata. 前缀的所有 section
232+
233+
### runtime linker/loader
234+
ld.so 运行时将程序所需的动态库加载到内存(多个程序还是能复用同一个动态库内存),并将程序动态库符号表 relocation
235+
236+
### linker-qemu.ld 源码
237+
手动做 symbol merging 和 relocation 的步骤,手动去合并 .text 等 section
238+
239+
stext,etext 分别表示 start text 和 end text
240+
241+
`global_asm!(include_str!("entry.asm"));` 做了一些跟 sbi/qemu 之前初始化的工作,然后再跳转到 rust main 函数,因此 text 段先拼上了 .entry.start
242+
243+
### PIE,Position-independent Executable
244+
gdb `x/10i $pc` 看内存上当前指令往后的 10 个指令是什么
245+
246+
rcore 程序中的寻址全都是基础地址 0x80200000 的【相对地址】,因此**加载**到内存任意位置都能执行,
247+
相反如果有的程序寻址是固定的内存地址,则要求一个固定的内存布局
248+
249+
## entry.asm 代码解读
250+
251+
汇编 `.global` 表示全局函数
252+
253+
以下代码是初始化【创建栈空间】的代码
254+
255+
```
256+
.globl _start
257+
_start:
258+
# la 是伪指令 load address of src symbol to dst register
259+
la sp, boot_stack_top
260+
call rust_main
261+
262+
...
263+
# 如果发生爆栈,则新数据会覆盖掉内核的其他代码
264+
boot_stack_lower_bound:
265+
.space 4096 * 16
266+
.globl boot_stack_top
267+
boot_stack_top:
268+
```
269+
270+
对应 linker-qemu.ld 和 Rust 代码 clear_bss() `#[link_section]`
271+
272+
```
273+
.bss : {
274+
*(.bss.stack)
275+
sbss = .;
276+
*(.bss .bss.*)
277+
*(.sbss .sbss.*)
278+
}
279+
```

2023/08/riscv_asm_swap_two_integer.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ deref example: movl (%rdi), %eax copies the value from the memory address pointe
3737
|x10,x11|a0,a1|function argument or return value register|
3838
|x12,x17|a2,a7|function argument register|
3939

40+
寄存器越多电信号传播越久时钟周期变长,寄存器越少写代码不方便,RISCV 的寄存器数量精心设计过
41+
4042
除了 general register 还有以下几个特殊寄存器
4143
- pc: Program Counter, address of the current instruction being executed
4244

43-
4445
## 试试编译汇编
4546

4647
我还不会写汇编,可以先写出 C 代码编译出汇编来学习下
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# [RISC-V 函数调用](/2023/08/riscv_function_call_and_return.md)
2+
3+
a0-a7,t0-t6 函数调用者压栈保存寄存器状态
4+
5+
s0-s11 函数被调用者保存寄存器状态
6+
7+
## call 伪指令
8+
9+
> jal x1, 100
10+
11+
x1=pc+4; go to pc+100
12+
13+
x1 就是 ra 寄存器,pc + 100 是被调用函数地址
14+
15+
+4/+100 我理解就是额外多留点栈空间存储寄存器状态
16+
17+
## return 伪指令
18+
19+
> jalr x1, 100(x5)
20+
21+
ra=pc+4; go to x5+100
22+
23+
x5 别名是 t0
24+
25+
---
26+
27+
```
28+
// prologue:
29+
addi sp, sp, -16
30+
sd ra, 0(sp)
31+
32+
// function body
33+
34+
// epilogue:
35+
ld ra, 0(sp)
36+
addi sp, sp, 16
37+
ret

2023/08/riscv_interrupt_and_trap.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# [中断和 trap](/2023/08/riscv_interrupt_and_trap.md)
2+
3+
RISCV 目前有三种中断
4+
5+
软中断 IPI=Internal Processor Interrupt 通过往内存寄存器中存数来触发,例如核心一发出软中断通知核心二
6+
7+
软中断也是 core local interrupt?
8+
9+
时钟中断 stimecmp stime 时钟硬件定时会发出中断
10+
11+
Platform level interrupt controller 外设中断
12+
13+
14+
## 中断相关背景知识
15+
16+
### riscv 中断相关寄存器(CSR)
17+
18+
- sstatus: 保存全局中断的使能位
19+
- sie: 能处理或忽略的中断
20+
- stvec: 指向中断服务总控函数入口
21+
22+
对应 rcore 源码的 汇编代码 __alltraps 和 interrupt::init
23+
24+
sstatus 要设置成 sie
25+
26+
### 中断向量表
27+
收到哪种中断后,查表得到内存地址再去跳转到这个内存地址
28+
29+
## nested interrupt
30+
家用机都是支持嵌套中断,初期教学实验中我们可以暂不支持
31+
32+
注意不支持嵌套中断的操作系统中,当中断处理中的时候,必须关闭全局中断使能位,防止中断处理中时又发生另一个中断
33+
34+
## Is IO/timer interrupt also a trap in riscv
35+
```
36+
No, I/O and timer interrupts are not considered traps in RISC-V. Traps in RISC-V are typically exceptions or interrupts that are caused by specific events during program execution, such as illegal instructions, memory access faults, or environment calls.
37+
38+
I/O and timer interrupts, on the other hand, are external events triggered by devices or timers. They are not treated as traps but rather as interrupts in the RISC-V architecture. When an I/O or timer interrupt occurs, the processor suspends the current execution and jumps to an interrupt handler routine to handle the interrupt. Once the interrupt handler has completed its task, the processor resumes the interrupted program.
39+
40+
Interrupts and traps serve different purposes in RISC-V. Interrupts allow the processor to handle events from external devices asynchronously, while traps are primarily used for handling exceptional conditions or invoking privileged operations within the program flow.
41+
```
42+
43+
trap 更多指的是内部"软中断"事件,例如内存访问越界、environment call from user mode
44+
45+
S mode 的操作系统发现用户态触发了异常/trap 再判断下如果异常是 malware 恶意软件例如内存越界访问就杀掉进程,如果是系统调用就继续往下传递 ecall 给 SBI
46+
47+
---
48+
49+
## TLB
50+
Translation Lookaside Buffer, cache virtual-to-physical address translation

2023/08/riscv_privilege_mode.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# [特权级机制](/2023/08/riscv_privilege_mode.md)
2+
3+
<https://learningos.github.io/rCore-Tutorial-Book-v3/chapter2/1rv-privilege.html>
4+
5+
对指令/控制的隔离: 特权级机制,地址空间对数据隔离,中断对时间隔离,对破坏/malware 的隔离是异常处理
6+
7+
包括 Machine Mode, Supervisor Mode, User Mode, (optional)Hypervisor mode
8+
9+
用户态的程序只能访问通用寄存器,内核态的程序可以访问控制状态寄存器
10+
11+
具体用什么模式看业务场景 M-mode 是必备的,例如点亮一个 LED 灯的超简单嵌入式场景应用就只需要 M mode
12+
13+
如果希望 CPU 内置 MMU(memory manage unit) 去做虚拟内存到物理这样比 OS 层做地址翻译效率更高
14+
15+
所以 PS5/amd 的家用机处理器是 M,S,U,H 模式通通存在的
16+
17+
在 RISC-V 中 ecall 指令从 U->S 或者 U->M 取决于业务场景的 context 如果简单嵌入式场景一次 ecall 就能从 U/S -> M 一次 ecall 只能跨越一级
18+
19+
CSR(Control and Status Register)/mstatus
20+
21+
准确来说 ecall/eret 是特权提高一级,在 rcore 教程中只会涉及 S/U 两个模式德切换,对 RustSBI 所在的 M 级别不做深入探讨
22+
23+
## ecall and sret/mret
24+
25+
环境调用异常: ecall 时产生
26+
27+
sret/mret 跟 ecall 成对出现起 return 效果
28+
29+
- sret: supervisor mode return
30+
- mret: machine mode return
31+
32+
规律: riscv 命名上 m/s mode 状态下特有的命令/寄存器会命名成 m/s 前缀,例如 mret,mstatus 和 sret,sstatus

2023/08/riscv_qemu_opensbi.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ ELF = executable or linkable format
2828

2929
## firmware and OpenSBI
3030

31+
以下是 RISC-V 硬件分层抽象的架构设计
32+
33+
1. application execution environment: OS, TEE(trusted execution environment e.g. Intel SGX)
34+
2. supervisor binary interface
35+
3. supervisor execution enviroment: hypervisor/VM monitor
36+
4. hypervisor binary interface
37+
5. hypervisor execution enviroment: software layer that enables virtualization on RISC-V processors
38+
6. (optional)hardward abstract layer
39+
7. baremetal hardware
40+
41+
中断: 控制流脱离了其所在的执行环境,并产生 执行环境的切换。 我们把这种“突变”的控制流称为 异常控制流 (ECF, Exceptional Control Flow)
42+
43+
在操作系统中,需要处理三类异常控制流:外设中断 (Device Interrupt) 、陷入 (Trap 系统调用切换到内核态) 和异常 (内存访问越界等Exception,也称Fault Interrupt)
44+
3145
**Supervisor Binary Interface**
3246

3347
It is an interface provided by the RISC-V architecture to enable interaction between the privileged software (such as firmware or operating system kernel) and the underlying hardware
@@ -76,6 +90,7 @@ static const MemMapEntry virt_memmap[] = {
7690
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
7791
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
7892
// 操作系统的代码在 DRAM
93+
// qemu 默认启动参数是 128M 内存
7994
[VIRT_DRAM] = { 0x80000000, 0x0 },
8095
};
8196
```

2023/08/riscv_terminology.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# [RISC-V 术语](/2023/08/riscv_terminology.md)
2+
3+
||||
4+
|---|---|---|
5+
|TLB|Translation Lookaside Buffer|cache virtual-to-physical address translation|
6+
|AMO|Atomic Memory Operations|exception code 6: Store/AMO address misaligned|
7+
|sfence.vma|指令|刷新 TLB 缓存|
8+
|wfi|指令|进入低功耗状态等待中断|

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
- [文章列表 - 吴翱翔的博客](/)
22
- [正在读的书](/books.md)
33
- **2023-08**
4+
- [特权级机制](/2023/08/riscv_privilege_mode.md)
5+
- [中断和 trap](/2023/08/riscv_interrupt_and_trap.md)
6+
- [RISC-V 术语](/2023/08/riscv_terminology.md)
47
- [volatile 不解决分支预测](/2023/08/volatile_and_cpu_branch_prediction.md)
5-
- [qemu vscode gdb](/2023/08/qemu_riscv_vscode_gdb.md)
8+
- [RISC-V 函数调用](/2023/08/riscv_function_call_and_return.md)
9+
- [rcore lab1 qemu gdb](/2023/08/rcore_os_lab1_qemu_gdb.md)
610
- [gcc/ld --as-needed](/2023/08/gcc_ld_as_needed.md)
711
- [dumpbin](/2023/08/dumpbin_ldd_alternative_on_windows.md)
812
- [ptr::addr_of!](/2023/08/ptr_addr_of.md)

0 commit comments

Comments
 (0)