#![allow(unused_parens)]
use modular_bitfield::{bitfield, prelude::*};
extern crate core;
use core::{mem::size_of, u8};
use crate::{vmexit::ExitType, x86::vmx_consts::{control, ro}, x86::vmx_support::{vmread, vmwrite}, vmxerror::{ExceptionInterrupt, InterruptionType}};
const VALID: u8 = 1;
const _INVALID: u8 = 0;
impl EventInjection {
fn general_protection() -> u32 {
let mut event = EventInjection::new();
event.set_vector(ExceptionInterrupt::GeneralProtectionFault as u8);
event.set_eventype(InterruptionType::HardwareException as u8);
event.set_deliver_error_code(true);
event.set_valid(VALID);
u32::from_ne_bytes(event.bytes)
}
fn breakpoint() -> u32 {
let mut event = EventInjection::new();
event.set_vector(ExceptionInterrupt::Breakpoint as u8);
event.set_eventype(InterruptionType::HardwareException as u8);
event.set_valid(VALID);
u32::from_ne_bytes(event.bytes)
}
fn page_fault() -> u32 {
let mut event = EventInjection::new();
event.set_vector(ExceptionInterrupt::PageFault as u8);
event.set_eventype(InterruptionType::HardwareException as u8);
event.set_valid(VALID);
u32::from_ne_bytes(event.bytes)
}
fn undefined_opcode() -> u32 {
let mut event = EventInjection::new();
event.set_vector(ExceptionInterrupt::InvalidOpcode as u8 );
event.set_eventype(InterruptionType::HardwareException as u8);
event.set_valid(VALID);
u32::from_ne_bytes(event.bytes)
}
pub fn vmentry_inject_ud() {
vmwrite(
control::VMENTRY_INTERRUPTION_INFO_FIELD,
EventInjection::undefined_opcode() as u64,
).unwrap();
}
pub fn vmentry_inject_gp(error_code: u32) {
vmwrite(control::VMENTRY_EXCEPTION_ERR_CODE, error_code.into()).unwrap();
vmwrite(
control::VMENTRY_INTERRUPTION_INFO_FIELD,
EventInjection::general_protection().into(),
).unwrap();
}
pub fn vmentry_inject_pf(error_code: u32) {
vmwrite(control::VMENTRY_EXCEPTION_ERR_CODE, error_code.into()).unwrap();
vmwrite(
control::VMENTRY_INTERRUPTION_INFO_FIELD,
EventInjection::page_fault() as u64,
).unwrap();
}
pub fn vmentry_inject_bp() {
vmwrite(
control::VMENTRY_INTERRUPTION_INFO_FIELD,
EventInjection::breakpoint() as u64,
).unwrap();
}
}
pub fn handle_undefined_opcode_exception() -> ExitType {
log::debug!("Undefined Opcode Exception");
EventInjection::vmentry_inject_ud();
log::debug!("Undefined Opcode Exception handled successfully!");
ExitType::Continue
}
#[rustfmt::skip]
pub fn handle_exception<T>(guest_registers: &mut crate::cputure::GuestRegisters, vmx: &mut T) -> ExitType {
log::debug!("Handling ExceptionOrNmi VM exit...");
let interruption_info_value = vmread(ro::VMEXIT_INTERRUPTION_INFO).unwrap();
let interruption_error_code_value = vmread(ro::VMEXIT_INTERRUPTION_ERR_CODE).unwrap();
if let Some(interruption_info) = crate::vmxerror::VmExitInterruptionInformation::from_u32(interruption_info_value as u32) {
if let Some(exception_interrupt) = ExceptionInterrupt::from_u32(interruption_info.vector.into()) {
match exception_interrupt {
ExceptionInterrupt::PageFault => {
let exit_qualification_value = vmread(ro::EXIT_QUALIFICATION).unwrap();
let ept_violation_qualification = crate::vmxerror::EptViolationExitQualification::from_exit_qualification(exit_qualification_value);
log::trace!("Exit Qualification for EPT Violations: {}", ept_violation_qualification);
EventInjection::vmentry_inject_pf(interruption_error_code_value as u32);
},
ExceptionInterrupt::GeneralProtectionFault => {
EventInjection::vmentry_inject_gp(interruption_error_code_value as u32);
},
ExceptionInterrupt::Breakpoint => {
handle_breakpoint_exception(guest_registers, vmx);
},
ExceptionInterrupt::InvalidOpcode => {
EventInjection::vmentry_inject_ud();
},
_ => {
log::debug!("Unhandled exception: {:?}", exception_interrupt);
panic!("Unhandled exception: {:?}", exception_interrupt);
}
}
} else {
log::debug!("Invalid Exception Interrupt Vector: {}", interruption_info.vector);
panic!("Invalid Exception Interrupt Vector: {}", interruption_info.vector);
}
} else {
log::debug!("Invalid VM Exit Interruption Information!");
panic!("Invalid VM Exit Interruption Information");
}
log::debug!("Exception Handled successfully!");
ExitType::Continue
}
fn handle_breakpoint_exception<T>(guest_registers: &mut crate::cputure::GuestRegisters, _vmx: &mut T) {
log::debug!("Breakpoint Exception");
log::trace!("Finding hook for RIP: {:#x}", guest_registers.rip);
if 1!=1{
log::debug!("Breakpoint (int3) hook handled successfully!");
} else {
EventInjection::vmentry_inject_bp();
log::debug!("Breakpoint exception handled successfully!");
};
}
static_assertions::const_assert_eq!(size_of::<EventInjection>(), size_of::<u32>());
#[bitfield(bits = 32)]
#[derive(Debug, Clone, Copy)]
pub struct EventInjection {
pub vector: B8,
pub eventype:B3,
pub deliver_error_code:bool,
pub pading3: B19,
pub valid: B1,
}