Use x86_64 IDT again

master
WangRunji 7 years ago
parent f35d74c734
commit 2f71eab39b

@ -0,0 +1,44 @@
use alloc::boxed::Box;
use x86_64::structures::idt::*;
pub fn init() {
IDT.load();
}
lazy_static! {
static ref IDT: Idt = {
use arch::interrupt::{handler::*, consts::*};
use arch::gdt::DOUBLE_FAULT_IST_INDEX;
use x86_64::PrivilegeLevel;
use core::mem::transmute;
// 这里主要利用了x86_64库提供的IDT结构
// 它进行了完善的封装,有强类型约束
// 然而这里我们需要绕过一些限制,例如:
// * 依赖于 "x86-interrupt" 函数ABI而我们的是裸函数
// * 某些保留中断号不允许设置会触发panic
// 于是下面用了一些trick绕过了它们
let ring3 = [T_SWITCH_TOK, T_SYSCALL, 0x80];
let mut idt = Idt::new();
let entries = unsafe{ &mut *(&mut idt as *mut _ as *mut [IdtEntry<HandlerFunc>; 256]) };
for i in 0..256 {
let mut opt = entries[i].set_handler_fn(unsafe { transmute(__vectors[i]) });
if ring3.contains(&(i as u8)) {
opt.set_privilege_level(PrivilegeLevel::Ring3);
}
if i == T_DBLFLT as usize {
unsafe{ opt.set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); }
}
}
idt
};
}
extern {
/// 中断向量表
/// 符号定义在 [trap.asm](boot/trap.asm)
//noinspection RsStaticConstNaming
static __vectors: [extern fn(); 256];
}

@ -1,105 +0,0 @@
// 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::<Self>() - 1) as u16,
};
unsafe { lidt(&ptr) };
}
}
impl Index<u8> for Idt {
type Output = IdtEntry;
fn index(&self, index: u8) -> &Self::Output {
&self.entries[index as usize]
}
}
impl IndexMut<u8> 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,
ist: u8,
attribute: u8,
offsetm: u16,
offseth: u32,
zero2: u32
}
impl IdtEntry {
pub const fn new() -> IdtEntry {
IdtEntry {
offsetl: 0,
selector: 0,
ist: 0,
attribute: 0,
offsetm: 0,
offseth: 0,
zero2: 0
}
}
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) -> &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
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.ist = (index + 1) as u8;
self
}
}

@ -1,36 +0,0 @@
use self::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();
for i in 0u8..=255 {
idt[i].set_handler_fn(unsafe { __vectors[i as usize] });
}
idt[T_SWITCH_TOK].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
// TODO: Enable interrupt during syscall
idt[T_SYSCALL].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
idt[0x80].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT);
unsafe {
idt[T_DBLFLT].set_stack_index(DOUBLE_FAULT_IST_INDEX as u16);
}
idt
});
let idt = unsafe{ &*Box::into_raw(idt) };
idt.load();
}
extern {
//noinspection RsStaticConstNaming
static __vectors: [extern fn(); 256];
}
Loading…
Cancel
Save