<commit_before>use log::trace;

use crate::msr;
use crate::vmcs_fields::PinBasedControlsVmxPreemption;
use crate::{
    vcpu::get_current_vcpu,
    vmcs_fields::{CpuBasedControlsInterruptWindowExiting, VmcsField},
    vmx::{vmread, vmwrite},
};

const VM_PREEMPTION_TIMER_VALUE: u64 = 0xffff;
const INTERRUPT_COUNT: usize = 256;
pub struct VirtualLocalInterruptController {
    total_interrupts_count: usize,
    delayed_delivery_interrupts: [usize; INTERRUPT_COUNT],
    requested_poll_of_interrupts_on_next_preemption_timer: bool,
    we_should_disable_preemption_timer: bool,
}

fn get_local_interrupt_controller() -> &'static mut VirtualLocalInterruptController {
    unsafe { &mut *get_current_vcpu().virtual_local_interrupt_controller }
}

fn delay_interrupt_delivery(interrupt_number: u64) {
    let interrupt_controller = get_local_interrupt_controller();
    let count = &mut interrupt_controller.delayed_delivery_interrupts[interrupt_number as usize];
    *count += 1;
    interrupt_controller.total_interrupts_count = interrupt_controller
        .total_interrupts_count
        .checked_add(1)
        .unwrap();
}

fn check_for_highest_priority_interrupt() -> Option<u64> {
    let interrupt_controller = get_local_interrupt_controller();
    if interrupt_controller.total_interrupts_count == 0 {
        return None;
    }
    for (interrupt_number, count) in &mut interrupt_controller
        .delayed_delivery_interrupts
        .iter_mut()
        .enumerate()
    {
        if *count > 0 {
            *count -= 1;
            interrupt_controller.total_interrupts_count -= 1;
            return Some(interrupt_number as u64);
        }
    }
    unreachable!();
}

// See 192.168.3.11 Generation of Virtual Interrupt Events by VMM
fn vmx_is_guest_interruptable() -> bool {
    let guest_rflags = vmread(VmcsField::GuestRFlags).unwrap();
    // Is the guest interrupt flag clear?
    if (guest_rflags & 0x200) == 0 {
        return false;
    }
    // Are interrupts blocked by a hardware state like sti?
    // Remember, interrupts won't be injected until the instruction *after* sti.
    // There are other instructions which do this too, see vol 3 33.3.3.4
    let guest_interruptability_info = vmread(VmcsField::GuestInterruptibilityInfo).unwrap();
    // See Table 24-3. Format of Interruptibility State
    guest_interruptability_info == 0
}

fn vmx_inject_interrupt_into_guest(vector: u64) -> Result<(), x86::vmx::VmFail> {
    assert!(vector < INTERRUPT_COUNT as u64);
    let interrupt_info = vector | (1 << 31) | (0 << 8); // valid, external interrupts
    crate::debug::breakpoint();
    vmwrite(VmcsField::VmEntryIntrInfoField, interrupt_info)
}

fn vmx_configure_interrupts_wakeup() {
    let pair = msr::rdmsr(msr::Msr::Ia32VmxProcBasedControls);
    let disallowed_exit_values = pair.edx;

    // If we are allowed to set interrupt window exiting, set it.
    if u64::from(disallowed_exit_values) & CpuBasedControlsInterruptWindowExiting == 0 {
        trace!("CPU allows interrupt window exiting");
        let mut cpu_based_controls = vmread(VmcsField::CpuBasedVmExecControl).unwrap();
        cpu_based_controls |= CpuBasedControlsInterruptWindowExiting;<commit_msg>Fix clippy lint 'the operation is ineffective'<commit_after>use log::trace;

use crate::msr;
use crate::vmcs_fields::PinBasedControlsVmxPreemption;
use crate::{
    vcpu::get_current_vcpu,
    vmcs_fields::{CpuBasedControlsInterruptWindowExiting, VmcsField},
    vmx::{vmread, vmwrite},
};

const VM_PREEMPTION_TIMER_VALUE: u64 = 0xffff;
const INTERRUPT_COUNT: usize = 256;
pub struct VirtualLocalInterruptController {
    total_interrupts_count: usize,
    delayed_delivery_interrupts: [usize; INTERRUPT_COUNT],
    requested_poll_of_interrupts_on_next_preemption_timer: bool,
    we_should_disable_preemption_timer: bool,
}

fn get_local_interrupt_controller() -> &'static mut VirtualLocalInterruptController {
    unsafe { &mut *get_current_vcpu().virtual_local_interrupt_controller }
}

fn delay_interrupt_delivery(interrupt_number: u64) {
    let interrupt_controller = get_local_interrupt_controller();
    let count = &mut interrupt_controller.delayed_delivery_interrupts[interrupt_number as usize];
    *count += 1;
    interrupt_controller.total_interrupts_count = interrupt_controller
        .total_interrupts_count
        .checked_add(1)
        .unwrap();
}

fn check_for_highest_priority_interrupt() -> Option<u64> {
    let interrupt_controller = get_local_interrupt_controller();
    if interrupt_controller.total_interrupts_count == 0 {
        return None;
    }
    for (interrupt_number, count) in &mut interrupt_controller
        .delayed_delivery_interrupts
        .iter_mut()
        .enumerate()
    {
        if *count > 0 {
            *count -= 1;
            interrupt_controller.total_interrupts_count -= 1;
            return Some(interrupt_number as u64);
        }
    }
    unreachable!();
}

// See 192.168.3.11 Generation of Virtual Interrupt Events by VMM
fn vmx_is_guest_interruptable() -> bool {
    let guest_rflags = vmread(VmcsField::GuestRFlags).unwrap();
    // Is the guest interrupt flag clear?
    if (guest_rflags & 0x200) == 0 {
        return false;
    }
    // Are interrupts blocked by a hardware state like sti?
    // Remember, interrupts won't be injected until the instruction *after* sti.
    // There are other instructions which do this too, see vol 3 192.168.3.11
    let guest_interruptability_info = vmread(VmcsField::GuestInterruptibilityInfo).unwrap();
    // See Table 24-3. Format of Interruptibility State
    guest_interruptability_info == 0
}

const VM_ENTRY_INTERRUPT_INFO_VALID: u64 = 1 << 31;
const VM_ENTRY_INTERRUPT_INFO_TYPE_EXTERNAL_INTERRUPT: u64 = 0 << 8;
fn vmx_inject_interrupt_into_guest(vector: u64) -> Result<(), x86::vmx::VmFail> {
    assert!(vector < INTERRUPT_COUNT as u64);
    let interrupt_info = vector | VM_ENTRY_INTERRUPT_INFO_VALID | VM_ENTRY_INTERRUPT_INFO_TYPE_EXTERNAL_INTERRUPT;
    crate::debug::breakpoint();
    vmwrite(VmcsField::VmEntryIntrInfoField, interrupt_info)
}

fn vmx_configure_interrupts_wakeup() {
    let pair = msr::rdmsr(msr::Msr::Ia32VmxProcBasedControls);
    let disallowed_exit_values = pair.edx;

    // If we are allowed to set interrupt window exiting, set it.
    if u64::from(disallowed_exit_values) & CpuBasedControlsInterruptWindowExiting == 0 {
        trace!("CPU allows interrupt window exiting");
        let mut cpu_based_controls = vmread(VmcsField::CpuBasedVmExecControl).unwrap();
        cpu_based_controls |= CpuBasedControlsInterruptWindowExiting;
{'fraction_non_alphanumeric': 0.09209528144439387, 'fraction_numerical': 0.018813533606433015, 'mean_word_length': 4.219319081551861, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7305304', 'n_tokens_mistral': 2155, 'n_tokens_neox': 2050, 'n_words': 446}