Add CR3 to Context (x86_64)

master
WangRunji 6 years ago
parent 548951abda
commit 7c7dbc9ded

@ -11,6 +11,7 @@ pub trait InactivePageTable {
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)); fn edit(&mut self, f: impl FnOnce(&mut Self::Active));
unsafe fn activate(&self); unsafe fn activate(&self);
unsafe fn with(&self, f: impl FnOnce()); unsafe fn with(&self, f: impl FnOnce());
fn token(&self) -> usize;
fn alloc_frame() -> Option<PhysAddr>; fn alloc_frame() -> Option<PhysAddr>;
fn dealloc_frame(target: PhysAddr); fn dealloc_frame(target: PhysAddr);
@ -171,22 +172,12 @@ impl<T: InactivePageTable> MemorySet<T> {
pub unsafe fn activate(&self) { pub unsafe fn activate(&self) {
self.page_table.activate(); self.page_table.activate();
} }
pub fn token(&self) -> usize {
self.page_table.token()
}
pub fn kstack_top(&self) -> usize { pub fn kstack_top(&self) -> usize {
self.kstack.top self.kstack.top
} }
pub fn clone(&self) -> Self {
let mut page_table = T::new();
page_table.edit(|pt| {
for area in self.areas.iter() {
area.map::<T>(pt);
}
});
MemorySet {
areas: self.areas.clone(),
page_table,
kstack: T::alloc_stack(),
}
}
pub fn clear(&mut self) { pub fn clear(&mut self) {
let Self { ref mut page_table, ref mut areas, .. } = self; let Self { ref mut page_table, ref mut areas, .. } = self;
page_table.edit(|pt| { page_table.edit(|pt| {
@ -198,9 +189,19 @@ impl<T: InactivePageTable> MemorySet<T> {
} }
} }
impl<T: InactivePageTable> Drop for MemorySet<T> { impl<T: InactivePageTable> Clone for MemorySet<T> {
fn drop(&mut self) { fn clone(&self) -> Self {
self.clear(); let mut page_table = T::new();
page_table.edit(|pt| {
for area in self.areas.iter() {
area.map::<T>(pt);
}
});
MemorySet {
areas: self.areas.clone(),
page_table,
kstack: T::alloc_stack(),
}
} }
} }

@ -64,6 +64,7 @@ impl TrapFrame {
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[repr(C)] #[repr(C)]
struct ContextData { struct ContextData {
cr3: usize,
r15: usize, r15: usize,
r14: usize, r14: usize,
r13: usize, r13: usize,
@ -74,49 +75,22 @@ struct ContextData {
} }
impl ContextData { impl ContextData {
fn new() -> Self { fn new(cr3: usize) -> Self {
let mut context = ContextData::default(); ContextData { rip: forkret as usize, cr3, ..ContextData::default() }
context.rip = forkret as usize;
context
} }
} }
/// 新线程的内核栈初始内容 /// 新线程的内核栈初始内容
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct InitStack { struct InitStack {
context: ContextData, context: ContextData,
trapret: usize, trapret: usize,
tf: TrapFrame, tf: TrapFrame,
} }
impl InitStack { impl InitStack {
pub fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, rsp: usize) -> Self { unsafe fn push_at(self, stack_top: usize) -> Context {
InitStack {
context: ContextData::new(),
trapret: trap_ret as usize,
tf: TrapFrame::new_kernel_thread(entry, arg, rsp),
}
}
pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
InitStack {
context: ContextData::new(),
trapret: trap_ret as usize,
tf: TrapFrame::new_user_thread(entry_addr, rsp, is32),
}
}
pub fn new_fork(tf: &TrapFrame) -> Self {
InitStack {
context: ContextData::new(),
trapret: trap_ret as usize,
tf: {
let mut tf = tf.clone();
tf.rax = 0;
tf
},
}
}
pub unsafe fn push_at(self, stack_top: usize) -> Context {
let ptr = (stack_top as *mut Self).offset(-1); let ptr = (stack_top as *mut Self).offset(-1);
*ptr = self; *ptr = self;
Context(ptr as usize) Context(ptr as usize)
@ -158,6 +132,8 @@ impl Context {
push r13 push r13
push r14 push r14
push r15 push r15
mov r15, cr3
push r15
// Switch stacks // Switch stacks
mov [rdi], rsp // rdi = from_rsp mov [rdi], rsp // rdi = from_rsp
@ -165,6 +141,8 @@ impl Context {
// Save old callee-save registers // Save old callee-save registers
pop r15 pop r15
mov cr3, r15
pop r15
pop r14 pop r14
pop r13 pop r13
pop r12 pop r12
@ -179,4 +157,30 @@ impl Context {
pub unsafe fn null() -> Self { pub unsafe fn null() -> Self {
Context(0) Context(0)
} }
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self {
InitStack {
context: ContextData::new(cr3),
trapret: trap_ret as usize,
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.push_at(kstack_top)
}
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self {
InitStack {
context: ContextData::new(cr3),
trapret: trap_ret as usize,
tf: TrapFrame::new_user_thread(entry_addr, ustack_top, is32),
}.push_at(kstack_top)
}
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self {
InitStack {
context: ContextData::new(cr3),
trapret: trap_ret as usize,
tf: {
let mut tf = tf.clone();
tf.rax = 0;
tf
},
}.push_at(kstack_top)
}
} }

@ -213,6 +213,10 @@ impl InactivePageTable for InactivePageTable0 {
} }
} }
fn token(&self) -> usize {
self.p4_frame.start_address().as_u64() as usize // as CR3
}
fn alloc_frame() -> Option<usize> { fn alloc_frame() -> Option<usize> {
alloc_frame() alloc_frame()
} }

@ -25,8 +25,8 @@ pub fn dealloc_frame(target: usize) {
// alloc from heap // alloc from heap
pub fn alloc_stack() -> Stack { pub fn alloc_stack() -> Stack {
use alloc::boxed::Box; use alloc::boxed::Box;
const STACK_SIZE: usize = 8 * 4096; const STACK_SIZE: usize = 0x8000;
#[repr(align(4096))] #[repr(align(0x8000))]
struct StackData([u8; STACK_SIZE]); struct StackData([u8; STACK_SIZE]);
let data = Box::new(StackData([0; STACK_SIZE])); let data = Box::new(StackData([0; STACK_SIZE]));
let bottom = Box::into_raw(data) as usize; let bottom = Box::into_raw(data) as usize;

@ -11,7 +11,6 @@ pub struct Process {
pub(in process) memory_set: MemorySet, pub(in process) memory_set: MemorySet,
pub(in process) status: Status, pub(in process) status: Status,
pub(in process) context: Context, pub(in process) context: Context,
pub(in process) is_user: bool,
} }
pub type Pid = usize; pub type Pid = usize;
@ -30,8 +29,7 @@ impl Process {
/// Make a new kernel thread /// Make a new kernel thread
pub fn new(name: &str, entry: extern fn(usize) -> !, arg: usize) -> Self { pub fn new(name: &str, entry: extern fn(usize) -> !, arg: usize) -> Self {
let ms = MemorySet::new(); let ms = MemorySet::new();
let data = InitStack::new_kernel_thread(entry, arg, ms.kstack_top()); let context = unsafe { Context::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) };
let context = unsafe { data.push_at(ms.kstack_top()) };
Process { Process {
pid: 0, pid: 0,
@ -40,7 +38,6 @@ impl Process {
memory_set: ms, memory_set: ms,
status: Status::Ready, status: Status::Ready,
context, context,
is_user: false,
} }
} }
@ -55,7 +52,6 @@ impl Process {
memory_set: MemorySet::new(), memory_set: MemorySet::new(),
status: Status::Running, status: Status::Running,
context: unsafe { Context::null() }, // will be set at first schedule context: unsafe { Context::null() }, // will be set at first schedule
is_user: false,
} }
} }
@ -111,8 +107,10 @@ impl Process {
// Allocate kernel stack and push trap frame // Allocate kernel stack and push trap frame
let data = InitStack::new_user_thread(entry_addr, user_stack_top - 8, is32); let context = unsafe {
let context = unsafe { data.push_at(memory_set.kstack_top()) }; Context::new_user_thread(
entry_addr, user_stack_top - 8, memory_set.kstack_top(), is32, memory_set.token())
};
Process { Process {
pid: 0, pid: 0,
@ -121,14 +119,11 @@ impl Process {
memory_set, memory_set,
status: Status::Ready, status: Status::Ready,
context, context,
is_user: true,
} }
} }
/// Fork /// Fork
pub fn fork(&self, tf: &TrapFrame) -> Self { pub fn fork(&self, tf: &TrapFrame) -> Self {
assert!(self.is_user);
// Clone memory set, make a new page table // Clone memory set, make a new page table
let memory_set = self.memory_set.clone(); let memory_set = self.memory_set.clone();
@ -147,9 +142,8 @@ impl Process {
}); });
} }
// Allocate kernel stack and push trap frame // Push context at kstack top
let data = InitStack::new_fork(tf); let context = unsafe { Context::new_fork(tf, memory_set.kstack_top(), memory_set.token()) };
let context = unsafe { data.push_at(memory_set.kstack_top()) };
Process { Process {
pid: 0, pid: 0,
@ -158,7 +152,6 @@ impl Process {
memory_set, memory_set,
status: Status::Ready, status: Status::Ready,
context, context,
is_user: true,
} }
} }

@ -133,8 +133,6 @@ impl Processor {
info!("switch from {} to {}\n rsp: ??? -> {:?}", pid0, pid, to.context); info!("switch from {} to {}\n rsp: ??? -> {:?}", pid0, pid, to.context);
unsafe { unsafe {
// switch page table
to.memory_set.activate();
// FIXME: safely pass MutexGuard // FIXME: safely pass MutexGuard
use core::mem::forget; use core::mem::forget;
super::PROCESSOR.try().unwrap().force_unlock(); super::PROCESSOR.try().unwrap().force_unlock();

@ -3,11 +3,13 @@
//! Based on process mod. //! Based on process mod.
//! Used in the kernel. //! Used in the kernel.
use process::*; use alloc::boxed::Box;
use alloc::BTreeMap;
use core::any::Any;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::ptr; use core::ptr;
use core::time::Duration; use core::time::Duration;
use alloc::boxed::Box; use process::*;
/// Gets a handle to the thread that invokes it. /// Gets a handle to the thread that invokes it.
pub fn current() -> Thread { pub fn current() -> Thread {
@ -37,8 +39,8 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
{ {
info!("spawn:"); info!("spawn:");
use process; use process;
let f = Box::leak(Box::new(f)); let f = Box::into_raw(Box::new(f));
let pid = process::add_kernel_process(kernel_thread_entry::<F, T>, f as *mut _ as usize); let pid = process::add_kernel_process(kernel_thread_entry::<F, T>, f as usize);
return JoinHandle { return JoinHandle {
thread: Thread { pid }, thread: Thread { pid },
mark: PhantomData, mark: PhantomData,

Loading…
Cancel
Save