Nothing to see here, move along meow
1use crate::sync::IrqMutex;
2use crate::types::Pid;
3use lancer_core::header::NONE_SENTINEL;
4
5pub const MAX_FRAME_TABLE_ENTRIES: usize = 16384;
6const FREE_STACK_SIZE: usize = MAX_FRAME_TABLE_ENTRIES;
7
8#[derive(Clone, Copy)]
9struct FrameMappingSlot {
10 pid_raw: u32,
11 vaddr: u64,
12}
13
14impl FrameMappingSlot {
15 const EMPTY: Self = Self {
16 pid_raw: NONE_SENTINEL,
17 vaddr: 0,
18 };
19}
20
21#[derive(Clone, Copy)]
22pub struct IommuMapping {
23 pub bus: u8,
24 pub devfn: u8,
25 pub iova: u64,
26}
27
28pub struct FrameMappingEntry {
29 mappings: [FrameMappingSlot; 4],
30 mapping_count: u8,
31 has_iommu: bool,
32 iommu: IommuMapping,
33}
34
35impl FrameMappingEntry {
36 const fn new() -> Self {
37 Self {
38 mappings: [FrameMappingSlot::EMPTY; 4],
39 mapping_count: 0,
40 has_iommu: false,
41 iommu: IommuMapping {
42 bus: 0,
43 devfn: 0,
44 iova: 0,
45 },
46 }
47 }
48
49 pub fn add_mapping(
50 &mut self,
51 pid: Pid,
52 vaddr: x86_64::VirtAddr,
53 ) -> Result<(), crate::error::KernelError> {
54 match (self.mapping_count as usize) < 4 {
55 true => {
56 self.mappings[self.mapping_count as usize] = FrameMappingSlot {
57 pid_raw: pid.raw(),
58 vaddr: vaddr.as_u64(),
59 };
60 self.mapping_count += 1;
61 Ok(())
62 }
63 false => Err(crate::error::KernelError::ResourceExhausted),
64 }
65 }
66
67 pub fn remove_mapping(&mut self, pid: Pid, vaddr: x86_64::VirtAddr) -> bool {
68 let target_pid = pid.raw();
69 let target_vaddr = vaddr.as_u64();
70 let mut found = false;
71 let mut write_idx = 0usize;
72 (0..self.mapping_count as usize).for_each(|read_idx| {
73 let slot = self.mappings[read_idx];
74 match slot.pid_raw == target_pid && slot.vaddr == target_vaddr && !found {
75 true => {
76 found = true;
77 }
78 false => {
79 self.mappings[write_idx] = slot;
80 write_idx += 1;
81 }
82 }
83 });
84 if found {
85 self.mapping_count -= 1;
86 self.mappings[self.mapping_count as usize] = FrameMappingSlot::EMPTY;
87 }
88 found
89 }
90
91 pub fn for_each_mapping(&self, mut f: impl FnMut(Pid, x86_64::VirtAddr)) {
92 (0..self.mapping_count as usize).for_each(|i| {
93 let slot = self.mappings[i];
94 if let Some(pid) = Pid::try_new(slot.pid_raw) {
95 f(pid, x86_64::VirtAddr::new(slot.vaddr));
96 }
97 });
98 }
99
100 #[cfg(lancer_test)]
101 pub fn mapping_count(&self) -> u8 {
102 self.mapping_count
103 }
104
105 pub fn set_iommu(&mut self, mapping: IommuMapping) {
106 self.iommu = mapping;
107 self.has_iommu = true;
108 }
109
110 pub fn clear_iommu(&mut self) {
111 self.has_iommu = false;
112 }
113
114 pub fn iommu_mapping(&self) -> Option<&IommuMapping> {
115 match self.has_iommu {
116 true => Some(&self.iommu),
117 false => None,
118 }
119 }
120
121 fn clear(&mut self) {
122 *self = Self::new();
123 }
124}
125
126pub struct FrameMappingTable {
127 entries: [FrameMappingEntry; MAX_FRAME_TABLE_ENTRIES],
128 free_stack: [u16; FREE_STACK_SIZE],
129 free_count: u16,
130 next_fresh: u16,
131}
132
133impl FrameMappingTable {
134 const fn new() -> Self {
135 Self {
136 entries: [const { FrameMappingEntry::new() }; MAX_FRAME_TABLE_ENTRIES],
137 free_stack: [0u16; FREE_STACK_SIZE],
138 free_count: 0,
139 next_fresh: 0,
140 }
141 }
142
143 pub fn alloc_idx(&mut self) -> Option<u16> {
144 match self.free_count > 0 {
145 true => {
146 self.free_count -= 1;
147 Some(self.free_stack[self.free_count as usize])
148 }
149 false => match (self.next_fresh as usize) < MAX_FRAME_TABLE_ENTRIES {
150 true => {
151 let idx = self.next_fresh;
152 self.next_fresh += 1;
153 Some(idx)
154 }
155 false => None,
156 },
157 }
158 }
159
160 pub fn get(&self, idx: u16) -> &FrameMappingEntry {
161 debug_assert!(
162 (idx as usize) < MAX_FRAME_TABLE_ENTRIES,
163 "frame table OOB: {idx}"
164 );
165 &self.entries[idx as usize]
166 }
167
168 pub fn get_mut(&mut self, idx: u16) -> &mut FrameMappingEntry {
169 debug_assert!(
170 (idx as usize) < MAX_FRAME_TABLE_ENTRIES,
171 "frame table OOB: {idx}"
172 );
173 &mut self.entries[idx as usize]
174 }
175
176 pub fn clear(&mut self, idx: u16) {
177 debug_assert!(
178 (idx as usize) < MAX_FRAME_TABLE_ENTRIES,
179 "frame table OOB: {idx}"
180 );
181 self.entries[idx as usize].clear();
182 if (self.free_count as usize) < FREE_STACK_SIZE {
183 self.free_stack[self.free_count as usize] = idx;
184 self.free_count += 1;
185 }
186 }
187}
188
189pub static FRAME_TABLE: IrqMutex<FrameMappingTable, 2> = IrqMutex::new(FrameMappingTable::new());