Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 5.3 kB View raw
1use crate::error::KernelError; 2use crate::mem::phys::BitmapFrameAllocator; 3use crate::mem::virt; 4use crate::pci::config::{self, EcamAddress}; 5use crate::pci::device::BarInfo; 6use crate::sync::IrqMutex; 7use x86_64::structures::paging::OffsetPageTable; 8 9use crate::arch::idt::IrqVector; 10 11const MAX_MSIX_DEVICES: usize = 8; 12 13#[derive(Clone, Copy)] 14struct MsixTableMapping { 15 table_virt: u64, 16 table_entries: u16, 17} 18 19static MSIX_STATE: IrqMutex<[Option<MsixTableMapping>; MAX_MSIX_DEVICES], 3> = 20 IrqMutex::new([None; MAX_MSIX_DEVICES]); 21 22pub fn ensure_table_mapped( 23 device_table_idx: u8, 24 mapper: &mut OffsetPageTable, 25 allocator: &mut BitmapFrameAllocator, 26 hhdm_offset: u64, 27) -> Result<(), KernelError> { 28 let idx = device_table_idx as usize; 29 { 30 let state = MSIX_STATE.lock(); 31 if state.get(idx).and_then(|s| s.as_ref()).is_some() { 32 return Ok(()); 33 } 34 } 35 36 let dev_table = crate::pci::DEVICE_TABLE.lock(); 37 let dev = dev_table.get(idx).ok_or(KernelError::InvalidObject)?; 38 let msix_cap = dev.msix_cap.ok_or(KernelError::InvalidParameter)?; 39 let bar = dev.bars[msix_cap.table_bir as usize]; 40 drop(dev_table); 41 42 let phys_base = match bar { 43 BarInfo::Memory { phys_base, .. } => phys_base, 44 _ => return Err(KernelError::InvalidParameter), 45 }; 46 47 let table_phys = phys_base + msix_cap.table_offset as u64; 48 let table_byte_size = (msix_cap.table_size as u64) * 16; 49 let page_count = table_byte_size.div_ceil(4096); 50 51 (0..page_count).try_for_each(|i| { 52 let page_phys = (table_phys & !0xFFF) + i * 4096; 53 virt::map_mmio(mapper, allocator, page_phys, hhdm_offset) 54 })?; 55 56 let table_virt = table_phys + hhdm_offset; 57 58 let mut state = MSIX_STATE.lock(); 59 match state.get_mut(idx) { 60 Some(slot) => { 61 *slot = Some(MsixTableMapping { 62 table_virt, 63 table_entries: msix_cap.table_size, 64 }); 65 Ok(()) 66 } 67 None => Err(KernelError::ResourceExhausted), 68 } 69} 70 71pub fn configure_entry( 72 device_table_idx: u8, 73 entry_idx: u16, 74 vector: IrqVector, 75 dest_apic_id: u8, 76) -> Result<(), KernelError> { 77 let state = MSIX_STATE.lock(); 78 let mapping = state 79 .get(device_table_idx as usize) 80 .and_then(|s| s.as_ref()) 81 .ok_or(KernelError::BadState)?; 82 83 if entry_idx >= mapping.table_entries { 84 return Err(KernelError::InvalidParameter); 85 } 86 87 let entry_base = mapping.table_virt + (entry_idx as u64) * 16; 88 89 let msg_addr: u32 = 0xFEE0_0000 | ((dest_apic_id as u32) << 12); 90 let msg_data: u32 = vector.raw() as u32; 91 let vector_control: u32 = 1; 92 93 unsafe { 94 core::ptr::write_volatile(entry_base as *mut u32, msg_addr); 95 core::ptr::write_volatile((entry_base + 4) as *mut u32, 0); 96 core::ptr::write_volatile((entry_base + 8) as *mut u32, msg_data); 97 core::ptr::write_volatile((entry_base + 12) as *mut u32, vector_control); 98 } 99 100 Ok(()) 101} 102 103pub fn unmask_entry(device_table_idx: u8, entry_idx: u16) -> Result<(), KernelError> { 104 let state = MSIX_STATE.lock(); 105 let mapping = state 106 .get(device_table_idx as usize) 107 .and_then(|s| s.as_ref()) 108 .ok_or(KernelError::BadState)?; 109 110 if entry_idx >= mapping.table_entries { 111 return Err(KernelError::InvalidParameter); 112 } 113 114 let vc_addr = mapping.table_virt + (entry_idx as u64) * 16 + 12; 115 unsafe { 116 let current = core::ptr::read_volatile(vc_addr as *const u32); 117 core::ptr::write_volatile(vc_addr as *mut u32, current & !1); 118 } 119 120 Ok(()) 121} 122 123#[allow(dead_code)] 124pub fn mask_entry(device_table_idx: u8, entry_idx: u16) -> Result<(), KernelError> { 125 let state = MSIX_STATE.lock(); 126 let mapping = state 127 .get(device_table_idx as usize) 128 .and_then(|s| s.as_ref()) 129 .ok_or(KernelError::BadState)?; 130 131 if entry_idx >= mapping.table_entries { 132 return Err(KernelError::InvalidParameter); 133 } 134 135 let vc_addr = mapping.table_virt + (entry_idx as u64) * 16 + 12; 136 unsafe { 137 let current = core::ptr::read_volatile(vc_addr as *const u32); 138 core::ptr::write_volatile(vc_addr as *mut u32, current | 1); 139 } 140 141 Ok(()) 142} 143 144pub fn enable_msix(device_table_idx: u8) -> Result<(), KernelError> { 145 let dev_table = crate::pci::DEVICE_TABLE.lock(); 146 let dev = dev_table 147 .get(device_table_idx as usize) 148 .ok_or(KernelError::InvalidObject)?; 149 let msix_cap = dev.msix_cap.ok_or(KernelError::InvalidParameter)?; 150 151 let mcfg_entries = crate::acpi::mcfg::cached_mcfg_entries(); 152 let ecam_base = mcfg_entries 153 .iter() 154 .find(|e| dev.bus >= e.start_bus && dev.bus <= e.end_bus) 155 .map(|e| e.base_address) 156 .ok_or(KernelError::InvalidObject)?; 157 158 let addr = EcamAddress::new(ecam_base, dev.bus, dev.device, dev.function) 159 .ok_or(KernelError::InvalidParameter)?; 160 drop(dev_table); 161 162 let cap_dword_offset = msix_cap.cap_offset & !0x3; 163 let current = config::read_config_u32(addr, cap_dword_offset); 164 let enabled = current | (1 << 31); 165 let unmasked = enabled & !(1 << 30); 166 config::write_config_u32(addr, cap_dword_offset, unmasked); 167 168 Ok(()) 169}