Documentation
#![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  {
    /// Inject General Protection (#GP) to the guest (Event Injection).
    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)
    }

    /// Inject Breakpoint (#BP) to the guest (Event Injection).
    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)
    }

    /// Inject Page Fault (#PF) to the guest (Event Injection).
    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)
    }

    ///  Inject undefined (#UD)  to the guest (Event Injection).
    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)
    }


    /// Injects an undefined opcode exception into the guest.
    ///
    /// This function is used to signal to the guest that an invalid or undefined opcode
    /// has been encountered, typically indicating an error in the guest's execution.
    ///
    /// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 25.8.3 VM-Entry Controls for Event Injection
    /// and Table 25-17. Format of the VM-Entry Interruption-Information Field.
    pub fn vmentry_inject_ud() {
    vmwrite(
        control::VMENTRY_INTERRUPTION_INFO_FIELD,
        EventInjection::undefined_opcode() as u64,
    ).unwrap();
    }
    

    /// Injects a general protection fault into the guest.
    ///
    /// This function is used to signal to the guest that a protection violation
    /// has occurred, typically due to accessing a reserved MSR.
    ///
    /// # Arguments
    ///
    /// * `error_code` - The error code to be associated with the fault.
    ///
    /// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 25.8.3 VM-Entry Controls for Event Injection
    /// and Table 25-17. Format of the VM-Entry Interruption-Information Field.
    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();
    }


    /// Injects a page fault into the guest.
    ///
    /// This function is used to signal to the guest that a page fault has occurred.
    /// It's typically used in response to a memory access violation.
    ///
    /// # Arguments
    ///
    /// * `error_code` - The error code to be associated with the page fault.
    ///
    /// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 25.8.3 VM-Entry Controls for Event Injection
    /// and Table 25-17. Format of the VM-Entry Interruption-Information Field.
    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();
    }

    /// Injects a breakpoint exception into the guest.
    ///
    /// This function is used to signal to the guest that a breakpoint exception
    /// has occurred, typically used for debugging purposes.
    ///
    /// Reference: Intel® 64 and IA-32 Architectures Software Developer's Manual: 25.8.3 VM-Entry Controls for Event Injection
    /// and Table 25-17. Format of the VM-Entry Interruption-Information Field.
    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
}

/// Handles breakpoint (`#BP`) exceptions specifically.
///
/// When a breakpoint exception occurs, this function checks for a registered hook
/// at the current instruction pointer (RIP). If a hook is found, it transfers control
/// to the hook's handler. Otherwise, it injects a breakpoint exception into the VM.
///
/// # Arguments
///
/// * `guest_registers` - A mutable reference to the guest's current register state.
/// * `vmx` - A mutable reference to the Vmx structure.
fn handle_breakpoint_exception<T>(guest_registers: &mut crate::cputure::GuestRegisters, _vmx: &mut T) {
    log::debug!("Breakpoint Exception");

    //let hook_manager = unsafe { vmx.shared_data.as_mut().hook_manager.as_mut() };

    log::trace!("Finding hook for RIP: {:#x}", guest_registers.rip);

    // Find the handler address for the current instruction pointer (RIP) and
    // transfer the execution to it. If we couldn't find a hook, we inject the
    // #BP exception.
    //
    // if let Some(Some(handler)) =
    //         None

    if 1!=1{
        // Call our hook handle function (it will automatically call trampoline).
        // log::trace!("Transferring execution to handler: {:#x}", handler);
        // guest_registers.rip = handler;
        // vmwrite(crate::vmx_consts::guest::RIP, guest_registers.rip);

        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 {

    /// #[skip]
    /// pading1: bool,
    /// nmi:bool,
    /// hard_exception: bool,
    /// soft_interrupt: bool,
    /// privileged_soft: bool,
    /// soft_exception: bool,
    /// #[skip(getters)]
    /// set_vector: B1,
    pub vector: B8, 
    pub eventype:B3,
    pub deliver_error_code:bool,
    pub pading3: B19,
    pub valid: B1, 
}