Can switch between ring0 and ring 3. Fix IDT bugs.

master
WangRunji 7 years ago
parent 7d28231f1b
commit 4f18f70e19

@ -5,6 +5,7 @@ use x86_64::structures::gdt::SegmentSelector;
use x86_64::{PrivilegeLevel, VirtualAddress}; use x86_64::{PrivilegeLevel, VirtualAddress};
use spin::Once; use spin::Once;
use alloc::boxed::Box; use alloc::boxed::Box;
use core::ptr::Unique;
/// Alloc TSS & GDT at kernel heap, then init and load it. /// Alloc TSS & GDT at kernel heap, then init and load it.
/// The double fault stack will be allocated at kernel heap too. /// 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; use x86_64::instructions::tables::load_tss;
let double_fault_stack_top = Box::into_raw(Box::new([0u8; 4096])) as usize + 4096; 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 = Box::new({
let mut tss = TaskStateSegment::new(); let mut tss = TaskStateSegment::new();
// 设置 Double Fault 时,自动切换栈的地址
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX]
= VirtualAddress(double_fault_stack_top); = VirtualAddress(double_fault_stack_top);
tss 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 gdt = Box::new({
let mut gdt = Gdt::new(); let mut gdt = Gdt::new();
code_selector =
gdt.add_entry(KCODE); gdt.add_entry(KCODE);
gdt.add_entry(UCODE); gdt.add_entry(UCODE);
gdt.add_entry(KDATA); gdt.add_entry(KDATA);
gdt.add_entry(UDATA); gdt.add_entry(UDATA);
tss_selector = gdt.add_entry(Descriptor::tss_segment(&tss)); gdt.add_entry(Descriptor::tss_segment(&tss));
gdt gdt
}); });
let gdt = unsafe{ &*Box::into_raw(gdt) }; let gdt = unsafe{ &*Box::into_raw(gdt) };
@ -40,9 +43,23 @@ pub fn init() {
unsafe { unsafe {
// reload code segment register // reload code segment register
set_cs(code_selector); set_cs(KCODE_SELECTOR);
// load TSS // load TSS
load_tss(tss_selector); load_tss(TSS_SELECTOR);
}
}
// TODO: more elegant?
static mut TSS_PTR: Unique<TaskStateSegment> = 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 KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | 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 { pub struct Gdt {
table: [u64; 8], table: [u64; 8],
next_free: usize, next_free: usize,

@ -56,7 +56,7 @@ bitflags! {
pub struct IdtEntry { pub struct IdtEntry {
offsetl: u16, offsetl: u16,
selector: u16, selector: u16,
zero: u8, ist: u8,
attribute: u8, attribute: u8,
offsetm: u16, offsetm: u16,
offseth: u32, offseth: u32,
@ -68,7 +68,7 @@ impl IdtEntry {
IdtEntry { IdtEntry {
offsetl: 0, offsetl: 0,
selector: 0, selector: 0,
zero: 0, ist: 0,
attribute: 0, attribute: 0,
offsetm: 0, offsetm: 0,
offseth: 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.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.selector = selector;
self.offsetl = base as u16; self.offsetl = base as u16;
self.offsetm = (base >> 16) as u16; self.offsetm = (base >> 16) as u16;
self.offseth = (base >> 32) as u32; self.offseth = (base >> 32) as u32;
self
} }
// A function to set the offset more easily // 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 { pub unsafe fn set_stack_index(&mut self, index: u16) -> &mut Self {
// The hardware IST index starts at 1, but our software IST index // The hardware IST index starts at 1, but our software IST index
// starts at 0. Therefore we need to add 1 here. // starts at 0. Therefore we need to add 1 here.
self.offsetl &= !0b111; self.ist = (index + 1) as u8;
self.offsetl += index + 1;
self self
} }
} }

@ -1,4 +1,4 @@
use self::idt::Idt; use self::idt::*;
use spin::Once; use spin::Once;
use alloc::boxed::Box; use alloc::boxed::Box;
@ -12,17 +12,21 @@ pub fn init() {
let mut idt = Idt::new(); let mut idt = Idt::new();
idt[T_BRKPT].set_handler_fn(breakpoint); 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_GPFLT].set_handler_fn(general_protection_fault);
idt[T_IRQ0 + IRQ_COM1].set_handler_fn(com1); idt[T_IRQ0 + IRQ_COM1].set_handler_fn(com1);
idt[T_IRQ0 + IRQ_COM2].set_handler_fn(com2); idt[T_IRQ0 + IRQ_COM2].set_handler_fn(com2);
idt[T_IRQ0 + IRQ_KBD].set_handler_fn(keyboard); idt[T_IRQ0 + IRQ_KBD].set_handler_fn(keyboard);
idt[T_IRQ0 + IRQ_TIMER].set_handler_fn(timer); idt[T_IRQ0 + IRQ_TIMER].set_handler_fn(timer);
idt[T_SWITCH_TOU].set_handler_fn(to_user); idt[T_SWITCH_TOU].set_handler_fn(to_user);
idt[T_SWITCH_TOK].set_handler_fn(to_kernel); idt[T_SWITCH_TOK].set_handler_fn(to_kernel)
idt[T_SYSCALL].set_handler_fn(syscall); .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 { 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); .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
} }
idt idt

@ -59,28 +59,40 @@ interrupt!(com2, {
}); });
use spin::Mutex; use spin::Mutex;
static TICK: Mutex<usize> = Mutex::new(0); // FIXME: Deadlock
//static TICK: Mutex<usize> = Mutex::new(0);
interrupt_stack_p!(timer, stack, { interrupt_stack_p!(timer, stack, {
let mut tick = TICK.lock(); // let mut tick = TICK.lock();
*tick += 1; // *tick += 1;
let tick = *tick; // let tick = *tick;
static mut tick: usize = 0;
unsafe{ tick += 1; }
if tick % 100 == 0 { if tick % 100 == 0 {
println!("\nInterupt: Timer\ntick = {}", tick); println!("\nInterupt: Timer\ntick = {}", tick);
use process; use process;
process::schedule(stack); // process::schedule(stack);
} }
stack.dump();
ack(IRQ_TIMER); ack(IRQ_TIMER);
}); });
interrupt_stack_p!(to_user, stack, { interrupt_stack_p!(to_user, stack, {
use arch::gdt;
println!("\nInterupt: To User"); 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, { interrupt_stack_p!(to_kernel, stack, {
// println!("rsp @ {:#x}", stack as *const _ as usize);
use arch::gdt;
println!("\nInterupt: To Kernel"); 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, { interrupt_stack_p!(syscall, stack, {

@ -129,10 +129,14 @@ pub struct IretRegisters {
pub rip: usize, pub rip: usize,
pub cs: usize, pub cs: usize,
pub rflags: usize, pub rflags: usize,
pub rsp: usize,
pub ss: usize,
} }
impl IretRegisters { impl IretRegisters {
pub fn dump(&self) { pub fn dump(&self) {
println!("SS: {:>016X}", { self.ss });
println!("RSP: {:>016X}", { self.rsp });
println!("RFLAG: {:>016X}", { self.rflags }); println!("RFLAG: {:>016X}", { self.rflags });
println!("CS: {:>016X}", { self.cs }); println!("CS: {:>016X}", { self.cs });
println!("RIP: {:>016X}", { self.rip }); println!("RIP: {:>016X}", { self.rip });

@ -4,4 +4,5 @@ pub mod interrupt;
pub mod paging; pub mod paging;
pub mod gdt; pub mod gdt;
pub mod idt; pub mod idt;
pub mod smp; pub mod smp;
pub mod syscall;

@ -78,7 +78,8 @@ impl Mapper {
let mut p1 = p2.next_table_create(page.p2_index(), allocator); let mut p1 = p2.next_table_create(page.p2_index(), allocator);
assert!(p1[page.p1_index()].is_unused()); 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<A>(&mut self, page: Page, flags: EntryFlags, allocator: &mut A) pub fn map<A>(&mut self, page: Page, flags: EntryFlags, allocator: &mut A)

@ -50,7 +50,8 @@ impl<L> Table<L> where L: HierarchicalLevel {
assert!(!self.entries[index].flags().contains(EntryFlags::HUGE_PAGE), assert!(!self.entries[index].flags().contains(EntryFlags::HUGE_PAGE),
"mapping code does not support huge pages"); "mapping code does not support huge pages");
let frame = allocator.allocate_frame().expect("no frames available"); 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().zero();
} }
self.next_table_mut(index).unwrap() self.next_table_mut(index).unwrap()

@ -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); }
}

@ -75,13 +75,22 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
let acpi = arch::driver::init( let acpi = arch::driver::init(
|addr: usize| memory_controller.map_page_identity(addr)); |addr: usize| memory_controller.map_page_identity(addr));
// memory_controller.print_page_table(); // 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); 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{} loop{}

@ -1,8 +1,15 @@
use alloc::{boxed::Box, string::String, btree_map::BTreeMap}; use alloc::{boxed::Box, string::String, btree_map::BTreeMap};
use memory::{MemoryController, Stack}; use memory::{MemoryController, Stack};
use arch::interrupt::TrapFrame;
use spin::{Once, Mutex}; use spin::{Once, Mutex};
/// 平台相关依赖struct TrapFrame
///
/// ## 必须实现的特性
///
/// * Clone: 用于对栈中TrapFrame的替换
/// * Debug: 用于Debug输出
use arch::interrupt::TrapFrame;
pub fn init(mc: &mut MemoryController) { pub fn init(mc: &mut MemoryController) {
PROCESSOR.call_once(|| {Mutex::new(Processor::new(mc))}); PROCESSOR.call_once(|| {Mutex::new(Processor::new(mc))});
} }
@ -78,20 +85,30 @@ impl Processor {
return next; return next;
} }
fn schedule(&mut self, trap_frame: &mut TrapFrame) { 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 { if pid == self.current_pid {
return; 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; self.current_pid = pid;
*trap_frame = process.trap_frame.clone();
// TODO switch page table
} }
} }
extern fn idle_thread() { extern fn idle_thread() {
println!("idle ..."); loop {
loop {} println!("idle ...");
for i in 0 .. 1 << 20 {
}
}
} }
Loading…
Cancel
Save