diff --git a/ch2/os/Cargo.toml b/ch2/os/Cargo.toml index 60b4d6d..c02e785 100644 --- a/ch2/os/Cargo.toml +++ b/ch2/os/Cargo.toml @@ -5,4 +5,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] +# 设置release模式下保存调试信息 +[profile.release] +debug=true \ No newline at end of file diff --git a/ch2/os/Makefile b/ch2/os/Makefile new file mode 100644 index 0000000..adb85bb --- /dev/null +++ b/ch2/os/Makefile @@ -0,0 +1,51 @@ +TARGET := riscv64gc-unknown-none-elf +KERNEL_ENTRY := 0x80200000 +MODE := release +KERNEL_ELF := target/$(TARGET)/$(MODE)/os +KERNEL_BIN := $(KERNEL_ELF).bin +SYMBOL_MAP := target/system.map +QEMU_CMD_PATH := /Users/zhangxinyu/Downloads/qemu-7.0.0/build/qemu-system-riscv64 +QEMU_PID = $(shell ps aux | grep "[q]emu-system' | awk '{print $$2}") +OBJDUMP := rust-objdump --arch-name=riscv64 +OBJCOPY := rust-objcopy --binary-architecture=riscv64 + +RUST_FLAGS := -Clink-arg=-Tsrc/linker.ld # 使用我们自己的链接脚本 +RUST_FLAGS += -Cforce-frame-pointers=yes # 强制编译器生成帧指针 +RUST_FLAGS:=$(strip ${RUST_FLAGS}) + +# 编译elf文件 +build_elf: clean + CARGO_BUILD_RUSTFLAGS="$(RUST_FLAGS)" \ + cargo build --$(MODE) --target=$(TARGET) + +# 导出一个符号表, 供我们查看 +$(SYMBOL_MAP):build_elf + nm $(KERNEL_ELF) | sort > $(SYMBOL_MAP) + +# 丢弃内核可执行elf文件中的元数据得到内核镜像 +$(KERNEL_BIN): build_elf + @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ + + +debug:build_elf $(KERNEL_BIN) $(SYMBOL_MAP) kill + $(QEMU_CMD_PATH) \ + -machine virt \ + -display none \ + -daemonize \ + -bios ../bootloader/rustsbi-qemu.bin \ + -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY) \ + -s -S + +run:build_elf $(KERNEL_BIN) $(SYMBOL_MAP) kill + $(QEMU_CMD_PATH) \ + -machine virt \ + -nographic \ + -bios ../bootloader/rustsbi-qemu.bin \ + -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY) + +clean: + rm -rf ./target* + +kill: + -kill -9 $(QEMU_PID) + diff --git a/ch2/os/src/entry.asm b/ch2/os/src/entry.asm new file mode 100644 index 0000000..f790219 --- /dev/null +++ b/ch2/os/src/entry.asm @@ -0,0 +1,15 @@ +.section .text.entry +.globl _start // 声明_start是全局符号 +_start: + la sp, boot_stack_top_bound + call rust_main + + + +// 声明栈空间 后续 .bss.stack 会被link脚本链接到 .bss段 + .section .bss.stack + .globl boot_stack_lower_bound // 栈低地址公开为全局符号 + .globl boot_stack_top_bound // 栈高地址公开为全局符号 +boot_stack_lower_bound: + .space 4096 * 16 +boot_stack_top_bound: diff --git a/ch2/os/src/lang_items.rs b/ch2/os/src/lang_items.rs new file mode 100644 index 0000000..53e74c5 --- /dev/null +++ b/ch2/os/src/lang_items.rs @@ -0,0 +1,2 @@ +pub mod panic; +pub mod console; \ No newline at end of file diff --git a/ch2/os/src/lang_items/console.rs b/ch2/os/src/lang_items/console.rs new file mode 100644 index 0000000..e4330a1 --- /dev/null +++ b/ch2/os/src/lang_items/console.rs @@ -0,0 +1,33 @@ + +use crate::sbi::console_put_char; +use core::fmt::{self, Write}; + +struct Stdout; + +impl Write for Stdout{ + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + console_put_char(c as usize); + } + Ok(()) + } +} + +// 用函数包装一下, 表示传进来的参数满足Arguments trait, 然后供宏调用 +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)+)?)); + } +} diff --git a/ch2/os/src/lang_items/panic.rs b/ch2/os/src/lang_items/panic.rs new file mode 100644 index 0000000..2e893c2 --- /dev/null +++ b/ch2/os/src/lang_items/panic.rs @@ -0,0 +1,18 @@ +use core::panic::PanicInfo; +use crate::println; +use crate::sbi::shutdown; + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + if let Some(location) = info.location() { + println!( + "Panicked at {}:{} {}", + location.file(), + location.line(), + info.message().unwrap() + ); + } else { + println!("Panicked: {}", info.message().unwrap()); + } + shutdown(); +} \ No newline at end of file diff --git a/ch2/os/src/linker.ld b/ch2/os/src/linker.ld new file mode 100644 index 0000000..099fd87 --- /dev/null +++ b/ch2/os/src/linker.ld @@ -0,0 +1,48 @@ +OUTPUT_ARCH(riscv) /* 目标平台 */ +ENTRY(_start) /* 设置程序入口点为entry.asm中定义的全局符号 */ +BASE_ADDRESS = 0x80200000; /* 一个常量, 我们的kernel将来加载到这个物理地址 */ + +SECTIONS +{ + . = BASE_ADDRESS; /* 我们对 . 进行赋值, 调整接下来的段的开始位置放在我们定义的常量出 */ +/* skernel = .;*/ + + stext = .; /* .text段的开始位置 */ + .text : { /* 表示生成一个为 .text的段, 花括号内按照防止顺序表示将输入文件中的哪些段放在 当前.text段中 */ + *(.text.entry) /* entry.asm中, 我们自己定义的.text.entry段, 被放在顶部*/ + *(.text .text.*) + } + + . = ALIGN(4K); + etext = .; + srodata = .; + .rodata : { + *(.rodata .rodata.*) + *(.srodata .srodata.*) + } + + . = ALIGN(4K); + erodata = .; + sdata = .; + .data : { + *(.data .data.*) + *(.sdata .sdata.*) + } + + . = ALIGN(4K); + edata = .; + .bss : { + *(.bss.stack) /* 全局符号 sbss 和 ebss 分别指向 .bss 段除 .bss.stack 以外的起始和终止地址(.bss.stack是我们在entry.asm中定义的栈) */ + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + } + + . = ALIGN(4K); + ebss = .; + ekernel = .; + + /DISCARD/ : { + *(.eh_frame) + } +} \ No newline at end of file diff --git a/ch2/os/src/main.rs b/ch2/os/src/main.rs index e7a11a9..bcbe1e2 100644 --- a/ch2/os/src/main.rs +++ b/ch2/os/src/main.rs @@ -1,3 +1,41 @@ -fn main() { - println!("Hello, world!"); +#![feature(panic_info_message)] +#![no_std] +#![no_main] + +use core::arch::global_asm; +use sbi::{console_put_char, shutdown}; +use lang_items::console; + +mod lang_items; +mod sbi; + +// 汇编脚本引入, 调整内核的内存布局之后, 会跳入到 rust_main中执行 +global_asm!(include_str!("entry.asm")); + +extern "C" { + fn stext(); + fn etext(); + fn sbss(); + fn ebss(); + fn boot_stack_top_bound(); + fn boot_stack_lower_bound(); +} + +#[no_mangle] +pub fn rust_main(){ + init_bss(); + + println!("stext: {:#x}, etext: {:#x}", stext as usize, etext as usize); + println!("sbss: {:#x}, ebss: {:#x}", sbss as usize, ebss as usize); + println!("boot_stack_top_bound: {:#x}, boot_stack_lower_bound: {:#x}", boot_stack_top_bound as usize, boot_stack_lower_bound as usize); + + panic!("my panic"); +} + +/// ## 初始化bss段 +/// +fn init_bss() { + unsafe { + (sbss as usize..ebss as usize).for_each(|p| (p as *mut u8).write_unaligned(0)) + } } diff --git a/ch2/os/src/sbi.rs b/ch2/os/src/sbi.rs new file mode 100644 index 0000000..e954239 --- /dev/null +++ b/ch2/os/src/sbi.rs @@ -0,0 +1,40 @@ +use core::arch::asm; + +// 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_put_char(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!") +} \ No newline at end of file diff --git a/ch2/user/Makefile b/ch2/user/Makefile index f2ee41e..f2746fc 100644 --- a/ch2/user/Makefile +++ b/ch2/user/Makefile @@ -20,6 +20,7 @@ build_elf: clean cargo build --$(MODE) --target=$(TARGET) +# 把每个elf文件去掉无关代码 build: build_elf @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)