use crate::arch::kvm::VmcsFields::{
    GUEST_CS_ACCESS_RIGHTS, GUEST_CS_BASE, GUEST_CS_LIMIT, GUEST_CS_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_DS_ACCESS_RIGHTS, GUEST_DS_BASE, GUEST_DS_LIMIT, GUEST_DS_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_ES_ACCESS_RIGHTS, GUEST_ES_BASE, GUEST_ES_LIMIT, GUEST_ES_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_FS_ACCESS_RIGHTS, GUEST_FS_BASE, GUEST_FS_LIMIT, GUEST_FS_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_GS_ACCESS_RIGHTS, GUEST_GS_BASE, GUEST_GS_LIMIT, GUEST_GS_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_LDTR_ACCESS_RIGHTS, GUEST_LDTR_BASE, GUEST_LDTR_LIMIT, GUEST_LDTR_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_SS_ACCESS_RIGHTS, GUEST_SS_BASE, GUEST_SS_LIMIT, GUEST_SS_SELECTOR,
};
use crate::arch::kvm::VmcsFields::{
    GUEST_TR_ACCESS_RIGHTS, GUEST_TR_BASE, GUEST_TR_LIMIT, GUEST_TR_SELECTOR,
};
use system_error::SystemError;

use super::vmx_asm_wrapper::vmx_vmwrite;

// pub const TSS_IOPB_BASE_OFFSET: usize = 0x66;
// pub const TSS_BASE_SIZE: usize = 0x68;
// pub const TSS_IOPB_SIZE: usize = 65536 / 8;
// pub const TSS_REDIRECTION_SIZE: usize = 256 / 8;
// pub const RMODE_TSS_SIZE: usize = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1;

#[derive(Debug)]
pub struct KvmVmxSegmentField {
    selector: u32,
    base: u32,
    limit: u32,
    access_rights: u32,
}

macro_rules! VMX_SEGMENT_FIELD {
    ($struct_name: ident) => {
        KvmVmxSegmentField {
            selector: concat_idents!(GUEST_, $struct_name, _SELECTOR) as u32,
            base: concat_idents!(GUEST_, $struct_name, _BASE) as u32,
            limit: concat_idents!(GUEST_, $struct_name, _LIMIT) as u32,
            access_rights: concat_idents!(GUEST_, $struct_name, _ACCESS_RIGHTS) as u32,
        }
    };
}
#[derive(FromPrimitive)]
pub enum Sreg {
    ES = 0,
    CS = 1,
    SS = 2,
    DS = 3,
    FS = 4,
    GS = 5,
    TR = 6,
    LDTR = 7,
}

static KVM_VMX_SEGMENT_FIELDS: [KvmVmxSegmentField; 8] = [
    VMX_SEGMENT_FIELD!(ES),
    VMX_SEGMENT_FIELD!(CS),
    VMX_SEGMENT_FIELD!(SS),
    VMX_SEGMENT_FIELD!(DS),
    VMX_SEGMENT_FIELD!(FS),
    VMX_SEGMENT_FIELD!(GS),
    VMX_SEGMENT_FIELD!(TR),
    VMX_SEGMENT_FIELD!(LDTR),
];

pub fn seg_setup(seg: usize) -> Result<(), SystemError> {
    let seg_field = &KVM_VMX_SEGMENT_FIELDS[seg];
    let mut access_rigt = 0x0093;
    if seg == Sreg::CS as usize {
        access_rigt |= 0x08;
    }
    // setup segment fields
    vmx_vmwrite(seg_field.selector, 0)?;
    vmx_vmwrite(seg_field.base, 0)?;
    vmx_vmwrite(seg_field.limit, 0x0000_FFFF)?;
    vmx_vmwrite(seg_field.access_rights, access_rigt)?;

    Ok(())
}
