From 69f6f4070ea42fdb0e248ada29fbb7a7857b8bcc Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 18 Apr 2018 21:53:39 +0800 Subject: [PATCH 1/7] Add IRQ handler for ToUser, ToKernel, GPF, Syscall. Now trigger ToUser interrupt will cause GPF. --- src/arch/x86_64/gdt.rs | 4 +--- src/arch/x86_64/idt.rs | 4 ++++ src/arch/x86_64/interrupt/irq.rs | 28 ++++++++++++++++++++++++++++ src/consts.rs | 3 +++ src/lib.rs | 5 +++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index a4cee8f..2db9cca 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -32,8 +32,7 @@ pub fn init() { let mut tss_selector = SegmentSelector(0); let gdt = Box::new({ let mut gdt = Gdt::new(); - gdt.add_entry(GNULL); - code_selector = + code_selector = gdt.add_entry(KCODE); gdt.add_entry(UCODE); gdt.add_entry(KDATA); @@ -55,7 +54,6 @@ pub fn init() { pub const DOUBLE_FAULT_IST_INDEX: usize = 0; // Copied from xv6 x86_64 -const GNULL: Descriptor = Descriptor::UserSegment(0); const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index e2d412b..f08428a 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -12,10 +12,14 @@ pub fn init() { let mut idt = Idt::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); idt.double_fault.set_handler_fn(double_fault_handler); + idt.general_protection_fault.set_handler_fn(general_protection_fault_handler); idt[(T_IRQ0 + IRQ_COM1) as usize].set_handler_fn(com1_handler); idt[(T_IRQ0 + IRQ_COM2) as usize].set_handler_fn(com2_handler); idt[(T_IRQ0 + IRQ_KBD) as usize].set_handler_fn(keyboard_handler); idt[(T_IRQ0 + IRQ_TIMER) as usize].set_handler_fn(timer_handler); + idt[T_SWITCH_TOU as usize].set_handler_fn(to_user_handler); + idt[T_SWITCH_TOK as usize].set_handler_fn(to_kernel_handler); + idt[T_SYSCALL as usize].set_handler_fn(syscall_handler); unsafe { idt.page_fault.set_handler_fn(page_fault_handler) .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 1b5523b..b875805 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -22,6 +22,12 @@ pub extern "x86-interrupt" fn page_fault_handler( loop {} } +pub extern "x86-interrupt" fn general_protection_fault_handler( + stack_frame: &mut ExceptionStackFrame, error_code: u64) +{ + println!("\nEXCEPTION: General Protection Fault\n{:#?}\nErrorCode: {:#x}", stack_frame, error_code); +} + #[cfg(feature = "use_apic")] use arch::driver::apic::ack; #[cfg(not(feature = "use_apic"))] @@ -70,4 +76,26 @@ pub extern "x86-interrupt" fn timer_handler( println!("\nInterupt: Timer\ntick = {}", tick); } ack(IRQ_TIMER); +} + +pub extern "x86-interrupt" fn to_user_handler( + stack_frame: &mut ExceptionStackFrame) +{ + println!("\nInterupt: To User"); + stack_frame.code_segment = 16; + stack_frame.stack_segment = 32; +} + +pub extern "x86-interrupt" fn to_kernel_handler( + stack_frame: &mut ExceptionStackFrame) +{ + println!("\nInterupt: To Kernel"); + stack_frame.code_segment = 8; + stack_frame.stack_segment = 24; +} + +pub extern "x86-interrupt" fn syscall_handler( + stack_frame: &mut ExceptionStackFrame) +{ + println!("\nInterupt: Syscall"); } \ No newline at end of file diff --git a/src/consts.rs b/src/consts.rs index 67ab9b6..19f5cb3 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -104,4 +104,7 @@ pub mod irq { pub const IRQ_IDE : u8 = 14; pub const IRQ_ERROR : u8 = 19; pub const IRQ_SPURIOUS : u8 = 31; + pub const T_SYSCALL : u8 = 0x80; // SYSCALL, ONLY FOR THIS PROJ + pub const T_SWITCH_TOU : u8 = 120; // user/kernel switch + pub const T_SWITCH_TOK : u8 = 121; // user/kernel switch } diff --git a/src/lib.rs b/src/lib.rs index 3affcd9..fc4f920 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![feature(abi_x86_interrupt)] #![feature(iterator_step_by)] #![feature(unboxed_closures)] +#![feature(asm)] #![no_std] @@ -21,6 +22,7 @@ extern crate spin; extern crate multiboot2; #[macro_use] extern crate bitflags; +#[macro_use] extern crate x86_64; #[macro_use] extern crate once; @@ -74,6 +76,9 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { arch::smp::start_other_cores(&acpi, &mut memory_controller); unsafe{ arch::interrupt::enable(); } + + unsafe{ int!(120); } // to user + loop{} test_end!(); From 0539f8673e3db2cb7f6bfcd5dd9ba7884187693a Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 26 Apr 2018 01:00:32 +0800 Subject: [PATCH 2/7] Rewrite interrupt handlers using Redox style. Prepare for saving context. --- src/arch/x86_64/driver/apic/ioapic.rs | 2 +- src/arch/x86_64/driver/keyboard/mod.rs | 2 +- src/arch/x86_64/driver/serial.rs | 3 +- src/arch/x86_64/gdt.rs | 7 +- src/arch/x86_64/idt.rs | 32 -- src/arch/x86_64/idt/idt.rs | 104 +++++++ src/arch/x86_64/idt/mod.rs | 33 +++ src/arch/x86_64/interrupt/consts.rs | 31 ++ src/arch/x86_64/interrupt/handler.rs | 85 ++++++ src/arch/x86_64/interrupt/irq.rs | 101 ------- src/arch/x86_64/interrupt/mod.rs | 3 +- src/arch/x86_64/interrupt/template.rs | 394 +++++++++++++++++++++++++ src/consts.rs | 14 - src/io/mod.rs | 10 +- src/lib.rs | 1 + 15 files changed, 659 insertions(+), 163 deletions(-) delete mode 100644 src/arch/x86_64/idt.rs create mode 100644 src/arch/x86_64/idt/idt.rs create mode 100644 src/arch/x86_64/idt/mod.rs create mode 100644 src/arch/x86_64/interrupt/consts.rs create mode 100644 src/arch/x86_64/interrupt/handler.rs delete mode 100644 src/arch/x86_64/interrupt/irq.rs create mode 100644 src/arch/x86_64/interrupt/template.rs diff --git a/src/arch/x86_64/driver/apic/ioapic.rs b/src/arch/x86_64/driver/apic/ioapic.rs index c123dba..91f9797 100644 --- a/src/arch/x86_64/driver/apic/ioapic.rs +++ b/src/arch/x86_64/driver/apic/ioapic.rs @@ -6,7 +6,7 @@ use syscall::io::{Io, Mmio}; use bit_field::BitField; -use consts::irq::T_IRQ0; +use arch::interrupt::consts::T_IRQ0; use spin::Mutex; pub fn init(ioapic_id: u8) diff --git a/src/arch/x86_64/driver/keyboard/mod.rs b/src/arch/x86_64/driver/keyboard/mod.rs index d922bea..396d5d0 100644 --- a/src/arch/x86_64/driver/keyboard/mod.rs +++ b/src/arch/x86_64/driver/keyboard/mod.rs @@ -1,7 +1,7 @@ pub fn init() { assert_has_not_been_called!("keyboard::init must be called only once"); - use consts::irq::*; + use arch::interrupt::consts::*; use arch::interrupt::enable_irq; enable_irq(IRQ_KBD); } diff --git a/src/arch/x86_64/driver/serial.rs b/src/arch/x86_64/driver/serial.rs index 9895099..2e98289 100644 --- a/src/arch/x86_64/driver/serial.rs +++ b/src/arch/x86_64/driver/serial.rs @@ -12,8 +12,7 @@ pub fn init() { COM1.lock().init(); COM2.lock().init(); - use consts::irq::*; - use arch::interrupt::enable_irq; + use arch::interrupt::{enable_irq, consts::{IRQ_COM1, IRQ_COM2}}; enable_irq(IRQ_COM1); enable_irq(IRQ_COM2); } diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index 2db9cca..5d2f8b1 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -13,12 +13,7 @@ pub fn init() { use x86_64::instructions::segmentation::set_cs; use x86_64::instructions::tables::load_tss; - struct DoubleFaultStack { - space: [u8; 4096] - } - let double_fault_stack_top = Box::into_raw(Box::new( - DoubleFaultStack{space: [0; 4096]} - )) as usize + 4096; + let double_fault_stack_top = Box::into_raw(Box::new([0u8; 4096])) as usize + 4096; let mut tss = Box::new({ let mut tss = TaskStateSegment::new(); diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs deleted file mode 100644 index f08428a..0000000 --- a/src/arch/x86_64/idt.rs +++ /dev/null @@ -1,32 +0,0 @@ -use x86_64::structures::idt::Idt; -use spin::Once; -use alloc::boxed::Box; - -/// Alloc IDT at kernel heap, then init and load it. -pub fn init() { - let idt = Box::new({ - use arch::interrupt::irq::*; - use consts::irq::*; - use arch::gdt::DOUBLE_FAULT_IST_INDEX; - - let mut idt = Idt::new(); - idt.breakpoint.set_handler_fn(breakpoint_handler); - idt.double_fault.set_handler_fn(double_fault_handler); - idt.general_protection_fault.set_handler_fn(general_protection_fault_handler); - idt[(T_IRQ0 + IRQ_COM1) as usize].set_handler_fn(com1_handler); - idt[(T_IRQ0 + IRQ_COM2) as usize].set_handler_fn(com2_handler); - idt[(T_IRQ0 + IRQ_KBD) as usize].set_handler_fn(keyboard_handler); - idt[(T_IRQ0 + IRQ_TIMER) as usize].set_handler_fn(timer_handler); - idt[T_SWITCH_TOU as usize].set_handler_fn(to_user_handler); - idt[T_SWITCH_TOK as usize].set_handler_fn(to_kernel_handler); - idt[T_SYSCALL as usize].set_handler_fn(syscall_handler); - unsafe { - idt.page_fault.set_handler_fn(page_fault_handler) - .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); - } - idt - }); - let idt = unsafe{ &*Box::into_raw(idt) }; - - idt.load(); -} \ No newline at end of file diff --git a/src/arch/x86_64/idt/idt.rs b/src/arch/x86_64/idt/idt.rs new file mode 100644 index 0000000..d8af161 --- /dev/null +++ b/src/arch/x86_64/idt/idt.rs @@ -0,0 +1,104 @@ +// Following copied from crate `x86_64` + +use core::ops::{Index, IndexMut}; + +pub struct Idt { + entries: [IdtEntry; 256], +} + +impl Idt { + pub const fn new() -> Idt { + Idt {entries: [IdtEntry::new(); 256]} + } + pub fn load(&'static self) { + use x86_64::instructions::tables::{DescriptorTablePointer, lidt}; + use core::mem::size_of; + + let ptr = DescriptorTablePointer { + base: self as *const _ as u64, + limit: (size_of::() - 1) as u16, + }; + + unsafe { lidt(&ptr) }; + } +} + +impl Index for Idt { + type Output = IdtEntry; + fn index(&self, index: u8) -> &Self::Output { + &self.entries[index as usize] + } +} + +impl IndexMut for Idt { + fn index_mut(&mut self, index: u8) -> &mut Self::Output { + &mut self.entries[index as usize] + } +} + +// Following copied from Redox + +bitflags! { + pub struct IdtFlags: u8 { + const PRESENT = 1 << 7; + const RING_0 = 0 << 5; + const RING_1 = 1 << 5; + const RING_2 = 2 << 5; + const RING_3 = 3 << 5; + const SS = 1 << 4; + const INTERRUPT = 0xE; + const TRAP = 0xF; + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct IdtEntry { + offsetl: u16, + selector: u16, + zero: u8, + attribute: u8, + offsetm: u16, + offseth: u32, + zero2: u32 +} + +impl IdtEntry { + pub const fn new() -> IdtEntry { + IdtEntry { + offsetl: 0, + selector: 0, + zero: 0, + attribute: 0, + offsetm: 0, + offseth: 0, + zero2: 0 + } + } + + pub fn set_flags(&mut self, flags: IdtFlags) { + self.attribute = flags.bits; + } + + pub fn set_offset(&mut self, selector: u16, base: usize) { + self.selector = selector; + self.offsetl = base as u16; + self.offsetm = (base >> 16) as u16; + self.offseth = (base >> 32) as u32; + } + + // A function to set the offset more easily + pub fn set_handler_fn(&mut self, func: unsafe extern fn()) -> &mut Self { + self.set_flags(IdtFlags::PRESENT | IdtFlags::RING_0 | IdtFlags::INTERRUPT); + self.set_offset(8, func as usize); + self + } + + pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self { + // The hardware IST index starts at 1, but our software IST index + // starts at 0. Therefore we need to add 1 here. + self.offsetl &= !0b111; + self.offsetl += index + 1; + self + } +} \ No newline at end of file diff --git a/src/arch/x86_64/idt/mod.rs b/src/arch/x86_64/idt/mod.rs new file mode 100644 index 0000000..cf751c8 --- /dev/null +++ b/src/arch/x86_64/idt/mod.rs @@ -0,0 +1,33 @@ +use self::idt::Idt; +use spin::Once; +use alloc::boxed::Box; + +mod idt; + +/// Alloc IDT at kernel heap, then init and load it. +pub fn init() { + let idt = Box::new({ + use arch::interrupt::{handler::*, consts::*}; + use arch::gdt::DOUBLE_FAULT_IST_INDEX; + + let mut idt = Idt::new(); + idt[T_BRKPT].set_handler_fn(breakpoint); + idt[T_DBLFLT].set_handler_fn(double_fault); + idt[T_GPFLT].set_handler_fn(general_protection_fault); + idt[T_IRQ0 + IRQ_COM1].set_handler_fn(com1); + idt[T_IRQ0 + IRQ_COM2].set_handler_fn(com2); + idt[T_IRQ0 + IRQ_KBD].set_handler_fn(keyboard); + idt[T_IRQ0 + IRQ_TIMER].set_handler_fn(timer); + idt[T_SWITCH_TOU].set_handler_fn(to_user); + idt[T_SWITCH_TOK].set_handler_fn(to_kernel); + idt[T_SYSCALL].set_handler_fn(syscall); + unsafe { + idt[T_PGFLT].set_handler_fn(page_fault) + .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); + } + idt + }); + let idt = unsafe{ &*Box::into_raw(idt) }; + + idt.load(); +} \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/consts.rs b/src/arch/x86_64/interrupt/consts.rs new file mode 100644 index 0000000..ba9cc0b --- /dev/null +++ b/src/arch/x86_64/interrupt/consts.rs @@ -0,0 +1,31 @@ +pub const T_DIVIDE : u8 = 0 ; // divide error +pub const T_DEBUG : u8 = 1 ; // debug exception +pub const T_NMI : u8 = 2 ; // non-maskable interrupt +pub const T_BRKPT : u8 = 3 ; // breakpoint +pub const T_OFLOW : u8 = 4 ; // overflow +pub const T_BOUND : u8 = 5 ; // bounds check +pub const T_ILLOP : u8 = 6 ; // illegal opcode +pub const T_DEVICE : u8 = 7 ; // device not available +pub const T_DBLFLT : u8 = 8 ; // double fault +pub const T_COPROC : u8 = 9 ; // reserved (not used since 486) +pub const T_TSS : u8 = 10; // invalid task switch segment +pub const T_SEGNP : u8 = 11; // segment not present +pub const T_STACK : u8 = 12; // stack exception +pub const T_GPFLT : u8 = 13; // general protection fault +pub const T_PGFLT : u8 = 14; // page fault +pub const T_RES : u8 = 15; // reserved +pub const T_FPERR : u8 = 16; // floating point error +pub const T_ALIGN : u8 = 17; // aligment check +pub const T_MCHK : u8 = 18; // machine check +pub const T_SIMDERR : u8 = 19; // SIMD floating point error +pub const T_IRQ0 : u8 = 32; // IRQ 0 corresponds to int T_IRQ +pub const IRQ_TIMER : u8 = 0; +pub const IRQ_KBD : u8 = 1; +pub const IRQ_COM2 : u8 = 3; +pub const IRQ_COM1 : u8 = 4; +pub const IRQ_IDE : u8 = 14; +pub const IRQ_ERROR : u8 = 19; +pub const IRQ_SPURIOUS : u8 = 31; +pub const T_SYSCALL : u8 = 0x80; // SYSCALL, ONLY FOR THIS PROJ +pub const T_SWITCH_TOU : u8 = 120; // user/kernel switch +pub const T_SWITCH_TOK : u8 = 121; // user/kernel switch \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs new file mode 100644 index 0000000..c1d8cf0 --- /dev/null +++ b/src/arch/x86_64/interrupt/handler.rs @@ -0,0 +1,85 @@ +#[macro_use] +#[path = "./template.rs"] +mod template; +use self::template::*; + +interrupt_stack!(breakpoint, stack, { + println!("\nEXCEPTION: Breakpoint"); + stack.dump(); +}); + +interrupt_error_p!(double_fault, stack, { + println!("\nEXCEPTION: Double Fault"); + stack.dump(); + loop {} +}); + +interrupt_stack_p!(page_fault, stack, { + use x86_64::registers::control_regs::cr2; + println!("\nEXCEPTION: Page Fault\nAddress: {:#x}", cr2()); + stack.dump(); + loop {} +}); + +interrupt_error_p!(general_protection_fault, stack, { + println!("\nEXCEPTION: General Protection Fault"); + stack.dump(); + loop {} +}); + +#[cfg(feature = "use_apic")] +use arch::driver::apic::ack; +#[cfg(not(feature = "use_apic"))] +use arch::driver::pic::ack; + +use super::consts::*; + +interrupt!(keyboard, { + use arch::driver::keyboard; + println!("\nInterupt: Keyboard"); + let c = keyboard::get(); + println!("Key = '{}' {}", c as u8 as char, c); + ack(IRQ_KBD); + +}); + +interrupt!(com1, { + use arch::driver::serial::COM1; + println!("\nInterupt: COM1"); + COM1.lock().receive(); + ack(IRQ_COM1); +}); + +interrupt!(com2, { + use arch::driver::serial::COM2; + println!("\nInterupt: COM2"); + COM2.lock().receive(); + ack(IRQ_COM2); +}); + +use spin::Mutex; +static TICK: Mutex = Mutex::new(0); + +interrupt!(timer, { + let mut tick = TICK.lock(); + *tick += 1; + let tick = *tick; + if tick % 100 == 0 { + println!("\nInterupt: Timer\ntick = {}", tick); + } + ack(IRQ_TIMER); +}); + +interrupt_stack_p!(to_user, stack, { + println!("\nInterupt: To User"); + stack.iret.cs = 16; +}); + +interrupt_stack_p!(to_kernel, stack, { + println!("\nInterupt: To Kernel"); + stack.iret.cs = 8; +}); + +interrupt_stack_p!(syscall, stack, { + println!("\nInterupt: Syscall"); +}); \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs deleted file mode 100644 index b875805..0000000 --- a/src/arch/x86_64/interrupt/irq.rs +++ /dev/null @@ -1,101 +0,0 @@ -use x86_64::structures::idt::*; - -pub extern "x86-interrupt" fn breakpoint_handler( - stack_frame: &mut ExceptionStackFrame) -{ - println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); -} - -pub extern "x86-interrupt" fn double_fault_handler( - stack_frame: &mut ExceptionStackFrame, _error_code: u64) -{ - println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}\nErrorCode: {:#x}", stack_frame, _error_code); - loop {} -} - -pub extern "x86-interrupt" fn page_fault_handler( - stack_frame: &mut ExceptionStackFrame, error_code: PageFaultErrorCode) -{ - use x86_64::registers::control_regs::cr2; - println!("\nEXCEPTION: PAGE FAULT\n{:#?}\nErrorCode: {:#?}\nAddress: {:#x}", - stack_frame, error_code, cr2()); - loop {} -} - -pub extern "x86-interrupt" fn general_protection_fault_handler( - stack_frame: &mut ExceptionStackFrame, error_code: u64) -{ - println!("\nEXCEPTION: General Protection Fault\n{:#?}\nErrorCode: {:#x}", stack_frame, error_code); -} - -#[cfg(feature = "use_apic")] -use arch::driver::apic::ack; -#[cfg(not(feature = "use_apic"))] -use arch::driver::pic::ack; - -use consts::irq::*; - -pub extern "x86-interrupt" fn keyboard_handler( - stack_frame: &mut ExceptionStackFrame) -{ - use arch::driver::keyboard; - println!("\nInterupt: Keyboard"); - let c = keyboard::get(); - println!("Key = '{}' {}", c as u8 as char, c); - ack(IRQ_KBD); -} - -pub extern "x86-interrupt" fn com1_handler( - stack_frame: &mut ExceptionStackFrame) -{ - use arch::driver::serial::COM1; - println!("\nInterupt: COM1"); - COM1.lock().receive(); - ack(IRQ_COM1); -} - -pub extern "x86-interrupt" fn com2_handler( - stack_frame: &mut ExceptionStackFrame) -{ - use arch::driver::serial::COM2; - println!("\nInterupt: COM2"); - COM2.lock().receive(); - ack(IRQ_COM2); -} - -use spin::Mutex; -static TICK: Mutex = Mutex::new(0); - -pub extern "x86-interrupt" fn timer_handler( - stack_frame: &mut ExceptionStackFrame) -{ - let mut tick = TICK.lock(); - *tick += 1; - let tick = *tick; - if tick % 100 == 0 { - println!("\nInterupt: Timer\ntick = {}", tick); - } - ack(IRQ_TIMER); -} - -pub extern "x86-interrupt" fn to_user_handler( - stack_frame: &mut ExceptionStackFrame) -{ - println!("\nInterupt: To User"); - stack_frame.code_segment = 16; - stack_frame.stack_segment = 32; -} - -pub extern "x86-interrupt" fn to_kernel_handler( - stack_frame: &mut ExceptionStackFrame) -{ - println!("\nInterupt: To Kernel"); - stack_frame.code_segment = 8; - stack_frame.stack_segment = 24; -} - -pub extern "x86-interrupt" fn syscall_handler( - stack_frame: &mut ExceptionStackFrame) -{ - println!("\nInterupt: Syscall"); -} \ No newline at end of file diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index 9c6931a..7bc24c0 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -1,7 +1,8 @@ use x86_64; use arch::driver::{apic::IOAPIC, pic}; -pub mod irq; +pub mod handler; +pub mod consts; #[inline(always)] pub unsafe fn enable() { diff --git a/src/arch/x86_64/interrupt/template.rs b/src/arch/x86_64/interrupt/template.rs new file mode 100644 index 0000000..f323e7b --- /dev/null +++ b/src/arch/x86_64/interrupt/template.rs @@ -0,0 +1,394 @@ +//! Copy from Redox + +#[allow(dead_code)] +#[repr(packed)] +pub struct ScratchRegisters { + pub r11: usize, + pub r10: usize, + pub r9: usize, + pub r8: usize, + pub rsi: usize, + pub rdi: usize, + pub rdx: usize, + pub rcx: usize, + pub rax: usize, +} + +impl ScratchRegisters { + pub fn dump(&self) { + println!("RAX: {:>016X}", { self.rax }); + println!("RCX: {:>016X}", { self.rcx }); + println!("RDX: {:>016X}", { self.rdx }); + println!("RDI: {:>016X}", { self.rdi }); + println!("RSI: {:>016X}", { self.rsi }); + println!("R8: {:>016X}", { self.r8 }); + println!("R9: {:>016X}", { self.r9 }); + println!("R10: {:>016X}", { self.r10 }); + println!("R11: {:>016X}", { self.r11 }); + } +} + +macro_rules! scratch_push { + () => (asm!( + "push rax + push rcx + push rdx + push rdi + push rsi + push r8 + push r9 + push r10 + push r11" + : : : : "intel", "volatile" + )); +} + +macro_rules! scratch_pop { + () => (asm!( + "pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rdx + pop rcx + pop rax" + : : : : "intel", "volatile" + )); +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct PreservedRegisters { + pub r15: usize, + pub r14: usize, + pub r13: usize, + pub r12: usize, + pub rbp: usize, + pub rbx: usize, +} + +impl PreservedRegisters { + pub fn dump(&self) { + println!("RBX: {:>016X}", { self.rbx }); + println!("RBP: {:>016X}", { self.rbp }); + println!("R12: {:>016X}", { self.r12 }); + println!("R13: {:>016X}", { self.r13 }); + println!("R14: {:>016X}", { self.r14 }); + println!("R15: {:>016X}", { self.r15 }); + } +} + +macro_rules! preserved_push { + () => (asm!( + "push rbx + push rbp + push r12 + push r13 + push r14 + push r15" + : : : : "intel", "volatile" + )); +} + +macro_rules! preserved_pop { + () => (asm!( + "pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx" + : : : : "intel", "volatile" + )); +} + +macro_rules! fs_push { + () => (asm!( + "push fs + mov rax, 0x18 + mov fs, ax" + : : : : "intel", "volatile" + )); +} + +macro_rules! fs_pop { + () => (asm!( + "pop fs" + : : : : "intel", "volatile" + )); +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct IretRegisters { + pub rip: usize, + pub cs: usize, + pub rflags: usize, +} + +impl IretRegisters { + pub fn dump(&self) { + println!("RFLAG: {:>016X}", { self.rflags }); + println!("CS: {:>016X}", { self.cs }); + println!("RIP: {:>016X}", { self.rip }); + } +} + +macro_rules! iret { + () => (asm!( + "iretq" + : : : : "intel", "volatile" + )); +} + +/// Create an interrupt function that can safely run rust code +#[macro_export] +macro_rules! interrupt { + ($name:ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner() { + $func + } + + // Push scratch registers + scratch_push!(); + fs_push!(); + + // Map kernel +// $crate::arch::x86_64::pti::map(); + + // Call inner rust function + inner(); + + // Unmap kernel +// $crate::arch::x86_64::pti::unmap(); + + // Pop scratch registers and return + fs_pop!(); + scratch_pop!(); + iret!(); + } + }; +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct InterruptStack { + pub fs: usize, + pub scratch: ScratchRegisters, + pub iret: IretRegisters, +} + +impl InterruptStack { + pub fn dump(&self) { + self.iret.dump(); + self.scratch.dump(); + println!("FS: {:>016X}", { self.fs }); + } +} + +#[macro_export] +macro_rules! interrupt_stack { + ($name:ident, $stack: ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner($stack: &mut InterruptStack) { + $func + } + + // Push scratch registers + scratch_push!(); + fs_push!(); + + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Map kernel +// $crate::arch::x86_64::pti::map(); + + // Call inner rust function + inner(&mut *(rsp as *mut InterruptStack)); + + // Unmap kernel +// $crate::arch::x86_64::pti::unmap(); + + // Pop scratch registers and return + fs_pop!(); + scratch_pop!(); + iret!(); + } + }; +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct InterruptErrorStack { + pub fs: usize, + pub scratch: ScratchRegisters, + pub code: usize, + pub iret: IretRegisters, +} + +impl InterruptErrorStack { + pub fn dump(&self) { + self.iret.dump(); + println!("CODE: {:>016X}", { self.code }); + self.scratch.dump(); + println!("FS: {:>016X}", { self.fs }); + } +} + +#[macro_export] +macro_rules! interrupt_error { + ($name:ident, $stack:ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner($stack: &InterruptErrorStack) { + $func + } + + // Push scratch registers + scratch_push!(); + fs_push!(); + + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Map kernel +// $crate::arch::x86_64::pti::map(); + + // Call inner rust function + inner(&*(rsp as *const InterruptErrorStack)); + + // Unmap kernel +// $crate::arch::x86_64::pti::unmap(); + + // Pop scratch registers, error code, and return + fs_pop!(); + scratch_pop!(); + asm!("add rsp, 8" : : : : "intel", "volatile"); + iret!(); + } + }; +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct InterruptStackP { + pub fs: usize, + pub preserved: PreservedRegisters, + pub scratch: ScratchRegisters, + pub iret: IretRegisters, +} + +impl InterruptStackP { + pub fn dump(&self) { + self.iret.dump(); + self.scratch.dump(); + self.preserved.dump(); + println!("FS: {:>016X}", { self.fs }); + } +} + +#[macro_export] +macro_rules! interrupt_stack_p { + ($name:ident, $stack: ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner($stack: &mut InterruptStackP) { + $func + } + + // Push scratch registers + scratch_push!(); + preserved_push!(); + fs_push!(); + + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Map kernel +// $crate::arch::x86_64::pti::map(); + + // Call inner rust function + inner(&mut *(rsp as *mut InterruptStackP)); + + // Unmap kernel +// $crate::arch::x86_64::pti::unmap(); + + // Pop scratch registers and return + fs_pop!(); + preserved_pop!(); + scratch_pop!(); + iret!(); + } + }; +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct InterruptErrorStackP { + pub fs: usize, + pub preserved: PreservedRegisters, + pub scratch: ScratchRegisters, + pub code: usize, + pub iret: IretRegisters, +} + +impl InterruptErrorStackP { + pub fn dump(&self) { + self.iret.dump(); + println!("CODE: {:>016X}", { self.code }); + self.scratch.dump(); + self.preserved.dump(); + println!("FS: {:>016X}", { self.fs }); + } +} + +#[macro_export] +macro_rules! interrupt_error_p { + ($name:ident, $stack:ident, $func:block) => { + #[naked] + pub unsafe extern fn $name () { + #[inline(never)] + unsafe fn inner($stack: &InterruptErrorStackP) { + $func + } + + // Push scratch registers + scratch_push!(); + preserved_push!(); + fs_push!(); + + // Get reference to stack variables + let rsp: usize; + asm!("" : "={rsp}"(rsp) : : : "intel", "volatile"); + + // Map kernel +// $crate::arch::x86_64::pti::map(); + + // Call inner rust function + inner(&*(rsp as *const InterruptErrorStackP)); + + // Unmap kernel +// $crate::arch::x86_64::pti::unmap(); + + // Pop scratch registers, error code, and return + fs_pop!(); + preserved_pop!(); + scratch_pop!(); + asm!("add rsp, 8" : : : : "intel", "volatile"); + iret!(); + } + }; +} diff --git a/src/consts.rs b/src/consts.rs index 19f5cb3..6281cd4 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -94,17 +94,3 @@ pub const MAX_CPU_NUM: usize = 8; /// Offset for usage in other temporary pages pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE; pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK)/PML4_SIZE; - -pub mod irq { - pub const T_IRQ0 : u8 = 32; // IRQ 0 corresponds to int T_IRQ - pub const IRQ_TIMER : u8 = 0; - pub const IRQ_KBD : u8 = 1; - pub const IRQ_COM2 : u8 = 3; - pub const IRQ_COM1 : u8 = 4; - pub const IRQ_IDE : u8 = 14; - pub const IRQ_ERROR : u8 = 19; - pub const IRQ_SPURIOUS : u8 = 31; - pub const T_SYSCALL : u8 = 0x80; // SYSCALL, ONLY FOR THIS PROJ - pub const T_SWITCH_TOU : u8 = 120; // user/kernel switch - pub const T_SWITCH_TOK : u8 = 121; // user/kernel switch -} diff --git a/src/io/mod.rs b/src/io/mod.rs index b4a037e..b1b19af 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -30,11 +30,11 @@ use arch::driver::vga::Color; fn print_in_color(args: fmt::Arguments, color: Color) { use core::fmt::Write; use arch::driver::vga::*; - { - let mut writer = vga_writer::VGA_WRITER.lock(); - writer.set_color(color); - writer.write_fmt(args).unwrap(); - } +// { +// let mut writer = vga_writer::VGA_WRITER.lock(); +// writer.set_color(color); +// writer.write_fmt(args).unwrap(); +// } COM1.lock().write_fmt(args).unwrap(); } diff --git a/src/lib.rs b/src/lib.rs index fc4f920..c8801c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ #![feature(abi_x86_interrupt)] #![feature(iterator_step_by)] #![feature(unboxed_closures)] +#![feature(naked_functions)] #![feature(asm)] #![no_std] From 5d857c38eb574847c3b3a5cc7f22756d0db0531f Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 26 Apr 2018 21:53:20 +0800 Subject: [PATCH 3/7] Let struct Stack own the stack, panic on Drop. Add a little process mod. --- src/arch/x86_64/smp.rs | 6 +++- src/lib.rs | 7 ++-- src/memory/mod.rs | 18 ++++++---- src/memory/stack_allocator.rs | 8 ++++- src/process.rs | 64 +++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/process.rs diff --git a/src/arch/x86_64/smp.rs b/src/arch/x86_64/smp.rs index 3bc2af0..3af5555 100644 --- a/src/arch/x86_64/smp.rs +++ b/src/arch/x86_64/smp.rs @@ -19,8 +19,12 @@ pub fn start_other_cores(acpi: &ACPI_Result, mc: &mut MemoryController) { let page_table = unsafe{ *(0xFFFF_FFFF_FFFF_FFF8 as *const u32) } & 0xFFFF_F000; for i in 1 .. acpi.cpu_num { let apic_id = acpi.cpu_acpi_ids[i as usize]; + let kstack = mc.alloc_stack(7).unwrap(); + let kstack_top = kstack.top() as u64; + use core::mem::forget; + forget(kstack); // TODO pass this kstack to new AP *args = EntryArgs { - kstack: mc.alloc_stack(7).unwrap().top() as u64, + kstack: kstack_top, page_table: page_table, stack: 0x8000, // just enough stack to get us to entry64mp }; diff --git a/src/lib.rs b/src/lib.rs index c8801c3..1b997cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,7 @@ mod util; #[macro_use] // test! mod test_util; mod consts; +mod process; #[allow(dead_code)] #[cfg(target_arch = "x86_64")] @@ -76,9 +77,11 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { // memory_controller.print_page_table(); arch::smp::start_other_cores(&acpi, &mut memory_controller); + process::init(memory_controller.kernel_stack.take().unwrap()); + unsafe{ arch::interrupt::enable(); } - unsafe{ int!(120); } // to user +// unsafe{ int!(120); } // to user loop{} @@ -95,7 +98,7 @@ pub extern "C" fn other_main() -> ! { let cpu_id = arch::driver::apic::lapic_id(); println!("Hello world! from CPU {}!", arch::driver::apic::lapic_id()); unsafe{ arch::smp::notify_started(cpu_id); } - unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault +// unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault loop {} } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index d039ddb..29a6b39 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -46,7 +46,7 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { boot_info_start, boot_info_end, memory_map_tag.memory_areas()); - let mut active_table = remap_the_kernel(&mut frame_allocator, boot_info); + let (mut active_table, kernel_stack) = remap_the_kernel(&mut frame_allocator, boot_info); use self::paging::Page; use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; @@ -67,14 +67,15 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { }; MemoryController { - active_table: active_table, - frame_allocator: frame_allocator, - stack_allocator: stack_allocator, + kernel_stack: Some(kernel_stack), + active_table, + frame_allocator, + stack_allocator, } } pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) - -> ActivePageTable + -> (ActivePageTable, Stack) where A: FrameAllocator { let mut temporary_page = TemporaryPage::new(Page::containing_address(0xcafebabe), allocator); @@ -137,12 +138,14 @@ pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) let stack_bottom = PhysicalAddress(stack_bottom as u64).to_kernel_virtual(); let stack_bottom_page = Page::containing_address(stack_bottom); active_table.unmap(stack_bottom_page, allocator); + let kernel_stack = Stack::new(stack_bottom + 8 * PAGE_SIZE, stack_bottom + 1 * PAGE_SIZE); println!("guard page at {:#x}", stack_bottom_page.start_address()); - active_table + (active_table, kernel_stack) } pub struct MemoryController { + pub kernel_stack: Option, active_table: paging::ActivePageTable, frame_allocator: AreaFrameAllocator, stack_allocator: stack_allocator::StackAllocator, @@ -150,7 +153,8 @@ pub struct MemoryController { impl MemoryController { pub fn alloc_stack(&mut self, size_in_pages: usize) -> Option { - let &mut MemoryController { ref mut active_table, + let &mut MemoryController { ref mut kernel_stack, + ref mut active_table, ref mut frame_allocator, ref mut stack_allocator } = self; stack_allocator.alloc_stack(active_table, frame_allocator, diff --git a/src/memory/stack_allocator.rs b/src/memory/stack_allocator.rs index 7249874..83a2f37 100644 --- a/src/memory/stack_allocator.rs +++ b/src/memory/stack_allocator.rs @@ -61,7 +61,7 @@ pub struct Stack { } impl Stack { - fn new(top: usize, bottom: usize) -> Stack { + pub(super) fn new(top: usize, bottom: usize) -> Stack { assert!(top > bottom); Stack { top: top, @@ -77,3 +77,9 @@ impl Stack { self.bottom } } + +impl Drop for Stack { + fn drop(&mut self) { + panic!("stack leak: {:#x?}", self); + } +} \ No newline at end of file diff --git a/src/process.rs b/src/process.rs new file mode 100644 index 0000000..9706526 --- /dev/null +++ b/src/process.rs @@ -0,0 +1,64 @@ +use alloc::{boxed::Box, string::String, btree_map::BTreeMap}; +use memory::Stack; + +pub fn init(kstack: Stack) { + let processor = Box::new(Processor::new(kstack)); + Box::into_raw(processor); +} + +#[derive(Debug)] +pub struct Process { + pid: Pid, + name: String, + kstack: Stack, +// page_table: Box, + status: Status, + context: Context, +} + +#[derive(Debug)] +struct Context { + +} + +#[derive(Debug)] +enum Status { + Uninit, Ready, Running, Sleeping(usize), Exited +} + +struct Processor { + procs: BTreeMap>, +} + +type Pid = usize; + +impl Processor { + fn new(kernel_stack: Stack) -> Self { + let mut processor = Processor { + procs: BTreeMap::>::new(), + }; + let initproc = Box::new(Process{ + pid: 0, + name: String::from("initproc"), + kstack: kernel_stack, + status: Status::Running, + context: Context{}, + }); + processor.procs.insert(0, initproc); + processor + } + fn alloc_pid(&self) -> Pid { + let mut next: Pid = 0; + for &i in self.procs.keys() { + if i != next { + return next; + } else { + next = i + 1; + } + } + return next; + } + fn schedule(&self) { + + } +} \ No newline at end of file From 7d28231f1b45bf53e4702cde2db08de0096591ad Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 27 Apr 2018 00:03:24 +0800 Subject: [PATCH 4/7] Can run into another kernel thread --- src/arch/x86_64/interrupt/handler.rs | 5 ++- src/arch/x86_64/interrupt/mod.rs | 2 + src/arch/x86_64/interrupt/template.rs | 15 +++++++ src/lib.rs | 6 +-- src/{test_util.rs => macros.rs} | 9 ++++ src/process.rs | 63 ++++++++++++++++++++------- 6 files changed, 81 insertions(+), 19 deletions(-) rename src/{test_util.rs => macros.rs} (73%) diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index c1d8cf0..c853026 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -2,6 +2,7 @@ #[path = "./template.rs"] mod template; use self::template::*; +pub type TrapFrame = InterruptStackP; interrupt_stack!(breakpoint, stack, { println!("\nEXCEPTION: Breakpoint"); @@ -60,12 +61,14 @@ interrupt!(com2, { use spin::Mutex; static TICK: Mutex = Mutex::new(0); -interrupt!(timer, { +interrupt_stack_p!(timer, stack, { let mut tick = TICK.lock(); *tick += 1; let tick = *tick; if tick % 100 == 0 { println!("\nInterupt: Timer\ntick = {}", tick); + use process; + process::schedule(stack); } ack(IRQ_TIMER); }); diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index 7bc24c0..efc692b 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -4,6 +4,8 @@ use arch::driver::{apic::IOAPIC, pic}; pub mod handler; pub mod consts; +pub use self::handler::TrapFrame; + #[inline(always)] pub unsafe fn enable() { x86_64::instructions::interrupts::enable(); diff --git a/src/arch/x86_64/interrupt/template.rs b/src/arch/x86_64/interrupt/template.rs index f323e7b..b1d73dd 100644 --- a/src/arch/x86_64/interrupt/template.rs +++ b/src/arch/x86_64/interrupt/template.rs @@ -2,6 +2,7 @@ #[allow(dead_code)] #[repr(packed)] +#[derive(Clone, Default)] pub struct ScratchRegisters { pub r11: usize, pub r10: usize, @@ -60,6 +61,7 @@ macro_rules! scratch_pop { #[allow(dead_code)] #[repr(packed)] +#[derive(Clone, Default)] pub struct PreservedRegisters { pub r15: usize, pub r14: usize, @@ -122,6 +124,7 @@ macro_rules! fs_pop { #[allow(dead_code)] #[repr(packed)] +#[derive(Clone, Default)] pub struct IretRegisters { pub rip: usize, pub cs: usize, @@ -282,6 +285,7 @@ macro_rules! interrupt_error { #[allow(dead_code)] #[repr(packed)] +#[derive(Clone, Default)] pub struct InterruptStackP { pub fs: usize, pub preserved: PreservedRegisters, @@ -298,6 +302,17 @@ impl InterruptStackP { } } +use core::fmt::Debug; +use core::fmt::Formatter; +use core::fmt::Error; + +impl Debug for InterruptStackP { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + self.dump(); + Ok(()) + } +} + #[macro_export] macro_rules! interrupt_stack_p { ($name:ident, $stack: ident, $func:block) => { diff --git a/src/lib.rs b/src/lib.rs index 1b997cc..78ed98d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,8 +38,8 @@ mod io; mod memory; mod lang; mod util; -#[macro_use] // test! -mod test_util; +#[macro_use] +mod macros; mod consts; mod process; @@ -77,7 +77,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { // memory_controller.print_page_table(); arch::smp::start_other_cores(&acpi, &mut memory_controller); - process::init(memory_controller.kernel_stack.take().unwrap()); + process::init(&mut memory_controller); unsafe{ arch::interrupt::enable(); } diff --git a/src/test_util.rs b/src/macros.rs similarity index 73% rename from src/test_util.rs rename to src/macros.rs index 3e79aa3..3cfea74 100644 --- a/src/test_util.rs +++ b/src/macros.rs @@ -22,4 +22,13 @@ macro_rules! test { println!("Success: {}", stringify!($func)); } ) +} + +macro_rules! no_interrupt { + {$func:block} => { + use arch::interrupt; + unsafe{ interrupt::disable(); } + $func; + unsafe{ interrupt::enable(); } + }; } \ No newline at end of file diff --git a/src/process.rs b/src/process.rs index 9706526..b928dc1 100644 --- a/src/process.rs +++ b/src/process.rs @@ -1,9 +1,17 @@ use alloc::{boxed::Box, string::String, btree_map::BTreeMap}; -use memory::Stack; +use memory::{MemoryController, Stack}; +use arch::interrupt::TrapFrame; +use spin::{Once, Mutex}; -pub fn init(kstack: Stack) { - let processor = Box::new(Processor::new(kstack)); - Box::into_raw(processor); +pub fn init(mc: &mut MemoryController) { + PROCESSOR.call_once(|| {Mutex::new(Processor::new(mc))}); +} + +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); } #[derive(Debug)] @@ -13,12 +21,7 @@ pub struct Process { kstack: Stack, // page_table: Box, status: Status, - context: Context, -} - -#[derive(Debug)] -struct Context { - + trap_frame: TrapFrame, } #[derive(Debug)] @@ -28,23 +31,39 @@ enum Status { struct Processor { procs: BTreeMap>, + current_pid: Pid, } type Pid = usize; impl Processor { - fn new(kernel_stack: Stack) -> Self { + fn new(mc: &mut MemoryController) -> Self { let mut processor = Processor { procs: BTreeMap::>::new(), + current_pid: 0, }; let initproc = Box::new(Process{ pid: 0, name: String::from("initproc"), - kstack: kernel_stack, + kstack: mc.kernel_stack.take().unwrap(), status: Status::Running, - context: Context{}, + 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 { @@ -58,7 +77,21 @@ impl Processor { } return next; } - fn schedule(&self) { - + fn schedule(&mut self, trap_frame: &mut TrapFrame) { + self.run(1, trap_frame); + } + fn run(&mut self, pid: Pid, trap_frame: &mut TrapFrame) { + if pid == self.current_pid { + return; + } + let process = self.procs.get_mut(&pid).unwrap(); + self.current_pid = pid; + *trap_frame = process.trap_frame.clone(); + // TODO switch page table } +} + +extern fn idle_thread() { + println!("idle ..."); + loop {} } \ No newline at end of file From 4f18f70e19356e998ef27ada637a9502bf003483 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 27 Apr 2018 16:32:57 +0800 Subject: [PATCH 5/7] Can switch between ring0 and ring 3. Fix IDT bugs. --- src/arch/x86_64/gdt.rs | 38 ++++++++++++++++++++++----- src/arch/x86_64/idt/idt.rs | 13 ++++----- src/arch/x86_64/idt/mod.rs | 14 ++++++---- src/arch/x86_64/interrupt/handler.rs | 26 +++++++++++++----- src/arch/x86_64/interrupt/template.rs | 4 +++ src/arch/x86_64/mod.rs | 3 ++- src/arch/x86_64/paging/mapper.rs | 3 ++- src/arch/x86_64/paging/table.rs | 3 ++- src/arch/x86_64/syscall.rs | 9 +++++++ src/lib.rs | 15 ++++++++--- src/process.rs | 33 +++++++++++++++++------ 11 files changed, 122 insertions(+), 39 deletions(-) create mode 100644 src/arch/x86_64/syscall.rs diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index 5d2f8b1..4516f7f 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -5,6 +5,7 @@ use x86_64::structures::gdt::SegmentSelector; use x86_64::{PrivilegeLevel, VirtualAddress}; use spin::Once; use alloc::boxed::Box; +use core::ptr::Unique; /// Alloc TSS & GDT at kernel heap, then init and load it. /// The double fault stack will be allocated at kernel heap too. @@ -14,25 +15,27 @@ pub fn init() { use x86_64::instructions::tables::load_tss; let double_fault_stack_top = Box::into_raw(Box::new([0u8; 4096])) as usize + 4096; + debug!("Double fault stack top @ {:#x}", double_fault_stack_top); let mut tss = Box::new({ let mut tss = TaskStateSegment::new(); + + // 设置 Double Fault 时,自动切换栈的地址 tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = VirtualAddress(double_fault_stack_top); + tss }); - let tss = unsafe{ &*Box::into_raw(tss) }; + unsafe{ TSS_PTR = Unique::new_unchecked(Box::into_raw(tss)); } + let tss = unsafe{ TSS_PTR.as_ref() }; - let mut code_selector = SegmentSelector(0); - let mut tss_selector = SegmentSelector(0); let gdt = Box::new({ let mut gdt = Gdt::new(); - code_selector = gdt.add_entry(KCODE); gdt.add_entry(UCODE); gdt.add_entry(KDATA); gdt.add_entry(UDATA); - tss_selector = gdt.add_entry(Descriptor::tss_segment(&tss)); + gdt.add_entry(Descriptor::tss_segment(&tss)); gdt }); let gdt = unsafe{ &*Box::into_raw(gdt) }; @@ -40,9 +43,23 @@ pub fn init() { unsafe { // reload code segment register - set_cs(code_selector); + set_cs(KCODE_SELECTOR); // load TSS - load_tss(tss_selector); + load_tss(TSS_SELECTOR); + } +} + +// TODO: more elegant? +static mut TSS_PTR: Unique = unsafe{ Unique::new_unchecked(0 as *mut _) }; + +/// 设置从Ring3跳到Ring0时,自动切换栈的地址 +/// +/// 每次进入用户态前,都要调用此函数,才能保证正确返回内核态 +pub fn set_ring0_rsp(rsp: usize) { + debug!("gdt.set_ring0_rsp: {:#x}", rsp); + unsafe { + TSS_PTR.as_mut().privilege_stack_table[0] = VirtualAddress(rsp); +// debug!("TSS:\n{:?}", TSS_PTR.as_ref()); } } @@ -54,6 +71,13 @@ const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECU const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT +pub const KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0); +pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring3); +pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0); +pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3); +pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring0); + + pub struct Gdt { table: [u64; 8], next_free: usize, diff --git a/src/arch/x86_64/idt/idt.rs b/src/arch/x86_64/idt/idt.rs index d8af161..2d35123 100644 --- a/src/arch/x86_64/idt/idt.rs +++ b/src/arch/x86_64/idt/idt.rs @@ -56,7 +56,7 @@ bitflags! { pub struct IdtEntry { offsetl: u16, selector: u16, - zero: u8, + ist: u8, attribute: u8, offsetm: u16, offseth: u32, @@ -68,7 +68,7 @@ impl IdtEntry { IdtEntry { offsetl: 0, selector: 0, - zero: 0, + ist: 0, attribute: 0, offsetm: 0, offseth: 0, @@ -76,15 +76,17 @@ impl IdtEntry { } } - pub fn set_flags(&mut self, flags: IdtFlags) { + pub fn set_flags(&mut self, flags: IdtFlags) -> &mut Self { self.attribute = flags.bits; + self } - pub fn set_offset(&mut self, selector: u16, base: usize) { + pub fn set_offset(&mut self, selector: u16, base: usize) -> &mut Self { self.selector = selector; self.offsetl = base as u16; self.offsetm = (base >> 16) as u16; self.offseth = (base >> 32) as u32; + self } // A function to set the offset more easily @@ -97,8 +99,7 @@ impl IdtEntry { pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self { // The hardware IST index starts at 1, but our software IST index // starts at 0. Therefore we need to add 1 here. - self.offsetl &= !0b111; - self.offsetl += index + 1; + self.ist = (index + 1) as u8; self } } \ No newline at end of file diff --git a/src/arch/x86_64/idt/mod.rs b/src/arch/x86_64/idt/mod.rs index cf751c8..1e1cff0 100644 --- a/src/arch/x86_64/idt/mod.rs +++ b/src/arch/x86_64/idt/mod.rs @@ -1,4 +1,4 @@ -use self::idt::Idt; +use self::idt::*; use spin::Once; use alloc::boxed::Box; @@ -12,17 +12,21 @@ pub fn init() { let mut idt = Idt::new(); idt[T_BRKPT].set_handler_fn(breakpoint); - idt[T_DBLFLT].set_handler_fn(double_fault); + idt[T_PGFLT].set_handler_fn(page_fault); idt[T_GPFLT].set_handler_fn(general_protection_fault); idt[T_IRQ0 + IRQ_COM1].set_handler_fn(com1); idt[T_IRQ0 + IRQ_COM2].set_handler_fn(com2); idt[T_IRQ0 + IRQ_KBD].set_handler_fn(keyboard); idt[T_IRQ0 + IRQ_TIMER].set_handler_fn(timer); + idt[T_SWITCH_TOU].set_handler_fn(to_user); - idt[T_SWITCH_TOK].set_handler_fn(to_kernel); - idt[T_SYSCALL].set_handler_fn(syscall); + idt[T_SWITCH_TOK].set_handler_fn(to_kernel) + .set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); + idt[T_SYSCALL].set_handler_fn(syscall) + .set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::TRAP); + unsafe { - idt[T_PGFLT].set_handler_fn(page_fault) + idt[T_DBLFLT].set_handler_fn(double_fault) .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); } idt diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index c853026..39aaa37 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -59,28 +59,40 @@ interrupt!(com2, { }); use spin::Mutex; -static TICK: Mutex = Mutex::new(0); +// FIXME: Deadlock +//static TICK: Mutex = Mutex::new(0); interrupt_stack_p!(timer, stack, { - let mut tick = TICK.lock(); - *tick += 1; - let tick = *tick; +// let mut tick = TICK.lock(); +// *tick += 1; +// let tick = *tick; + static mut tick: usize = 0; + unsafe{ tick += 1; } if tick % 100 == 0 { println!("\nInterupt: Timer\ntick = {}", tick); use process; - process::schedule(stack); +// process::schedule(stack); } + stack.dump(); ack(IRQ_TIMER); }); interrupt_stack_p!(to_user, stack, { + use arch::gdt; println!("\nInterupt: To User"); - stack.iret.cs = 16; + let rsp = unsafe{ (stack as *const InterruptStackP).offset(1) } as usize; + gdt::set_ring0_rsp(rsp); + stack.iret.cs = gdt::UCODE_SELECTOR.0 as usize; + stack.iret.ss = gdt::UDATA_SELECTOR.0 as usize; + stack.iret.rflags |= 3 << 12; // 设置EFLAG的I/O特权位,使得在用户态可使用in/out指令 }); interrupt_stack_p!(to_kernel, stack, { +// println!("rsp @ {:#x}", stack as *const _ as usize); + use arch::gdt; println!("\nInterupt: To Kernel"); - stack.iret.cs = 8; + stack.iret.cs = gdt::KCODE_SELECTOR.0 as usize; + stack.iret.ss = gdt::KDATA_SELECTOR.0 as usize; }); interrupt_stack_p!(syscall, stack, { diff --git a/src/arch/x86_64/interrupt/template.rs b/src/arch/x86_64/interrupt/template.rs index b1d73dd..9b42b36 100644 --- a/src/arch/x86_64/interrupt/template.rs +++ b/src/arch/x86_64/interrupt/template.rs @@ -129,10 +129,14 @@ pub struct IretRegisters { pub rip: usize, pub cs: usize, pub rflags: usize, + pub rsp: usize, + pub ss: usize, } impl IretRegisters { pub fn dump(&self) { + println!("SS: {:>016X}", { self.ss }); + println!("RSP: {:>016X}", { self.rsp }); println!("RFLAG: {:>016X}", { self.rflags }); println!("CS: {:>016X}", { self.cs }); println!("RIP: {:>016X}", { self.rip }); diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index debd61a..51147a7 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -4,4 +4,5 @@ pub mod interrupt; pub mod paging; pub mod gdt; pub mod idt; -pub mod smp; \ No newline at end of file +pub mod smp; +pub mod syscall; \ No newline at end of file diff --git a/src/arch/x86_64/paging/mapper.rs b/src/arch/x86_64/paging/mapper.rs index d9a394c..46b87b6 100644 --- a/src/arch/x86_64/paging/mapper.rs +++ b/src/arch/x86_64/paging/mapper.rs @@ -78,7 +78,8 @@ impl Mapper { let mut p1 = p2.next_table_create(page.p2_index(), allocator); assert!(p1[page.p1_index()].is_unused()); - p1[page.p1_index()].set(frame, flags | EntryFlags::PRESENT); + // TODO: Remove USER_ACCESSIBLE + p1[page.p1_index()].set(frame, flags | EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE); } pub fn map(&mut self, page: Page, flags: EntryFlags, allocator: &mut A) diff --git a/src/arch/x86_64/paging/table.rs b/src/arch/x86_64/paging/table.rs index 17736b0..c7c0d26 100644 --- a/src/arch/x86_64/paging/table.rs +++ b/src/arch/x86_64/paging/table.rs @@ -50,7 +50,8 @@ impl Table where L: HierarchicalLevel { assert!(!self.entries[index].flags().contains(EntryFlags::HUGE_PAGE), "mapping code does not support huge pages"); let frame = allocator.allocate_frame().expect("no frames available"); - self.entries[index].set(frame, EntryFlags::PRESENT | EntryFlags::WRITABLE); + // TODO: Remove USER_ACCESSIBLE + self.entries[index].set(frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::USER_ACCESSIBLE); self.next_table_mut(index).unwrap().zero(); } self.next_table_mut(index).unwrap() diff --git a/src/arch/x86_64/syscall.rs b/src/arch/x86_64/syscall.rs new file mode 100644 index 0000000..39d3baf --- /dev/null +++ b/src/arch/x86_64/syscall.rs @@ -0,0 +1,9 @@ +use arch::interrupt::consts::*; + +pub fn switch_to_user() { + unsafe { int!(T_SWITCH_TOU); } +} + +pub fn switch_to_kernel() { + unsafe { int!(T_SWITCH_TOK); } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 78ed98d..59109ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,13 +75,22 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! { let acpi = arch::driver::init( |addr: usize| memory_controller.map_page_identity(addr)); // memory_controller.print_page_table(); - arch::smp::start_other_cores(&acpi, &mut memory_controller); + // FIXME: 开启SMP后,导致switch_to_user中设置rsp无效 +// arch::smp::start_other_cores(&acpi, &mut memory_controller); process::init(&mut memory_controller); - unsafe{ arch::interrupt::enable(); } + // FIXME: 在用户模式下触发时钟中断,导致GPF +// unsafe{ arch::interrupt::enable(); } -// unsafe{ int!(120); } // to user + unsafe{ + use arch::syscall; + syscall::switch_to_user(); + println!("Now in user mode"); +// loop{} + syscall::switch_to_kernel(); + println!("Now in kernel mode"); + } loop{} diff --git a/src/process.rs b/src/process.rs index b928dc1..7d5cde6 100644 --- a/src/process.rs +++ b/src/process.rs @@ -1,8 +1,15 @@ use alloc::{boxed::Box, string::String, btree_map::BTreeMap}; use memory::{MemoryController, Stack}; -use arch::interrupt::TrapFrame; use spin::{Once, Mutex}; +/// 平台相关依赖:struct TrapFrame +/// +/// ## 必须实现的特性 +/// +/// * Clone: 用于对栈中TrapFrame的替换 +/// * Debug: 用于Debug输出 +use arch::interrupt::TrapFrame; + pub fn init(mc: &mut MemoryController) { PROCESSOR.call_once(|| {Mutex::new(Processor::new(mc))}); } @@ -78,20 +85,30 @@ impl Processor { return next; } fn schedule(&mut self, trap_frame: &mut TrapFrame) { - self.run(1, trap_frame); + self.switch(1, trap_frame); } - fn run(&mut self, pid: Pid, trap_frame: &mut TrapFrame) { + fn switch(&mut self, pid: Pid, trap_frame: &mut TrapFrame) { if pid == self.current_pid { return; } - let process = self.procs.get_mut(&pid).unwrap(); + { + let current = self.procs.get_mut(&self.current_pid).unwrap(); + current.status = Status::Ready; + } + { + let process = self.procs.get_mut(&pid).unwrap(); + *trap_frame = process.trap_frame.clone(); + // TODO switch page table + } self.current_pid = pid; - *trap_frame = process.trap_frame.clone(); - // TODO switch page table } } extern fn idle_thread() { - println!("idle ..."); - loop {} + loop { + println!("idle ..."); + for i in 0 .. 1 << 20 { + + } + } } \ No newline at end of file From 0553d3374d792079f28725902ed5b6a6b0695167 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 27 Apr 2018 21:49:01 +0800 Subject: [PATCH 6/7] 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 From 6e157ee97d50d378bdd7f92f28bbb16aa670f777 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 27 Apr 2018 23:10:39 +0800 Subject: [PATCH 7/7] Split process mod. Move TrapFrame operation to arch. --- src/arch/x86_64/interrupt/mod.rs | 13 +++ src/process.rs | 156 ------------------------------- src/process/mod.rs | 45 +++++++++ src/process/process.rs | 50 ++++++++++ src/process/processor.rs | 69 ++++++++++++++ 5 files changed, 177 insertions(+), 156 deletions(-) delete mode 100644 src/process.rs create mode 100644 src/process/mod.rs create mode 100644 src/process/process.rs create mode 100644 src/process/processor.rs diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index efc692b..eb0fc3f 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -6,6 +6,19 @@ pub mod consts; pub use self::handler::TrapFrame; +impl TrapFrame { + pub fn new_kernel_thread(entry: extern fn(), rsp: usize) -> Self { + use arch::gdt; + let mut tf = TrapFrame::default(); + tf.iret.cs = gdt::KCODE_SELECTOR.0 as usize; + tf.iret.rip = entry as usize; + tf.iret.ss = gdt::KDATA_SELECTOR.0 as usize; + tf.iret.rsp = rsp; + tf.iret.rflags = 0x282; + tf + } +} + #[inline(always)] pub unsafe fn enable() { x86_64::instructions::interrupts::enable(); diff --git a/src/process.rs b/src/process.rs deleted file mode 100644 index 03a0d72..0000000 --- a/src/process.rs +++ /dev/null @@ -1,156 +0,0 @@ -use alloc::{boxed::Box, string::String, btree_map::BTreeMap}; -use memory::{MemoryController, Stack}; -use spin::{Once, Mutex}; - -/// 平台相关依赖:struct TrapFrame -/// -/// ## 必须实现的特性 -/// -/// * Debug: 用于Debug输出 -use arch::interrupt::TrapFrame; - -pub fn init(mc: &mut MemoryController) { - 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 -/// 设置rsp,指向接下来要执行线程的 内核栈顶 -/// 之后中断处理例程会重置rsp,恢复对应线程的上下文 -pub fn schedule(rsp: &mut usize) { - PROCESSOR.try().unwrap().lock().schedule(rsp); -} - -#[derive(Debug)] -pub struct Process { - pid: Pid, - name: &'static str, - kstack: Stack, -// page_table: Box, - status: Status, - rsp: usize, -} - -#[derive(Debug)] -enum Status { - Uninit, Ready, Running, Sleeping(usize), Exited -} - -struct Processor { - procs: BTreeMap>, - current_pid: Pid, -} - -type Pid = usize; - -impl Processor { - fn new(mc: &mut MemoryController) -> Self { - Processor { - procs: BTreeMap::>::new(), - current_pid: 0, - } - } - fn alloc_pid(&self) -> Pid { - let mut next: Pid = 0; - for &i in self.procs.keys() { - if i != next { - return next; - } else { - next = i + 1; - } - } - return next; - } - 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_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(); - 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 ..."); - let mut i = 0; - while i < 1 << 22 { - i += 1; - } - } -} \ No newline at end of file diff --git a/src/process/mod.rs b/src/process/mod.rs new file mode 100644 index 0000000..76beeef --- /dev/null +++ b/src/process/mod.rs @@ -0,0 +1,45 @@ +use memory::MemoryController; +use spin::{Once, Mutex}; + +use self::process::*; +use self::processor::*; + +mod process; +mod processor; + +/// 平台相关依赖:struct TrapFrame +/// +/// ## 必须实现的特性 +/// +/// * Debug: 用于Debug输出 +use arch::interrupt::TrapFrame; + +pub fn init(mc: &mut MemoryController) { + 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 +/// 设置rsp,指向接下来要执行线程的 内核栈顶 +/// 之后中断处理例程会重置rsp,恢复对应线程的上下文 +pub fn schedule(rsp: &mut usize) { + PROCESSOR.try().unwrap().lock().schedule(rsp); +} + +extern fn idle_thread() { + loop { + println!("idle ..."); + let mut i = 0; + while i < 1 << 22 { + i += 1; + } + } +} \ No newline at end of file diff --git a/src/process/process.rs b/src/process/process.rs new file mode 100644 index 0000000..5e95e66 --- /dev/null +++ b/src/process/process.rs @@ -0,0 +1,50 @@ +use super::*; +use memory::Stack; + +#[derive(Debug)] +pub struct Process { + pub(in process) pid: Pid, + name: &'static str, + kstack: Stack, + // page_table: Box, + pub(in process) status: Status, + pub(in process) rsp: usize, +} + +pub type Pid = usize; + +#[derive(Debug)] +pub enum Status { + Ready, Running, Sleeping(usize), Exited +} + +impl Process { + /// Make a new kernel thread + pub fn new(name: &'static str, entry: extern fn(), mc: &mut MemoryController) -> Self { + let kstack = mc.alloc_stack(7).unwrap(); + let rsp = unsafe{ (kstack.top() as *mut TrapFrame).offset(-1) } as usize; + + let tf = unsafe{ &mut *(rsp as *mut TrapFrame) }; + *tf = TrapFrame::new_kernel_thread(entry, kstack.top()); + + Process { + pid: 0, + name, + kstack, + status: Status::Ready, + rsp, + } + } + /// Make the first kernel thread `initproc` + /// Should be called only once + pub fn new_init(mc: &mut MemoryController) -> Self { + assert_has_not_been_called!(); + Process { + pid: 0, + name: "init", + kstack: mc.kernel_stack.take().unwrap(), + status: Status::Running, + rsp: 0, // will be set at first schedule + } + } +} \ No newline at end of file diff --git a/src/process/processor.rs b/src/process/processor.rs new file mode 100644 index 0000000..b09e067 --- /dev/null +++ b/src/process/processor.rs @@ -0,0 +1,69 @@ +use alloc::BTreeMap; +use super::*; + +#[derive(Debug)] +pub struct Processor { + procs: BTreeMap, + current_pid: Pid, +} + +impl Processor { + pub fn new(mc: &mut MemoryController) -> Self { + Processor { + procs: BTreeMap::::new(), + current_pid: 0, + } + } + + fn alloc_pid(&self) -> Pid { + let mut next: Pid = 0; + for &i in self.procs.keys() { + if i != next { + return next; + } else { + next = i + 1; + } + } + return next; + } + + pub fn add(&mut self, mut process: Process) { + let pid = self.alloc_pid(); + process.pid = pid; + self.procs.insert(pid, process); + } + + pub 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_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(); + 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); + } +} \ No newline at end of file