Documentation
use alloc::boxed::Box;
use bit_field::BitField;
use crate::{
  contorls::{VmxControl, adjust_vmx_controls}, cputure::{CONTEXT, GuestRegisters}, error::HypervisorError, pagetable::PageTables, share_data::SharedData, vmxerror::ExceptionInterrupt, vt_x::descriptor::DescriptorTables, x86::{controlregs::{self, cr0, cr3, cr4}, dtable, msr::{self, rdmsr}, segmentation::SegmentSelector, task, vmx_consts::{control, host}, vmx_support::{vmclear, vmptrld, vmwrite}}, x86_64::addr::Addrtransfer
};
use crate::x86::vmx_consts::guest;
use crate::x86_64::segmentation_x86_64::SegmentDescriptor;
#[derive(Debug, Clone, Copy)]
#[repr(C, align(4096))]
pub struct __VMCS {
    pub revision_id: u32,
    pub abort_indicator: u32,
    pub reserved: [u8; 0x1000 - size_of::<u32>() * 2],
}


impl __VMCS {
  pub fn vmcs_init_cpu<T: Addrtransfer>( index: usize, vmxcs_region:  &mut Box<__VMCS, impl core::alloc::Allocator>, trans: &mut T) -> Result<(), HypervisorError> {
      //let mut vmxcs_region: Box<__VMCS, PhysicalAllocator> = unsafe { Box::try_new_zeroed_in(PhysicalAllocator).unwrap().assume_init() };
      // let irql = unsafe { KeGetCurrentIrql() };
      // if irql as u32 > win_kernel_sys::base::DISPATCH_LEVEL {
      //     unsafe { win_kernel_sys::ntoskrnl::KeRaiseIrqlToDpcLevel() };
      // }


      //vmxcs_region.revision_id =rdmsr(crate::consts::MSR_IA32_VMX_BASIC)  as u32;
      vmxcs_region.revision_id =rdmsr(msr::IA32_VMX_BASIC)  as u32;
      log::debug!("rust: ------------------------------------------------");
      vmxcs_region.revision_id.set_bit(31, false);
      log::debug!("rust: ------------------------------------------------");
      log::debug!("rust: vmxon revision_id {}", vmxcs_region.revision_id);
      log::debug!("rust: ------------------------------------------------");

    
                  //let mut current_vcpu_ptr = VMCPU[index];
          let va = vmxcs_region.as_ref() as *const _ as u64;
                  
          log::debug!("rust: cr0 cr4 vmxon executed for cpu core:{}", index);
    
          let phys_addr = trans.va_into_pa(va as u64);
                  
                  // log::debug!("rust: 3vmcs executed for cpu core:{}", index);
                  //utils::set_cr4_bits();
                  //  log::debug!("rust: 4vmxcs executed for cpu core:{}", index);
                  //utils::set_cr0_bits();
                  
                  

                  
          log::debug!("rust: vmcs casted addr for cpu core:{} phys_addr:{:#16x} va:{:#16x}", index, phys_addr, va);
          // match vmclear(phys_addr) {
          //     Ok(_) => {log::debug!("rust cleared ")},
          //     Err(_) => {log::debug!("rust  non cleared ")},
          // }
          vmclear(phys_addr)?;
          vmptrld(phys_addr)?;
          // match  crate::vmx_support::vmptrld(phys_addr) {
          //     Ok(_) => {
          //             log::debug!("rust: vmcs vmptr is load");
          //             let mut guard =VMCPU.lock();
          //             guard.get_mut().unwrap().get_mut(index).unwrap().vmcs =Some(vmxcs_region);
          //             //guard[index].vmcs = Some(vmxcs_region);
          //             return STATUS_SUCCESS;
          //     },
          //     Err(e) => {
          //         match e {
          //             crate::vmx_support::VmFail::VmFailValid => {
          //                 drop(vmxcs_region);
          //                 log::debug!("rust: vmcs vmfailvaild other err core:{}", index);
          //                 return STATUS_UNSUCCESSFUL;
          //             },
          //             crate::vmx_support::VmFail::VmFailInvalid => {
          //                 drop(vmxcs_region);
          //                 log::debug!("rust: vmxcs vmfailvaild not vaild core:{}", index);
          //                 return STATUS_UNSUCCESSFUL;
          //             },
          //         }
          //     },
          // };
          Ok(())
  }


  #[rustfmt::skip]
  pub fn setup_guest_registers_state(context: &CONTEXT, guest_descriptor_table: &Box<DescriptorTables, impl core::alloc::Allocator>, guest_registers: &mut GuestRegisters) -> Result<(), crate::error::HypervisorError>{
          log::debug!("Setting up Guest Registers State");
      
          vmwrite(guest::CR0, cr0().bits() as u64)?;
          vmwrite(guest::CR3, cr3())?;
          vmwrite(guest::CR4, cr4().bits() as u64)?;
          vmwrite(guest::DR7, context.Dr7)?;
          vmwrite(guest::RSP, context.Rsp)?;
          vmwrite(guest::RIP, context.Rip)?;
          vmwrite(guest::RFLAGS, context.EFlags.into())?;



          vmwrite(guest::CS_SELECTOR, context.SegCs.into())?;
          vmwrite(guest::SS_SELECTOR, context.SegSs.into())?;
          vmwrite(guest::DS_SELECTOR, context.SegDs.into())?;
          vmwrite(guest::ES_SELECTOR, context.SegEs.into())?;
          vmwrite(guest::FS_SELECTOR, context.SegFs.into())?;
          vmwrite(guest::GS_SELECTOR, context.SegGs.into())?;
          vmwrite(guest::LDTR_SELECTOR, dtable::ldtr().bits() as u64)?;
          vmwrite(guest::TR_SELECTOR, task::tr().bits() as u64)?;


          // log::debug!("Setting up Guest Registers State tr");
          vmwrite(guest::CS_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegCs), &guest_descriptor_table.gdtr).base_address)?;
          vmwrite(guest::SS_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegSs), &guest_descriptor_table.gdtr).base_address)?;
          vmwrite(guest::DS_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegDs), &guest_descriptor_table.gdtr).base_address)?;
          vmwrite(guest::ES_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegEs), &guest_descriptor_table.gdtr).base_address)?;
          vmwrite(guest::FS_BASE, msr::rdmsr(msr::IA32_FS_BASE))?;
          vmwrite(guest::GS_BASE, msr::rdmsr(msr::IA32_GS_BASE))?;
          vmwrite(guest::LDTR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtable::ldtr().bits()), &guest_descriptor_table.gdtr).base_address)?;
          vmwrite(guest::TR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &guest_descriptor_table.gdtr).base_address)?;
      
        // log::debug!("Setting up Guest Registers State tr base");
          vmwrite(guest::CS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegCs), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::SS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegSs), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::DS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegDs), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::ES_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegEs), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::FS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegFs), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::GS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegGs), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::LDTR_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtable::ldtr().bits()), &guest_descriptor_table.gdtr).segment_limit.into())?;
          vmwrite(guest::TR_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &guest_descriptor_table.gdtr).segment_limit.into())?;
       
          //log::debug!("Setting up Guest Registers State tr LIMIT");
          vmwrite(guest::CS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegCs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::SS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegSs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::DS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegDs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::ES_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegEs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::FS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegFs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::GS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegGs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::LDTR_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtable::ldtr().bits()), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          vmwrite(guest::TR_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
          

          vmwrite(guest::GDTR_BASE, guest_descriptor_table.gdtr.base as u64)?;
          vmwrite(guest::IDTR_BASE, guest_descriptor_table.idtr.base as u64)?;

          vmwrite(guest::GDTR_LIMIT, guest_descriptor_table.gdtr.limit as u64)?;
          vmwrite(guest::IDTR_LIMIT, guest_descriptor_table.idtr.limit as u64)?;
          
         //     log::debug!("Setting up Guest Registers State :IDTR_LIMIT");
    
          vmwrite(guest::IA32_DEBUGCTL_FULL, msr::rdmsr(msr::IA32_DEBUGCTL))?;
          vmwrite(guest::IA32_SYSENTER_CS, msr::rdmsr(msr::IA32_SYSENTER_CS))?;
          vmwrite(guest::IA32_SYSENTER_ESP, msr::rdmsr(msr::IA32_SYSENTER_ESP))?;
          vmwrite(guest::IA32_SYSENTER_EIP, msr::rdmsr(msr::IA32_SYSENTER_EIP))?;
          vmwrite(guest::LINK_PTR_FULL, u64::MAX)?;
          
 //   log::debug!("Setting up Guest Registers State :LINK_PTR_FULL");
    
          let xmm_context = unsafe { context.Anonymous.Anonymous };

          // Note: VMCS does not manage all registers; some require manual intervention for saving and loading.
          // This includes general-purpose registers and xmm registers, which must be explicitly preserved and restored by the software.
          guest_registers.xmm0 = xmm_context.Xmm0;
          guest_registers.xmm1 = xmm_context.Xmm1;
          guest_registers.xmm2 = xmm_context.Xmm2;
          guest_registers.xmm3 = xmm_context.Xmm3;
          guest_registers.xmm4 = xmm_context.Xmm4;
          guest_registers.xmm5 = xmm_context.Xmm5;
          guest_registers.xmm6 = xmm_context.Xmm6;
          guest_registers.xmm7 = xmm_context.Xmm7;
          guest_registers.xmm8 = xmm_context.Xmm8;
          guest_registers.xmm9 = xmm_context.Xmm9;
          guest_registers.xmm10 = xmm_context.Xmm10;
          guest_registers.xmm11 = xmm_context.Xmm11;
          guest_registers.xmm12 = xmm_context.Xmm12;
          guest_registers.xmm13 = xmm_context.Xmm13;
          guest_registers.xmm14 = xmm_context.Xmm14;
          guest_registers.xmm15 = xmm_context.Xmm15;

          guest_registers.rax = context.Rax;
          guest_registers.rbx = context.Rbx;
          guest_registers.rcx = context.Rcx;
          guest_registers.rdx = context.Rdx;
          guest_registers.rdi = context.Rdi;
          guest_registers.rsi = context.Rsi;
          guest_registers.rbp = context.Rbp;
          guest_registers.r8 = context.R8;
          guest_registers.r9 = context.R9;
          guest_registers.r10 = context.R10;
          guest_registers.r11 = context.R11;
          guest_registers.r12 = context.R12;
          guest_registers.r13 = context.R13;
          guest_registers.r14 = context.R14;
          guest_registers.r15 = context.R15;

          log::debug!("Guest Registers State setup successfully!");
          Ok(())
  }


    #[rustfmt::skip]
    pub fn setup_host_registers_state<T: Addrtransfer>(context: &CONTEXT, host_descriptor_table: &Box<DescriptorTables, impl core::alloc::Allocator>, host_paging: &Box<PageTables, impl core::alloc::Allocator>, trans: &mut T) -> Result<(), crate::error::HypervisorError> {
        log::debug!("Setting up Host Registers State");

        vmwrite(host::CR0, controlregs::cr0().bits() as u64)?;
        vmwrite(host::CR3, host_paging.get_pml4_pa(trans)?)?;
        vmwrite(host::CR4, cr4().bits() as u64)?;

        // The RIP/RSP registers are set within `launch_vm`.
     
        const SELECTOR_MASK: u16 = 0xF8;
        vmwrite(host::CS_SELECTOR, (context.SegCs & SELECTOR_MASK) as u64)?;
        vmwrite(host::SS_SELECTOR, (context.SegSs & SELECTOR_MASK)as u64)?;
        vmwrite(host::DS_SELECTOR, (context.SegDs & SELECTOR_MASK)as u64)?;
        vmwrite(host::ES_SELECTOR, (context.SegEs & SELECTOR_MASK)as u64)?;
        vmwrite(host::FS_SELECTOR, (context.SegFs & SELECTOR_MASK)as u64)?;
        vmwrite(host::GS_SELECTOR, (context.SegGs & SELECTOR_MASK)as u64)?;
        vmwrite(host::TR_SELECTOR, (task::tr().bits() & SELECTOR_MASK).into())?;

        vmwrite(host::FS_BASE, msr::rdmsr(msr::IA32_FS_BASE))?;
        vmwrite(host::GS_BASE, msr::rdmsr(msr::IA32_GS_BASE))?;
        vmwrite(host::TR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &host_descriptor_table.gdtr).base_address)?;

        vmwrite(host::GDTR_BASE, host_descriptor_table.gdtr.base as u64)?;
        vmwrite(host::IDTR_BASE, host_descriptor_table.idtr.base as u64)?;

      
        vmwrite(host::IA32_SYSENTER_CS, msr::rdmsr(msr::IA32_SYSENTER_CS))?;
        vmwrite(host::IA32_SYSENTER_ESP, msr::rdmsr(msr::IA32_SYSENTER_ESP))?;
        vmwrite(host::IA32_SYSENTER_EIP, msr::rdmsr(msr::IA32_SYSENTER_EIP))?;
        

        log::debug!("Host Registers State setup successfully!");

        Ok(())
    }






    #[rustfmt::skip]
    pub fn setup_vmcs_control_fields<T: Addrtransfer>(shared_data: &mut SharedData<impl core::alloc::Allocator>, trans: &mut T) -> Result<(), HypervisorError> {
        log::debug!("Setting up VMCS Control Fields");

        const PRIMARY_CTL: u64 = (control::PrimaryControls::SECONDARY_CONTROLS.bits() | control::PrimaryControls::USE_MSR_BITMAPS.bits()) as u64;
        const SECONDARY_CTL: u64 = (control::SecondaryControls::ENABLE_RDTSCP.bits()
            | control::SecondaryControls::ENABLE_XSAVES_XRSTORS.bits()
            | control::SecondaryControls::ENABLE_INVPCID.bits()
            | control::SecondaryControls::ENABLE_VPID.bits()
            | control::SecondaryControls::ENABLE_EPT.bits()) as u64;
        const ENTRY_CTL: u64 = control::EntryControls::IA32E_MODE_GUEST.bits() as u64;
        const EXIT_CTL: u64 = control::ExitControls::HOST_ADDRESS_SPACE_SIZE.bits() as u64;
        const PINBASED_CTL: u64 = 0;


        vmwrite(control::VMENTRY_CONTROLS, adjust_vmx_controls(VmxControl::VmEntry, ENTRY_CTL))?;
        vmwrite(control::VMEXIT_CONTROLS, adjust_vmx_controls(VmxControl::VmExit, EXIT_CTL))?;
        vmwrite(control::PRIMARY_PROCBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::ProcessorBased, PRIMARY_CTL ))?;
        vmwrite(control::SECONDARY_PROCBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::ProcessorBased2, SECONDARY_CTL))?;
        vmwrite(control::PINBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::PinBased, PINBASED_CTL))?;

      
        //vmwrite(control::CR0_READ_SHADOW, controlregs::cr0().bits() as u64)?;
        //vmwrite(control::CR4_READ_SHADOW, cr4().bits() as u64)?;
 

        vmwrite(control::MSR_BITMAPS_ADDR_FULL, trans.va_into_pa(shared_data.msr_bitmap.as_ref() as *const _ as _))?;
        vmwrite(control::EXCEPTION_BITMAP, 1u64 << (ExceptionInterrupt::Breakpoint as u32))?;

        vmwrite(control::EPTP_FULL, shared_data.primary_eptp)?;
        vmwrite(control::VPID, crate::invvpid::VPID_TAG.into())?;

        crate::invept::invept_single_context(shared_data.primary_eptp);
        crate::invvpid::invvpid_single_context(crate::invvpid::VPID_TAG);

        log::debug!("VMCS Control Fields setup successfully!");

        Ok(())
    }

    /// Retrieves the VMCS revision ID.


    /// Retrieves the VMCS revision ID.
    pub fn get_vmcs_revision_id() -> u32 {
      (msr::rdmsr(msr::IA32_VMX_BASIC) as u32) & 0x7FFF_FFFF 
    }

}