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!(offset.is_multiple_of(PAGE_SIZE));
130 assert!(0 < offset && offset < self.size());
131
132 let old = ManuallyDrop::new(self);
133 let at = old.range.start + offset;
134
135 (
136 Self {
137 range: old.range.start..at,
138 _marker: core::marker::PhantomData,
139 },
140 Self {
141 range: at..old.range.end,
142 _marker: core::marker::PhantomData,
143 },
144 )
145 }
146}
147
148impl<M: AnyFrameMeta + ?Sized> Segment<M> {
149 pub fn slice(&self, range: &Range<usize>) -> Self {
159 assert!(range.start.is_multiple_of(PAGE_SIZE) && range.end.is_multiple_of(PAGE_SIZE));
160 let start = self.range.start + range.start;
161 let end = self.range.start + range.end;
162 assert!(start <= end && end <= self.range.end);
163
164 for paddr in (start..end).step_by(PAGE_SIZE) {
165 unsafe { inc_frame_ref_count(paddr) };
169 }
170
171 Self {
172 range: start..end,
173 _marker: core::marker::PhantomData,
174 }
175 }
176
177 pub(crate) fn into_raw(self) -> Range<Paddr> {
179 let range = self.range.clone();
180 let _ = ManuallyDrop::new(self);
181 range
182 }
183}
184
185impl Segment<dyn AnyFrameMeta> {
186 pub fn from_unsized<M: AnyFrameMeta + ?Sized>(
199 segment: Segment<M>,
200 ) -> Segment<dyn AnyFrameMeta> {
201 let seg = ManuallyDrop::new(segment);
202 Self {
203 range: seg.range.clone(),
204 _marker: core::marker::PhantomData,
205 }
206 }
207}
208
209impl<M: AnyFrameMeta + ?Sized> HasPaddr for Segment<M> {
210 fn paddr(&self) -> Paddr {
211 self.range.start
212 }
213}
214
215impl<M: AnyFrameMeta + ?Sized> HasSize for Segment<M> {
216 fn size(&self) -> usize {
217 self.range.end - self.range.start
218 }
219}
220
221impl<M: AnyFrameMeta + ?Sized> From<Frame<M>> for Segment<M> {
222 fn from(frame: Frame<M>) -> Self {
223 let pa = frame.paddr();
224 let _ = ManuallyDrop::new(frame);
225 Self {
226 range: pa..pa + PAGE_SIZE,
227 _marker: core::marker::PhantomData,
228 }
229 }
230}
231
232impl<M: AnyFrameMeta + ?Sized> Iterator for Segment<M> {
233 type Item = Frame<M>;
234
235 fn next(&mut self) -> Option<Self::Item> {
236 if self.range.start < self.range.end {
237 let frame = unsafe { Frame::<M>::from_raw(self.range.start) };
240 self.range.start += PAGE_SIZE;
241 debug_assert!(self.range.start <= self.range.end);
243 Some(frame)
244 } else {
245 None
246 }
247 }
248}
249
250impl<M: AnyFrameMeta> From<Segment<M>> for Segment<dyn AnyFrameMeta> {
251 fn from(seg: Segment<M>) -> Self {
252 Self::from_unsized(seg)
253 }
254}
255
256impl<M: AnyFrameMeta> TryFrom<Segment<dyn AnyFrameMeta>> for Segment<M> {
257 type Error = Segment<dyn AnyFrameMeta>;
258
259 fn try_from(seg: Segment<dyn AnyFrameMeta>) -> core::result::Result<Self, Self::Error> {
260 let first_frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(seg.range.start) };
263 let first_frame = ManuallyDrop::new(first_frame);
264 if !(first_frame.dyn_meta() as &dyn core::any::Any).is::<M>() {
265 return Err(seg);
266 }
267 #[cfg(debug_assertions)]
270 {
271 for paddr in seg.range.clone().step_by(PAGE_SIZE) {
272 let frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(paddr) };
273 let frame = ManuallyDrop::new(frame);
274 debug_assert!((frame.dyn_meta() as &dyn core::any::Any).is::<M>());
275 }
276 }
277 Ok(unsafe { core::mem::transmute::<Segment<dyn AnyFrameMeta>, Segment<M>>(seg) })
279 }
280}
281
282impl<M: AnyUFrameMeta> From<Segment<M>> for USegment {
283 fn from(seg: Segment<M>) -> Self {
284 unsafe { core::mem::transmute(seg) }
286 }
287}
288
289impl TryFrom<Segment<dyn AnyFrameMeta>> for USegment {
290 type Error = Segment<dyn AnyFrameMeta>;
291
292 fn try_from(seg: Segment<dyn AnyFrameMeta>) -> core::result::Result<Self, Self::Error> {
297 let first_frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(seg.range.start) };
300 let first_frame = ManuallyDrop::new(first_frame);
301 if !first_frame.dyn_meta().is_untyped() {
302 return Err(seg);
303 }
304 #[cfg(debug_assertions)]
307 {
308 for paddr in seg.range.clone().step_by(PAGE_SIZE) {
309 let frame = unsafe { Frame::<dyn AnyFrameMeta>::from_raw(paddr) };
310 let frame = ManuallyDrop::new(frame);
311 debug_assert!(frame.dyn_meta().is_untyped());
312 }
313 }
314 Ok(unsafe { core::mem::transmute::<Segment<dyn AnyFrameMeta>, USegment>(seg) })
316 }
317}