Nothing to see here, move along meow
0

Configure Feed

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

at main 9.7 kB View raw
1use crate::cap::cnode; 2use crate::cap::frame_table::{self, FRAME_TABLE}; 3use crate::cap::object::ObjectTag; 4use crate::cap::pool::POOL; 5use crate::cap::table::Rights; 6use crate::error::KernelError; 7use crate::pci::DEVICE_TABLE; 8use crate::proc::PROCESSES; 9use crate::proc::context::CpuContext; 10use lancer_core::object_layout::{FrameObject, PciDeviceObject}; 11 12use super::{SyscallResult, try_syscall}; 13 14pub fn sys_iommu_map(ctx: &mut CpuContext) { 15 let pci_cap_addr = ctx.rdi; 16 let frame_cap_addr = ctx.rsi; 17 let pid = crate::arch::syscall::current_pid(); 18 19 let (pci_cap, frame_cap) = { 20 let ptable = PROCESSES.lock(); 21 let pool = POOL.lock_after(&ptable); 22 let pci = try_syscall!( 23 ctx, 24 cnode::resolve_caller_validate( 25 pid, 26 pci_cap_addr, 27 ObjectTag::PciDevice, 28 Rights::WRITE, 29 &ptable, 30 &pool, 31 ) 32 ); 33 let frame = try_syscall!( 34 ctx, 35 cnode::resolve_caller_validate( 36 pid, 37 frame_cap_addr, 38 ObjectTag::Frame, 39 Rights::WRITE, 40 &ptable, 41 &pool, 42 ) 43 ); 44 (pci, frame) 45 }; 46 47 let device_table_idx = { 48 let pool = POOL.lock(); 49 match pool.read_as::<PciDeviceObject>(pci_cap.phys(), pci_cap.generation()) { 50 Ok(d) => d.device_table_idx, 51 Err(e) => { 52 ctx.rax = SyscallResult::error(e).raw(); 53 return; 54 } 55 } 56 }; 57 58 let (bus, devfn) = { 59 let dev_table = DEVICE_TABLE.lock(); 60 match dev_table.get(device_table_idx as usize) { 61 Some(d) => (d.bus, d.devfn()), 62 None => { 63 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 64 return; 65 } 66 } 67 }; 68 69 let (frame_phys, ft_idx) = { 70 let pool = POOL.lock(); 71 match pool.read_as::<FrameObject>(frame_cap.phys(), frame_cap.generation()) { 72 Ok(f) => (f.phys_addr, f.frame_table_idx), 73 Err(e) => { 74 ctx.rax = SyscallResult::error(e).raw(); 75 return; 76 } 77 } 78 }; 79 80 if ft_idx == lancer_core::header::NONE_SENTINEL as u16 { 81 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw(); 82 return; 83 } 84 85 if !crate::iommu::is_available() { 86 ctx.rax = SyscallResult::error(KernelError::NotInitialized).raw(); 87 return; 88 } 89 90 let hhdm_offset = crate::mem::addr::hhdm_offset(); 91 let mut allocator = crate::mem::phys::BitmapFrameAllocator; 92 93 let (iova, domain_id) = { 94 let mut devices = crate::iommu::DMA_DEVICES.lock(); 95 let dev = match devices 96 .iter_mut() 97 .find(|d| d.bus == bus && d.devfn == devfn) 98 { 99 Some(d) => d, 100 None => { 101 ctx.rax = SyscallResult::error(KernelError::NotFound).raw(); 102 return; 103 } 104 }; 105 106 let iova = match dev.iova_alloc.allocate(1) { 107 Some(base) => base, 108 None => { 109 ctx.rax = SyscallResult::error(KernelError::ResourceExhausted).raw(); 110 return; 111 } 112 }; 113 114 match crate::iommu::tables::map_iova_to_phys( 115 &dev.dma_pt, 116 iova, 117 x86_64::PhysAddr::new(frame_phys), 118 &mut allocator, 119 hhdm_offset, 120 ) { 121 Ok(()) => {} 122 Err(e) => { 123 let _ = dev.iova_alloc.free(iova, 1); 124 ctx.rax = SyscallResult::error(e).raw(); 125 return; 126 } 127 } 128 129 (iova, dev.domain_id) 130 }; 131 132 if let Err(e) = crate::iommu::invalidate_iotlb_domain(domain_id) { 133 crate::kprintln!( 134 "[IOMMU] IOTLB invalidation warning during iommu_map: {:?}", 135 e 136 ); 137 } 138 139 let mut ft = FRAME_TABLE.lock(); 140 let entry = ft.get_mut(ft_idx); 141 match entry.iommu_mapping() { 142 Some(_) => { 143 drop(ft); 144 crate::iommu::unmap_frame_iommu(bus, devfn, iova); 145 ctx.rax = SyscallResult::error(KernelError::AlreadyExists).raw(); 146 } 147 None => { 148 entry.set_iommu(frame_table::IommuMapping { bus, devfn, iova }); 149 ctx.rax = SyscallResult::success(iova).raw(); 150 } 151 } 152} 153 154pub fn sys_iommu_unmap(ctx: &mut CpuContext) { 155 let pci_cap_addr = ctx.rdi; 156 let frame_cap_addr = ctx.rsi; 157 let pid = crate::arch::syscall::current_pid(); 158 159 let (pci_cap, frame_cap) = { 160 let ptable = PROCESSES.lock(); 161 let pool = POOL.lock_after(&ptable); 162 let pci = try_syscall!( 163 ctx, 164 cnode::resolve_caller_validate( 165 pid, 166 pci_cap_addr, 167 ObjectTag::PciDevice, 168 Rights::WRITE, 169 &ptable, 170 &pool, 171 ) 172 ); 173 let frame = try_syscall!( 174 ctx, 175 cnode::resolve_caller_validate( 176 pid, 177 frame_cap_addr, 178 ObjectTag::Frame, 179 Rights::WRITE, 180 &ptable, 181 &pool, 182 ) 183 ); 184 (pci, frame) 185 }; 186 187 let device_table_idx = { 188 let pool = POOL.lock(); 189 match pool.read_as::<PciDeviceObject>(pci_cap.phys(), pci_cap.generation()) { 190 Ok(d) => d.device_table_idx, 191 Err(e) => { 192 ctx.rax = SyscallResult::error(e).raw(); 193 return; 194 } 195 } 196 }; 197 198 let (bus, devfn) = { 199 let dev_table = DEVICE_TABLE.lock(); 200 match dev_table.get(device_table_idx as usize) { 201 Some(d) => (d.bus, d.devfn()), 202 None => { 203 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 204 return; 205 } 206 } 207 }; 208 209 let ft_idx = { 210 let pool = POOL.lock(); 211 match pool.read_as::<FrameObject>(frame_cap.phys(), frame_cap.generation()) { 212 Ok(f) => f.frame_table_idx, 213 Err(e) => { 214 ctx.rax = SyscallResult::error(e).raw(); 215 return; 216 } 217 } 218 }; 219 if ft_idx == lancer_core::header::NONE_SENTINEL as u16 { 220 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 221 return; 222 } 223 let mapping = { 224 let mut ft = FRAME_TABLE.lock(); 225 let entry = ft.get_mut(ft_idx); 226 match entry.iommu_mapping() { 227 Some(m) if m.bus == bus && m.devfn == devfn => { 228 let m_copy = frame_table::IommuMapping { 229 bus: m.bus, 230 devfn: m.devfn, 231 iova: m.iova, 232 }; 233 entry.clear_iommu(); 234 m_copy 235 } 236 Some(_) => { 237 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw(); 238 return; 239 } 240 None => { 241 ctx.rax = SyscallResult::error(KernelError::InvalidParameter).raw(); 242 return; 243 } 244 } 245 }; 246 247 crate::iommu::unmap_frame_iommu(bus, devfn, mapping.iova); 248 ctx.rax = SyscallResult::ok().raw(); 249} 250 251pub fn sys_iommu_setup_device(ctx: &mut CpuContext) { 252 let pid = crate::arch::syscall::current_pid(); 253 if pid != crate::types::Pid::new(0) { 254 ctx.rax = SyscallResult::error(KernelError::PermissionDenied).raw(); 255 return; 256 } 257 258 let pci_cap_addr = ctx.rdi; 259 let target_proc_addr = ctx.rsi; 260 261 let (device_table_idx, target_pid) = { 262 let ptable = PROCESSES.lock(); 263 let pool = POOL.lock_after(&ptable); 264 let pci_cap = try_syscall!( 265 ctx, 266 cnode::resolve_caller_validate( 267 pid, 268 pci_cap_addr, 269 ObjectTag::PciDevice, 270 Rights::WRITE, 271 &ptable, 272 &pool, 273 ) 274 ); 275 let proc_cap = try_syscall!( 276 ctx, 277 cnode::resolve_caller_validate( 278 pid, 279 target_proc_addr, 280 ObjectTag::Process, 281 Rights::READ, 282 &ptable, 283 &pool, 284 ) 285 ); 286 let idx = match pool.read_as::<PciDeviceObject>(pci_cap.phys(), pci_cap.generation()) { 287 Ok(d) => d.device_table_idx, 288 Err(e) => { 289 ctx.rax = SyscallResult::error(e).raw(); 290 return; 291 } 292 }; 293 let tpid = match pool.read_as::<lancer_core::object_layout::ProcessObject>( 294 proc_cap.phys(), 295 proc_cap.generation(), 296 ) { 297 Ok(p) => match crate::types::Pid::try_new(p.pid) { 298 Some(pid) => pid, 299 None => { 300 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); 301 return; 302 } 303 }, 304 Err(e) => { 305 ctx.rax = SyscallResult::error(e).raw(); 306 return; 307 } 308 }; 309 (idx, tpid) 310 }; 311 312 if !crate::iommu::is_available() { 313 ctx.rax = SyscallResult::ok().raw(); 314 return; 315 } 316 317 let hhdm_offset = crate::mem::addr::hhdm_offset(); 318 let mut allocator = crate::mem::phys::BitmapFrameAllocator; 319 320 ctx.rax = match crate::iommu::setup_device_context( 321 device_table_idx, 322 target_pid, 323 &mut allocator, 324 hhdm_offset, 325 ) { 326 Ok(()) => SyscallResult::ok().raw(), 327 Err(e) => SyscallResult::error(e).raw(), 328 }; 329}