Buhe Blog - Microsoft Internet Explorer

OS 简单教程三


打印

继续打印,幸好 SBI 实现了打印,省去了自己实现驱动,调用系统调用就行了。 实现系统调用,在 scall_sbi/mod.rs 中

#[inline(always)]
fn scall(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
   let mut ret;
   unsafe {
       asm!("ecall",
           in( "x10") arg0,
           in("x11") arg1,
           in ("x12") arg2,
           in("x17") which,
           lateout("x10") ret,
           options(nostack)
      );
  }
   ret
}
const SBI_CONSOLE_PUTCHAR: usize = 1;
const SBI_SHUTDOWN: usize = 8;

pub fn shutdown() -> ! {
   scall(SBI_SHUTDOWN, 0, 0, 0);
   panic!("It should shutdown!");
}

pub fn put_char(c: usize) {
   scall(SBI_CONSOLE_PUTCHAR, c, 0, 0);
}

建立 console.rs 调用刚才的系统调用,内容是

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

use crate::scall_sbi::put_char;

struct STDOUT;

impl Write for STDOUT {
   fn write_str(&mut self, s: &str) -> core::fmt::Result {
       for c in s.chars() {
           put_char(c as usize);
      }
       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)+)?) => {
      $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
  }
}

说明一下

  • 利用 宏 + core::fmt::Write 来解析参数 main.rs 里就可以调用宏输出了,这时 main.rs 的内容
#![feature(llvm_asm)]
#![feature(global_asm)]
#![no_std]
#![no_main]

use scall_sbi::shutdown;

mod lang;
mod scall_sbi;
#[macro_use]
mod console;

global_asm!(include_str!("stack.asm"));

#[no_mangle]
extern "C" fn rust_main() ->! {
   println!("hello OS");
   shutdown();
}

编译一下,make build,编译过了,运行一下 make run 也成功了,输出

[rustsbi] RustSBI version 0.2.0-alpha.3
.______       __   __     _______.___________. _______..______   __
|   _ \     | | | |   /       |           | /       ||   _ \ | |
| |_) |   | | | |   |   (----`---| |----`|   (----`| |_) || |
|     /     | | | |   \   \       | |     \   \   |   _ < | |
| |\ \----.| `--' |.----)   |     | | .----)   |   | |_) || |
| _| `._____| \______/ |_______/       |__| |_______/   |______/ |__|

[rustsbi] Platform: K210 (Version 0.2.0)
[rustsbi] misa: RV64ACDFIMSU
[rustsbi] mideleg: 0x22
[rustsbi] medeleg: 0x1ab
[rustsbi] Kernel entry: 0x80020000
hello OS
[rustsbi] reset triggered! todo: shutdown all harts on k210; program halt. Type: 0, reason: 0

至此我们成功准备了运行环境并在 k210 上输出,接下来我们开始虚拟化 CPU 和内存,这更有趣!

后续

  • 全局位初始化变量清零
fn clear_bss() {
   extern "C" {
       fn sbss();
       fn ebss();
  }
  (sbss as usize..ebss as usize).for_each(|a| {
       unsafe { (a as *mut u8).write_volatile(0) }
  });
}

具体代码请参考 https://github.com/buhe/bugu/tree/0.1.0