Merge pull request #10 from HUST-OS/enter_user_mode

Enter user mode
This commit is contained in:
Luo Jia 2021-04-01 01:41:17 -05:00 committed by GitHub
commit 90ba868d31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 356 additions and 145 deletions

View File

@ -55,6 +55,19 @@ SECTIONS
_eshared_text = .;
}
/* 暂时使用,等文件系统完工后移除 */
.user_data : ALIGN(4K) {
_suser_data = .;
*(.user_data .user_data.*)
_euser_data = .;
}
/* 暂时使用,等文件系统完工后移除 */
.user_text : ALIGN(4K) {
_suser_text = .;
*(.user_text .user_text.*)
_euser_text = .;
}
. = ALIGN(4K);
free_memory_start = .;

View File

@ -17,6 +17,7 @@ mod trap;
mod memory;
mod task;
mod hart;
mod user;
#[cfg(not(test))]
global_asm!(include_str!("entry.asm"));
@ -106,42 +107,45 @@ pub extern "C" fn rust_main(hart_id: usize) -> ! {
// todo: 这里要有个地方往tp里写东西目前会出错
let kernel_memory = memory::MemorySet::new_kernel().expect("create kernel memory set");
kernel_memory.activate();
let process = task::Process::new(kernel_memory).expect("create process 1");
// let stack_handle = process.alloc_stack().expect("alloc initial stack");
let _stack_handle = process.alloc_stack().expect("alloc initial stack");
// 尝试进入用户态
user::try_enter_user()
let task_1 = task::KernelTask::new(task_1(), process.clone());
let task_2 = task::KernelTask::new(task_2(), process.clone());
let task_3 = task::KernelTask::new(FibonacciFuture::new(5), process);
// let task_1 = task::KernelTask::new(task_1(), process.clone());
// let task_2 = task::KernelTask::new(task_2(), process.clone());
// let task_3 = task::KernelTask::new(FibonacciFuture::new(5), process);
println!("task_1: {:?}", task_1);
println!("task_2: {:?}", task_2);
println!("task_3: {:?}", task_3);
// println!("task_1: {:?}", task_1);
// println!("task_2: {:?}", task_2);
// println!("task_3: {:?}", task_3);
let shared_scheduler = task::shared_scheduler();
println!("Shared scheduler: {:?}", shared_scheduler);
// let shared_scheduler = task::shared_scheduler();
// println!("Shared scheduler: {:?}", shared_scheduler);
let user_1_memory = memory::MemorySet::new_user().expect("create user 1 memory set");
let process_2 = task::Process::new(user_1_memory).expect("create process 2");
let task_4 = task::user_task::UserTask::new(user_task_1(), process_2);
unsafe {
task::shared_add_task(shared_scheduler, task_4.shared_task_handle()); // 用户任务
task::shared_add_task(shared_scheduler, task_3.shared_task_handle());
task::shared_add_task(shared_scheduler, task_1.shared_task_handle());
}
unsafe {
riscv::register::sscratch::write(0); // todo 寄存器sscratch
riscv::register::sstatus::set_sie() // todo 允许被特权级中断打断
};
// let user_1_memory = memory::MemorySet::new_user().expect("create user 1 memory set");
// let process_2 = task::Process::new(user_1_memory).expect("create process 2");
// let task_4 = task::user_task::UserTask::new(user_task_1(), process_2);
// unsafe {
// task::shared_add_task(shared_scheduler, task_4.shared_task_handle()); // 用户任务
// task::shared_add_task(shared_scheduler, task_3.shared_task_handle());
// task::shared_add_task(shared_scheduler, task_1.shared_task_handle());
// }
// unsafe {
// riscv::register::sscratch::write(0); // todo 寄存器sscratch
// riscv::register::sstatus::set_sie() // todo 允许被特权级中断打断
// };
task::run_until_idle(
|| unsafe { task::shared_pop_task(shared_scheduler) },
|handle| unsafe { task::shared_add_task(shared_scheduler, handle) }
);
// task::run_until_idle(
// || unsafe { task::shared_pop_task(shared_scheduler) },
// |handle| unsafe { task::shared_add_task(shared_scheduler, handle) }
// );
// 关机之前,卸载当前的核。虽然关机后内存已经清空,不是必要,预留未来热加载热卸载处理核的情况
unsafe { hart::KernelHartInfo::unload_hart() };
// 没有任务了,关机
sbi::shutdown()
// // 关机之前,卸载当前的核。虽然关机后内存已经清空,不是必要,预留未来热加载热卸载处理核的情况
// unsafe { hart::KernelHartInfo::unload_hart() };
// // 没有任务了,关机
// sbi::shutdown()
}
fn spawn(future: impl Future<Output = ()> + 'static + Send + Sync) {
@ -189,6 +193,7 @@ use core::future::Future;
use core::task::{Context, Poll};
use core::pin::Pin;
impl Future for FibonacciFuture {
type Output = ();
@ -207,7 +212,3 @@ impl Future for FibonacciFuture {
}
}
}
fn try_enter_user() -> ! {
todo!()
}

View File

@ -1,4 +1,4 @@
use crate::memory::{AddressSpaceId, PhysicalPageNumber, VirtualAddress, VirtualPageNumber, config::PAGE_SIZE, frame::FrameTracker, frame_alloc};
use crate::memory::{AddressSpaceId, PhysicalPageNumber, PhysicalAddress, VirtualAddress, VirtualPageNumber, config::PAGE_SIZE, frame::FrameTracker, frame_alloc};
use super::{Flags, MapType, Segment, page_table::{PageTable, PageTableTracker}, page_table_entry::PageTableEntry};
use alloc::{collections::VecDeque, vec::Vec};
use core::ops::Range;
@ -26,6 +26,7 @@ impl Mapping {
mapped_pairs: VecDeque::new(),
})
}
/// 软件找到虚拟页号对应最终的页表项。这个页表项合上偏移地址,就是物理地址了
pub fn find_or_insert_entry(&mut self, vpn: VirtualPageNumber) -> Option<&mut PageTableEntry> {
let root_table_pa = self.root_ppn.start_address();
@ -75,7 +76,7 @@ impl Mapping {
)
}
/// 插入一项虚拟页号对物理页号的映射关系Some表示成功
fn map_one(&mut self, vpn: VirtualPageNumber, ppn: Option<PhysicalPageNumber>, flags: Flags) -> Option<()> {
pub fn map_one(&mut self, vpn: VirtualPageNumber, ppn: Option<PhysicalPageNumber>, flags: Flags) -> Option<()> {
// 先找到页表项
let entry_mut = self.find_or_insert_entry(vpn)?;
// 要插入映射关系,页表项必须是空的
@ -101,6 +102,31 @@ impl Mapping {
),
}
}
/// 自由映射一个段
pub fn map_defined(
&mut self, va_range: &Range<VirtualAddress>, pa_range: &Range<PhysicalAddress>, flags: Flags
) {
let vpn_range = range_vpn_contains_va(va_range.clone());
let ppn_range = range_vpn_contains_pa(pa_range.clone());
self.map_range(vpn_range, ppn_range, flags);
}
// 映射指定的虚拟页号和物理页号
// 不能指定初始数据
fn map_range(
&mut self,
vpn_range: Range<VirtualPageNumber>,
ppn_range: Range<PhysicalPageNumber>,
flags: Flags
) {
let mut vpn_iter = vpn_step_iter(vpn_range);
let mut ppn_iter = ppn_step_iter(ppn_range);
assert_eq!(vpn_iter.len(), ppn_iter.len());
// todo: 这里应该为 (VpnRangeIter, VpnRangeIter) 实现迭代器
// 不对,这语义太复杂,可能两个区间不相同,这样就会出现问题--luojia65
while let (Some(vpn), Some(ppn)) = (vpn_iter.next(), ppn_iter.next()) {
self.map_one(vpn, Some(ppn), flags);
}
}
// 插入和映射线性的段
fn map_range_linear(
&mut self, vpn_range: Range<VirtualPageNumber>, flags: Flags, init: Option<(&[u8], Range<VirtualAddress>)>
@ -151,7 +177,7 @@ impl Mapping {
Some(allocated_pairs) // todo!
}
/// 把当前的映射保存到satp寄存器
pub fn activate(&self, asid: AddressSpaceId) {
pub fn activate_on(&self, asid: AddressSpaceId) {
use riscv::register::satp::{self, Mode};
let asid = asid.into_inner();
unsafe {
@ -185,6 +211,10 @@ fn range_vpn_contains_va(src: Range<VirtualAddress>) -> Range<VirtualPageNumber>
VirtualPageNumber::floor(src.start)..VirtualPageNumber::ceil(src.end)
}
fn range_vpn_contains_pa(src: Range<PhysicalAddress>) -> Range<PhysicalPageNumber> {
PhysicalPageNumber::floor(src.start)..PhysicalPageNumber::ceil(src.end)
}
// 一个虚拟页号段区间的迭代器
struct VpnRangeIter {
// 区间结束,不包含
@ -193,6 +223,12 @@ struct VpnRangeIter {
current_addr: usize,
}
impl VpnRangeIter {
pub fn len(&self) -> usize {
self.end_addr - self.current_addr
}
}
impl Iterator for VpnRangeIter {
type Item = VirtualPageNumber;
fn next(&mut self) -> Option<Self::Item> {
@ -207,6 +243,34 @@ impl Iterator for VpnRangeIter {
}
}
// 一个物理页号段区间的迭代器
struct PpnRangeIter {
// 区间结束,不包含
end_addr: usize,
// 区间开始,包含
current_addr: usize,
}
impl PpnRangeIter {
pub fn len(&self) -> usize {
self.end_addr - self.current_addr
}
}
impl Iterator for PpnRangeIter {
type Item = PhysicalPageNumber;
fn next(&mut self) -> Option<Self::Item> {
if self.current_addr == self.end_addr {
return None;
}
// 这里只要右移12位即可ceil和floor区别不大
let current_ppn = PhysicalPageNumber::ceil(PhysicalAddress(self.current_addr));
let next_addr = self.current_addr.wrapping_add(PAGE_SIZE);
self.current_addr = next_addr;
Some(current_ppn)
}
}
// 等到Step trait稳定之后可以用trait Step的迭代器实现
// 目前先自己实现迭代器
fn vpn_step_iter(src: Range<VirtualPageNumber>) -> VpnRangeIter {
@ -215,3 +279,28 @@ fn vpn_step_iter(src: Range<VirtualPageNumber>) -> VpnRangeIter {
current_addr: src.start.start_address().0,
}
}
fn ppn_step_iter(src: Range<PhysicalPageNumber>) -> PpnRangeIter {
PpnRangeIter {
end_addr: src.end.start_address().0,
current_addr: src.start.start_address().0,
}
}
// 我觉得应当换一种方式,而不是用这种迭代方法 --luojia65
// impl Iterator for (VpnRangeIter, PpnRangeIter) {
// type Item = (VirtualPageNumber, PhysicalPageNumber);
// // todo: 这里语法应该更严格一点
// fn next(&mut self) -> Option<Self::Item> {
// if self.0.current_addr == self.0.end_addr || self.1.current_addr == self.1.end_addr {
// return None;
// }
// let current_vpn = VirtualPageNumber::ceil(VirtualAddress(self.0.current_addr));
// let next_va = self.0.current_addr.wrapping_add(PAGE_SIZE);
// self.0.current_addr = next_va;
// let current_ppn = PhysicalPageNumber::ceil(PhysicalAddress(self.1.current_addr));
// let next_pa = self.1.current_addr.wrapping_add(PAGE_SIZE);
// self.1.current_addr = next_pa;
// Some(current_vpn, current_ppn)
// }
// }

View File

@ -1,10 +1,8 @@
use crate::memory::{KERNEL_MAP_OFFSET, PhysicalPageNumber, config::{FREE_MEMORY_START, MEMORY_END_ADDRESS, PAGE_SIZE, SWAP_FRAME_VA}};
use crate::memory::{KERNEL_MAP_OFFSET, PhysicalPageNumber, SWAP_CONTEXT_VA, config::{FREE_MEMORY_START, MEMORY_END_ADDRESS, PAGE_SIZE, SWAP_FRAME_VA}};
use crate::memory::{Mapping, MapType, Segment, Flags, VirtualAddress, VirtualPageNumber, PhysicalAddress, FrameTracker, AddressSpaceId};
use alloc::vec::Vec;
use core::ops::Range;
use super::mapping;
/// 一个地址空间中,所有与内存空间有关的信息
#[derive(Debug)]
pub struct MemorySet {
@ -35,6 +33,12 @@ impl MemorySet {
fn _eshared_data();
fn _sshared_text();
fn _eshared_text();
/* 暂时使用,等文件系统完工后移除 */
fn _suser_data();
fn _euser_data();
fn _suser_text();
fn _euser_text();
/* 以上在文件系统完工后移除 */
fn _swap_frame();
}
@ -44,6 +48,8 @@ impl MemorySet {
println!("bss: {:x?}", VirtualAddress(_sbss as usize)..VirtualAddress(_ebss as usize));
println!("shared_data: {:x?}", VirtualAddress(_sshared_data as usize)..VirtualAddress(_eshared_data as usize));
println!("shared_text: {:x?}", VirtualAddress(_sshared_text as usize)..VirtualAddress(_eshared_text as usize));
println!("user_data: {:x?}", VirtualAddress(_suser_data as usize)..VirtualAddress(_euser_data as usize));
println!("user_text: {:x?}", VirtualAddress(_suser_text as usize)..VirtualAddress(_euser_text as usize));
println!("swap frame: {:x?}", VirtualAddress(_swap_frame as usize)..VirtualAddress(_etext as usize));
println!("free: {:x?}", *FREE_MEMORY_START..MEMORY_END_ADDRESS.virtual_address_linear());
@ -53,25 +59,25 @@ impl MemorySet {
Segment {
map_type: MapType::Linear,
range: VirtualAddress(_stext as usize)..VirtualAddress(_swap_frame as usize),
flags: Flags::READABLE | Flags::EXECUTABLE,
flags: Flags::READABLE | Flags::EXECUTABLE
},
// .rodata 段r--
Segment {
map_type: MapType::Linear,
range: VirtualAddress(_srodata as usize)..VirtualAddress(_erodata as usize),
flags: Flags::READABLE,
flags: Flags::READABLE
},
// .data 段rw-
Segment {
map_type: MapType::Linear,
range: VirtualAddress(_sdata as usize)..VirtualAddress(_edata as usize),
flags: Flags::READABLE | Flags::WRITABLE,
flags: Flags::READABLE | Flags::WRITABLE
},
// .bss 段rw-
Segment {
map_type: MapType::Linear,
range: VirtualAddress(_sbss as usize)..VirtualAddress(_ebss as usize),
flags: Flags::READABLE | Flags::WRITABLE,
flags: Flags::READABLE | Flags::WRITABLE
},
// 共享段的内核映射部分
Segment {
@ -84,6 +90,18 @@ impl MemorySet {
range: VirtualAddress(_sshared_text as usize)..VirtualAddress(_eshared_text as usize),
flags: Flags::EXECUTABLE // 没有READABLE
},
// 用户段映射部分
/* 暂时使用,等文件系统完工后移除 */
Segment {
map_type: MapType::Linear,
range: VirtualAddress(_suser_data as usize)..VirtualAddress(_euser_data as usize),
flags: Flags::READABLE | Flags::WRITABLE
},
Segment {
map_type: MapType::Linear,
range: VirtualAddress(_suser_text as usize)..VirtualAddress(_euser_text as usize),
flags: Flags::EXECUTABLE | Flags::READABLE | Flags::WRITABLE
},
// 剩余内存空间rw-
Segment {
map_type: MapType::Linear,
@ -100,14 +118,22 @@ impl MemorySet {
mapping.map_segment(segment, None)?;
}
// 映射 .swap 段
let swap_frame_va = VirtualAddress(_swap_frame as usize);
println!("map _swap_frame: swap_frame_va: {:x?}", swap_frame_va);
mapping.map_segment(&Segment {
map_type: MapType::Linear,
range: swap_frame_va..swap_frame_va + PAGE_SIZE,
flags: Flags::READABLE | Flags::WRITABLE | Flags::EXECUTABLE,
}, None)?;
// 映射 _swap_frame
let swap_frame_va = VirtualAddress(SWAP_FRAME_VA);
let swap_frame_vpn = VirtualPageNumber::floor(swap_frame_va);
let swap_frame_pa = PhysicalAddress((_swap_frame as usize).wrapping_sub(KERNEL_MAP_OFFSET));
let swap_frame_ppn = PhysicalPageNumber::floor(swap_frame_pa);
println!("swap_frame_vpn: {:x?}, swap_frame_ppn: {:x?}", swap_frame_vpn, swap_frame_ppn);
mapping.map_one(swap_frame_vpn, Some(swap_frame_ppn), Flags::EXECUTABLE | Flags::READABLE | Flags::WRITABLE)?;
// // 映射 SwapContext
// let swap_cx_va = VirtualAddress(SWAP_CONTEXT_VA);
// mapping.map_segment(&Segment {
// map_type: MapType::Linear,
// range: swap_cx_va..swap_cx_va + PAGE_SIZE,
// flags: Flags::READABLE | Flags::WRITABLE | Flags::EXECUTABLE,
// }, None)?;
let address_space_id = crate::hart::KernelHartInfo::alloc_address_space_id()?; // todo: 释放asid
println!("Kernel new asid = {:?}", address_space_id);
Some(MemorySet { mapping, segments, allocated_pairs, address_space_id })
@ -116,47 +142,39 @@ impl MemorySet {
pub fn new_user() -> Option<MemorySet> {
// 各个字段的起始和结束点,在链接器脚本中给出
extern "C" {
fn _stext(); fn _etext(); fn _srodata(); fn _erodata();
fn _sdata(); fn _edata(); fn _sbss(); fn _ebss();
fn _suser_text();
fn _euser_text();
fn _suser_data();
fn _euser_data();
fn _swap_frame();
}
// 建立字段
let segments = vec![
Segment { // .text 段r-x
map_type: MapType::Linear,
range: VirtualAddress(_stext as usize)..VirtualAddress(_swap_frame as usize),
flags: Flags::READABLE | Flags::EXECUTABLE,
},
Segment { // .rodata 段r--
map_type: MapType::Linear,
range: VirtualAddress(_srodata as usize)..VirtualAddress(_erodata as usize),
flags: Flags::READABLE,
},
Segment { // .data 段rw-
map_type: MapType::Linear,
range: VirtualAddress(_sdata as usize)..VirtualAddress(_edata as usize),
flags: Flags::READABLE | Flags::WRITABLE,
},
Segment { // .bss 段rw-
map_type: MapType::Linear,
range: VirtualAddress(_sbss as usize)..VirtualAddress(_ebss as usize),
flags: Flags::READABLE | Flags::WRITABLE,
},
];
let mut mapping = Mapping::new_alloc()?;
let allocated_pairs = Vec::new();
for segment in segments.iter() {
mapping.map_segment(segment, None)?;
}
let swap_frame_va = VirtualAddress(_swap_frame as usize);
// 暂时不映射 .user_data 段,映射 .user_text 段
let user_text_len = _euser_text as usize - _suser_text as usize;
let va_range = VirtualAddress(0)..VirtualAddress(user_text_len);
let pa_range = PhysicalAddress((_suser_text as usize).wrapping_sub(KERNEL_MAP_OFFSET))..PhysicalAddress((_euser_text as usize).wrapping_sub(KERNEL_MAP_OFFSET));
mapping.map_defined(&va_range, &pa_range, Flags::EXECUTABLE | Flags::READABLE | Flags::WRITABLE | Flags::USER);
// 映射 _swap_frame
let swap_frame_va = VirtualAddress(SWAP_FRAME_VA);
let swap_frame_vpn = VirtualPageNumber::floor(swap_frame_va);
let swap_frame_pa = VirtualAddress(_swap_frame as usize).physical_address_linear();
let swap_frame_ppn = PhysicalPageNumber::floor(swap_frame_pa);
mapping.map_one(swap_frame_vpn, Some(swap_frame_ppn), Flags::EXECUTABLE | Flags::READABLE | Flags::WRITABLE);
// 映射 SwapContext
let swap_cx_va = VirtualAddress(SWAP_CONTEXT_VA);
mapping.map_segment(&Segment {
map_type: MapType::Linear,
range: swap_frame_va..swap_frame_va + PAGE_SIZE,
flags: Flags::READABLE | Flags::WRITABLE | Flags::EXECUTABLE,
map_type: MapType::Framed,
range: swap_cx_va..swap_cx_va + PAGE_SIZE,
flags: Flags::READABLE | Flags::WRITABLE,
}, None)?;
let address_space_id = crate::hart::KernelHartInfo::alloc_address_space_id()?; // todo: 释放asid
println!("New asid = {:?}", address_space_id);
Some(MemorySet { mapping, segments, allocated_pairs, address_space_id })
// 这里暂时不管 segment 字段
Some(MemorySet { mapping, segments: Vec::new(), allocated_pairs, address_space_id })
}
/// 检测一段内存区域和已有的是否存在重叠区域
pub fn overlap_with(&self, range: Range<VirtualPageNumber>) -> bool {
@ -217,8 +235,9 @@ impl MemorySet {
/// 如果当前页表就是自身,则不会替换,但仍然会刷新 TLB。
pub fn activate(&self) {
println!("Activating memory set in asid {:?}", self.address_space_id);
self.mapping.activate(self.address_space_id)
self.mapping.activate_on(self.address_space_id)
}
}
fn range_vpn_from_range_va(src: &Range<VirtualAddress>) -> Range<VirtualPageNumber> {

View File

@ -2,6 +2,7 @@ use crate::memory::{PhysicalAddress, PhysicalPageNumber};
use bit_field::BitField;
#[derive(Copy, Clone, Default)]
#[repr(C)]
pub struct PageTableEntry(usize);
const FLAG_RANGE: core::ops::Range<usize> = 0..8;

View File

@ -45,7 +45,7 @@ impl Process {
// pub fn process_id(&self) -> ProcessId {
// self.id
// }
/// 得到进程对应的地址空间编号
/// 得到进程*所在*的地址空间编号。进程不*对应*地址空间编号
pub fn address_space_id(&self) -> AddressSpaceId {
self.inner.lock().memory_set.address_space_id
}
@ -58,11 +58,8 @@ impl Process {
flags |= Flags::VALID;
self.inner.lock().memory_set.alloc_page_range(STACK_SIZE, flags)
}
/// 得到进程对应的satp寄存器值
pub fn satp(&self) -> usize {
let asid = self.inner.lock().memory_set.address_space_id;
self.inner.lock().memory_set.mapping.get_satp(asid)
}
// 进程和satp值没有一一对应关系地址空间对应satp值
}
/// 进程的编号

View File

@ -1,5 +1,8 @@
use crate::{hart::KernelHartInfo, memory::VirtualAddress};
// 注意:这个模块是没有文件系统的前提下临时使用的,未来将在用户层的库中提供
// 请记得到时候删除这个模块!这不是协程内核设计的一部分。
/// 用户态任务
///
/// 目前只是暂时设计,将用户态任务硬编码在内核中

View File

@ -112,8 +112,10 @@ impl SwapContext {
#[export_name = "_user_to_supervisor"]
pub unsafe extern "C" fn user_to_supervisor() -> ! {
asm!(
// 交换 a0 和 sscratch原先保存着交换栈的栈顶指针
"csrrw a0, sscratch, a0",
//开始保存 SwapContext
"
sd ra, 40(a0)
@ -177,57 +179,55 @@ pub unsafe extern "C" fn user_to_supervisor() -> ! {
// a1新的 satp 寄存器的值,用于切换地址空间
#[link_section = ".swap"]
#[export_name = "_supervisor_to_user"]
pub unsafe extern "C" fn supervisor_to_user(ctx: *mut SwapContext, satp: usize) -> ! {
asm!("
csrw satp, {satp}
pub unsafe extern "C" fn supervisor_to_user() -> ! {
asm!(
"csrw satp, a1
sfence.vma", // 刷新页表
// 从 SwapContext 中恢复用户的上下文
// 将用户的 a0 寄存器保存在 sscratch 寄存器中,
// 这样子可以在最后一步将它和 a0ctx 进行交换
"
ld t0, 112({ctx})
ld t0, 112(a0)
csrw sscratch, t0
",
// 恢复通用寄存器的上下文
"
ld ra, 40({ctx})
ld sp, 48({ctx})
ld gp, 56({ctx})
ld tp, 64({ctx})
ld t0, 72({ctx})
ld t1, 80({ctx})
ld t2, 88({ctx})
ld s0, 96({ctx})
ld s1, 104({ctx})
ld a1, 120({ctx})
ld a2, 128({ctx})
ld a3, 136({ctx})
ld a4, 144({ctx})
ld a5, 152({ctx})
ld a6, 160({ctx})
ld a7, 168({ctx})
ld s2, 176({ctx})
ld s3, 184({ctx})
ld s4, 192({ctx})
ld s5, 200({ctx})
ld s6, 208({ctx})
ld s7, 216({ctx})
ld s8, 224({ctx})
ld s9, 232({ctx})
ld s10, 240({ctx})
ld s11, 248({ctx})
ld t3, 256({ctx})
ld t4, 264({ctx})
ld t5, 272({ctx})
ld t6, 280({ctx})
ld ra, 40(a0)
ld sp, 48(a0)
ld gp, 56(a0)
ld tp, 64(a0)
ld t0, 72(a0)
ld t1, 80(a0)
ld t2, 88(a0)
ld s0, 96(a0)
ld s1, 104(a0)
ld a1, 120(a0)
ld a2, 128(a0)
ld a3, 136(a0)
ld a4, 144(a0)
ld a5, 152(a0)
ld a6, 160(a0)
ld a7, 168(a0)
ld s2, 176(a0)
ld s3, 184(a0)
ld s4, 192(a0)
ld s5, 200(a0)
ld s6, 208(a0)
ld s7, 216(a0)
ld s8, 224(a0)
ld s9, 232(a0)
ld s10, 240(a0)
ld s11, 248(a0)
ld t3, 256(a0)
ld t4, 264(a0)
ld t5, 272(a0)
ld t6, 280(a0)
",
// 恢复用户的 a0 寄存器,并且保存交换栈顶在 sscratch 寄存器中
"csrrw a0, sscratch, a0",
// 返回到用户态
"sret",
ctx = in(reg) ctx,
satp = in(reg) satp,
options(noreturn)
)
}
@ -236,16 +236,20 @@ use crate::memory::{SWAP_FRAME_VA, SWAP_CONTEXT_VA};
/// 上升到用户态
/// 目前让这个函数接收一个 SwapContext 参数和用户的页表,测试使用
pub fn switch_to_user(context: &SwapContext, satp: usize) -> ! {
#[no_mangle]
pub fn switch_to_user(context: &SwapContext, user_satp: usize) -> ! {
use riscv::register::{sstatus::{self, SPP}, stvec::{self, TrapMode}};
// 关中断
unsafe { sstatus::clear_sie(); }
extern "C" {
fn _swap_frame();
fn _supervisor_to_user();
}
// 用户态发生中断时 pc 将会被设置成此值
let user_trap_va = SWAP_FRAME_VA as usize;
// 该函数最后应该跳转的虚拟地址
let jmp_va = supervisor_to_user as usize - _swap_frame as usize + SWAP_FRAME_VA;
println!("jmp_va = {:#x}", jmp_va);
// println!("jmp_va = {:#x}", jmp_va);
// 设置用户态陷入内核时需要跳转的地址
unsafe { stvec::write(user_trap_va, TrapMode::Direct); }
@ -254,23 +258,35 @@ pub fn switch_to_user(context: &SwapContext, satp: usize) -> ! {
unsafe { sstatus::set_spp(SPP::User); }
// 将 SwapContext.epc 写到 sepc 寄存器
// 这个是用户程序入口
// println!("sepc: {:#x}", context.epc);
riscv::register::sepc::write(context.epc);
// todo: 如何处理 tp 寄存器
// 用户 satp 寄存器
// 需要获取当前任务的页表
let user_satp: usize = satp;
// unsafe {
// asm!(
// "fence.i",
// "li a0, {}",
// "mv a1, {}",
// "jr {}",
// const SWAP_CONTEXT_VA,
// in(reg) user_satp,
// in(reg) jmp_va,
// options(noreturn)
// );
// }
// 上面这样写生产出的汇编好像不太对,因此改为下面这样写
unsafe {
asm!(
"fence.i",
"li a0, {}",
"mv a1, {}",
"jr {}",
const SWAP_CONTEXT_VA,
in(reg) user_satp,
in(reg) jmp_va,
);
llvm_asm!("fence.i" :::: "volatile");
llvm_asm!("jr $0" :: "r"(jmp_va), "{a0}"(SWAP_CONTEXT_VA), "{a1}"(user_satp) :: "volatile");
}
unreachable!()
}
// 打印 satp 寄存器
#[allow(unused)]
fn print_satp(satp: usize) {
use bit_field::BitField;
println!("root ppn: {:#x}", &satp.get_bits(0..44));
}

View File

@ -0,0 +1,72 @@
/// 临时的用户态程序和数据
use crate::memory;
use crate::trap;
use crate::task;
// 尝试进入用户态
pub fn try_enter_user() -> ! {
extern {
// 用户陷入内核时候的中断处理函数
fn _test_user_trap();
// 用户程序入口点
fn _test_user_entry();
}
println!("_test_user_trap: {:#x}, _test_user_entry: {:#x}", _test_user_trap as usize, _test_user_entry as usize);
// 创建一个用户态映射
let user_memory = memory::MemorySet::new_user().unwrap();
// 存放用户特权级切换上下文的虚拟地址
let swap_cx_va = memory::VirtualAddress(memory::SWAP_CONTEXT_VA);
// 存放用户特权级切换上下文的虚拟页号
let swap_cx_vpn = memory::VirtualPageNumber::floor(swap_cx_va);
// 获取存放用户特权级切换上下文的物理页号
let swap_cx_ppn = user_memory.mapping
.translate(swap_cx_vpn)
.unwrap()
.page_number();
// println!("swap_cx_ppn: {:x?}", swap_cx_ppn);
// 将物理页号转换为裸指针
let swap_cx = unsafe { (swap_cx_ppn.start_address().0.wrapping_add(memory::KERNEL_MAP_OFFSET) as *mut trap::SwapContext).as_mut().unwrap() };
// println!("swap_cx_va: {:#x}, swap_cx_pa: {:#x}", memory::SWAP_CONTEXT_VA, swap_cx_ppn.start_address().0.wrapping_add(memory::KERNEL_MAP_OFFSET));
// 用户态程序入口,这里将映射到的物理页号打印出来
let user_entry_va = memory::VirtualAddress(0);
let user_entry_vpn = memory::VirtualPageNumber::floor(user_entry_va);
let user_entry_ppn = user_memory.mapping
.translate(user_entry_vpn)
.unwrap()
.page_number();
println!("user_entry_ppn: {:x?}", user_entry_ppn);
// let read_user_va: &mut [u16; 2] = unsafe {user_entry_ppn.start_address().deref_linear_static() };
// println!("code in user text:");
// for code in read_user_va {
// println!("{:#x}", &code);
// }
// 获取用户的satp寄存器
let user_satp = user_memory.mapping.get_satp(user_memory.address_space_id);
let process = task::Process::new(user_memory).unwrap();
// 获取内核的satp寄存器
let kernel_satp = riscv::register::satp::read().bits();
// 往 SwapContext 写东西
// _test_user_entry 由虚拟地址 0 映射到真实物理地址
*swap_cx = trap::SwapContext::new_to_user(
kernel_satp, 0, 0, 0, 0, _test_user_trap as usize);
// println!("swap_cx.epc: {:#x}", swap_cx.epc);
// println!("swap_cx.trap_handler: {:#x}", swap_cx.user_trap_handler);
trap::switch_to_user(swap_cx, user_satp)
}
// 测试用的中断处理函数,用户态发生中断会陷入到这里
#[export_name = "_test_user_trap"]
pub extern "C" fn test_user_trap() {
println!("trap from user");
loop {}
}
// 测试用的用户程序入口
#[export_name = "_test_user_entry"]
#[link_section = ".user_text"]
pub extern "C" fn test_user_entry() {
loop {}
}