rCore-Tutorial-Book-v3
rCore-Tutorial-Book-v3 copied to clipboard
rCore-Tutorial-Book-v3/chapter1/6print-and-shutdown-based-on-sbi
基于 SBI 服务完成输出和关机 — rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档
https://rcore-os.github.io/rCore-Tutorial-Book-v3/chapter1/6print-and-shutdown-based-on-sbi.html
最后使用 Qemu 运行内核的时候没有输出可能是什么问题呀 oslab@oslab-virtual-machine:~/Documents/os$ qemu-system-riscv64 \
-machine virt \ -nographic \ -bios ../bootloader/rustsbi-qemu.bin \ -device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000
[rustsbi] RustSBI version 0.2.0-alpha.6
.______ __ __ .___________. .. __
| _ \ | | | | / | | / || _ \ | |
| |) | | | | | | (-------| |----| (----| |_) || | | / | | | | \ \ | | \ \ | _ < | | | |\ \----.| --' |.----) | | | .----) | | |) || |
| | `.| _/ |/ || |_/ |/ ||
[rustsbi] Implementation: RustSBI-QEMU Version 0.0.2 [rustsbi-dtb] Hart count: cluster0 with 1 cores [rustsbi] misa: RV64ACDFIMSU [rustsbi] mideleg: ssoft, stimer, sext (0x222) [rustsbi] medeleg: ima, ia, bkpt, la, sa, uecall, ipage, lpage, spage (0xb1ab) [rustsbi] pmp0: 0x10000000 ..= 0x10001fff (rwx) [rustsbi] pmp1: 0x80000000 ..= 0x8fffffff (rwx) [rustsbi] pmp2: 0x0 ..= 0xffffffffffffff (---) qemu-system-riscv64: clint: invalid write: 00000004 [rustsbi] enter supervisor 0x80200000
就一直在这里没有任何输出
@xuanranxiaoshi 是否通过GDB检查内核第一条指令的执行情况(参考本章第四节内容)?Qemu版本是否为5.0.0?运行代码仓库的ch1分支是否有输出?
@xuanranxiaoshi 也可以看一下是否重新cargo build --release, 以及strip OS内核前的初始化数据。
有可能就是没有重新cargo build --release并生成os.bin,所以运行的还是之前修改x1的程序,可以看看x1是否被赋值为100,如果是的话就是这个情况了
谢谢大家,已解决
[rustsbi] enter supervisor 0x80200000 一直停在这里没输出,debug发现_start的偏移地址不在0x80200000,在网上抄了个link脚本搞定了。 OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80200000;
SECTIONS { . = BASE_ADDRESS;
start = .;
.text : {
stext = .;
*(.text.entry)
*(.text .text.*)
. = ALIGN(4K);
etext = .;
}
.rodata : {
srodata = .;
*(.rodata .rodata.*)
. = ALIGN(4K);
erodata = .;
}
.data : {
sdata = .;
*(.data .data.*)
. = ALIGN(4K);
edata = .;
}
.bss : {
sbss = .;
*(.bss.stack)
. = ALIGN(4K);
ebss = .;
}
end = .;
}
仔细研究linker脚本后发现自已在输入linker脚本时少了.rodata段,导致编译后这段内容放到.text前面去了。
qemu-system-riscv64
-machine virt
-nographic
-bios ../bootloader/rustsbi-qemu.bin
-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000
-s -S
是通过这条命令启动 Qemu 运行我们的内核? 太愚笨了
@mjh11930673 是的
想问一下sbi.rs中的#![allow(unused)],尝试cargo build时会报error: an inner attribute is not permitted in this context,且编译器提示应改为#[allow(unused)],我字面理解这应该是允许变量未使用的一个宏,因此我改成了#[allow(unused)],可以正常build,是文章写错了吗
@jklinCN 加上了一点补充说明。
我开始也没有输出 然后执行 rust-objcopy --strip-all target/riscv64gc-unknown-none-elf/release/os -O binary target/riscv64gc-unknown-none-elf/release/os.bin 去掉元数据 就有输出了
问题:运行make run直接打印「Hello,World和panic具体行数信息」,运行qumu-system-riscv64需要gdb链接调试最后quit才能打印信息,不清楚为什么会有这种区别
运行下面命令qumu加载内核后一直卡顿在那里,没有任何输出。
qemu-system-riscv64 \
-machine virt \
-nographic \
-bios ../bootloader/rustsbi-qemu.bin \
-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000 \
-s -S
按照第四小节gdb调试,最后quit后可输出「Hello,World和panic具体行数信息」
切换到了ch1分支也是这种情况,如果直接运行make run就不会卡顿,不用gdb调试可直接输出「Hello,World和panic具体行数信息」
去看了Makefile里面的代码 也是对qumu-system-riscv64 运行做了封装,并没有什么其他的特殊地方,请问下老师这是什么原因造成的?
@baipangbai 注意,如果不想通过 GDB 对于 Qemu 进行调试而是直接运行 Qemu 的话,则要删掉最后一行的 -s -S 。
Stdout.write_fmt(args).unwrap();
}```中 fmt::Arguments是什么类型 在实验编写的print时应该填入什么格式参数
我的报错
| print("world");
| ----- ^^^^^^^ expected struct Arguments, found &str
| |
| arguments to this function are incorrect
pub fn print(args: fmt::Arguments){
Stdout.write_fmt(args).unwrap();
}
中 fmt::Arguments是什么类型 在实验编写的print时应该填入什么格式参数?
下面是我的报错:
print("world");
| ----- ^^^^^^^ expected struct `Arguments`, found `&str`
| |
| arguments to this function are incorrect
将字符串按字节切片输出,而不是按字符切片
for c in s.chars() {
console_putchar(c as usize);
}
修改为
for b in s.bytes() {
console_putchar(b as usize);
}
可以在终端中显示中文,Emoji
he@ubuntu:~/C_TEST/os$ cargo build
Compiling os v0.1.0 (/home/he/C_TEST/os)
error: cannot find macro println in this scope
--> src/lang_items.rs:41:9
|
41 | println!(
| ^^^^^^^
|
= note: consider importing this macro:
crate::println
= help: have you added the #[macro_use] on the module/import?
error: cannot find macro println in this scope
--> src/lang_items.rs:48:9
|
48 | println!("Panicked: {}", info.message().unwrap());
| ^^^^^^^
|
= note: consider importing this macro:
crate::println
= help: have you added the #[macro_use] on the module/import?
error: could not compile os due to 2 previous errors
这个报错如何解决呀
@zhuiYeah 注意mod console;前面加上一行#[macro_use],参考这里。
在lang_items前几行加入 #[macro_use] mod console;
仍出现这个报错file not found for module console
--> src/lang_items.rs:6:1
|
6 | mod console;
| ^^^^^^^^^^^^
|
= help: to create the module console, create file "src/lang_items/console.rs" or "src/lang_items/console/mod.rs"
error: cannot find macro println in this scope
@zhuiYeah 请参考我们整个框架的代码。
@zhuiYeah 我也遇到这个问题了。补充说明一下,mod 的顺序有要求。必须是:
#[macro_use]
mod console;
mod lang_items;
mod sbi;
console要在其他两个前面
@zhuiYeah @tomtomtomtony 另一个解决办法是直接在 lang_items.rs 里面引用 mod console;
error[E0554]: #![feature] may not be used on the stable release channel
--> src/main.rs:3:12
|
3 | #![feature(panic_info_message)]
| ^^^^^^^^^^^^^^^^^^
For more information about this error, try rustc --explain E0554.
error: could not compile os due to previous error
#![feature] may not be used on the stable release channel
同问
我重新倒回第0章 可通过如下命令安装 rustc 的 nightly 版本,并把该版本设置为 rustc 的缺省版本。
rustup install nightly
rustup default nightly
http://rcore-os.cn/rCore-Tutorial-Book-v3/chapter0/5setup-devel-env.html
如果已经在rust_main()中添加了 console_putchar() 但是还是没有输出,需要重新cargo build --release 然后再裁减内核镜像 rust-objcopy --strip-all target/riscv64gc-unknown-none-elf/release/os -O binary target/riscv64gc-unknown-none-elf/release/os.bin
我的代码反复输出同一条内容,看起来是rust_main -> panic! -> shutdown -> panic! -> shutdown 陷入递归了,我猜原因是在我这儿用于 ecall shutdown 的值可能不是 8,所以 sbi_call(8) 的时候没有真正关机。但我确实是用的 qemu-system-riscv64,而且 rustsbi-qemu 也是拉取最新代码编译的。求助是否有思路定位原因?
Hello, world!
panicked at src/main.rs:17 Shutdown machine!
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
panicked at src/sbi.rs:27 It should shutdown
请问按照这节写下来后,用qemu运行内核,但是一直没有输出可能是什么原因啊?
运行内核后的输出
[rustsbi] RustSBI version 0.3.0-alpha.4, adapting to RISC-V SBI v1.0.0 .______ __ __ _______.___________. _______..______ __ | _ \ | | | | / | | / || _ \ | | | |_) | | | | | | (----`---| |----`| (----`| |_) || | | / | | | | \ \ | | \ \ | _ < | | | |\ \----.| `--' |.----) | | | .----) | | |_) || | | _| `._____| \______/ |_______/ |__| |_______/ |______/ |__| [rustsbi] Implementation : RustSBI-QEMU Version 0.2.0-alpha.2 [rustsbi] Platform Name : riscv-virtio,qemu [rustsbi] Platform SMP : 1 [rustsbi] Platform Memory : 0x80000000..0x88000000 [rustsbi] Boot HART : 0 [rustsbi] Device Tree Region : 0x87000000..0x87000ef2 [rustsbi] Firmware Address : 0x80000000 [rustsbi] Supervisor Address : 0x80200000 [rustsbi] pmp01: 0x00000000..0x80000000 (-wr) [rustsbi] pmp02: 0x80000000..0x80200000 (---) [rustsbi] pmp03: 0x80200000..0x88000000 (xwr) [rustsbi] pmp04: 0x88000000..0x00000000 (-wr)
运行内核所使用的命令
cargo build --release rust-objcopy --strip-all target/riscv64gc-unknown-none-elf/release/os -O binary target/riscv64gc-unknown-none-elf/release/os.bin qemu-system-riscv64 \ machine virt \ -nographic \ -bios ../bootloader/rustsbi-qemu.bin \ -device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000
其中,使用rust-objcopy得到的文件os.bin查看其信息,如下所示
stat os/target/riscv64gc-unknown-none-elf/release/os.bin # 输出 文件:os/target/riscv64gc-unknown-none-elf/release/os.bin 大小:0 块:0 IO 块大小:4096 普通空文件 设备:803h/2051d Inode:1108612 硬链接:1 权限:(0775/-rwxrwxr-x) Uid: ( 1000/zephyrus) Gid: ( 1000/zephyrus) 访问时间:2023-03-09 15:53:14.616402778 +0800 修改时间:2023-03-09 15:53:05.904545932 +0800 变更时间:2023-03-09 15:53:05.912545800 +0800 创建时间:2023-03-09 15:53:05.904545932 +0800
反汇编的话也是空的
# 执行 rust-objdump -all target/riscv64gc-unknown-none-elf/release/os # 输出 target/riscv64gc-unknown-none-elf/release/os: file format elf64-littleriscv
使用gdb进行调试,当运行到位于0x80200000这条指令时,查看查看$pc及后面几条指令,发现都是空
Remote debugging using localhost:1234 0x0000000000001000 in ?? () (gdb) b *0x80200000 Breakpoint 1 at 0x80200000 (gdb) c Continuing. Breakpoint 1, 0x0000000080200000 in ?? () (gdb) x/10i $pc => 0x80200000: unimp 0x80200002: unimp 0x80200004: unimp 0x80200006: unimp 0x80200008: unimp 0x8020000a: unimp 0x8020000c: unimp 0x8020000e: unimp 0x80200010: unimp 0x80200012: unimp
似乎是链接的时候内存布局有问题,导致入口代码没有被排在0x80200000。
我已经尝试过评论区中说的重新cargo build --release,以及rust-objcopy --strip-all <> -O binary <>这两个方法,但是还是没有输出。我个人感觉是链接的时候除了问题,但是还是不知道怎么解决这个问题。代码在ZephyrusZhang/rCore。求大佬赐教。
@kayoch1n 如果你使用了最新的rustsbi的话,请注意SBI标准已经发生了更改。将源代码改为如下形式可以完成功能。
//src/sbi.rs
use core::arch::asm;
#[allow(unused)]
// legacy extensions: ignore fid
const SBI_SET_TIMER: usize = 0;
const SBI_CONSOLE_PUTCHAR: usize = 1;
const SBI_CONSOLE_GETCHAR: usize = 2;
const SBI_CLEAR_IPI: usize = 3;
const SBI_SEND_IPI: usize = 4;
const SBI_REMOTE_FENCE_I: usize = 5;
const SBI_REMOTE_SFENCE_VMA: usize = 6;
const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7;
// system reset extension
const SRST_EXTENSION: usize = 0x53525354;
const SBI_SHUTDOWN: usize = 0;
#[inline(always)]
fn sbi_call(eid: usize, fid: 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("x16") fid,
in("x17") eid,
);
}
ret
}
pub fn console_putchar(c: usize) {
sbi_call(SBI_CONSOLE_PUTCHAR, 0, c, 0, 0);
}
pub fn shutdown() -> ! {
sbi_call(SRST_EXTENSION, SBI_SHUTDOWN, 0, 0, 0);
panic!("It should shutdown!")
}
@kayoch1n 如果你使用了最新的rustsbi的话,请注意SBI标准已经发生了更改。将源代码改为如下形式可以完成功能。
//src/sbi.rs use core::arch::asm; #[allow(unused)] // legacy extensions: ignore fid const SBI_SET_TIMER: usize = 0; const SBI_CONSOLE_PUTCHAR: usize = 1; const SBI_CONSOLE_GETCHAR: usize = 2; const SBI_CLEAR_IPI: usize = 3; const SBI_SEND_IPI: usize = 4; const SBI_REMOTE_FENCE_I: usize = 5; const SBI_REMOTE_SFENCE_VMA: usize = 6; const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; // system reset extension const SRST_EXTENSION: usize = 0x53525354; const SBI_SHUTDOWN: usize = 0; #[inline(always)] fn sbi_call(eid: usize, fid: 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("x16") fid, in("x17") eid, ); } ret } pub fn console_putchar(c: usize) { sbi_call(SBI_CONSOLE_PUTCHAR, 0, c, 0, 0); } pub fn shutdown() -> ! { sbi_call(SRST_EXTENSION, SBI_SHUTDOWN, 0, 0, 0); panic!("It should shutdown!") }
多谢指导。顺便给其他可能遇到类似问题的小伙伴指个路 -> Call SBI in different programming languages