Nothing to see here, move along
1use crate::cap::cnode;
2use crate::cap::object::ObjectTag;
3use crate::cap::pool::POOL;
4use crate::cap::table::Rights;
5use crate::error::KernelError;
6use crate::pci::DEVICE_TABLE;
7use crate::proc::PROCESSES;
8use crate::proc::context::CpuContext;
9use lancer_core::object_layout::PciDeviceObject;
10
11use super::{SyscallResult, USER_ADDR_LIMIT, try_syscall, validate_user_vaddr};
12
13pub fn sys_dma_alloc(ctx: &mut CpuContext) {
14 let cap_addr = ctx.rdi;
15 let page_count = ctx.rsi;
16 let user_vaddr = ctx.rdx;
17 let pid = crate::arch::syscall::current_pid();
18
19 if user_vaddr & 0xFFF != 0 {
20 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
21 return;
22 }
23
24 let _ = try_syscall!(ctx, validate_user_vaddr(user_vaddr));
25
26 match page_count
27 .checked_mul(4096)
28 .and_then(|sz| user_vaddr.checked_add(sz))
29 {
30 Some(end) if end <= USER_ADDR_LIMIT => {}
31 _ => {
32 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
33 return;
34 }
35 }
36
37 let (cap, pml4_phys) = {
38 let ptable = PROCESSES.lock();
39 let pool = POOL.lock_after(&ptable);
40 match cnode::resolve_caller_validate(
41 pid,
42 cap_addr,
43 ObjectTag::PciDevice,
44 Rights::WRITE,
45 &ptable,
46 &pool,
47 ) {
48 Ok(c) => {
49 let pml4 = ptable
50 .exec(pid)
51 .map(|e| e.pml4_phys)
52 .ok_or(KernelError::InvalidObject);
53 match pml4 {
54 Ok(pml4_phys) => (c, pml4_phys),
55 Err(e) => {
56 ctx.rax = SyscallResult::error(e).raw();
57 return;
58 }
59 }
60 }
61 Err(e) => {
62 ctx.rax = SyscallResult::error(e).raw();
63 return;
64 }
65 }
66 };
67
68 let device_table_idx = {
69 let pool = POOL.lock();
70 match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) {
71 Ok(d) => d.device_table_idx,
72 Err(e) => {
73 ctx.rax = SyscallResult::error(e).raw();
74 return;
75 }
76 }
77 };
78
79 let (bus, devfn) = {
80 let dev_table = DEVICE_TABLE.lock();
81 match dev_table.get(device_table_idx as usize) {
82 Some(d) => (d.bus, d.devfn()),
83 None => {
84 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
85 return;
86 }
87 }
88 };
89
90 if !crate::iommu::is_available() {
91 ctx.rax = SyscallResult::error(KernelError::NotInitialized).raw();
92 return;
93 }
94
95 let hhdm_offset = crate::mem::addr::hhdm_offset();
96 let mut allocator = crate::mem::phys::BitmapFrameAllocator;
97
98 ctx.rax = match crate::iommu::dma_alloc(
99 bus,
100 devfn,
101 page_count,
102 user_vaddr,
103 pml4_phys,
104 pid,
105 &mut allocator,
106 hhdm_offset,
107 ) {
108 Ok(iova) => SyscallResult::success(iova).raw(),
109 Err(e) => SyscallResult::error(e).raw(),
110 };
111}
112
113pub fn sys_dma_free(ctx: &mut CpuContext) {
114 let cap_addr = ctx.rdi;
115 let iova = ctx.rsi;
116 let page_count = ctx.rdx;
117 let pid = crate::arch::syscall::current_pid();
118
119 if iova & 0xFFF != 0 {
120 ctx.rax = SyscallResult::error(KernelError::InvalidAddress).raw();
121 return;
122 }
123
124 let (cap, pml4_phys) = {
125 let ptable = PROCESSES.lock();
126 let pool = POOL.lock_after(&ptable);
127 match cnode::resolve_caller_validate(
128 pid,
129 cap_addr,
130 ObjectTag::PciDevice,
131 Rights::WRITE,
132 &ptable,
133 &pool,
134 ) {
135 Ok(c) => {
136 let pml4 = ptable
137 .exec(pid)
138 .map(|e| e.pml4_phys)
139 .ok_or(KernelError::InvalidObject);
140 match pml4 {
141 Ok(pml4_phys) => (c, pml4_phys),
142 Err(e) => {
143 ctx.rax = SyscallResult::error(e).raw();
144 return;
145 }
146 }
147 }
148 Err(e) => {
149 ctx.rax = SyscallResult::error(e).raw();
150 return;
151 }
152 }
153 };
154
155 let device_table_idx = {
156 let pool = POOL.lock();
157 match pool.read_as::<PciDeviceObject>(cap.phys(), cap.generation()) {
158 Ok(d) => d.device_table_idx,
159 Err(e) => {
160 ctx.rax = SyscallResult::error(e).raw();
161 return;
162 }
163 }
164 };
165
166 let (bus, devfn) = {
167 let dev_table = DEVICE_TABLE.lock();
168 match dev_table.get(device_table_idx as usize) {
169 Some(d) => (d.bus, d.devfn()),
170 None => {
171 ctx.rax = SyscallResult::error(KernelError::InvalidObject).raw();
172 return;
173 }
174 }
175 };
176
177 let hhdm_offset = crate::mem::addr::hhdm_offset();
178
179 ctx.rax =
180 match crate::iommu::dma_free(bus, devfn, iova, page_count, pml4_phys, pid, hhdm_offset) {
181 Ok(()) => SyscallResult::ok().raw(),
182 Err(e) => SyscallResult::error(e).raw(),
183 };
184}