Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@

/target
*.asm
!/**/m_entry*.asm
*.bin
!/rustsbi-qemu.bin
5 changes: 0 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion ch1-lab/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ version = "0.0.1"
edition = "2021"
authors = ["YdrMaster <ydrml@hotmail.com>"]

[features]
default = []
nobios = []

[dependencies]
sbi-rt = { version = "0.0.2", features = ["legacy"] }
rcore-console = { path = "../console" }
26 changes: 24 additions & 2 deletions ch1-lab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,38 @@

第一章实验的示例,展示如何依赖 `rcore_console` crate。

在 [Cargo.toml](Cargo.toml#L9) 里添加:
在 [Cargo.toml](Cargo.toml#L12) 里添加:

```toml
rcore_console = { path = "../rcore_console"}
```

在 [main.rs](src/main.rs#L38) 里初始化:
在 [main.rs](src/main.rs#L47) 里初始化:

```rust
rcore_console::init_console(&Console);
rcore_console::set_timestamp(timer::get_time_ms);
```

## 时间戳功能

本章实现了 `timer.rs` 模块,提供 `get_time_ms()` 函数用于获取当前时间(毫秒)。通过 `rcore_console::set_timestamp()` 注册后,所有 `println!` 输出都会自动在开头显示时间戳,格式为 `[ X ms]`。

## 运行方式

### SBI 模式(默认)
```bash
cargo qemu --ch 1 --lab
```

### nobios 模式
```bash
cargo qemu --ch 1 --lab --nobios
```

### RV32 nobios 模式
```bash
cargo qemu --ch 1 --lab --arch riscv32 --nobios
```

后续的章节都可以这样依赖 `rcore_console`。
68 changes: 62 additions & 6 deletions ch1-lab/build.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,62 @@
fn main() {
use std::{env, fs, path::PathBuf};

let ld = &PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("linker.ld");
fs::write(ld, LINKER).unwrap();
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-link-arg=-T{}", ld.display());
}
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_NOBIOS");

const LINKER: &[u8] = b"
let nobios = env::var("CARGO_FEATURE_NOBIOS").is_ok();

let linker_script = if nobios {
// nobios mode: M-Mode entry at 0x80000000, then jump to S-Mode at 0x80200000
r#"
OUTPUT_ARCH(riscv)
ENTRY(_m_start)
M_BASE_ADDRESS = 0x80000000;
S_BASE_ADDRESS = 0x80200000;

SECTIONS {
. = M_BASE_ADDRESS;

.text.m_entry : {
*(.text.m_entry)
}

.text.m_trap : {
*(.text.m_trap)
}

.bss.m_stack : {
*(.bss.m_stack)
}

.bss.m_data : {
*(.bss.m_data)
}

. = S_BASE_ADDRESS;

.text : {
*(.text.entry)
*(.text .text.*)
}
.rodata : {
*(.rodata .rodata.*)
*(.srodata .srodata.*)
}
.data : {
*(.data .data.*)
*(.sdata .sdata.*)
}
.bss : {
*(.bss.uninit)
*(.bss .bss.*)
*(.sbss .sbss.*)
}
}
"#
} else {
// SBI mode: kernel at 0x80200000
r#"
OUTPUT_ARCH(riscv)
SECTIONS {
.text 0x80200000 : {
Expand All @@ -27,4 +76,11 @@ SECTIONS {
*(.bss .bss.*)
*(.sbss .sbss.*)
}
}";
}
"#
};

let ld = &PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("linker.ld");
fs::write(ld, linker_script).unwrap();
println!("cargo:rustc-link-arg=-T{}", ld.display());
}
102 changes: 102 additions & 0 deletions ch1-lab/src/m_entry_rv32.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# M-Mode entry point for -bios none boot (RV32)
# This code runs at 0x80000000 in M-Mode when QEMU starts with -bios none

.section .text.m_entry
.globl _m_start
_m_start:
# Set up M-Mode stack
la sp, m_stack_top
# Save M-Mode sp to mscratch for trap handler
csrw mscratch, sp

# Set mstatus: MPP=01 (S-Mode), MPIE=1
li t0, (1 << 11) | (1 << 7)
csrw mstatus, t0

# Set mepc to S-Mode entry point
la t0, _start
csrw mepc, t0

# Set mtvec to M-Mode trap handler
la t0, m_trap_vector
csrw mtvec, t0

# Delegate interrupts and exceptions to S-Mode (except ecall from S-Mode)
li t0, 0xffff
csrw mideleg, t0
li t0, 0xffff
li t1, (1 << 9) # Environment call from S-mode
not t1, t1
and t0, t0, t1
csrw medeleg, t0

# Set up PMP to allow S-Mode full access
li t0, -1
csrw pmpaddr0, t0
li t0, 0x0f # TOR, RWX
csrw pmpcfg0, t0

# Enable S-Mode to access counters
li t0, -1
csrw mcounteren, t0

# Jump to S-Mode
mret

.section .text.m_trap
.globl m_trap_vector
.align 4
m_trap_vector:
# Simple trap handler: handle ecall from S-Mode
csrrw sp, mscratch, sp
addi sp, sp, -64

# Save registers (RV32: use sw instead of sd)
sw ra, 0(sp)
sw t0, 4(sp)
sw t1, 8(sp)
sw t2, 12(sp)
sw a0, 16(sp)
sw a1, 20(sp)
sw a2, 24(sp)
sw a3, 28(sp)
sw a4, 32(sp)
sw a5, 36(sp)
sw a6, 40(sp)
sw a7, 44(sp)

# Call Rust trap handler
call m_trap_handler

# Advance mepc past ecall instruction
csrr t0, mepc
addi t0, t0, 4
csrw mepc, t0

# Restore registers
lw ra, 0(sp)
lw t0, 4(sp)
lw t1, 8(sp)
lw t2, 12(sp)
lw a0, 16(sp)
lw a1, 20(sp)
lw a2, 24(sp)
lw a3, 28(sp)
lw a4, 32(sp)
lw a5, 36(sp)
lw a6, 40(sp)
lw a7, 44(sp)

addi sp, sp, 64
csrrw sp, mscratch, sp
mret

.section .bss.m_stack
.globl m_stack_lower_bound
m_stack_lower_bound:
.space 4096 * 4
.globl m_stack_top
m_stack_top:

.section .bss.m_data
.space 64
102 changes: 102 additions & 0 deletions ch1-lab/src/m_entry_rv64.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# M-Mode entry point for -bios none boot (RV64)
# This code runs at 0x80000000 in M-Mode when QEMU starts with -bios none

.section .text.m_entry
.globl _m_start
_m_start:
# Set up M-Mode stack
la sp, m_stack_top
# Save M-Mode sp to mscratch for trap handler
csrw mscratch, sp

# Set mstatus: MPP=01 (S-Mode), MPIE=1
li t0, (1 << 11) | (1 << 7)
csrw mstatus, t0

# Set mepc to S-Mode entry point
la t0, _start
csrw mepc, t0

# Set mtvec to M-Mode trap handler
la t0, m_trap_vector
csrw mtvec, t0

# Delegate interrupts and exceptions to S-Mode (except ecall from S-Mode)
li t0, 0xffff
csrw mideleg, t0
li t0, 0xffff
li t1, (1 << 9) # Environment call from S-mode
not t1, t1
and t0, t0, t1
csrw medeleg, t0

# Set up PMP to allow S-Mode full access
li t0, -1
csrw pmpaddr0, t0
li t0, 0x0f # TOR, RWX
csrw pmpcfg0, t0

# Enable S-Mode to access counters
li t0, -1
csrw mcounteren, t0

# Jump to S-Mode
mret

.section .text.m_trap
.globl m_trap_vector
.align 4
m_trap_vector:
# Simple trap handler: handle ecall from S-Mode
csrrw sp, mscratch, sp
addi sp, sp, -128

# Save registers
sd ra, 0(sp)
sd t0, 8(sp)
sd t1, 16(sp)
sd t2, 24(sp)
sd a0, 32(sp)
sd a1, 40(sp)
sd a2, 48(sp)
sd a3, 56(sp)
sd a4, 64(sp)
sd a5, 72(sp)
sd a6, 80(sp)
sd a7, 88(sp)

# Call Rust trap handler
call m_trap_handler

# Advance mepc past ecall instruction
csrr t0, mepc
addi t0, t0, 4
csrw mepc, t0

# Restore registers
ld ra, 0(sp)
ld t0, 8(sp)
ld t1, 16(sp)
ld t2, 24(sp)
ld a0, 32(sp)
ld a1, 40(sp)
ld a2, 48(sp)
ld a3, 56(sp)
ld a4, 64(sp)
ld a5, 72(sp)
ld a6, 80(sp)
ld a7, 88(sp)

addi sp, sp, 128
csrrw sp, mscratch, sp
mret

.section .bss.m_stack
.globl m_stack_lower_bound
m_stack_lower_bound:
.space 4096 * 4
.globl m_stack_top
m_stack_top:

.section .bss.m_data
.space 64
Loading