Post

rCore - Chapter01

rCore - Chapter01

课后练习

实现一个linux应用程序A,显示当前目录下的文件名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use std::fs;
use std::io;

fn main() -> io::Result<()> {
    let current_dir = std::env::current_dir()?;

    let entries = fs::read_dir(current_dir)?;

    for entry in entries {
        let entry = entry?;
        let file_name = entry.file_name();
        println!("{}", file_name.to_string_lossy());
    }

    Ok(())
}

实现一个linux应用程序B,能打印出调用栈链信息。

可以参考Stanford CS110L的Project 1,用Rust语言实现了一个简单的debugger,比较有意思


实现一个基于rcore tutorial的应用程序C,用sleep系统调用睡眠5秒

如果你做过xv6,你应该知道需要通过qemu模拟的CLINT(Core Local Interruptor)去得到mtime寄存器的值,该寄存器映射到了内存中0x2000000 + 0xBFF8上,其中前者是CLINT映射的起始地址,后者是mtime相对于CLINT基地址的偏移量,mtime寄存器的大小是8字节,记得在[dependency]里加入riscv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const CLINT_BASE: usize = 0x2000000;
const MTIME_OFFSET: usize = 0xBFF8;
const TIMER_FREQUENCY: u64 = 10_000_000;

pub fn sleep(duration: u64) {
    let ticks = duration * TIMER_FREQUENCY;
    sleep_ticks(ticks);
}

fn sleep_ticks(duration: u64) {
    let current_time = read_mtime();
    let wake_time = current_time + duration;

    sbi_rt::set_timer(wake_time); // 设置wakeup时间
    riscv::asm::wfi(); // 让cpu进入low-power等待状态,等待interrupt
}

fn read_mtime() -> u64 {
    unsafe { core::ptr::read_volatile((CLINT_BASE + MTIME_OFFSET) as *const u64) }
}

实验练习

彩色化LOG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use core::sync::atomic::{AtomicU8, Ordering};

pub const RESET: &str = "\x1b[0m";

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum LogLevel {
    NONE = 0, // No output
    ERROR = 1,
    WARN = 2,
    INFO = 3,
    DEBUG = 4,
    TRACE = 5,
}

/// Atomic global log level (Safe access without `unsafe`)
static LOG_LEVEL_FILTER: AtomicU8 = AtomicU8::new(LogLevel::INFO as u8);

#[derive(Debug, Clone, Copy)]
pub struct LogConfig {
    pub color: &'static str,
    pub name: &'static str,
    pub level: LogLevel,
}

pub const ERROR: LogConfig = LogConfig {
    color: "\x1b[31m",
    name: "ERROR",
    level: LogLevel::ERROR,
};
pub const WARN: LogConfig = LogConfig {
    color: "\x1b[93m",
    name: "WARN",
    level: LogLevel::WARN,
};
pub const INFO: LogConfig = LogConfig {
    color: "\x1b[34m",
    name: "INFO",
    level: LogLevel::INFO,
};
pub const DEBUG: LogConfig = LogConfig {
    color: "\x1b[32m",
    name: "DEBUG",
    level: LogLevel::DEBUG,
};
pub const TRACE: LogConfig = LogConfig {
    color: "\x1b[90m",
    name: "TRACE",
    level: LogLevel::TRACE,
};

#[macro_export]
macro_rules! log {
    ($level:expr, $($arg:tt)*) => {
        if $level.level as u8 <= $crate::logging::get_log_level() as u8 {
            print!("{}[{}] ", $level.color, $level.name);
            println!($($arg)*);
            print!("{}", $crate::logging::RESET);
        }
    };
}

#[macro_export]
macro_rules! error {
    ($($arg:tt)*) => (log!($crate::logging::ERROR, $($arg)*));
}

#[macro_export]
macro_rules! warn {
    ($($arg:tt)*) => (log!($crate::logging::WARN, $($arg)*));
}

#[macro_export]
macro_rules! info {
    ($($arg:tt)*) => (log!($crate::logging::INFO, $($arg)*));
}

#[macro_export]
macro_rules! debug {
    ($($arg:tt)*) => (log!($crate::logging::DEBUG, $($arg)*));
}

#[macro_export]
macro_rules! trace {
    ($($arg:tt)*) => (log!($crate::logging::TRACE, $($arg)*));
}

/// **Set log level safely**
pub fn set_log_level(level: LogLevel) {
    LOG_LEVEL_FILTER.store(level as u8, Ordering::Relaxed);
}

/// **Get current log level safely**
pub fn get_log_level() -> LogLevel {
    match LOG_LEVEL_FILTER.load(Ordering::Relaxed) {
        0 => LogLevel::NONE,
        1 => LogLevel::ERROR,
        2 => LogLevel::WARN,
        3 => LogLevel::INFO,
        4 => LogLevel::DEBUG,
        5 => LogLevel::TRACE,
        _ => LogLevel::INFO, // Default to INFO
    }
}

/// **Initialize log level from environment variable (`LOG`)**
pub fn init_log_level() {
    use core::option_env;

    let log_str = option_env!("LOG").unwrap_or("INFO");

    let level = match log_str {
        "NONE" => LogLevel::NONE,
        "ERROR" => LogLevel::ERROR,
        "WARN" => LogLevel::WARN,
        "INFO" => LogLevel::INFO,
        "DEBUG" => LogLevel::DEBUG,
        "TRACE" => LogLevel::TRACE,
        _ => LogLevel::INFO, // Default INFO
    };

    set_log_level(level);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
LOG ?= INFO

build:
	cargo build --release
	rust-objcopy \
		--strip-all \
		target/riscv64gc-unknown-none-elf/release/os \
		-O binary \
		target/riscv64gc-unknown-none-elf/release/os.bin

run: build
	qemu-system-riscv64 \
		-machine virt \
		-nographic \
		-bios ../bootloader/rustsbi-qemu.bin \
		-device loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr=0x80200000
	
clean:
	cargo clean

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
[rustsbi] RustSBI version 0.3.1, 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)
[INFO] .text [0x80200000, 0x80202000)
[INFO] .rodata [0x80202000, 0x80203000)
[INFO] .data [0x80203000, 0x80204000)
[INFO] .bss [0x80214000, 0x80214000)
Hello, world!
Panicked at src/main.rs:23 Shutdown machine!
make: *** [Makefile:12: run] Error 255
This post is licensed under CC BY 4.0 by the author.