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));
unsafe fn activate(&self);
unsafe fn with(&self, f: impl FnOnce());
fn token(&self) -> usize;
fn alloc_frame() -> Option<PhysAddr>;
fn dealloc_frame(target: PhysAddr);
@ -171,22 +172,12 @@ impl<T: InactivePageTable> MemorySet<T> {
pub unsafe fn activate(&self) {
self.page_table.activate();
}
pub fn token(&self) -> usize {
self.page_table.token()
}
pub fn kstack_top(&self) -> usize {
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) {
let Self { ref mut page_table, ref mut areas, .. } = self;
page_table.edit(|pt| {
@ -198,9 +189,19 @@ impl<T: InactivePageTable> MemorySet<T> {
}
}
impl<T: InactivePageTable> Drop for MemorySet<T> {
fn drop(&mut self) {
self.clear();
impl<T: InactivePageTable> Clone for MemorySet<T> {
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(),
}
}
}

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

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

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

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

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

Loading…
Cancel
Save