Documentation
use alloc::boxed::Box;
use bit_field::BitField;


use crate::{error::HypervisorError, x86::{controlregs::{Cr4, cr4, cr4_write}, msr::{self, rdmsr}}, x86_64::addr::Addrtransfer};

#[derive(Debug, Clone, Copy)]
#[repr(C, align(4096))]
pub struct __VMXON {
    pub revision_id: u32,
    pub reserved: [u8; 0x1000 - size_of::<u32>()],
}






impl __VMXON {

    pub fn vmxon_init_cpu<T: Addrtransfer>(vgp_index: usize, vmxon_region: &mut Box<__VMXON, impl core::alloc::Allocator>, trans: &mut T) -> Result<(), HypervisorError> {
        // let mut vmxon_region: Box<__VMCS, PhysicalAllocator> =unsafe { Box::try_new_zeroed_in(PhysicalAllocator).unwrap().assume_init() };
        //let mut vcpu = Vec::<__VMCPU>::new();

        //let mut current_vcpu_ptr = unsafe { VMCPU }[vgp_index];
        vmxon_region.revision_id = rdmsr(msr::IA32_VMX_BASIC)  as u32;
        log::debug!("rust: ------------------------------------------------");
        vmxon_region.revision_id.set_bit(31, false);
        log::debug!("rust: ------------------------------------------------");
        log::debug!("rust: vmxon revision_id{}", vmxon_region.revision_id);
        log::debug!("rust: ------------------------------------------------");
        Self::enable_vmx_operation()?;
        let va = vmxon_region.as_ref() as *const _ as u64;
        
        log::debug!("rust: cr0 cr4 vmxon executed for cpu core:{}", vgp_index);

        let phys_addr = trans.va_into_pa(va as u64);

        log::debug!("rust: addr cast vmxon executed for cpu core:{} va:{:#16x} pa:{:#16x}", vgp_index, va, phys_addr);
        crate::x86::vmx_support::vmxon(phys_addr)?;
        // let mut cpu = __VMX::default();
        // cpu.vmxon = Some(vmxon_region.to_owned());
        // cpu.cpu_index =Some(vgp_index);
        // // vcpu.push(cpu);
        // VMCPU.lock().get_mut().unwrap().push(cpu);


        // match enable_vmx_operation() {
        //     Ok(_) => {
        //             let va = vmxon_region.as_ref() as *const _ as u64;
                    
            //         log::debug!("rust: cr0 cr4 vmxon executed for cpu core:{}", vgp_index);
    
        //             let phys_addr = va_into_pa(va as u64);

            //         log::debug!("rust: addr cast vmxon executed for cpu core:{} va:{:#16x} pa:{:#16x}", vgp_index, va, phys_addr);
        //             match  crate::vmx_support::vmxon(phys_addr) {
        //                 Ok(_) => {
        //                     let mut cpu = __VMCPU::default();
        //                     cpu.vmxon = Some(vmxon_region);
        //                     cpu.cpu_index =Some(vgp_index);
        //                     // vcpu.push(cpu);
        //                     VMCPU.lock().get_mut().unwrap().push(cpu);
        //                    // let arc_for_thread = Arc::clone(vmcpu_arc);
        //                     //guard.set(vcpu).unwrap();
        //                     // guard[vgp_index].vmxon = Some(vmxon_region);
        //                     return STATUS_SUCCESS;
        //                 },
        //                 Err(e) => match e {
                            
        //                     crate::vmx_support::VmFail::VmFailValid => {drop(vmxon_region); printlnw!("rust: vmxon vmfailvaild other err core:{}", vgp_index); return STATUS_UNSUCCESSFUL;},
        //                     crate::vmx_support::VmFail::VmFailInvalid => {drop(vmxon_region); printlnw!("rust: vmxon vmfailvaild not vaild core:{}", vgp_index); return STATUS_UNSUCCESSFUL;},
        //                 },
        //             }
                
        //     },
        //     Err(e) =>  {
        //         //HypervisorError::ERR => {drop(vmxon_region);printlnw!("rust: vmxon 未知道错误 core:{}", vgp_index); return STATUS_UNSUCCESSFUL;},
        //          drop(vmxon_region);
            //     log::debug!("rust: vmxon HypervisorError{} core:{}", e, vgp_index); 
        //         return STATUS_UNSUCCESSFUL;
                
        //     },
        // };
        Ok(())
    }






    pub fn enable_vmx_operation() -> Result<(), HypervisorError> {
        const CR4_VMX_ENABLE_BIT: usize = 13;
        let cr4 = cr4() ;
        let mut cr4 = cr4.bits();
        cr4.set_bit(CR4_VMX_ENABLE_BIT, true);
        let cr4 = Cr4::from_bits_truncate(cr4);
        cr4_write(cr4);

        /* Intel® 64 and IA-32 Architectures Software Developer's Manual: 24.7 ENABLING AND ENTERING VMX OPERATION */
        Self::set_lock_bit()?;
        log::debug!("rust: Setting Lock Bit set via IA32_FEATURE_CONTROL");

        /* Intel® 64 and IA-32 Architectures Software Developer's Manual: 24.8 RESTRICTIONS ON VMX OPERATION */
        set_cr4_cr0();
        log::debug!("rust: Adjusting Control Registers");

        Ok(())
    }


    pub fn set_lock_bit() -> Result<(), HypervisorError> {
        const VMX_LOCK_BIT: u64 = 1 << 0;
        const VMXON_OUTSIDE_SMX: u64 = 1 << 2;

        let ia32_feature_control = msr::rdmsr(msr::IA32_FEATURE_CONTROL);

        if (ia32_feature_control & VMX_LOCK_BIT) == 0 {
            unsafe {
                msr::wrmsr(
                    msr::IA32_FEATURE_CONTROL,
                    VMXON_OUTSIDE_SMX | VMX_LOCK_BIT | ia32_feature_control,
                )
            };
        } else if (ia32_feature_control & VMXON_OUTSIDE_SMX) == 0 {
            return Err(HypervisorError::VMXBIOSLock);
        }

        Ok(())
    }

}



pub  fn set_cr0_bits() {
        let ia32_vmx_cr0_fixed0 = msr::rdmsr(msr::IA32_VMX_CR0_FIXED0);
        let ia32_vmx_cr0_fixed1 = msr::rdmsr(msr::IA32_VMX_CR0_FIXED1);

        let mut cr0 = crate::x86::controlregs::cr0();

        cr0 |= crate::x86::controlregs::Cr0::from_bits_truncate(ia32_vmx_cr0_fixed0 as usize);
        cr0 &= crate::x86::controlregs::Cr0::from_bits_truncate(ia32_vmx_cr0_fixed1 as usize);

        crate::x86::controlregs::cr0_write(cr0);
    }

    /// Modifies CR4 to set and clear mandatory bits.
pub fn set_cr4_bits() {
    let ia32_vmx_cr4_fixed0 = msr::rdmsr(msr::IA32_VMX_CR4_FIXED0);
    let ia32_vmx_cr4_fixed1 = msr::rdmsr(msr::IA32_VMX_CR4_FIXED1);

    let mut cr4 =  crate::x86::controlregs::cr4();

    cr4 |= crate::x86::controlregs::Cr4::from_bits_truncate(ia32_vmx_cr4_fixed0 as usize);
    cr4 &= crate::x86::controlregs::Cr4::from_bits_truncate(ia32_vmx_cr4_fixed1 as usize);

   crate::x86::controlregs::cr4_write(cr4);
}




pub fn set_cr4_cr0(){
    set_cr0_bits();
    set_cr4_bits();
}