Nothing to see here, move along
1use crate::error::KernelError;
2use crate::mem::addr;
3use crate::sync::IrqMutex;
4use crate::types::{Generation, ObjPhys};
5use lancer_core::header::KernelObjectHeader;
6use lancer_core::object_layout::KernelObject;
7use lancer_core::object_tag::ObjectTag;
8use x86_64::PhysAddr;
9
10pub struct ObjectPool {
11 generation_counter: u32,
12 #[cfg(lancer_test)]
13 active_count: u32,
14}
15
16impl ObjectPool {
17 const fn new() -> Self {
18 Self {
19 generation_counter: 0,
20 #[cfg(lancer_test)]
21 active_count: 0,
22 }
23 }
24
25 pub fn init(&mut self) {
26 self.generation_counter = 0;
27 #[cfg(lancer_test)]
28 {
29 self.active_count = 0;
30 }
31 }
32
33 #[cfg(lancer_test)]
34 pub fn active_count(&self) -> u32 {
35 self.active_count
36 }
37
38 pub fn register_object(
39 &mut self,
40 phys: u64,
41 _tag: ObjectTag,
42 ) -> Result<(ObjPhys, Generation), KernelError> {
43 debug_assert!(
44 phys.is_multiple_of(core::mem::align_of::<KernelObjectHeader>() as u64),
45 "register_object: misaligned phys {phys:#x}"
46 );
47 self.generation_counter = self.generation_counter.wrapping_add(1);
48 let generation = self.generation_counter;
49 unsafe {
50 let hdr_ptr =
51 addr::phys_to_virt(PhysAddr::new(phys)).as_mut_ptr::<KernelObjectHeader>();
52 (*hdr_ptr).generation = generation;
53 (*hdr_ptr).ref_count = 1;
54 }
55 #[cfg(lancer_test)]
56 {
57 self.active_count += 1;
58 }
59 Ok((ObjPhys::new(phys), Generation::new(generation)))
60 }
61
62 fn read_header(&self, phys: ObjPhys) -> &'static KernelObjectHeader {
63 unsafe {
64 &*(addr::phys_to_virt(PhysAddr::new(phys.raw())).as_ptr::<KernelObjectHeader>())
65 }
66 }
67
68 fn write_header(&mut self, phys: ObjPhys) -> &'static mut KernelObjectHeader {
69 unsafe {
70 &mut *(addr::phys_to_virt(PhysAddr::new(phys.raw()))
71 .as_mut_ptr::<KernelObjectHeader>())
72 }
73 }
74
75 fn validate_generation(
76 &self,
77 phys: ObjPhys,
78 generation: Generation,
79 ) -> Result<(), KernelError> {
80 let hdr = self.read_header(phys);
81 match hdr.generation != generation.raw() {
82 true => Err(KernelError::StaleGeneration),
83 false => match hdr.ref_count {
84 0 => Err(KernelError::InvalidObject),
85 _ => Ok(()),
86 },
87 }
88 }
89
90 pub fn inc_ref(&mut self, phys: ObjPhys, generation: Generation) -> Result<(), KernelError> {
91 self.validate_generation(phys, generation)?;
92 let hdr = self.write_header(phys);
93 hdr.inc_ref().ok_or(KernelError::ResourceExhausted)?;
94 Ok(())
95 }
96
97 pub fn get_tag(
98 &self,
99 phys: ObjPhys,
100 generation: Generation,
101 ) -> Result<ObjectTag, KernelError> {
102 self.validate_generation(phys, generation)?;
103 let hdr = self.read_header(phys);
104 ObjectTag::try_from(hdr.tag).map_err(|_| KernelError::InvalidType)
105 }
106
107 pub fn read_as<T: KernelObject + 'static>(
108 &self,
109 phys: ObjPhys,
110 generation: Generation,
111 ) -> Result<&T, KernelError> {
112 unsafe { super::accessor::read_object::<T>(PhysAddr::new(phys.raw()), generation.raw()) }
113 }
114
115 pub fn write_as<T: KernelObject>(
116 &mut self,
117 phys: ObjPhys,
118 generation: Generation,
119 ) -> Result<&mut T, KernelError> {
120 let ptr = unsafe {
121 super::accessor::write_object::<T>(PhysAddr::new(phys.raw()), generation.raw())?
122 };
123 Ok(unsafe { &mut *ptr })
124 }
125
126 pub fn dec_ref_phys(
127 &mut self,
128 phys: ObjPhys,
129 generation: Generation,
130 ) -> Option<(u64, ObjectTag)> {
131 let hdr = self.read_header(phys);
132 match hdr.generation != generation.raw() || hdr.ref_count == 0 {
133 true => return None,
134 false => {}
135 }
136
137 let tag_byte = hdr.tag;
138 let tag = ObjectTag::try_from(tag_byte).ok()?;
139
140 let hdr = self.write_header(phys);
141 let new_rc = hdr.dec_ref();
142 match new_rc {
143 0 => {
144 hdr.bump_generation();
145 #[cfg(lancer_test)]
146 {
147 self.active_count = self.active_count.saturating_sub(1);
148 }
149 Some((phys.raw(), tag))
150 }
151 _ => None,
152 }
153 }
154
155 pub fn free_phys(
156 &mut self,
157 phys: ObjPhys,
158 generation: Generation,
159 ) -> Result<Option<(u64, ObjectTag)>, KernelError> {
160 let hdr = self.read_header(phys);
161 match hdr.generation != generation.raw() {
162 true => return Err(KernelError::StaleGeneration),
163 false => {}
164 }
165 match hdr.ref_count {
166 0 => return Ok(None),
167 _ => {}
168 }
169
170 let tag = ObjectTag::try_from(hdr.tag).ok().map(|t| (phys.raw(), t));
171 let hdr = self.write_header(phys);
172 hdr.invalidate();
173 #[cfg(lancer_test)]
174 {
175 self.active_count = self.active_count.saturating_sub(1);
176 }
177 Ok(tag)
178 }
179
180 pub fn revoke_phys(
181 &mut self,
182 phys: ObjPhys,
183 generation: Generation,
184 ) -> Result<(Generation, Option<(u64, ObjectTag)>), KernelError> {
185 let hdr = self.read_header(phys);
186 match hdr.generation != generation.raw() || hdr.ref_count == 0 {
187 true => return Err(KernelError::StaleGeneration),
188 false => {}
189 }
190
191 let tag = ObjectTag::try_from(hdr.tag).ok().map(|t| (phys.raw(), t));
192 let hdr = self.write_header(phys);
193 hdr.invalidate();
194 let new_gen = hdr.generation;
195 #[cfg(lancer_test)]
196 {
197 self.active_count = self.active_count.saturating_sub(1);
198 }
199 Ok((Generation::new(new_gen), tag))
200 }
201
202 pub fn generation_of(&self, phys: ObjPhys) -> Option<u32> {
203 let hdr = self.read_header(phys);
204 match hdr.ref_count > 0 {
205 true => Some(hdr.generation),
206 false => None,
207 }
208 }
209}
210
211pub static POOL: IrqMutex<ObjectPool, 1> = IrqMutex::new(ObjectPool::new());