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