use core::arch::{asm, global_asm};
use hyperlight_common::outb::Exception;
use super::super::context;
use super::super::machine::{IDT, IdtEntry, IdtPointer, ProcCtrl};
unsafe extern "C" {
fn _do_excp0();
fn _do_excp1();
fn _do_excp2();
fn _do_excp3();
fn _do_excp4();
fn _do_excp5();
fn _do_excp6();
fn _do_excp7();
fn _do_excp8();
fn _do_excp9();
fn _do_excp10();
fn _do_excp11();
fn _do_excp12();
fn _do_excp13();
fn _do_excp14();
fn _do_excp15();
fn _do_excp16();
fn _do_excp17();
fn _do_excp18();
fn _do_excp19();
fn _do_excp20();
fn _do_excp30();
}
macro_rules! generate_excp {
($num:expr) => {
concat!(
".global _do_excp",
stringify!($num),
"\n",
"_do_excp",
stringify!($num),
":\n",
context::save!(),
" mov rsi, ",
stringify!($num),
"\n",
" mov rdx, 0\n",
" jmp _do_excp_common\n"
)
};
($num:expr, pusherrcode) => {
concat!(
".global _do_excp",
stringify!($num),
"\n",
"_do_excp",
stringify!($num),
":\n",
" push 0\n",
context::save!(),
" mov rsi, ",
stringify!($num),
"\n",
" mov rdx, 0\n",
" jmp _do_excp_common\n"
)
};
($num:expr, pagefault) => {
concat!(
".global _do_excp",
stringify!($num),
"\n",
"_do_excp",
stringify!($num),
":\n",
context::save!(),
" mov rsi, ",
stringify!($num),
"\n",
" mov rdx, cr2\n",
" jmp _do_excp_common\n"
)
};
}
macro_rules! generate_exceptions {
() => {
concat!(
".global _do_excp_common\n",
"_do_excp_common:\n",
" mov rdi, rsp\n",
" call {hl_exception_handler}\n",
context::restore!(),
" add rsp, 8\n", " iretq\n", generate_excp!(0, pusherrcode),
generate_excp!(1, pusherrcode),
generate_excp!(2, pusherrcode),
generate_excp!(3, pusherrcode),
generate_excp!(4, pusherrcode),
generate_excp!(5, pusherrcode),
generate_excp!(6, pusherrcode),
generate_excp!(7, pusherrcode),
generate_excp!(8),
generate_excp!(9, pusherrcode),
generate_excp!(10),
generate_excp!(11),
generate_excp!(12),
generate_excp!(13),
generate_excp!(14, pagefault),
generate_excp!(15, pusherrcode),
generate_excp!(16, pusherrcode),
generate_excp!(17),
generate_excp!(18, pusherrcode),
generate_excp!(19, pusherrcode),
generate_excp!(20, pusherrcode),
generate_excp!(30),
)
};
}
global_asm!(
generate_exceptions!(),
hl_exception_handler = sym super::handle::hl_exception_handler,
);
pub(in super::super) fn init_idt(pc: *mut ProcCtrl) {
let idt = unsafe { &raw mut (*pc).idt };
let set_idt_entry = |idx, handler: unsafe extern "C" fn()| {
let handler_addr = handler as *const () as u64;
unsafe {
(&raw mut (*idt).entries[idx as usize]).write_volatile(IdtEntry::new(handler_addr));
}
};
set_idt_entry(Exception::DivideByZero, _do_excp0); set_idt_entry(Exception::Debug, _do_excp1); set_idt_entry(Exception::NonMaskableInterrupt, _do_excp2); set_idt_entry(Exception::Breakpoint, _do_excp3); set_idt_entry(Exception::Overflow, _do_excp4); set_idt_entry(Exception::BoundRangeExceeded, _do_excp5); set_idt_entry(Exception::InvalidOpcode, _do_excp6); set_idt_entry(Exception::DeviceNotAvailable, _do_excp7); set_idt_entry(Exception::DoubleFault, _do_excp8); set_idt_entry(Exception::CoprocessorSegmentOverrun, _do_excp9); set_idt_entry(Exception::InvalidTSS, _do_excp10); set_idt_entry(Exception::SegmentNotPresent, _do_excp11); set_idt_entry(Exception::StackSegmentFault, _do_excp12); set_idt_entry(Exception::GeneralProtectionFault, _do_excp13); set_idt_entry(Exception::PageFault, _do_excp14); set_idt_entry(Exception::Reserved, _do_excp15); set_idt_entry(Exception::X87FloatingPointException, _do_excp16); set_idt_entry(Exception::AlignmentCheck, _do_excp17); set_idt_entry(Exception::MachineCheck, _do_excp18); set_idt_entry(Exception::SIMDFloatingPointException, _do_excp19); set_idt_entry(Exception::VirtualizationException, _do_excp20); set_idt_entry(Exception::SecurityException, _do_excp30);
let idtr = IdtPointer {
limit: (core::mem::size_of::<IDT>() - 1) as u16,
base: idt as u64,
};
unsafe {
asm!(
"lidt [{}]",
in(reg) &idtr,
options(readonly, nostack, preserves_flags)
);
}
}