use crate::cap::cnode; use crate::cap::object::ObjectTag; use crate::cap::pool::POOL; use crate::cap::table::Rights; use crate::error::KernelError; use crate::pci::DEVICE_TABLE; use crate::proc::PROCESSES; use crate::proc::context::CpuContext; use lancer_core::object_layout::PciDeviceObject; use super::{SyscallResult, USER_ADDR_LIMIT, try_syscall, validate_user_vaddr}; pub fn sys_dma_alloc(ctx: &mut CpuContext) { let cap_addr = ctx.rdi; let page_count = ctx.rsi; let user_vaddr = ctx.rdx; let pid = crate::arch::syscall::current_pid(); if user_vaddr & 0xFFF != 0 { ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw(); return; } let _ = try_syscall!(ctx, validate_user_vaddr(user_vaddr)); match page_count .checked_mul(4096) .and_then(|sz| user_vaddr.checked_add(sz)) { Some(end) if end <= USER_ADDR_LIMIT => {} _ => { ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw(); return; } } let (cap, pml4_phys) = { let ptable = PROCESSES.lock(); let pool = POOL.lock_after(&ptable); match cnode::resolve_caller_validate( pid, cap_addr, ObjectTag::PciDevice, Rights::WRITE, &ptable, &pool, ) { Ok(c) => { let pml4 = ptable .exec(pid) .map(|e| e.pml4_phys) .ok_or(KernelError::InvalidObject); match pml4 { Ok(pml4_phys) => (c, pml4_phys), Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } } } Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } } }; let device_table_idx = { let pool = POOL.lock(); match pool.read_as::(cap.phys(), cap.generation()) { Ok(d) => d.device_table_idx, Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } } }; let (bus, devfn) = { let dev_table = DEVICE_TABLE.lock(); match dev_table.get(device_table_idx as usize) { Some(d) => (d.bus, d.devfn()), None => { ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); return; } } }; if !crate::iommu::is_available() { ctx.rax = SyscallResult::error(KernelError::NotInitialized).raw(); return; } let hhdm_offset = crate::mem::addr::hhdm_offset(); let mut allocator = crate::mem::phys::BitmapFrameAllocator; ctx.rax = match crate::iommu::dma_alloc( bus, devfn, page_count, user_vaddr, pml4_phys, pid, &mut allocator, hhdm_offset, ) { Ok(iova) => SyscallResult::success(iova).raw(), Err(e) => SyscallResult::error(e).raw(), }; } pub fn sys_dma_free(ctx: &mut CpuContext) { let cap_addr = ctx.rdi; let iova = ctx.rsi; let page_count = ctx.rdx; let pid = crate::arch::syscall::current_pid(); if iova & 0xFFF != 0 { ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw(); return; } let (cap, pml4_phys) = { let ptable = PROCESSES.lock(); let pool = POOL.lock_after(&ptable); match cnode::resolve_caller_validate( pid, cap_addr, ObjectTag::PciDevice, Rights::WRITE, &ptable, &pool, ) { Ok(c) => { let pml4 = ptable .exec(pid) .map(|e| e.pml4_phys) .ok_or(KernelError::InvalidObject); match pml4 { Ok(pml4_phys) => (c, pml4_phys), Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } } } Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } } }; let device_table_idx = { let pool = POOL.lock(); match pool.read_as::(cap.phys(), cap.generation()) { Ok(d) => d.device_table_idx, Err(e) => { ctx.rax = SyscallResult::error(e).raw(); return; } } }; let (bus, devfn) = { let dev_table = DEVICE_TABLE.lock(); match dev_table.get(device_table_idx as usize) { Some(d) => (d.bus, d.devfn()), None => { ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw(); return; } } }; let hhdm_offset = crate::mem::addr::hhdm_offset(); ctx.rax = match crate::iommu::dma_free(bus, devfn, iova, page_count, pml4_phys, pid, hhdm_offset) { Ok(()) => SyscallResult::ok().raw(), Err(e) => SyscallResult::error(e).raw(), }; }