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

toolchain_update
WangRunji 7 years ago
parent 7d28231f1b
commit 4f18f70e19

@ -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<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 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,

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

@ -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

@ -59,28 +59,40 @@ interrupt!(com2, {
});
use spin::Mutex;
static TICK: Mutex<usize> = Mutex::new(0);
// FIXME: Deadlock
//static TICK: Mutex<usize> = 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, {

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

@ -4,4 +4,5 @@ pub mod interrupt;
pub mod paging;
pub mod gdt;
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);
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)

@ -50,7 +50,8 @@ impl<L> Table<L> 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()

@ -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(
|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{}

@ -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 {
}
}
}
Loading…
Cancel
Save