1use core::{fmt::Debug, mem::ManuallyDrop, ops::Range};
6
7use super::{
8 Frame, inc_frame_ref_count,
9 meta::{AnyFrameMeta, GetFrameError},
10};
11use crate::mm::{AnyUFrameMeta, HasPaddr, HasSize, PAGE_SIZE, Paddr, Split};
12
13#[repr(transparent)]
26pub struct Segment<M: AnyFrameMeta + ?Sized> {
27 range: Range<Paddr>,
28 _marker: core::marker::PhantomData<M>,
29}
30
31impl<M: AnyFrameMeta + ?Sized> Debug for Segment<M> {
32 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33 write!(f, "Segment({:#x}..{:#x})", self.range.start, self.range.end)
34 }
35}
36
37pub type USegment = Segment<dyn AnyUFrameMeta>;
45
46impl<M: AnyFrameMeta + ?Sized> Drop for Segment<M> {
47 fn drop(&mut self) {
48 for paddr in self.range.clone().step_by(PAGE_SIZE) {
49 drop(unsafe { Frame::<M>::from_raw(paddr) });
52 }
53 }
54}
55
56impl<M: AnyFrameMeta + ?Sized> Clone for Segment<M> {
57 fn clone(&self) -> Self {
58 for paddr in self.range.clone().step_by(PAGE_SIZE) {
59 unsafe { inc_frame_ref_count(paddr) };
63 }
64 Self {
65 range: self.range.clone(),
66 _marker: core::marker::PhantomData,
67 }
68 }
69}
70
71impl<M: AnyFrameMeta> Segment<M> {
72 pub fn from_unused<F>(range: Range<Paddr>, mut metadata_fn: F) -> Result<Self, GetFrameError>
86 where
87 F: FnMut(Paddr) -> M,
88 {
89 if !range.start.is_multiple_of(PAGE_SIZE) || !range.end.is_multiple_of(PAGE_SIZE) {
90 return Err(GetFrameError::NotAligned);
91 }
92 if range.end > super::max_paddr() {
93 return Err(GetFrameError::OutOfBound);
94 }
95 assert!(range.start < range.end);
96 let mut segment = Self {
99 range: range.start..range.start,
100 _marker: core::marker::PhantomData,
101 };
102 for paddr in range.step_by(PAGE_SIZE) {
103 let frame = Frame::<M>::from_unused(paddr, metadata_fn(paddr))?;
104 let _ = ManuallyDrop::new(frame);
105 segment.range.end = paddr + PAGE_SIZE;
106 }
107 Ok(segment)
108 }
109
110 pub(crate) unsafe fn from_raw(range: Range<Paddr>) -> Self {
118 debug_assert_eq!(range.start % PAGE_SIZE, 0);
119 debug_assert_eq!(range.end % PAGE_SIZE, 0);
120 Self {
121 range,
122 _marker: core::marker::PhantomData,
123 }
124 }
125}
126
127impl<M: AnyFrameMeta + ?Sized> Split for Segment<M> {
128 fn split(self, offset: usize) -> (Self, Self) {
129 assert!(
130 offset.is_multiple_of(PAGE_SIZE),
131 "segment virtual address not aligned for splitting"
132 );
133 assert!(
134 0 < offset && offset < self.size(),
135 "segment virtual address out-of-bound for splitting"
136 );
137
138 let old = ManuallyDrop::new(self);
139 let at = old.range.start + offset;
140
141 (
142 Self {
143 range: old.range.start..at,
144 _marker: core::marker::PhantomData,
145 },
146 Self {
147 range: at..old.range.end,
148 _marker: core::marker::PhantomData,
149 },
150 )
151 }
152}
153
154impl<M: AnyFrameMeta + ?Sized> Segment<M> {
155 pub fn slice(&self, range: &Range<usize>) -> Self {
165 assert!(
166 range.start.is_multiple_of(PAGE_SIZE) && range.end.is_multiple_of(PAGE_SIZE),
167 "segment virtual address not aligned for slicing"
168 );
169 assert!(
170 range.start <= range.end && range.end <= self.size(),
171 "segment virtual address out-of-bound for slicing"
172 );
173
174 let start = self.range.start + range.start;
175 let end = self.range.start + range.end;
176
177 for paddr in (start..end).step_by(PAGE_SIZE) {
178 unsafe { inc_frame_ref_count(paddr) };
182 }
183
184 Self {
185 range: start..end,
186 _marker: core::marker::PhantomData,
187 }
188 }
189
190 pub(crate) fn into_raw(self) -> Range<Paddr> {
192 let range = self.range.clone();
193 let _ = ManuallyDrop::new(self);
194 range
195 }
196}
197
198impl Segment<dyn AnyFrameMeta> {
199 pub fn from_unsized<M: AnyFrameMeta + ?Sized>(
212 segment: Segment<M>,
213 ) -> Segment<dyn AnyFrameMeta> {
214 let seg = ManuallyDrop::new(segment);
215 Self {
216 range: seg.range.clone(),
217 _marker: core::marker::PhantomData,
218 }
219 }
220}
221
222impl<M: AnyFrameMeta + ?Sized> HasPaddr for Segment<M> {
223 fn paddr(&self) -> Paddr {
224 self.range.start
225 }
226}
227
228impl<M: AnyFrameMeta + ?Sized> HasSize for Segment<M> {
229 fn size(&self) -> usize {
230 self.range.end - self.range.start
231 }
232}
233
234impl<M: AnyFrameMeta + ?Sized> From<Frame<M>> for Segment<M> {
235 fn from(frame: Frame<M>) -> Self {
236 let pa = frame.paddr();
237 let _ = ManuallyDrop::new(frame);
238 Self {
239 range: pa..pa + PAGE_SIZE,
240 _marker: core::marker::PhantomData,
241 }
242 }
243}
244
245impl<M: AnyFrameMeta + ?Sized> Iterator for Segment<M> {
246 type Item = Frame<M>;
247
248 fn next(&mut self) -> Option<Self::Item> {
249 if self.range.start < self.range.end {
250 let frame = unsafe { Frame::<M>::from_raw(self.range.start) };
253 self.range.start += PAGE_SIZE;
254 debug_assert!(self.range.start <= self.range.end);
256 Some(frame)
257 } else {
258 None
259 }
260 }
261}
262
263impl<M: AnyFrameMeta> From<Segment<M>> for Segment<dyn AnyFrameMeta> {
264 fn from(seg: Segment<M>) -> Self {
265 Self::from_unsized(seg)
266 }
267}
268
269impl<M: AnyFrameMeta> TryFrom<Segment<dyn AnyFrameMeta>> for Segment<M> {
270 type Error = Segment<dyn AnyFrameMeta>;
271
272 fn try_from(seg: Segment<dyn AnyFrameMeta>) -> Result<Self, Self::Error> {
273 let first_frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(seg.range.start) };
276 let first_frame = ManuallyDrop::new(first_frame);
277 if !(first_frame.dyn_meta() as &dyn core::any::Any).is::<M>() {
278 return Err(seg);
279 }
280 #[cfg(debug_assertions)]
283 {
284 for paddr in seg.range.clone().step_by(PAGE_SIZE) {
285 let frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(paddr) };
286 let frame = ManuallyDrop::new(frame);
287 debug_assert!((frame.dyn_meta() as &dyn core::any::Any).is::<M>());
288 }
289 }
290 Ok(unsafe { core::mem::transmute::<Segment<dyn AnyFrameMeta>, Segment<M>>(seg) })
292 }
293}
294
295impl<M: AnyUFrameMeta> From<Segment<M>> for USegment {
296 fn from(seg: Segment<M>) -> Self {
297 unsafe { core::mem::transmute(seg) }
299 }
300}
301
302impl TryFrom<Segment<dyn AnyFrameMeta>> for USegment {
303 type Error = Segment<dyn AnyFrameMeta>;
304
305 fn try_from(seg: Segment<dyn AnyFrameMeta>) -> Result<Self, Self::Error> {
310 let first_frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(seg.range.start) };
313 let first_frame = ManuallyDrop::new(first_frame);
314 if !first_frame.dyn_meta().is_untyped() {
315 return Err(seg);
316 }
317 #[cfg(debug_assertions)]
320 {
321 for paddr in seg.range.clone().step_by(PAGE_SIZE) {
322 let frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(paddr) };
323 let frame = ManuallyDrop::new(frame);
324 debug_assert!(frame.dyn_meta().is_untyped());
325 }
326 }
327 Ok(unsafe { core::mem::transmute::<Segment<dyn AnyFrameMeta>, USegment>(seg) })
329 }
330}