From 0553d3374d792079f28725902ed5b6a6b0695167 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 27 Apr 2018 21:49:01 +0800 Subject: [PATCH] Can switch between `init` and `idle` process --- src/arch/x86_64/interrupt/handler.rs | 7 +- src/arch/x86_64/interrupt/template.rs | 39 +++++++++ src/io/mod.rs | 3 + src/lib.rs | 24 ++++-- src/process.rs | 116 ++++++++++++++++++-------- 5 files changed, 140 insertions(+), 49 deletions(-) diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index 39aaa37..6810c1f 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -15,7 +15,7 @@ interrupt_error_p!(double_fault, stack, { loop {} }); -interrupt_stack_p!(page_fault, stack, { +interrupt_error_p!(page_fault, stack, { use x86_64::registers::control_regs::cr2; println!("\nEXCEPTION: Page Fault\nAddress: {:#x}", cr2()); stack.dump(); @@ -62,7 +62,7 @@ use spin::Mutex; // FIXME: Deadlock //static TICK: Mutex = Mutex::new(0); -interrupt_stack_p!(timer, stack, { +interrupt_switch!(timer, rsp, { // let mut tick = TICK.lock(); // *tick += 1; // let tick = *tick; @@ -71,9 +71,8 @@ interrupt_stack_p!(timer, stack, { if tick % 100 == 0 { println!("\nInterupt: Timer\ntick = {}", tick); use process; -// process::schedule(stack); + process::schedule(rsp); } - stack.dump(); ack(IRQ_TIMER); }); diff --git a/src/arch/x86_64/interrupt/template.rs b/src/arch/x86_64/interrupt/template.rs index 9b42b36..64451d7 100644 --- a/src/arch/x86_64/interrupt/template.rs +++ b/src/arch/x86_64/interrupt/template.rs @@ -317,6 +317,45 @@ impl Debug for InterruptStackP { } } +#[macro_export] +macro_rules! interrupt_switch { + ($name:ident, $rsp: ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner($rsp: &mut usize) { + $func + } + + // Push scratch registers + scratch_push!(); + preserved_push!(); + fs_push!(); + + // Get reference to stack variables + let mut rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Map kernel +// $crate::arch::x86_64::pti::map(); + + // Call inner rust function + inner(&mut rsp); + + asm!("" : : "{rsp}"(rsp) : : "intel", "volatile"); + + // Unmap kernel +// $crate::arch::x86_64::pti::unmap(); + + // Pop scratch registers and return + fs_pop!(); + preserved_pop!(); + scratch_pop!(); + iret!(); + } + }; +} + #[macro_export] macro_rules! interrupt_stack_p { ($name:ident, $stack: ident, $func:block) => { diff --git a/src/io/mod.rs b/src/io/mod.rs index b1b19af..8e68d5c 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -35,6 +35,9 @@ fn print_in_color(args: fmt::Arguments, color: Color) { // writer.set_color(color); // writer.write_fmt(args).unwrap(); // } + // TODO: 解决死锁问题 + // 若进程在持有锁时被中断,中断处理程序请求输出,就会死锁 + unsafe{ COM1.force_unlock(); } COM1.lock().write_fmt(args).unwrap(); } diff --git a/src/lib.rs b/src/lib.rs index 59109ad..9e4cd4c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,19 +80,27 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { // arch::smp::start_other_cores(&acpi, &mut memory_controller); process::init(&mut memory_controller); - // FIXME: 在用户模式下触发时钟中断,导致GPF -// unsafe{ arch::interrupt::enable(); } + unsafe{ arch::interrupt::enable(); } unsafe{ use arch::syscall; - syscall::switch_to_user(); - println!("Now in user mode"); -// loop{} - syscall::switch_to_kernel(); - println!("Now in kernel mode"); + // 在用户模式下触发时钟中断,会导致GPF + // (可能是由于没有合理分离栈) + no_interrupt!({ + syscall::switch_to_user(); + println!("Now in user mode"); + syscall::switch_to_kernel(); + println!("Now in kernel mode"); + }); } - loop{} + loop{ + println!("init ..."); + let mut i = 0; + while i < 1 << 22 { + i += 1; + } + } test_end!(); unreachable!(); diff --git a/src/process.rs b/src/process.rs index 7d5cde6..03a0d72 100644 --- a/src/process.rs +++ b/src/process.rs @@ -6,29 +6,37 @@ use spin::{Once, Mutex}; /// /// ## 必须实现的特性 /// -/// * Clone: 用于对栈中TrapFrame的替换 /// * Debug: 用于Debug输出 use arch::interrupt::TrapFrame; pub fn init(mc: &mut MemoryController) { - PROCESSOR.call_once(|| {Mutex::new(Processor::new(mc))}); + PROCESSOR.call_once(|| {Mutex::new({ + let mut processor = Processor::new(mc); + let initproc = Process::new_init(mc); + let idleproc = Process::new("idle", idle_thread, mc); + processor.add(initproc); + processor.add(idleproc); + processor + })}); } static PROCESSOR: Once> = Once::new(); /// Called by timer handler in arch -pub fn schedule(trap_frame: &mut TrapFrame) { - PROCESSOR.try().unwrap().lock().schedule(trap_frame); +/// 设置rsp,指向接下来要执行线程的 内核栈顶 +/// 之后中断处理例程会重置rsp,恢复对应线程的上下文 +pub fn schedule(rsp: &mut usize) { + PROCESSOR.try().unwrap().lock().schedule(rsp); } #[derive(Debug)] pub struct Process { pid: Pid, - name: String, + name: &'static str, kstack: Stack, // page_table: Box, status: Status, - trap_frame: TrapFrame, + rsp: usize, } #[derive(Debug)] @@ -45,33 +53,10 @@ type Pid = usize; impl Processor { fn new(mc: &mut MemoryController) -> Self { - let mut processor = Processor { + Processor { procs: BTreeMap::>::new(), current_pid: 0, - }; - let initproc = Box::new(Process{ - pid: 0, - name: String::from("initproc"), - kstack: mc.kernel_stack.take().unwrap(), - status: Status::Running, - trap_frame: TrapFrame::default(), - }); - let idleproc = Box::new(Process{ - pid: 1, - name: String::from("idleproc"), - kstack: mc.alloc_stack(7).unwrap(), - status: Status::Ready, - trap_frame: { - let mut tf = TrapFrame::default(); - tf.iret.cs = 8; - tf.iret.rip = idle_thread as usize; - tf.iret.rflags = 0x282; - tf - }, - }); - processor.procs.insert(0, initproc); - processor.procs.insert(1, idleproc); - processor + } } fn alloc_pid(&self) -> Pid { let mut next: Pid = 0; @@ -84,31 +69,88 @@ impl Processor { } return next; } - fn schedule(&mut self, trap_frame: &mut TrapFrame) { - self.switch(1, trap_frame); + fn add(&mut self, mut process: Box) { + let pid = self.alloc_pid(); + process.pid = pid; + self.procs.insert(pid, process); + } + fn schedule(&mut self, rsp: &mut usize) { + let pid = self.find_next(); + self.switch_to(pid, rsp); + } + fn find_next(&self) -> Pid { + *self.procs.keys() + .find(|&&i| i > self.current_pid) + .unwrap_or(self.procs.keys().nth(0).unwrap()) } - fn switch(&mut self, pid: Pid, trap_frame: &mut TrapFrame) { + fn switch_to(&mut self, pid: Pid, rsp: &mut usize) { + // for debug print + let pid0 = self.current_pid; + let rsp0 = *rsp; + if pid == self.current_pid { return; } { let current = self.procs.get_mut(&self.current_pid).unwrap(); current.status = Status::Ready; + current.rsp = *rsp; } { let process = self.procs.get_mut(&pid).unwrap(); - *trap_frame = process.trap_frame.clone(); + process.status = Status::Running; + *rsp = process.rsp; // TODO switch page table } self.current_pid = pid; + debug!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp); + } +} + +impl Process { + /// Make a new kernel thread + fn new(name: &'static str, entry: extern fn(), mc: &mut MemoryController) -> Box { + let kstack = mc.alloc_stack(7).unwrap(); + let rsp = unsafe{ (kstack.top() as *mut TrapFrame).offset(-1) } as usize; + + let mut tf = unsafe{ &mut *(rsp as *mut TrapFrame) }; + + // TODO: move to arch + *tf = TrapFrame::default(); + tf.iret.cs = 8; + tf.iret.rip = entry as usize; + tf.iret.ss = 24; + tf.iret.rsp = kstack.top(); + tf.iret.rflags = 0x282; + + Box::new(Process { + pid: 0, + name, + kstack, + status: Status::Ready, + rsp, + }) + } + /// Make the first kernel thread `initproc` + /// Should be called only once + fn new_init(mc: &mut MemoryController) -> Box { + assert_has_not_been_called!(); + Box::new(Process { + pid: 0, + name: "init", + kstack: mc.kernel_stack.take().unwrap(), + status: Status::Running, + rsp: 0, // will be set at first schedule + }) } } extern fn idle_thread() { loop { println!("idle ..."); - for i in 0 .. 1 << 20 { - + let mut i = 0; + while i < 1 << 22 { + i += 1; } } } \ No newline at end of file