diff --git a/ch4/os/src/config.rs b/ch4/os/src/config.rs index f351016..87e5fc2 100644 --- a/ch4/os/src/config.rs +++ b/ch4/os/src/config.rs @@ -10,6 +10,18 @@ pub const USER_STACK_SIZE: usize = 4096 * 2; // 每个应用用户态的栈大 pub const KERNEL_STACK_SIZE: usize = 4096 * 2; // 每个应用的内核栈 pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; // __alltraps对齐到了这里, (内核空间和用户空间这里虚拟地址都用这个)虚拟地址最高页 存放跳板, 跳板那一页, 被映射到 strampoline段(trap) 实际的物理地址, 即陷入时 cpu需要跳转的地址 -pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; // 用户 trap context开始的位置 在次高页 +pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; // 用户 trap context开始的位置 在 每个用户程序 它本身地址空间 的次高页 -pub use crate::board::*; \ No newline at end of file +pub use crate::board::*; + + + +/// 得到 "用户程序的内核栈" 的在 内核本身栈中的虚拟位置 +/// 这个在 次高页的下面的某个位置 +/// 每个用户除了分配 KERNEL_STACK_SIZE 大小外, 还额外 增加 一个PAGE_SIZE 放在比栈底要高的地址 用来隔离每个用户内核栈 +pub fn kernel_stack_position(app_id: usize) -> (usize, usize) { + let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE); + // 栈底只需要 KERNEL_STACK_SIZE 即可, + let bottom = top - KERNEL_STACK_SIZE; + (bottom, top) +} diff --git a/ch4/os/src/linker.ld b/ch4/os/src/linker.ld index 099fd87..3b18937 100644 --- a/ch4/os/src/linker.ld +++ b/ch4/os/src/linker.ld @@ -10,6 +10,10 @@ SECTIONS stext = .; /* .text段的开始位置 */ .text : { /* 表示生成一个为 .text的段, 花括号内按照防止顺序表示将输入文件中的哪些段放在 当前.text段中 */ *(.text.entry) /* entry.asm中, 我们自己定义的.text.entry段, 被放在顶部*/ + . = ALIGN(4K); /*4k对齐*/ + strampoline = .; + /* strampoline 段, 将来会被 memory set 导入, 当做跳板最高页vpn的实际物理帧 ppn*/ + *(.text.trampoline); *(.text .text.*) } @@ -31,6 +35,7 @@ SECTIONS . = ALIGN(4K); edata = .; + sbss_with_stack = .; .bss : { *(.bss.stack) /* 全局符号 sbss 和 ebss 分别指向 .bss 段除 .bss.stack 以外的起始和终止地址(.bss.stack是我们在entry.asm中定义的栈) */ sbss = .; diff --git a/ch4/os/src/mm/memory_set.rs b/ch4/os/src/mm/memory_set.rs index 235b97a..926fd10 100644 --- a/ch4/os/src/mm/memory_set.rs +++ b/ch4/os/src/mm/memory_set.rs @@ -1,6 +1,11 @@ use alloc::collections::BTreeMap; +use alloc::sync::Arc; use alloc::vec::Vec; +use core::arch::asm; use bitflags::bitflags; +use lazy_static::lazy_static; +use riscv::register::satp; +use crate::sync::UPSafeCell; use crate::config::{MEMORY_END, PAGE_SIZE, TRAMPOLINE}; use crate::mm::address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum, VPNRange}; use crate::mm::frame_allocator::{frame_alloc, FrameTracker}; @@ -20,6 +25,11 @@ extern "C" { fn ekernel(); fn strampoline(); // 这个符号 在linker.ld 中定义 } +lazy_static! { + /// a memory set instance through lazy_static! managing kernel space + pub static ref KERNEL_SPACE: Arc> = + Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) }); +} // 某逻辑段的映射方式 #[derive(Copy, Clone, PartialEq, Debug)] @@ -164,6 +174,21 @@ impl MemorySet { self.page_table.token() } + // 激活当前地址空间 + pub fn activate(&self) { + // let satp = self.page_table.token(); + // 得到当前地址空间的 页表 的规定格式 + let satp = self.token();; + unsafe { + // 设置satp CSR寄存器为我们 + satp::write(satp); + + // 刷新快表缓存TLB, 这个指令最简单的作用就是清空旧的快表 + // 更深层次其实是一个内存屏障 + asm!("sfence.vma"); + } + } + // 根据 start va 和end va 创建一个 逻辑段类型为逻辑映射, 插入到 当前地址空间 pub fn insert_framed_area(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) { self.push(MapArea::from(start_va, end_va, MapType::Framed, permission), None); diff --git a/ch4/os/src/mm/mod.rs b/ch4/os/src/mm/mod.rs index b373767..5787c05 100644 --- a/ch4/os/src/mm/mod.rs +++ b/ch4/os/src/mm/mod.rs @@ -1,3 +1,5 @@ +use crate::mm::memory_set::KERNEL_SPACE; + pub mod heap_allocator; pub mod address; pub mod frame_allocator; @@ -9,6 +11,8 @@ pub mod memory_set; pub fn init(){ // 开启 内核的内存分配器 heap_allocator::init_heap(); - // 初始化bin测试 物理页帧管理器 + // 初始化并测试 物理页帧管理器 frame_allocator::frame_allocator_test(); + // 激活内核的地址空间 + KERNEL_SPACE.exclusive_access().activate(); } \ No newline at end of file