From f348dcbad43c0a1390729cfe144fef4c2b595c63 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 17 May 2023 17:09:02 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E7=8E=B0=E4=BB=B7=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/user/src/bin/00hello_world.rs | 2 +- ch2/user/src/bin/01hello_world.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 ch2/user/src/bin/01hello_world.rs diff --git a/ch2/user/src/bin/00hello_world.rs b/ch2/user/src/bin/00hello_world.rs index 6995fb6..e1391d7 100644 --- a/ch2/user/src/bin/00hello_world.rs +++ b/ch2/user/src/bin/00hello_world.rs @@ -5,6 +5,6 @@ use user_lib::*; #[no_mangle] fn main() -> i32 { - println!("123"); + println!("hello 1"); 0 } \ No newline at end of file diff --git a/ch2/user/src/bin/01hello_world.rs b/ch2/user/src/bin/01hello_world.rs new file mode 100644 index 0000000..1e0f9bc --- /dev/null +++ b/ch2/user/src/bin/01hello_world.rs @@ -0,0 +1,10 @@ +#![no_std] +#![no_main] + +use user_lib::*; + +#[no_mangle] +fn main() -> i32 { + println!("hello 2"); + 0 +} \ No newline at end of file From 5628d6f253dfb2b0b936e44e979aba1e8d57a4a5 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 17 May 2023 17:09:46 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E8=87=AA=E5=B7=B1=E5=B0=81=E8=A3=85?= =?UTF-8?q?=E4=B8=80=E4=B8=AArefcell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/src/sync/mod.rs | 4 ++++ ch2/os/src/sync/up.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 ch2/os/src/sync/mod.rs create mode 100644 ch2/os/src/sync/up.rs diff --git a/ch2/os/src/sync/mod.rs b/ch2/os/src/sync/mod.rs new file mode 100644 index 0000000..1ccdd2e --- /dev/null +++ b/ch2/os/src/sync/mod.rs @@ -0,0 +1,4 @@ +//! Synchronization and interior mutability primitives + +mod up; +pub use up::UPSafeCell; diff --git a/ch2/os/src/sync/up.rs b/ch2/os/src/sync/up.rs new file mode 100644 index 0000000..e8ba20c --- /dev/null +++ b/ch2/os/src/sync/up.rs @@ -0,0 +1,31 @@ +//! Uniprocessor interior mutability primitives + +use core::cell::{RefCell, RefMut}; + +/// Wrap a static data structure inside it so that we are +/// able to access it without any `unsafe`. +/// +/// We should only use it in uniprocessor. +/// +/// In order to get mutable reference of inner data, call +/// `exclusive_access`. +pub struct UPSafeCell { + /// inner data + inner: RefCell, +} + +unsafe impl Sync for UPSafeCell {} + +impl UPSafeCell { + /// User is responsible to guarantee that inner struct is only used in + /// uniprocessor. + pub unsafe fn new(value: T) -> Self { + Self { + inner: RefCell::new(value), + } + } + /// Exclusive access inner data in UPSafeCell. Panic if the data has been borrowed. + pub fn exclusive_access(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() + } +} From a0fba7a3bd3bf97f9dca854f762b82c908b70300 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 17 May 2023 17:10:23 +0800 Subject: [PATCH 3/8] =?UTF-8?q?makefile=20=E5=A2=9E=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=B8=85=E7=90=86=E7=94=A8=E6=88=B7=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E6=B1=87=E7=BC=96=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch2/os/Makefile b/ch2/os/Makefile index faf1758..dccc8cc 100644 --- a/ch2/os/Makefile +++ b/ch2/os/Makefile @@ -44,7 +44,7 @@ run:build_elf $(KERNEL_BIN) $(SYMBOL_MAP) kill -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY) clean: - rm -rf ./target* + rm -rf ./target* && rm -rf ./src/link_app.S kill: -kill -9 $(QEMU_PID) From 4916c8bde941db3611c4276e56b97978ff46c1d4 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 17 May 2023 17:20:27 +0800 Subject: [PATCH 4/8] =?UTF-8?q?app=E5=BA=94=E7=94=A8=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=B7=B2=E7=BB=8F=E6=AD=A3=E5=B8=B8=E5=8A=A0=E8=BD=BD=E8=BF=9B?= =?UTF-8?q?=E5=86=85=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/Cargo.toml | 6 +++- ch2/os/src/batch.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++ ch2/os/src/main.rs | 11 +++++-- 3 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 ch2/os/src/batch.rs diff --git a/ch2/os/Cargo.toml b/ch2/os/Cargo.toml index c02e785..dd3234d 100644 --- a/ch2/os/Cargo.toml +++ b/ch2/os/Cargo.toml @@ -7,4 +7,8 @@ edition = "2021" # 设置release模式下保存调试信息 [profile.release] -debug=true \ No newline at end of file +debug=true + +[dependencies] +riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } \ No newline at end of file diff --git a/ch2/os/src/batch.rs b/ch2/os/src/batch.rs new file mode 100644 index 0000000..c8c4d72 --- /dev/null +++ b/ch2/os/src/batch.rs @@ -0,0 +1,72 @@ +use lazy_static::*; +use crate::println; +use crate::sync::UPSafeCell; + +const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb +const KERNEL_STACK_SIZE: usize = 4096 * 2; + +const MAX_APP_NUM: usize = 16; // 系统最大支持的运行程序数量 + +const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址 +const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 + +// 在此之后应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用 +static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE]; +static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE]; + +lazy_static! { + static ref APP_MANAGER: UPSafeCell = unsafe { + UPSafeCell::new({ + extern "C" { + fn _num_app(); + } + let num_app_ptr = _num_app as usize as *const usize; + let num_app = num_app_ptr.read_volatile(); // 用户app的总数量 + + let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; // 创建一个数组, 用来保存每个app的起始位置 + + // 得到每个app的起始地址 + let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1]; + let app_start_raw: &[usize] = + core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1); + app_start_lis[..=num_app].copy_from_slice(app_start_raw); + + AppManager{ + num_app, + current_app: 0, + app_start_lis + } + }) + }; +} + +// 由build.rs 生成的link_app.S, 根据里面的信息生成的结构体 +struct AppManager { + num_app: usize, // 用户app数量 + current_app: usize, // 当前需要执行的第几个app + app_start_lis: [usize; MAX_APP_NUM + 1], // 保存了每个app的起始位置, 后面会跳到这里, +1 是因为end的位置也占了一个usize, 需要知道end的位置 +} + +impl AppManager{ + fn show_app_info(&self){ + println!("[kernel] num_app = {}", self.num_app); + for i in 0..self.num_app { + println!( + "[kernel] app_{} [{:#x}, {:#x})", + i, + self.app_start_lis[i], + self.app_start_lis[i + 1] + ); + } + } +} + + +pub fn init() { + APP_MANAGER.exclusive_access().show_app_info(); +} + + + + + diff --git a/ch2/os/src/main.rs b/ch2/os/src/main.rs index bcbe1e2..4933aed 100644 --- a/ch2/os/src/main.rs +++ b/ch2/os/src/main.rs @@ -6,12 +6,17 @@ use core::arch::global_asm; use sbi::{console_put_char, shutdown}; use lang_items::console; -mod lang_items; -mod sbi; +pub mod lang_items; +pub mod sbi; +pub mod batch; +pub mod sync; // 汇编脚本引入, 调整内核的内存布局之后, 会跳入到 rust_main中执行 global_asm!(include_str!("entry.asm")); +// 引入用户的二进制文件 +global_asm!(include_str!("link_app.S")); + extern "C" { fn stext(); fn etext(); @@ -29,7 +34,7 @@ pub fn rust_main(){ 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"); + batch::init(); } /// ## 初始化bss段 From 5e0f3985ca84cc9d3dd705da211649da0042952a Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Wed, 17 May 2023 18:53:01 +0800 Subject: [PATCH 5/8] =?UTF-8?q?Makefile=E4=B8=ADkill=E4=B8=8D=E5=A5=BD?= =?UTF-8?q?=E4=BD=BF=E4=BA=86,=20=E5=85=88=E5=8E=BB=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch2/os/Makefile b/ch2/os/Makefile index dccc8cc..2b314fb 100644 --- a/ch2/os/Makefile +++ b/ch2/os/Makefile @@ -27,7 +27,7 @@ $(KERNEL_BIN): build_elf @$(OBJCOPY) $(KERNEL_ELF) --strip-all -O binary $@ -debug:build_elf $(KERNEL_BIN) $(SYMBOL_MAP) kill +debug:build_elf $(KERNEL_BIN) $(SYMBOL_MAP) $(QEMU_CMD_PATH) \ -machine virt \ -display none \ From fcf1af84ad8dd808f22e6192fe1d14a7ab9b4682 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Thu, 18 May 2023 08:57:19 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E9=99=B7=E5=85=A5=E4=B8=8A=E4=B8=8B=E6=96=87=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BD=93,=20=E7=94=A8=E6=9D=A5=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E9=99=B7=E5=85=A5=E5=89=8D=E5=AF=84=E5=AD=98=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/src/trap/context.rs | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 ch2/os/src/trap/context.rs diff --git a/ch2/os/src/trap/context.rs b/ch2/os/src/trap/context.rs new file mode 100644 index 0000000..7ed956d --- /dev/null +++ b/ch2/os/src/trap/context.rs @@ -0,0 +1,40 @@ +use riscv::register::sstatus::{self, Sstatus, SPP}; + +/// Trap Context +#[repr(C)] +pub struct TrapContext { + /// 保存了 [0..31] 号寄存器, 其中0/2/4 号寄存器我们不保存, 2有特殊用途 + /// > 其中 [17] 号寄存器保存的是系统调用号 + /// + /// > [10]/[11]/[12] 寄存器保存了系统调用时的3个参数 + /// + /// > [2] 号寄存器因为我们有特殊用途所以也跳过保存, (保存了用户栈)保存了用户 USER_STACK 的 栈顶 + /// + /// > [0] 被硬编码为了0, 不会有变化, 不需要做任何处理 + /// + /// > [4] 除非特殊用途使用它, 一般我们也用不到, 不需要做任何处理 + pub x: [usize; 32], + /// CSR sstatus 保存的是在trap发生之前, cpu处在哪一个特权级 + pub sstatus: Sstatus, + /// CSR sepc 保存的是用户态ecall时 所在的那一行的代码 + pub sepc: usize, +} + +impl TrapContext { + /// 把用户栈的栈顶 保存到 [2] + pub fn set_sp(&mut self, sp: usize) { + self.x[2] = sp; + } + /// init app context + pub fn app_init_context(entry: usize, sp: usize) -> Self { + let mut sstatus = sstatus::read(); // 读取CSR sstatus + sstatus.set_spp(SPP::User); // 设置特权级为用户模式 + let mut cx = Self { + x: [0; 32], + sstatus, + sepc: entry, // 设置代码执行的开头, 将来条入到这里执行 + }; + cx.set_sp(sp); // 设置用户栈的栈顶 + cx // 返回, 外面会恢复完 x[0; 32] 之后最后 sret 根据entry和sstatus 返回 + } +} From a866fea63498369c931eecee154c1214e099b81c Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Thu, 18 May 2023 08:59:47 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E9=99=B7=E5=85=A5=E4=B8=8A=E4=B8=8B=E6=96=87=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BD=93,=20=E7=94=A8=E6=9D=A5=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E9=99=B7=E5=85=A5=E5=89=8D=E5=AF=84=E5=AD=98=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/src/trap/mod.rs | 1 + 1 file changed, 1 insertion(+) create mode 100644 ch2/os/src/trap/mod.rs diff --git a/ch2/os/src/trap/mod.rs b/ch2/os/src/trap/mod.rs new file mode 100644 index 0000000..019f068 --- /dev/null +++ b/ch2/os/src/trap/mod.rs @@ -0,0 +1 @@ +mod context; \ No newline at end of file From 564506fe09a4475160274c243039c8e2b2eaeb43 Mon Sep 17 00:00:00 2001 From: zhangxinyu <840317537@qq.com> Date: Thu, 18 May 2023 18:44:47 +0800 Subject: [PATCH 8/8] =?UTF-8?q?run=5Fnext=5Fapp=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch2/os/src/batch.rs | 69 ++++++++++++++++++++++++++++++++++++++-- ch2/os/src/main.rs | 2 ++ ch2/os/src/trap/mod.rs | 3 +- ch2/os/src/trap/trap.S | 71 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 ch2/os/src/trap/trap.S diff --git a/ch2/os/src/batch.rs b/ch2/os/src/batch.rs index c8c4d72..cd88811 100644 --- a/ch2/os/src/batch.rs +++ b/ch2/os/src/batch.rs @@ -1,6 +1,9 @@ +use core::arch::asm; use lazy_static::*; +use riscv::register::mcause::Trap; use crate::println; use crate::sync::UPSafeCell; +use crate::trap::TrapContext; const USER_STACK_SIZE: usize = 4096 * 2; // 栈大小为8kb const KERNEL_STACK_SIZE: usize = 4096 * 2; @@ -10,7 +13,9 @@ const MAX_APP_NUM: usize = 16; // 系统最大支持的运行程序数量 const APP_BASE_ADDRESS: usize = 0x80400000; // 载入的app的起始的地址 const APP_SIZE_LIMIT: usize = 0x20000; // app的最大的二进制文件能够使用的大小 -// 在此之后应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用 +// 在此之后 应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用(首次运行run_next_app时被接管了 mv sp, a0) +// KERNEL_STACK 保存的是 Trap Context + static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE]; static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE]; @@ -52,13 +57,38 @@ impl AppManager{ println!("[kernel] num_app = {}", self.num_app); for i in 0..self.num_app { println!( - "[kernel] app_{} [{:#x}, {:#x})", + "[kernel] app_{} ({:#x}, {:#x})", i, self.app_start_lis[i], self.app_start_lis[i + 1] ); } } + + // 把app_idx位置的app 加载到指定的内存APP_BASE_ADDRESS位置 + unsafe fn load_app(&self, app_idx: usize){ + if app_idx >= self.num_app{ + panic!("All applications completed!") + } + // 清空app执行区域的内存 + core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, APP_SIZE_LIMIT).fill(0); + + // 得到指定app_idx位置的数据(下一个位置的开始 - 需要运行app的开始 = 需要运行app的内存大小 + let app_src = core::slice::from_raw_parts(self.app_start_lis[app_idx] as *const u8, + self.app_start_lis[app_idx + 1] - self.app_start_lis[app_idx]); + + // 把app的代码 copy到指定的运行的区域 + let app_len = app_src.len(); + if app_len > APP_SIZE_LIMIT { + panic!("app memory overrun!") + } + core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *mut u8, app_len) + .copy_from_slice(app_src); + + // 刷新cache + asm!("fence.i"); + } + } @@ -66,6 +96,41 @@ pub fn init() { APP_MANAGER.exclusive_access().show_app_info(); } +pub fn run_next_app() -> *mut TrapContext{ + // 运行一个新的app + // 把需要执行的指定app, 加载到执行位置APP_BASE_ADDRESS + // app_manager 需要drop 或者在一个作用域中, 因为这个函数不会返回, 后面直接进入用户态了 + { + let mut app_manager = APP_MANAGER.exclusive_access(); + + unsafe{ + app_manager.load_app(app_manager.current_app); + } + app_manager.current_app += 1; + } + + extern "C" { + fn __restore(trap_context_ptr: usize); + } + + unsafe { + // 得到用户栈的栈顶 + let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE; + // 得到用户trap的上下文以及寄存器状态 + let user_trap_context = TrapContext::app_init_context(APP_BASE_ADDRESS, user_stack_top); + + // 把用户trap copy到内核栈, 并把内核栈栈顶返回 + let kernel_stack_top = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE; // 现在栈顶和栈底都在一个内存位置 + let kernel_trap_context_ptr = (kernel_stack_top - core::mem::size_of::()) as * mut TrapContext; // 为trap context 分配栈空间 + + unsafe { + *kernel_trap_context_ptr = user_trap_context; + // 返回现在的内核栈顶 + kernel_trap_context_ptr + } + } +} + diff --git a/ch2/os/src/main.rs b/ch2/os/src/main.rs index 4933aed..38b837a 100644 --- a/ch2/os/src/main.rs +++ b/ch2/os/src/main.rs @@ -10,6 +10,7 @@ pub mod lang_items; pub mod sbi; pub mod batch; pub mod sync; +pub mod trap; // 汇编脚本引入, 调整内核的内存布局之后, 会跳入到 rust_main中执行 global_asm!(include_str!("entry.asm")); @@ -35,6 +36,7 @@ pub fn rust_main(){ println!("boot_stack_top_bound: {:#x}, boot_stack_lower_bound: {:#x}", boot_stack_top_bound as usize, boot_stack_lower_bound as usize); batch::init(); + batch::run_next_app(); } /// ## 初始化bss段 diff --git a/ch2/os/src/trap/mod.rs b/ch2/os/src/trap/mod.rs index 019f068..bc6c71e 100644 --- a/ch2/os/src/trap/mod.rs +++ b/ch2/os/src/trap/mod.rs @@ -1 +1,2 @@ -mod context; \ No newline at end of file +mod context; +pub use context::TrapContext; diff --git a/ch2/os/src/trap/trap.S b/ch2/os/src/trap/trap.S new file mode 100644 index 0000000..66444bd --- /dev/null +++ b/ch2/os/src/trap/trap.S @@ -0,0 +1,71 @@ +.altmacro +.macro SAVE_GP n + sd x\n, \n*8(sp) // 将寄存器 x_n 的值保存到栈空间中 +.endm +.macro LOAD_GP n + ld x\n, \n*8(sp) // 从栈空间中加载寄存器 x_n 的值 +.endm +.section .text // 进入 .text 段 +.globl __alltraps // 声明全局符号 __alltraps +.globl __restore // 声明全局符号 __restore +.align 2 // 对齐到 2^2 = 4 字节 + +__alltraps: // __alltraps 符号的实现 + csrrw sp, sscratch, sp // 交换 sp 和 sscratch 寄存器的值 + # 现在 sp 指向内核栈,sscratch 指向用户栈 + # 在内核栈上分配一个 TrapContext + addi sp, sp, -34*8 // 分配 34*8 字节的空间 + # 保存通用寄存器 + sd x1, 1*8(sp) // 保存寄存器 x1 的值 (这一步是为了跳过x0寄存器, 方便下面循环) + # 跳过 sp(x2),后面会再次保存 + sd x3, 3*8(sp) // 保存寄存器 x3 的值 (这一步是为了跳过x4寄存器, 方便下面循环) + # 跳过 tp(x4),应用程序不使用该寄存器 + # 保存 x5~x31 + .set n, 5 // 定义变量 n 的初始值为 5 + .rept 27 // 循环 27 次 + SAVE_GP %n // 保存寄存器 x_n 的值到栈空间中 + .set n, n+1 // 将 n 加 1 + .endr // 结束指令块 + # 我们可以自由使用 t0/t1/t2,因为它们已保存在内核栈上 + csrr t0, sstatus // 读取 sstatus 寄存器的值 + csrr t1, sepc // 读取 sepc 寄存器的值 + sd t0, 32*8(sp) // 保存 sstatus 寄存器的值到栈空间中 + sd t1, 33*8(sp) // 保存 sepc 寄存器的值到栈空间中 + # 从 sscratch 中读取用户栈,并将其保存到内核栈中 + csrr t2, sscratch // 读取 sscratch 寄存器的值 + sd t2, 2*8(sp) // 保存用户栈的地址到内核栈 trap context中 + # 设置 trap_handler(cx: &mut TrapContext) 的输入参数 + mv a0, sp // 将 TrapContext 的地址赋值给 a0 + call trap_handler // 调用 trap_handler 函# 数 + +__restore: // __restore 符号的实现 + # case1: 开始运行应用程序 + # case2: 从处理完中断后返回 U 级别 + mv sp, a0 // 将 a0 中保存的内核栈地址赋值给 sp 这个首次进入是在内核进入首次进入sp 这里会被修改为KERNEL_STACK_SIZE, 被接管 + + # 恢复 sstatus/sepc + ld t0, 32*8(sp) // 从栈空间中读取 sstatus 寄存器的值 + ld t1, 33*8(sp) // 从栈空间中读取 sepc 寄存器的值 + ld t2, 2*8(sp) // 从栈空间中读取用户栈的栈顶地址 + csrw sstatus, t0 // 恢复 sstatus 寄存器的值 + csrw sepc, t1 // 恢复 sepc 寄存器的值 + csrw sscratch, t2 // 将栈指针 用户栈 的值 临时保存到 sscratch 寄存器中 + # 现在 sp 指向内核栈,sscratch 指向用户栈 + + # 恢复通用寄存器,除了 sp/tp 以外的寄存器 + # 跳过x0 + ld x1, 1*8(sp) // 从栈空间中读取寄存器 x1 的值 + # 跳过x2 + ld x3, 3*8(sp) // 从栈空间中读取寄存器 x3 的值 + # 循环恢复 + .set n, 5 // 定义变量 n 的初始值为 5 + .rept 27 // 循环 27 次 + LOAD_GP %n // 从栈空间中加载寄存器 x_n 的值 + .set n, n+1 // 将 n 加 1 + .endr // 结束指令块 + + # 现在 sp 指向内核栈,sscratch 指向用户栈, 释放内核栈中的中的 TrapContext, 陷入已经执行完成, 即将返回用户态 不需要这个上下文了 + addi sp, sp, 34*8 // 释放 sizeof + + csrrw sp, sscratch, sp // 交换 sp内核栈 和 sscratch用户栈 寄存器的值, 交换之后sscratch保存的是内核栈顶, sp是用户栈 USER_STACK(栈底) 的栈顶 + sret // 返回指令, 根据sstatus(陷入/异常之前的特权级) 和 sepc(陷入/异常 之前的pc)返回 \ No newline at end of file