//! Interrupt instructions use core::mem; use paging::{ActivePageTable, VirtualAddress}; pub mod exception; pub mod irq; pub mod syscall; /// Clear interrupts #[inline(always)] pub unsafe fn disable() { asm!("cli" : : : : "intel", "volatile"); } /// Set interrupts #[inline(always)] pub unsafe fn enable() { asm!("sti" : : : : "intel", "volatile"); } /// Set interrupts and halt /// This will atomically wait for the next interrupt /// Performing enable followed by halt is not guaranteed to be atomic, use this instead! #[inline(always)] pub unsafe fn enable_and_halt() { asm!("sti hlt" : : : : "intel", "volatile"); } /// Set interrupts and nop /// This will enable interrupts and allow the IF flag to be processed /// Simply enabling interrupts does not gurantee that they will trigger, use this instead! #[inline(always)] pub unsafe fn enable_and_nop() { asm!("sti nop" : : : : "intel", "volatile"); } /// Halt instruction #[inline(always)] pub unsafe fn halt() { asm!("hlt" : : : : "intel", "volatile"); } /// Pause instruction /// Safe because it is similar to a NOP, and has no memory effects #[inline(always)] pub fn pause() { unsafe { asm!("pause" : : : : "intel", "volatile"); } } /// Get a stack trace //TODO: Check for stack being mapped before dereferencing #[inline(never)] pub unsafe fn stack_trace() { let mut rbp: usize; asm!("" : "={rbp}"(rbp) : : : "intel", "volatile"); println!("TRACE: {:>016X}", rbp); //Maximum 64 frames let active_table = ActivePageTable::new(); for _frame in 0..64 { if let Some(rip_rbp) = rbp.checked_add(mem::size_of::()) { if active_table.translate(VirtualAddress::new(rbp)).is_some() && active_table.translate(VirtualAddress::new(rip_rbp)).is_some() { let rip = *(rip_rbp as *const usize); if rip == 0 { println!(" {:>016X}: EMPTY RETURN", rbp); break; } println!(" {:>016X}: {:>016X}", rbp, rip); rbp = *(rbp as *const usize); } else { println!(" {:>016X}: GUARD PAGE", rbp); break; } } else { println!(" {:>016X}: RBP OVERFLOW", rbp); } } }