Skip to content

support RV32, nobios and timestamp print for ch1&ch2#4

Closed
Ivans-11 wants to merge 2 commits intorcore-os:mainfrom
Ivans-11:main
Closed

support RV32, nobios and timestamp print for ch1&ch2#4
Ivans-11 wants to merge 2 commits intorcore-os:mainfrom
Ivans-11:main

Conversation

@Ivans-11
Copy link
Copy Markdown
Collaborator

为 ch1 和 ch2 添加了以下主要功能:

  1. nobios 模式支持:允许内核在没有 BIOS 的情况下直接启动
  2. RV32 架构支持:支持 32 位 RISC-V 架构(riscv32imac)
  3. 时间戳功能:在 println! 和日志输出中自动显示时间戳

主要变更

1. nobios 模式支持

命令行参数

  • xtask 中添加 --nobios 参数
  • 当启用 nobios 时,QEMU 使用 -bios none 参数
  • 内核链接地址从 0x80200000 改为 0x80000000(M-Mode 入口)

新增文件

  • M-Mode 入口汇编

    • ch1/src/m_entry_rv64.asm - RV64 M-Mode 入口
    • ch1/src/m_entry_rv32.asm - RV32 M-Mode 入口
    • ch1-lab/src/m_entry_rv64.asm / m_entry_rv32.asm
    • ch2/src/m_entry_rv64.asm / m_entry_rv32.asm
  • SBI 相关模块

    • ch1/src/sbi.rs - SBI 服务调用实现(不依赖 sbi-rt)
    • ch1/src/msbi.rs - M-Mode SBI 处理器(处理来自 S-Mode 的 ecall)
    • 同样添加到 ch1-labch2

修改文件

  • xtask/src/main.rs

    • 添加 BuildArgs::nobios 字段
    • 修改 QEMU 命令生成逻辑,支持 -bios none
    • 根据 nobios 模式调整内核加载地址
  • 各章节的 build.rs

    • 根据 CARGO_FEATURE_NOBIOS 环境变量生成不同的链接脚本
    • nobios 模式包含 M-Mode 入口、trap处理、栈和数据段
  • 各章节的 Cargo.toml

    • 添加 nobios feature
    • 移除 sbi-rt 依赖
  • 各章节的 main.rs

    • 条件编译引入 M-Mode 入口汇编
    • 使用新的 sbi 模块替代 sbi-rt
  • linker/src/lib.rs

    • 添加 NOBIOS_SCRIPT 常量,包含完整的 nobios 模式链接脚本
    • ch2 及之后章节的 build.rs 可使用 NOBIOS_SCRIPT

2. RV32 架构支持

命令行参数

  • xtask 中添加 --arch riscv32 参数(默认 riscv64
  • 添加架构验证:RV32 只能与 nobios 模式一起使用

新增功能

  • xtask/src/main.rs

    • 添加 Arch 枚举(Riscv32, Riscv64
    • 实现 Arch::target() - 返回 Rust target triple
    • 实现 Arch::qemu_system() - 返回 QEMU 系统名称
    • 实现 Arch::target_dir() - 返回目标目录路径
  • xtask/src/user.rs

    • 修改 build_for()build_one() 接受 Arch 参数
    • 根据架构使用 .word(RV32)或 .quad(RV64)指令
    • 根据架构设置正确的对齐(.align 2.align 3

架构相关修复

  • kernel-context/src/lib.rs

    • 为 RV32 和 RV64 分别实现 execute_naked() 函数
    • RV32 使用 sw/lw 指令和 4 字节偏移
    • RV64 使用 sd/ld 指令和 8 字节偏移
    • execute() 函数也根据指针宽度条件编译
  • linker/src/app.rs

    • AppMeta 结构体字段从 u64 改为 usize
    • AppIterator::iu64 改为 usize
    • 确保在 RV32 和 RV64 上都能正确工作
  • user/src/heap.rs

    • 根据架构使用不同的 BuddyAllocator 层数
    • RV32: 12 层(避免位移溢出)
    • RV64: 32 层
  • ch2/src/main.rs

    • 增加用户栈大小从 256 到 512 个 usize(避免栈溢出覆盖 LocalContext

3. 时间戳功能

新增文件

  • ch1-lab/src/timer.rs

    • 实现 get_time() - 读取 RISC-V time CSR
    • 实现 get_time_ms() - 返回毫秒数
    • 支持 RV32(使用 rdtimehrdtime)和 RV64(使用 rdtime
  • ch2/src/timer.rs:同上

修改文件

  • console/src/lib.rs

    • 添加 GetTimeMsFn 类型和 GET_TIME_MS 静态变量
    • 添加 set_timestamp() 函数用于注册时间戳获取函数
    • 修改 _print_timestamp() 使用注册的函数
    • 修改 println! 宏在输出前打印时间戳
  • 各章节的 main.rs

    • 添加 mod timer;
    • 调用 rcore_console::set_timestamp(timer::get_time_ms)

运行

运行命令

# RV64 SBI 模式(默认)
cargo qemu --ch 1
cargo qemu --ch 1 --lab
cargo qemu --ch 2

# RV64 nobios 模式
cargo qemu --ch 1 --nobios
cargo qemu --ch 1 --lab --nobios
cargo qemu --ch 2 --nobios

# RV32 nobios 模式(RV32 只支持 nobios)
cargo qemu --ch 1 --arch riscv32 --nobios
cargo qemu --ch 1 --lab --arch riscv32 --nobios
cargo qemu --ch 2 --arch riscv32 --nobios

@AsakuraMizu
Copy link
Copy Markdown

My suggestions:

  1. Timestamp should be added to logger only, not println. See my implementation in feat: log time #2.
  2. Are you going to duplicate m_entry_rv32.asm/m_entry_rv64.asm/msbi.rs/etc. for every lab? Can we do some modularization?

@Ivans-11
Copy link
Copy Markdown
Collaborator Author

My suggestions:

  1. Timestamp should be added to logger only, not println. See my implementation in feat: log time #2.
  2. Are you going to duplicate m_entry_rv32.asm/m_entry_rv64.asm/msbi.rs/etc. for every lab? Can we do some modularization?

Create a new crate? Does sbi.rs need to be included?

@Ivans-11 Ivans-11 closed this Jan 12, 2026
chyyuu pushed a commit that referenced this pull request Mar 22, 2026
问题根因
lld 链接器的 .symtab(SHT_SYMTAB)和 .strtab(SHT_STRTAB)是链接器自行创建的特殊节,VMA=0、无 SHF_ALLOC 标志,不会被 QEMU -kernel 加载到内存。旧代码试图把它们合并进 .rodata 会报节类型冲突;即使放到独立输出节,VMA 仍为 0。运行时解引用地址 0 直接崩溃,连 Hello, world! 都无法输出。

解决方案:编译时 ELF 解析 + const 符号表嵌入
放弃运行时读 ELF .symtab,改为 build.rs 在编译前从上一次构建产物中提取函数符号,以 const 数组嵌入二进制。

改动的文件:

build.rs — 新增 extract_func_symbols() 和 write_func_syms_rs():直接解析 ELF64 的节头定位 .symtab+.strtab,过滤 STT_FUNC 符号(地址在 0x80200000..0x81000000),按地址排序后生成 OUT_DIR/func_syms_generated.rs。通过 cargo:rerun-if-changed 监控产物路径,产物出现或变化时自动重新提取。同时从链接脚本中移除了无效的 .symtab/.strtab 输出节。

src/symtab_resolve.rs — 完全重写:通过 include!() 引入生成的 const FUNC_SYMS: &[(u64, u64, &str)],二分查找匹配 ra,直接用 rustc_demangle + SbiWriter(core::fmt::Write)输出到串口。不再需要 alloc、Vec、运行时 ELF 解析、unsafe extern "C" 引用。

src/main.rs — 移除了 symtab_ptrs.S 的 global_asm! 引用(不再需要汇编中转指针)。

asm/symtab_ptrs.S — 已删除。

test_lec2_lab1.sh — 在 cargo run 前加了一次 cargo build(确保符号表已填充),并增加了对 bt_depth 和 rust_main 函数名的检查(共 20 项)。

运行效果:

[BACKTRACE] #0 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::stackwalk::print_backtrace
[BACKTRACE] #1 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::bt_depth3
[BACKTRACE] #2 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::bt_depth2
[BACKTRACE] #3 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::bt_depth1
[BACKTRACE] #4 fp=... ra=0x...
[BACKTRACE]   fn=tg_rcore_tutorial_ch1_show::rust_main
[BACKTRACE] end=ra_null_bottom_of_chain
从干净构建算起需要两次 cargo build(首次无上轮产物→空表;第二次提取到 554 个函数符号)。.text 在链接脚本中位于 .rodata 之前,函数地址不受符号数据大小变化影响,因此两次构建即可收敛。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants