#![allow(dead_code)]
#![allow(unused_variables)]
use alloc::{sync::Arc, vec::Vec};
#[cfg(feature = "intel_tdx")]
use ::tdx_guest::tdx_is_enabled;
#[cfg(feature = "intel_tdx")]
use crate::arch::tdx_guest;
use crate::{
bus::pci::{
cfg_space::{Bar, Command, MemoryBar},
common_device::PciCommonDevice,
device_info::PciDeviceLocation,
},
mm::VmIo,
trap::IrqLine,
};
#[derive(Debug)]
#[repr(C)]
pub struct CapabilityMsixData {
loc: PciDeviceLocation,
ptr: u16,
table_size: u16,
table_bar: Arc<MemoryBar>,
pending_table_bar: Arc<MemoryBar>,
table_offset: usize,
pending_table_offset: usize,
irqs: Vec<Option<IrqLine>>,
}
impl Clone for CapabilityMsixData {
fn clone(&self) -> Self {
let new_vec = self.irqs.clone().to_vec();
Self {
loc: self.loc,
ptr: self.ptr,
table_size: self.table_size,
table_bar: self.table_bar.clone(),
pending_table_bar: self.pending_table_bar.clone(),
irqs: new_vec,
table_offset: self.table_offset,
pending_table_offset: self.pending_table_offset,
}
}
}
impl CapabilityMsixData {
pub(super) fn new(dev: &mut PciCommonDevice, cap_ptr: u16) -> Self {
let table_info = dev.location().read32(cap_ptr + 4);
let pba_info = dev.location().read32(cap_ptr + 8);
let table_bar;
let pba_bar;
let bar_manager = dev.bar_manager_mut();
bar_manager.set_invisible((pba_info & 0b111) as u8);
bar_manager.set_invisible((table_info & 0b111) as u8);
match bar_manager
.bar_space_without_invisible((pba_info & 0b111) as u8)
.expect("MSIX cfg:pba BAR is none")
{
Bar::Memory(memory) => {
pba_bar = memory;
}
Bar::Io(_) => {
panic!("MSIX cfg:pba BAR is IO type")
}
};
match bar_manager
.bar_space_without_invisible((table_info & 0b111) as u8)
.expect("MSIX cfg:table BAR is none")
{
Bar::Memory(memory) => {
table_bar = memory;
}
Bar::Io(_) => {
panic!("MSIX cfg:table BAR is IO type")
}
}
let pba_offset = (pba_info & !(0b111u32)) as usize;
let table_offset = (table_info & !(0b111u32)) as usize;
let table_size = (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1;
let message_address = 0xFEE0_0000u32;
let message_upper_address = 0u32;
for i in 0..table_size {
#[cfg(feature = "intel_tdx")]
if tdx_is_enabled() {
unsafe {
tdx_guest::unprotect_gpa_range(table_bar.io_mem().paddr(), 1).unwrap();
}
}
table_bar
.io_mem()
.write_val((16 * i) as usize + table_offset, &message_address)
.unwrap();
table_bar
.io_mem()
.write_val((16 * i + 4) as usize + table_offset, &message_upper_address)
.unwrap();
table_bar
.io_mem()
.write_val((16 * i + 12) as usize + table_offset, &1_u32)
.unwrap();
}
dev.location()
.write16(cap_ptr + 2, dev.location().read16(cap_ptr + 2) | 0x8000);
dev.set_command(dev.command() | Command::INTERRUPT_DISABLE | Command::BUS_MASTER);
let mut irqs = Vec::with_capacity(table_size as usize);
for i in 0..table_size {
irqs.push(None);
}
Self {
loc: *dev.location(),
ptr: cap_ptr,
table_size: (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1,
table_bar,
pending_table_bar: pba_bar,
irqs,
table_offset,
pending_table_offset: pba_offset,
}
}
pub fn table_size(&self) -> u16 {
(self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1
}
pub fn set_interrupt_vector(&mut self, handle: IrqLine, index: u16) {
if index >= self.table_size {
return;
}
self.table_bar
.io_mem()
.write_val(
(16 * index + 8) as usize + self.table_offset,
&(handle.num() as u32),
)
.unwrap();
let old_handles = core::mem::replace(&mut self.irqs[index as usize], Some(handle));
self.table_bar
.io_mem()
.write_val((16 * index + 12) as usize + self.table_offset, &0_u32)
.unwrap();
}
pub fn irq_mut(&mut self, index: usize) -> Option<&mut IrqLine> {
self.irqs[index].as_mut()
}
}
fn set_bit(origin_value: u16, offset: usize, set: bool) -> u16 {
(origin_value & (!(1 << offset))) | ((set as u16) << offset)
}