OccupyMars2025 / rCore-Tutorial-v3

Let's write an OS which can run on RISC-V in Rust from scratch!
https://rcore-os.github.io/rCore-Tutorial-Book-v3/index.html
GNU General Public License v3.0
0 stars 0 forks source link

branch ch2 (record my learning process) 2023/5/27 15:00 - 6/5, (second round: 2023/7/3 21:24 - ) #1

Open OccupyMars2025 opened 1 year ago

OccupyMars2025 commented 1 year ago

[remain to solve]user/src/lib.rs : when the main() in _start() is replaced by an APP main() ?

image

我们使用 Rust 的宏将其函数符号 main 标志为弱链接。这样在最后链接的时候,虽然在 lib.rs 和 bin 目录下的某个应用程序都有 main 符号,但由于 lib.rs 中的 main 符号是弱链接,链接器会使用 bin 目录下的应用主逻辑作为 main 。这里我们主要是进行某种程度上的保护,如果在 bin 目录下找不到任何 main ,那么编译也能够通过,但会在运行时报错。

http://rcore-os.cn/rCore-Tutorial-Book-v3/chapter2/2application.html#id4

refer to weak linkage in the source code : https://github.com/rust-lang/rust compiler/rustc_codegen_ssa/src/codegen_attrs.rs tests/ui/lto/weak-works.rs

    match name {
        "appending" => Appending,
        "available_externally" => AvailableExternally,
        "common" => Common,
        "extern_weak" => ExternalWeak,
        "external" => External,
        "internal" => Internal,
        "linkonce" => LinkOnceAny,
        "linkonce_odr" => LinkOnceODR,
        "private" => Private,
        "weak" => WeakAny,
        "weak_odr" => WeakODR,
        _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
    }
OccupyMars2025 commented 1 year ago

My modification: copy os/src/logging.rs to user/src/logging.rs to enable colorful logging in app programs

// user/src/lib.rs
pub extern "C" fn _start() -> ! {
    logging::init();
    info!("Enter user/src/lib.rs _start() ");
    clear_bss();
    exit(main());
    panic!("unreachable after sys_exit!");
}

but it seems that if I want to enable logging for every function, I have to add logging::init(); to every function just like the following code. It is a little tedious

// user/src/lib.rs
pub fn exit(exit_code: i32) -> isize {
    logging::init();
    debug!("Enter user/src/lib.rs exit() ");
    sys_exit(exit_code)
}
OccupyMars2025 commented 1 year ago

My modification: change logging colors to help understand the mechanism

// user/src/logging.rs
        let color = match record.level() {
            Level::Error => 31, // Red
            Level::Warn => 93,  // BrightYellow
            // Level::Info => 34,  // Blue
            Level::Info => 41,  // background in red
            // Level::Debug => 32, // Green
            Level::Debug => 43, // background in gray
            // Level::Trace => 90, // BrightBlack
            Level::Trace => 46, // background in green
        };

image

OccupyMars2025 commented 1 year ago

[remain to solve] what's the implication of the differences in the implementation of Write.write_str() ? Is it about the transition between privileged levels ?

//  os/src/console.rs
impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        for c in s.chars() {
            console_putchar(c as usize);
        }
        Ok(())
    }
}
// user/src/console.rs
impl Write for Stdout {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        write(STDOUT, s.as_bytes());
        Ok(())
    }
}
OccupyMars2025 commented 1 year ago

[remain to solve] change release mode to debug mode.

In my current understanding, GDB can only show source code with debug-mode compiled code when "stepping" the excutable.

caution: os/src/link_app.S

app_0_start:
    .incbin "../user/target/riscv64gc-unknown-none-elf/release/00hello_world.bin"
app_0_end:
OccupyMars2025 commented 1 year ago

[remain to solve]

if you use cd os and make run, you can get the following: image

if you use cd os and LOG=TRACE make run, you can get the following: image

It may have something to do with option_env! :

// user/src/logging.rs
pub fn init() {
    static LOGGER: SimpleLogger = SimpleLogger;
    log::set_logger(&LOGGER).unwrap();
    log::set_max_level(match option_env!("LOG") {
        Some("ERROR") => LevelFilter::Error,
        Some("WARN") => LevelFilter::Warn,
        Some("INFO") => LevelFilter::Info,
        Some("DEBUG") => LevelFilter::Debug,
        Some("TRACE") => LevelFilter::Trace,
        _ => LevelFilter::Off,
    });
}

and what's the mechanism behind cargo build ? (there are so many APP programs)

OccupyMars2025 commented 1 year ago

study os/src/link_app.S


    .align 3
    .section .data
    .global _num_app
_num_app:
    .quad 5
    .quad app_0_start
    .quad app_1_start
    .quad app_2_start
    .quad app_3_start
    .quad app_4_start
    .quad app_4_end

    .section .data
    .global app_0_start
    .global app_0_end
app_0_start:
    .incbin "../user/target/riscv64gc-unknown-none-elf/release/00hello_world.bin"
app_0_end:

    .section .data
    .global app_1_start
    .global app_1_end
app_1_start:
    .incbin "../user/target/riscv64gc-unknown-none-elf/release/01store_fault.bin"
app_1_end:

    .section .data
    .global app_2_start
    .global app_2_end
app_2_start:
    .incbin "../user/target/riscv64gc-unknown-none-elf/release/02power.bin"
app_2_end:

    .section .data
    .global app_3_start
    .global app_3_end
app_3_start:
    .incbin "../user/target/riscv64gc-unknown-none-elf/release/03priv_inst.bin"
app_3_end:

    .section .data
    .global app_4_start
    .global app_4_end
app_4_start:
    .incbin "../user/target/riscv64gc-unknown-none-elf/release/04priv_csr.bin"
app_4_end:

https://sourceware.org/binutils/docs-2.40/

https://sourceware.org/binutils/docs-2.40/as.html

‘.align 3’ advances the location counter until it is a multiple of 8. If the location counter is already a multiple of 8, no change is needed. .align n 指令的对齐值有两种方案:n 或 2^n 。各种平台最初的汇编器一般都不是gas,采取方案1或2的都很多,gas的目标是取代原来的汇编器,必然要保持和原来汇编器的兼容,因此在gas中如何解释.align指令会显得有些混乱,原因在于保持兼容。

https://dwarfstd.org/

DWARF Package File Format

https://sourceware.org/binutils/docs-2.40/as.html#Quad

https://sourceware.org/binutils/docs-2.40/as.html#Incbin

OccupyMars2025 commented 1 year ago

study os/build.rs

os/src/link_app.S这个文件是在 cargo build 的时候,由脚本 os/build.rs 控制生成的

https://doc.rust-lang.org/cargo/reference/build-scripts.html

https://doc.rust-lang.org/cargo/reference/build-script-examples.html

add -vv to cargo build to show the println content of os/build.rs image image image

OccupyMars2025 commented 1 year ago

2023/6/1 9:50: How to interprete stvec ?

image

http://rcore-os.cn/rCore-Tutorial-Book-v3/chapter2/4trap-handling.html#trap-hw-mechanism

image

Answer:

// riscv-ab2abd16c438337b/11d43cf/src/register/stvec.rs
read_csr_as!(Stvec, 0x105, __read_stvec);
write_csr!(0x105, __write_stvec);

/// Writes the CSR
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
    _write(addr + mode as usize);
}
// os/src/trap/mod.rs
pub fn init() {
    extern "C" {
        fn __alltraps();
    }
    unsafe {
        stvec::write(__alltraps as usize, TrapMode::Direct);
    }
}

According to the implementation code, the entry address of the trap handler (more exactly, it is the entry address of some assembly code that stores the trap context, then the control flow goes to the trap handler) should be BASE << 2 . And __alltraps as usize must be a multiple of 4 which is guaranteed by the following assembly code

#  os/src/trap/trap.S
    .align 2
__alltraps:
    csrrw sp, sscratch, sp
OccupyMars2025 commented 1 year ago

(remain to solve) 2023/6/1 11:50: 两个类型是以全局变量的形式实例化在批处理操作系统的 .bss 段中的 . How and when ?

// os/src/batch.rs
static KERNEL_STACK: KernelStack = KernelStack {
    data: [0; KERNEL_STACK_SIZE],
};
static USER_STACK: UserStack = UserStack {
    data: [0; USER_STACK_SIZE],
};
OccupyMars2025 commented 1 year ago

image

OccupyMars2025 commented 1 year ago
# os/Cargo.toml
[dependencies]
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }

where does features = ["inline-asm"] take effect ?

// riscv-ab2abd16c438337b/11d43cf/src/register/macros.rs
macro_rules! read_csr {
    ($csr_number:expr, $asm_fn: ident) => {
        /// Reads the CSR
        #[inline]
        unsafe fn _read() -> usize {
            match () {
                #[cfg(all(riscv, feature = "inline-asm"))]
                () => {
                    let r: usize;
                    core::arch::asm!("csrrs {0}, {1}, x0", out(reg) r, const $csr_number);
                    r
                }

                #[cfg(all(riscv, not(feature = "inline-asm")))]
                () => {
                    extern "C" {
                        fn $asm_fn() -> usize;
                    }

                    $asm_fn()
                }

                #[cfg(not(riscv))]
                () => unimplemented!(),
            }
        }
    };
}