HUGE: Impl switch() like ucore/xv6.

toolchain_update
WangRunji 7 years ago
parent 25d459f389
commit 64b3716c92

@ -19,12 +19,15 @@ __alltraps:
push r15 push r15
mov rdi, rsp mov rdi, rsp
; extern fn rust_trap(rsp) -> rsp
extern rust_trap extern rust_trap
call rust_trap call rust_trap
mov rsp, rax global trap_ret
trap_ret:
mov rdi, rsp
extern set_return_rsp
call set_return_rsp
pop r15 pop r15
pop r14 pop r14

@ -24,7 +24,8 @@
use super::TrapFrame; use super::TrapFrame;
#[no_mangle] #[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) -> usize { pub extern fn rust_trap(tf: &mut TrapFrame) {
trace!("Interrupt: {:#x}", tf.trap_num);
// Dispatch // Dispatch
match tf.trap_num as u8 { match tf.trap_num as u8 {
T_BRKPT => breakpoint(), T_BRKPT => breakpoint(),
@ -53,15 +54,8 @@ pub extern fn rust_trap(tf: &mut TrapFrame) -> usize {
_ => panic!("Unhandled interrupt {:x}", tf.trap_num), _ => panic!("Unhandled interrupt {:x}", tf.trap_num),
} }
let mut rsp = tf as *const _ as usize;
use process::PROCESSOR; use process::PROCESSOR;
PROCESSOR.try().unwrap().lock().schedule(&mut rsp); PROCESSOR.try().unwrap().lock().schedule();
// Set return rsp if to user
let tf = unsafe { &*(rsp as *const TrapFrame) };
set_return_rsp(tf);
rsp
} }
fn breakpoint() { fn breakpoint() {
@ -144,13 +138,19 @@ fn syscall32(tf: &mut TrapFrame) {
fn error(tf: &TrapFrame) { fn error(tf: &TrapFrame) {
use process::PROCESSOR; use process::PROCESSOR;
let mut processor = PROCESSOR.try().unwrap().lock(); if let Some(processor) = PROCESSOR.try() {
let pid = processor.current_pid(); let mut processor = processor.lock();
error!("Process {} error:\n{:#x?}", pid, tf); let pid = processor.current_pid();
processor.exit(pid, 0x100); // TODO: Exit code for error error!("Process {} error:\n{:#x?}", pid, tf);
processor.exit(pid, 0x100); // TODO: Exit code for error
} else {
error!("Exception {:#x} when processor not inited\n{:#x?}", tf.trap_num, tf);
loop {}
}
} }
fn set_return_rsp(tf: &TrapFrame) { #[no_mangle]
pub extern fn set_return_rsp(tf: &TrapFrame) {
use arch::gdt::Cpu; use arch::gdt::Cpu;
use core::mem::size_of; use core::mem::size_of;
if tf.cs & 0x3 == 3 { if tf.cs & 0x3 == 3 {

@ -5,8 +5,8 @@ pub mod consts;
mod handler; mod handler;
mod trapframe; mod trapframe;
pub use self::trapframe::TrapFrame; pub use self::trapframe::*;
pub use self::handler::rust_trap; pub use self::handler::*;
#[inline(always)] #[inline(always)]
pub unsafe fn enable() { pub unsafe fn enable() {

@ -1,4 +1,5 @@
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
#[repr(C)]
pub struct TrapFrame { pub struct TrapFrame {
// Pushed by __alltraps at 'trap.asm' // Pushed by __alltraps at 'trap.asm'
pub r15: usize, pub r15: usize,
@ -34,7 +35,7 @@ pub struct TrapFrame {
/// 用于在内核栈中构造新线程的中断帧 /// 用于在内核栈中构造新线程的中断帧
impl TrapFrame { impl TrapFrame {
pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self { fn new_kernel_thread(entry: extern fn() -> !, rsp: usize) -> Self {
use arch::gdt; use arch::gdt;
let mut tf = TrapFrame::default(); let mut tf = TrapFrame::default();
tf.cs = gdt::KCODE_SELECTOR.0 as usize; tf.cs = gdt::KCODE_SELECTOR.0 as usize;
@ -44,7 +45,7 @@ impl TrapFrame {
tf.rflags = 0x282; tf.rflags = 0x282;
tf tf
} }
pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self { fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
use arch::gdt; use arch::gdt;
let mut tf = TrapFrame::default(); let mut tf = TrapFrame::default();
tf.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize; tf.cs = if is32 { gdt::UCODE32_SELECTOR.0 } else { gdt::UCODE_SELECTOR.0 } as usize;
@ -55,3 +56,108 @@ impl TrapFrame {
tf tf
} }
} }
#[derive(Debug, Default)]
#[repr(C)]
struct Context {
r15: usize,
r14: usize,
r13: usize,
r12: usize,
rbp: usize,
rbx: usize,
rip: usize,
}
impl Context {
fn new() -> Self {
let mut context = Context::default();
context.rip = forkret as usize;
context
}
}
/// 新线程的内核栈初始内容
#[derive(Debug)]
#[repr(C)]
pub struct InitStack {
context: Context,
trapret: usize,
tf: TrapFrame,
}
impl InitStack {
pub fn new_kernel_thread(entry: extern fn() -> !, rsp: usize) -> Self {
InitStack {
context: Context::new(),
trapret: trap_ret as usize,
tf: TrapFrame::new_kernel_thread(entry, rsp),
}
}
pub fn new_user_thread(entry_addr: usize, rsp: usize, is32: bool) -> Self {
InitStack {
context: Context::new(),
trapret: trap_ret as usize,
tf: TrapFrame::new_user_thread(entry_addr, rsp, is32),
}
}
pub fn new_fork(tf: &TrapFrame) -> Self {
InitStack {
context: Context::new(),
trapret: trap_ret as usize,
tf: {
let mut tf = tf.clone();
tf.rax = 0;
tf
},
}
}
}
extern {
fn trap_ret();
}
/// The entry point of new thread
extern fn forkret() {
debug!("forkret");
// Will return to `trapret`
}
/// Switch to another kernel thread.
///
/// Defined in `trap.asm`.
///
/// Push all callee-saved registers at the current kernel stack.
/// Store current rsp at `from_rsp`. Switch kernel stack to `to_rsp`.
/// Pop all callee-saved registers, then return to the target.
#[naked]
pub unsafe extern fn switch(from_rsp: &mut usize, to_rsp: usize) {
asm!(
"
// push rip (by caller)
// Save old callee-save registers
push rbx
push rbp
push r12
push r13
push r14
push r15
// Switch stacks
mov [rdi], rsp // rdi = from_rsp
mov rsp, rsi // rsi = to_rsp
// Save old callee-save registers
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
// pop rip
ret"
: : : : "intel" "volatile" )
}

@ -59,6 +59,7 @@ mod arch;
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
arch::cpu::init(); arch::cpu::init();
arch::idt::init();
io::init(); io::init();
// ATTENTION: we have a very small stack and no guard page // ATTENTION: we have a very small stack and no guard page
@ -70,7 +71,6 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
let mut memory_controller = memory::init(boot_info); let mut memory_controller = memory::init(boot_info);
arch::gdt::init(); arch::gdt::init();
arch::idt::init();
test!(cow); test!(cow);
test!(global_allocator); test!(global_allocator);
@ -127,7 +127,7 @@ pub extern "C" fn other_main() -> ! {
loop {} loop {}
} }
pub use arch::interrupt::rust_trap; pub use arch::interrupt::{rust_trap, set_return_rsp};
use linked_list_allocator::LockedHeap; use linked_list_allocator::LockedHeap;

@ -2,7 +2,6 @@ use memory::MemoryController;
use spin::{Once, Mutex}; use spin::{Once, Mutex};
use core::slice; use core::slice;
use alloc::String; use alloc::String;
use arch::interrupt::TrapFrame;
use self::process::*; use self::process::*;
pub use self::processor::*; pub use self::processor::*;
@ -26,7 +25,7 @@ pub fn init(mut mc: MemoryController) {
pub static PROCESSOR: Once<Mutex<Processor>> = Once::new(); pub static PROCESSOR: Once<Mutex<Processor>> = Once::new();
pub static MC: Once<Mutex<MemoryController>> = Once::new(); pub static MC: Once<Mutex<MemoryController>> = Once::new();
extern fn idle_thread() { extern fn idle_thread() -> ! {
loop { loop {
println!("idle ..."); println!("idle ...");
let mut i = 0; let mut i = 0;

@ -3,6 +3,7 @@ use memory::{self, Stack, InactivePageTable};
use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2}; use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2};
use core::slice; use core::slice;
use alloc::{rc::Rc, String}; use alloc::{rc::Rc, String};
use arch::interrupt::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Process { pub struct Process {
@ -34,10 +35,10 @@ pub enum Status {
impl Process { impl Process {
/// Make a new kernel thread /// Make a new kernel thread
pub fn new(name: &str, entry: extern fn(), mc: &mut MemoryController) -> Self { pub fn new(name: &str, entry: extern fn() -> !, mc: &mut MemoryController) -> Self {
let kstack = mc.alloc_stack(7).unwrap(); let kstack = mc.alloc_stack(7).unwrap();
let tf = TrapFrame::new_kernel_thread(entry, kstack.top()); let data = InitStack::new_kernel_thread(entry, kstack.top());
let rsp = kstack.push_at_top(tf); let rsp = kstack.push_at_top(data);
Process { Process {
pid: 0, pid: 0,
@ -124,7 +125,7 @@ impl Process {
// Allocate kernel stack and push trap frame // Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap(); let kstack = mc.alloc_stack(7).unwrap();
let tf = TrapFrame::new_user_thread(entry_addr, user_stack_top - 8, is32); let tf = InitStack::new_user_thread(entry_addr, user_stack_top - 8, is32);
let rsp = kstack.push_at_top(tf); let rsp = kstack.push_at_top(tf);
trace!("rsp = {:#x}", rsp); trace!("rsp = {:#x}", rsp);
@ -165,9 +166,8 @@ impl Process {
// Allocate kernel stack and push trap frame // Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap(); let kstack = mc.alloc_stack(7).unwrap();
let mut tf = tf.clone(); let data = InitStack::new_fork(tf);
tf.rax = 0; // sys_fork return 0 for child let rsp = kstack.push_at_top(data);
let rsp = kstack.push_at_top(tf);
Process { Process {
pid: 0, pid: 0,

@ -4,6 +4,7 @@ use super::process::*;
use core::cell::RefCell; use core::cell::RefCell;
use core::fmt::{Debug, Formatter, Error}; use core::fmt::{Debug, Formatter, Error};
use util::{EventHub, GetMut2}; use util::{EventHub, GetMut2};
use arch::interrupt::*;
pub struct Processor { pub struct Processor {
procs: BTreeMap<Pid, Process>, procs: BTreeMap<Pid, Process>,
@ -81,12 +82,12 @@ impl Processor {
/// Called every interrupt end /// Called every interrupt end
/// Do schedule ONLY IF current status != Running /// Do schedule ONLY IF current status != Running
pub fn schedule(&mut self, rsp: &mut usize) { pub fn schedule(&mut self) {
if self.current().status == Status::Running { if self.current().status == Status::Running {
return; return;
} }
let pid = self.next.take().unwrap_or_else(|| self.find_next()); let pid = self.next.take().unwrap_or_else(|| self.find_next());
self.switch_to(pid, rsp); self.switch_to(pid);
} }
fn find_next(&self) -> Pid { fn find_next(&self) -> Pid {
@ -99,10 +100,9 @@ impl Processor {
/// Switch process to `pid`, switch page table if necessary. /// Switch process to `pid`, switch page table if necessary.
/// Store `rsp` and point it to target kernel stack. /// Store `rsp` and point it to target kernel stack.
/// The current status must be set before, and not be `Running`. /// The current status must be set before, and not be `Running`.
fn switch_to(&mut self, pid: Pid, rsp: &mut usize) { fn switch_to(&mut self, pid: Pid) {
// for debug print // for debug print
let pid0 = self.current_pid; let pid0 = self.current_pid;
let rsp0 = *rsp;
if pid == self.current_pid { if pid == self.current_pid {
return; return;
@ -111,14 +111,9 @@ impl Processor {
let (from, to) = self.procs.get_mut2(pid0, pid); let (from, to) = self.procs.get_mut2(pid0, pid);
// set `from`
assert_ne!(from.status, Status::Running); assert_ne!(from.status, Status::Running);
from.rsp = *rsp;
// set `to`
assert_eq!(to.status, Status::Ready); assert_eq!(to.status, Status::Ready);
to.status = Status::Running; to.status = Status::Running;
*rsp = to.rsp;
// switch page table // switch page table
if from.is_user || to.is_user { if from.is_user || to.is_user {
@ -139,7 +134,11 @@ impl Processor {
unsafe { *(addr as *mut usize) = value; } unsafe { *(addr as *mut usize) = value; }
} }
info!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp); info!("Processor: switch from {} to {}\n rsp: ??? -> {:#x}", pid0, pid, to.rsp);
unsafe {
super::PROCESSOR.try().unwrap().force_unlock();
switch(&mut from.rsp, to.rsp);
}
} }
fn get(&self, pid: Pid) -> &Process { fn get(&self, pid: Pid) -> &Process {

Loading…
Cancel
Save