rCore-Tutorial-Book-v3 icon indicating copy to clipboard operation
rCore-Tutorial-Book-v3 copied to clipboard

rCore-Tutorial-Book-v3/chapter1/3-1-mini-rt-usrland

Open utterances-bot opened this issue 4 years ago • 31 comments

构建用户态执行环境 — rCore-Tutorial-Book-v3 0.1 文档

https://rcore-os.github.io/rCore-Tutorial-Book-v3/chapter1/3-1-mini-rt-usrland.html

utterances-bot avatar Jan 26 '21 14:01 utterances-bot

我在程序里加了这两行才能编译

use core::fmt::{self, Write};
const STDOUT: usize = ???;

但是这个STDOUT究竟该如何设置呢?

Nicolas-Li avatar Jan 26 '21 14:01 Nicolas-Li

有大佬解释一下这里模拟程序为什么能使用宿主操作系统提供的系统调用吗

dinghao188 avatar Jan 28 '21 16:01 dinghao188

@dinghao188 这里我也觉得很疑惑,我的理解是 这里调用的应该是 qemu 中的 openSBI 提供的 ecall

generalibm avatar Jan 31 '21 11:01 generalibm

有大佬解释一下这里模拟程序为什么能使用宿主操作系统提供的系统调用吗

这一节使用的模拟器是 qemu-riscv64 ,相当于是直接在 linux-riscv64 上跑用户程序,所以可以使用 syscall 。下一节使用的 qemu-system-riscv64 是裸机,只要是 riscv64 架构的软件都可以在上面运行,按照特权级组成可以分成只有 M 态,或者 M 态 + SBI + S 态,又或者 M 态 + SBI + S 态 + syscall + U 态。

wyfcyx avatar Jan 31 '21 12:01 wyfcyx

咦,我把.text.entry加进去之后反而core dump了? 按之前

#[no_mangle]
extern "C" fn _start() {
    println!("Hello, World!");
    sys_exit(0);
}

的写法反而能正常输出结果并正常退出?

frank-king avatar Feb 03 '21 14:02 frank-king

照教程没有执行成功

yunkaiOr2 avatar Feb 23 '21 00:02 yunkaiOr2

rustc 1.52.0-nightly (a15f484b9 2021-02-22) 没有设置栈的情况下可以运行,安装上文的方法设置了栈,反而出现段错误

mayi@mayi-deepin:~/riscos/mycodes/os$ qemu-riscv64 target/riscv64gc-unknown-none-elf/debug/os; echo $?
Hello, world! myprintln
9

zhugy08 avatar Feb 24 '21 01:02 zhugy08

@Nicolas-Li 我也遇到了编译不过的问题,只加上一行

use core::fmt::{self, Write};

就好了。

yinhaoxuan avatar Feb 25 '21 08:02 yinhaoxuan

环境:windows wsl2 Ubuntu 20.04.2 LTS rust 版本:rustc 1.51.0-nightly (b12290861 2021-01-29) 编译教程中如最下方所示的代码时,报错can't find crate for 'std' 但是加上之前提到的

#![no_std]
#![no_main]

mod lang_items;

也报错:

   Compiling os v0.1.0 (/root/OS/os)
error: an inner attribute is not permitted in this context
 --> src/main.rs:6:1
  |
6 | #![feature(llvm_asm)]
  | ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.

error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead
  --> src/main.rs:13:25
   |
13 |                         llvm_asm!("ecall"
   |                         ^^^^^^^^
   |
   = note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
   = help: add `#![feature(llvm_asm)]` to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
error: could not compile `os`

To learn more, run the command again with --verbose.

只加上评论中所说的:

use core::fmt::{self, Write};

也报错:

   Compiling os v0.1.0 (/root/OS/os)
error: an inner attribute is not permitted in this context
 --> src/main.rs:2:1
  |
2 | #![feature(llvm_asm)]
  | ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.

error[E0463]: can't find crate for `std`
  |
  = note: the `riscv64gc-unknown-none-elf` target may not be installed

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0463`.
error: could not compile `os`

To learn more, run the command again with --verbose.

请问应该如何解决呢,谢谢~

// os/src/main.rs
#![feature(llvm_asm)]

const SYSCALL_EXIT: usize = 93;

fn syscall(id: usize, args: [usize; 3]) -> isize {
    let mut ret: isize;
    unsafe {
        llvm_asm!("ecall"
            : "={x10}" (ret)
            : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id)
            : "memory"
            : "volatile"
        );
    }
    ret
}

pub fn sys_exit(xstate: i32) -> isize {
    syscall(SYSCALL_EXIT, [xstate as usize, 0, 0])
}

#[no_mangle]
extern "C" fn _start() {
    sys_exit(9);
}

HaoyunHong avatar Feb 26 '21 14:02 HaoyunHong

所以,我们可以断定,这个二进制程序虽然合法,但它是一个空程序。这不是我们希望的,我们希望有具体内容的执行程序。为什么会这样呢?

这是上一节的内容吧,似乎不应该出现在这一节里

Gallium70 avatar Feb 26 '21 14:02 Gallium70

操作系统会提供一个退出的系统调用服务接口,但应用程序调用这个接口

但 -> 当

zxdclyz avatar Feb 28 '21 09:02 zxdclyz

@HaoyunHong 我这里保留前面的内容,把#![feature(llvm_asm)]放到文件最前面就好了。

xinghaow99 avatar Feb 28 '21 11:02 xinghaow99

按照教程操作后,编译不通过并报错: src/main.rs:15:9 llvm_asm!("ecall")... ^ error: couldn't allocate output register for constraint '{x10}' 使用的版本是rustc 1.52.0-nightly,虚拟机映像是助教提供的那个 室友电脑上运行正常的程序在我的电脑上跑不出来 求问如何处理

sj-zhang18 avatar Mar 02 '21 08:03 sj-zhang18

按照教程操作后,编译不通过并报错: src/main.rs:15:9 llvm_asm!("ecall")... ^ error: couldn't allocate output register for constraint '{x10}' 使用的版本是rustc 1.52.0-nightly,虚拟机映像是助教提供的那个 室友电脑上运行正常的程序在我的电脑上跑不出来 求问如何处理

看看是否在 os/.cargo/config 中设置默认目标平台为 riscv64gc-unknown-none-elf,参考 这里

wyfcyx avatar Mar 02 '21 12:03 wyfcyx

@HaoyunHong main.rs中应该有#![no_std] 才能调用core吧

Ngolo372 avatar Mar 03 '21 08:03 Ngolo372

@wyfcyx 我确认我已经设置了os/.cargo/config,但仍然无法正确运行

sj-zhang18 avatar Mar 03 '21 10:03 sj-zhang18

@sj-zhang18 错误还和前面相同吗?你可以留一下具体的 commit 链接。

wyfcyx avatar Mar 03 '21 11:03 wyfcyx

@wyfcyx 麻烦助教了,现在我已解决

sj-zhang18 avatar Mar 03 '21 11:03 sj-zhang18

@zhugy08 可否试试 https://github.com/chyyuu/os_kernel_lab/tree/v4-null-to-mini-and-usr-to-baremetal-runtime 中的https://github.com/chyyuu/os_kernel_lab/commit/fe33ed0788c2575c853e7ba76922c466aea60b00

chyyuu avatar Mar 03 '21 13:03 chyyuu

@zhugy08 @whjpji 这里教程漏了最后一步添加linker.ld,所以sp初始化的.bss.stack在紧接.text之后的低地址,可能是导致装载出错

t4rf9 avatar Mar 03 '21 16:03 t4rf9

println宏里面print方法不改为$crate::console::print的话会报错,改为跟print宏一样的就好了。

jelipo avatar Apr 01 '21 03:04 jelipo

请问,都写在 main.rs 里了,print 调用并不存在的 console模块为什么可以成功,谢谢

#![no_std]
#![no_main]
#![feature(llvm_asm)]
use core::fmt::{self, Write};
mod lang_items;

const SYSCALL_EXIT: usize = 93;

fn syscall(id: usize, args: [usize; 3]) -> isize {
    let mut ret: isize;
    unsafe {
        llvm_asm!("ecall"
            : "={x10}" (ret)
            : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id)
            : "memory"
            : "volatile"
        );
    }
    ret
}

pub fn sys_exit(xstate: i32) -> isize {
    syscall(SYSCALL_EXIT, [xstate as usize, 0, 0])
}

const SYSCALL_WRITE: usize = 64;

pub fn sys_write(fd: usize, buffer: &[u8]) -> isize {
  syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()])
}

struct Stdout;

impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        sys_write(1, s.as_bytes());
        Ok(())
    }
}

pub fn print(args: fmt::Arguments) {
    Stdout.write_fmt(args).unwrap();
}

#[macro_export]
macro_rules! print {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::console::print(format_args!($fmt $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! println {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
    }
}


// fn main() {
    // println!("Hello, world!");
// }
#[no_mangle]
extern "C" fn _start() {
    // loop{};
    println!("Hello, world!");
    sys_exit(9);
}

buhe avatar Apr 04 '21 03:04 buhe

这里没贴能运行的完整代码。 贴一下我的以供参考 main.rs

#![feature(llvm_asm)]
#![no_std]
#![no_main]


mod lang_items;

use core::fmt::{self, Write};

const SYSCALL_EXIT: usize = 93;
const SYSCALL_WRITE: usize = 64;

fn syscall(id: usize, args: [usize; 3]) -> isize {
    let mut ret: isize;
    unsafe {
        llvm_asm!("ecall"
            : "={x10}" (ret)
            : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id)
            : "memory"
            : "volatile"
        );
    }
    ret
}

pub fn sys_exit(xstate: i32) -> isize {
    syscall(SYSCALL_EXIT, [xstate as usize, 0, 0])
}

pub fn sys_write(fd: usize, buffer: &[u8]) -> isize {
    syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()])
}


struct Stdout;

impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        sys_write(1, s.as_bytes());
        Ok(())
    }
}

pub fn print(args: fmt::Arguments) {
    Stdout.write_fmt(args).unwrap();
}

#[macro_export]
macro_rules! print {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        $crate::console::print(format_args!($fmt $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! println {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
    }
}

#[no_mangle]
extern "C" fn _start() {
    println!("Hello, world!");
    sys_exit(9);
}

NeverMoes avatar May 04 '21 13:05 NeverMoes

Rust语言初学者分享一个踩坑经历,之前把#[no_mangle]和extern “C” fn_start()分开写了,如下: #![no_std] #![no_main] #[no_mangle]

mod lang_items;

extern "C" fn _start() { loop{}; }

中间隔了写东西导致编译会有报警,如下:

warning: attribute should be applied to a function or static --> src/main.rs:3:1 | 3 | #[no_mangle] | ^^^^^^^^^^^^ 4 | 5 | mod lang_items; | --------------- not a function or static | = note: #[warn(unused_attributes)] on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

warning: 1 warning emitted

正确写法是: #![no_std] #![no_main]

mod lang_items;

#[no_mangle] extern "C" fn _start() { loop{}; }

wei-huan avatar May 10 '21 14:05 wei-huan

所以严格来讲第一章的程序并非真正的“裸机程序”?这个程序应该没法跑在真实的裸板上吧?

readlnh avatar Jul 11 '21 08:07 readlnh

啊,我似乎没注意到后面还有2个小节...总结一下,这一节的代码使用了linux的系统调用,这么设计的目的似乎是为了方便大家更快的写出有交互功能的代码(指print)?这里的程序严格来说并不是裸机程序,而是用户态程序,之所以能调用linux的系统调用,原因在与我们使用的qemu-riscv是user mode的模拟器,从某种程度上我们可以理解为我们的代码跑在riscv版的linux上。实际上如果我们使用qemu-system-riscv,是无法运行这个程序的,只有真正的“裸机”代码才能跑在上面

QEMU is a processor emulator and supports emulation of ARM, PowerPC, SPARC, x86, x86-64 and more.

QEMU has two operating modes:

  • User mode emulation: QEMU can launch Linux processes compiled for one CPU on another CPU, translating syscalls on the fly.
  • Full system emulation: QEMU emulates a full system (virtual machine), including a processor and various peripherals such as disk, ethernet controller etc.

readlnh avatar Jul 11 '21 08:07 readlnh

$crate::console::print(format_args!($fmt $(, $($arg)+)?));

这段代码中的$crate::console::起什么作用啊? 我去掉后编译运行也可成功,求解!

Fomalhauthmj avatar Jul 25 '21 06:07 Fomalhauthmj

$crate::console::的作用可以看这个,绝对路径引用,从仓库代码的 tag-ch1 来看,作者把 print 代码都放到了子模块 console 中,但是 ta 在其中引入了 sbi,当我尝试把 print 都弄到 consle 里面时,引发了更多的问题,尝试解决了不太好整,所以还是留在 main里,这一节的最终代码贴一个给大家参考

BackMountainDevil avatar Oct 03 '21 15:10 BackMountainDevil

出错提示: warning: use of deprecated macro llvm_asm: will be removed from the compiler, use asm! instead --> src/main.rs:13:9 | 13 | llvm_asm!("ecall" | ^^^^^^^^ | = note: #[warn(deprecated)] on by default

error: #[panic_handler] function required, but not found

代码: #![no_std] #![no_main]

// mod lang_items;

#![feature(llvm_asm)]

const SYSCALL_EXIT: usize = 93;

fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; unsafe { llvm_asm!("ecall" : "={x10}" (ret) : "{x10}" (args[0]), "{x11}" (args[1]), "{x12}" (args[2]), "{x17}" (id) : "memory" : "volatile" ); } ret }

pub fn sys_exit(xstate:i32)->isize { syscall(SYSCALL_EXIT,[xstate as usize,0,0]) }

#[no_mangle] extern "C" fn _start() { sys_exit(9); }

vagicc avatar Nov 07 '21 04:11 vagicc

文档似乎没有更新,我也贴一下能运行的代码,如果你阅读教程的日期和这条评论相差不远可以参考:

$ rustc --version
rustc 1.56.0-nightly (3d0774d0d 2021-08-18)
展开查看
// src/main.rs
#![no_std]
#![no_main]
#![feature(asm)]

use core::fmt::{self, Write};

mod lang_items;

const SYSCALL_EXIT: usize = 93;
const SYSCALL_WRITE: usize = 64;

fn syscall(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
}

pub fn sys_exit(xstate: usize) -> usize {
    syscall(SYSCALL_EXIT, xstate, 0, 0)
}

pub fn sys_write(fd: usize, buffer: &[u8]) -> usize {
    syscall(SYSCALL_WRITE, fd, buffer.as_ptr() as usize, buffer.len())
}

struct Stdout;

impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        sys_write(1, s.as_bytes());
        Ok(())
    }
}

pub fn print(args: fmt::Arguments) {
    Stdout.write_fmt(args).unwrap();
}

#[macro_export]
macro_rules! print {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        print(format_args!($fmt $(, $($arg)+)?));
    }
}

#[macro_export]
macro_rules! println {
    ($fmt: literal $(, $($arg: tt)+)?) => {
        print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
    }
}

#[no_mangle]
extern "C" fn _start() {
    print!("No new line, ");
    println!("Hello, world!");
    sys_exit(9);
}

vcheckzen avatar Nov 29 '21 17:11 vcheckzen