x86_64/structures/paging/
frame.rs1use super::page::AddressNotAligned;
4use crate::structures::paging::page::{PageSize, Size4KiB};
5use crate::PhysAddr;
6use core::convert::TryFrom;
7use core::fmt;
8use core::marker::PhantomData;
9use core::ops::{Add, AddAssign, Sub, SubAssign};
10
11#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[repr(C)]
14pub struct PhysFrame<S: PageSize = Size4KiB> {
15 pub(crate) start_address: PhysAddr,
17 size: PhantomData<S>,
18}
19
20impl<S: PageSize> PhysFrame<S> {
21 #[inline]
25 #[rustversion::attr(since(1.61), const)]
26 pub fn from_start_address(address: PhysAddr) -> Result<Self, AddressNotAligned> {
27 if !address.is_aligned_u64(S::SIZE) {
28 return Err(AddressNotAligned);
29 }
30
31 Ok(unsafe { PhysFrame::from_start_address_unchecked(address) })
33 }
34
35 #[inline]
41 #[rustversion::attr(since(1.61), const)]
42 pub unsafe fn from_start_address_unchecked(start_address: PhysAddr) -> Self {
43 PhysFrame {
44 start_address,
45 size: PhantomData,
46 }
47 }
48
49 #[inline]
61 #[rustversion::attr(
62 since(1.61),
63 dep_const_fn::const_fn(cfg(not(feature = "memory_encryption")))
64 )]
65 pub fn from_pfn(pfn: u64) -> Self {
66 match Self::try_from_pfn(pfn) {
67 Ok(frame) => frame,
68 Err(_) => panic!("PFNs must not have any bits in the range 40 to 64 set"),
69 }
70 }
71
72 #[inline]
84 #[rustversion::attr(
85 since(1.61),
86 dep_const_fn::const_fn(cfg(not(feature = "memory_encryption")))
87 )]
88 pub fn try_from_pfn(pfn: u64) -> Result<Self, PfnNotValid> {
89 let addr_raw = if let Some(addr_raw) = pfn.checked_mul(S::SIZE) {
90 addr_raw
91 } else {
92 return Err(PfnNotValid(pfn));
93 };
94 let addr = if let Ok(addr) = PhysAddr::try_new(addr_raw) {
95 addr
96 } else {
97 return Err(PfnNotValid(pfn));
98 };
99 Ok(PhysFrame {
100 start_address: addr,
101 size: PhantomData,
102 })
103 }
104
105 #[inline]
111 #[rustversion::attr(since(1.61), const)]
112 pub unsafe fn from_pfn_unchecked(pfn: u64) -> Self {
113 PhysFrame {
114 start_address: unsafe { PhysAddr::new_unsafe(pfn * S::SIZE) },
115 size: PhantomData,
116 }
117 }
118
119 #[inline]
121 #[rustversion::attr(since(1.61), const)]
122 pub fn containing_address(address: PhysAddr) -> Self {
123 PhysFrame {
124 start_address: address.align_down_u64(S::SIZE),
125 size: PhantomData,
126 }
127 }
128
129 #[inline]
131 #[rustversion::attr(since(1.61), const)]
132 pub fn start_address(self) -> PhysAddr {
133 self.start_address
134 }
135
136 #[inline]
138 #[rustversion::attr(since(1.61), const)]
139 pub fn size(self) -> u64 {
140 S::SIZE
141 }
142
143 #[inline]
159 #[rustversion::attr(since(1.61), const)]
160 pub fn pfn(self) -> u64 {
161 self.start_address.as_u64() / S::SIZE
162 }
163
164 #[inline]
166 #[rustversion::attr(since(1.61), const)]
167 pub fn range(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRange<S> {
168 PhysFrameRange { start, end }
169 }
170
171 #[inline]
173 #[rustversion::attr(since(1.61), const)]
174 pub fn range_inclusive(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRangeInclusive<S> {
175 PhysFrameRangeInclusive { start, end }
176 }
177}
178
179impl<S: PageSize> fmt::Debug for PhysFrame<S> {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 f.write_fmt(format_args!(
182 "PhysFrame[{}]({:#x})",
183 S::DEBUG_STR,
184 self.start_address().as_u64()
185 ))
186 }
187}
188
189impl<S: PageSize> Add<u64> for PhysFrame<S> {
190 type Output = Self;
191 #[inline]
192 fn add(self, rhs: u64) -> Self::Output {
193 PhysFrame::containing_address(self.start_address() + rhs * S::SIZE)
194 }
195}
196
197impl<S: PageSize> AddAssign<u64> for PhysFrame<S> {
198 #[inline]
199 fn add_assign(&mut self, rhs: u64) {
200 *self = *self + rhs;
201 }
202}
203
204impl<S: PageSize> Sub<u64> for PhysFrame<S> {
205 type Output = Self;
206 #[inline]
207 fn sub(self, rhs: u64) -> Self::Output {
208 PhysFrame::containing_address(self.start_address() - rhs * S::SIZE)
209 }
210}
211
212impl<S: PageSize> SubAssign<u64> for PhysFrame<S> {
213 #[inline]
214 fn sub_assign(&mut self, rhs: u64) {
215 *self = *self - rhs;
216 }
217}
218
219impl<S: PageSize> Sub<PhysFrame<S>> for PhysFrame<S> {
220 type Output = u64;
221 #[inline]
222 fn sub(self, rhs: PhysFrame<S>) -> Self::Output {
223 (self.start_address - rhs.start_address) / S::SIZE
224 }
225}
226
227#[derive(Clone, Copy, PartialEq, Eq, Hash)]
229#[repr(C)]
230pub struct PhysFrameRange<S: PageSize = Size4KiB> {
231 pub start: PhysFrame<S>,
233 pub end: PhysFrame<S>,
235}
236
237impl<S: PageSize> PhysFrameRange<S> {
238 #[inline]
240 pub fn is_empty(&self) -> bool {
241 self.start >= self.end
242 }
243
244 #[inline]
246 pub fn len(&self) -> u64 {
247 if !self.is_empty() {
248 self.end - self.start
249 } else {
250 0
251 }
252 }
253
254 #[inline]
256 pub fn size(&self) -> u64 {
257 S::SIZE * self.len()
258 }
259}
260
261impl<S: PageSize> Iterator for PhysFrameRange<S> {
262 type Item = PhysFrame<S>;
263
264 #[inline]
265 fn next(&mut self) -> Option<Self::Item> {
266 if self.start < self.end {
267 let frame = self.start;
268 self.start += 1;
269 Some(frame)
270 } else {
271 None
272 }
273 }
274
275 fn nth(&mut self, n: usize) -> Option<Self::Item> {
276 if self.is_empty() {
277 return None;
278 }
279
280 let n = u64::try_from(n).unwrap_or(u64::MAX);
284
285 if n >= self.len() {
290 self.nth(self.len() as usize - 1)?;
291 return self.next();
292 }
293
294 self.start += n;
295 self.next()
296 }
297
298 fn size_hint(&self) -> (usize, Option<usize>) {
299 let len = self.len();
300 usize::try_from(len)
301 .map(|len| (len, Some(len)))
302 .unwrap_or((usize::MAX, None))
303 }
304}
305
306impl<S: PageSize> DoubleEndedIterator for PhysFrameRange<S> {
307 #[inline]
308 fn next_back(&mut self) -> Option<Self::Item> {
309 if self.start < self.end {
310 self.end -= 1;
311 Some(self.end)
312 } else {
313 None
314 }
315 }
316
317 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
318 if self.is_empty() {
319 return None;
320 }
321
322 let n = u64::try_from(n).unwrap_or(u64::MAX);
326
327 if n >= self.len() {
332 self.nth_back(self.len() as usize - 1)?;
333 return self.next_back();
334 }
335
336 self.end -= n;
337 self.next_back()
338 }
339}
340
341impl<S: PageSize> fmt::Debug for PhysFrameRange<S> {
342 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
343 f.debug_struct("PhysFrameRange")
344 .field("start", &self.start)
345 .field("end", &self.end)
346 .finish()
347 }
348}
349
350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
356#[repr(transparent)]
357pub struct PfnNotValid(pub u64);
358
359impl fmt::Display for PfnNotValid {
361 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
362 f.debug_tuple("PhysAddrNotValid")
363 .field(&format_args!("{:#x}", self.0))
364 .finish()
365 }
366}
367
368#[derive(Clone, Copy, PartialEq, Eq, Hash)]
370#[repr(C)]
371pub struct PhysFrameRangeInclusive<S: PageSize = Size4KiB> {
372 pub start: PhysFrame<S>,
374 pub end: PhysFrame<S>,
376}
377
378impl<S: PageSize> PhysFrameRangeInclusive<S> {
379 #[inline]
381 pub fn is_empty(&self) -> bool {
382 self.start > self.end
383 }
384
385 #[inline]
387 pub fn len(&self) -> u64 {
388 if !self.is_empty() {
389 self.end - self.start + 1
390 } else {
391 0
392 }
393 }
394
395 #[inline]
397 pub fn size(&self) -> u64 {
398 S::SIZE * self.len()
399 }
400}
401
402impl<S: PageSize> Iterator for PhysFrameRangeInclusive<S> {
403 type Item = PhysFrame<S>;
404
405 #[inline]
406 fn next(&mut self) -> Option<Self::Item> {
407 if self.start <= self.end {
408 let frame = self.start;
409
410 let max_frame_addr = PhysAddr::new_truncate(u64::MAX) - (S::SIZE - 1);
414 if self.start.start_address() < max_frame_addr {
415 self.start += 1;
416 } else {
417 self.end -= 1;
418 }
419 Some(frame)
420 } else {
421 None
422 }
423 }
424
425 fn nth(&mut self, n: usize) -> Option<Self::Item> {
426 if self.is_empty() {
427 return None;
428 }
429
430 let n = u64::try_from(n).unwrap_or(u64::MAX);
434
435 if n >= self.len() {
440 self.nth(self.len() as usize - 1)?;
441 return self.next();
442 }
443
444 self.start += n;
445 self.next()
446 }
447
448 fn size_hint(&self) -> (usize, Option<usize>) {
449 let len = self.len();
450 usize::try_from(len)
451 .map(|len| (len, Some(len)))
452 .unwrap_or((usize::MAX, None))
453 }
454}
455
456impl<S: PageSize> DoubleEndedIterator for PhysFrameRangeInclusive<S> {
457 #[inline]
458 fn next_back(&mut self) -> Option<Self::Item> {
459 if self.start <= self.end {
460 let frame = self.end;
461
462 if self.end.start_address().as_u64() != 0 {
466 self.end -= 1;
467 } else {
468 self.start += 1;
469 }
470 Some(frame)
471 } else {
472 None
473 }
474 }
475
476 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
477 if self.is_empty() {
478 return None;
479 }
480
481 let n = u64::try_from(n).unwrap_or(u64::MAX);
485
486 if n >= self.len() {
491 self.nth_back(self.len() as usize - 1)?;
492 return self.next_back();
493 }
494
495 self.end -= n;
496 self.next_back()
497 }
498}
499
500impl<S: PageSize> fmt::Debug for PhysFrameRangeInclusive<S> {
501 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
502 f.debug_struct("PhysFrameRangeInclusive")
503 .field("start", &self.start)
504 .field("end", &self.end)
505 .finish()
506 }
507}
508
509#[cfg(kani)]
510impl<S: PageSize> kani::Arbitrary for PhysFrame<S> {
511 fn any() -> Self {
512 Self::containing_address(kani::any())
513 }
514}
515
516#[cfg(test)]
517mod tests {
518 use super::*;
519 #[test]
520 pub fn test_frame_range_len() {
521 let start_addr = PhysAddr::new(0xdead_beaf);
522 let start = PhysFrame::<Size4KiB>::containing_address(start_addr);
523 let end = start + 50;
524
525 let range = PhysFrameRange { start, end };
526 assert_eq!(range.len(), 50);
527
528 let range_inclusive = PhysFrameRangeInclusive { start, end };
529 assert_eq!(range_inclusive.len(), 51);
530 }
531}
532
533#[cfg(kani)]
534mod proofs {
535 use super::*;
536
537 #[kani::proof]
538 fn phys_frame_range_next() {
539 let start = kani::any::<PhysFrame>();
540 let end = kani::any::<PhysFrame>();
541 let mut range = PhysFrame::range(start, end);
542
543 let difference = end
545 .start_address()
546 .as_u64()
547 .checked_sub(start.start_address().as_u64());
548 let expected_result = difference.is_some_and(|d| d >= 0x1000).then(|| start);
549 assert_eq!(range.next(), expected_result);
550 let expected_result = difference.is_some_and(|d| d >= 0x2000).then(|| start + 1);
551 assert_eq!(range.next(), expected_result);
552 }
553
554 #[kani::proof]
555 fn phys_frame_range_inclusive_next() {
556 let start = kani::any::<PhysFrame>();
557 let end = kani::any::<PhysFrame>();
558 let mut range = PhysFrame::range_inclusive(start, end);
559
560 let difference = end
562 .start_address()
563 .as_u64()
564 .checked_sub(start.start_address().as_u64());
565 let expected_result = difference.is_some().then(|| start);
566 assert_eq!(range.next(), expected_result);
567 let expected_result = difference.is_some_and(|d| d >= 0x1000).then(|| start + 1);
568 assert_eq!(range.next(), expected_result);
569 }
570
571 #[kani::proof]
572 fn phys_frame_range_next_back() {
573 let start = kani::any::<PhysFrame>();
574 let end = kani::any::<PhysFrame>();
575 let mut range = PhysFrame::range(start, end);
576
577 let difference = end
579 .start_address()
580 .as_u64()
581 .checked_sub(start.start_address().as_u64());
582 let expected_result = difference.is_some_and(|d| d >= 0x1000).then(|| end - 1);
583 assert_eq!(range.next_back(), expected_result);
584 let expected_result = difference.is_some_and(|d| d >= 0x2000).then(|| end - 2);
585 assert_eq!(range.next_back(), expected_result);
586 }
587
588 #[kani::proof]
589 fn phys_frame_range_inclusive_next_back() {
590 let start = kani::any::<PhysFrame>();
591 let end = kani::any::<PhysFrame>();
592 let mut range = PhysFrame::range_inclusive(start, end);
593
594 let difference = end
596 .start_address()
597 .as_u64()
598 .checked_sub(start.start_address().as_u64());
599 let expected_result = difference.is_some().then(|| end);
600 assert_eq!(range.next_back(), expected_result);
601 let expected_result = difference.is_some_and(|d| d >= 0x1000).then(|| end - 1);
602 assert_eq!(range.next_back(), expected_result);
603 }
604
605 #[kani::proof]
606 #[kani::unwind(1)]
607 fn phys_frame_range_nth_0() {
608 let start = kani::any::<PhysFrame>();
609 let end = kani::any::<PhysFrame>();
610 let mut range = PhysFrame::range(start, end);
611 let mut range2 = PhysFrame::range(start, end);
612
613 assert_eq!(range.next(), range2.nth(0));
615 assert_eq!(range.next(), range2.nth(0));
616 }
617
618 #[kani::proof]
619 #[kani::unwind(1)]
620 fn phys_frame_range_nth() {
621 let start = kani::any::<PhysFrame>();
622 let end = kani::any::<PhysFrame>();
623 let m = kani::any::<usize>();
624 let n = kani::any::<usize>();
625 let sum = m.saturating_add(n).saturating_add(1);
626 let mut range = PhysFrame::range(start, end);
627 let mut range2 = PhysFrame::range(start, end);
628
629 range.nth(m);
632 assert_eq!(range.nth(n), range2.nth(sum));
633 }
634
635 #[kani::proof]
636 #[kani::unwind(1)]
637 fn phys_frame_range_inclusive_nth_0() {
638 let start = kani::any::<PhysFrame>();
639 let end = kani::any::<PhysFrame>();
640 let mut range = PhysFrame::range_inclusive(start, end);
641 let mut range2 = PhysFrame::range_inclusive(start, end);
642
643 assert_eq!(range.next(), range2.nth(0));
645 assert_eq!(range.next(), range2.nth(0));
646 }
647
648 #[kani::proof]
649 #[kani::unwind(1)]
650 fn phys_frame_range_inclusive_nth() {
651 let start = kani::any::<PhysFrame>();
652 let end = kani::any::<PhysFrame>();
653 let m = kani::any::<usize>();
654 let n = kani::any::<usize>();
655 let sum = m.saturating_add(n).saturating_add(1);
656 let mut range = PhysFrame::range_inclusive(start, end);
657 let mut range2 = PhysFrame::range_inclusive(start, end);
658
659 range.nth(m);
662 assert_eq!(range.nth(n), range2.nth(sum));
663 }
664
665 #[kani::proof]
666 #[kani::unwind(1)]
667 fn phys_frame_range_nth_back_0() {
668 let start = kani::any::<PhysFrame>();
669 let end = kani::any::<PhysFrame>();
670 let mut range = PhysFrame::range(start, end);
671 let mut range2 = PhysFrame::range(start, end);
672
673 assert_eq!(range.next_back(), range2.nth_back(0));
675 assert_eq!(range.next_back(), range2.nth_back(0));
676 }
677
678 #[kani::proof]
679 #[kani::unwind(1)]
680 fn phys_frame_range_nth_back() {
681 let start = kani::any::<PhysFrame>();
682 let end = kani::any::<PhysFrame>();
683 let m = kani::any::<usize>();
684 let n = kani::any::<usize>();
685 let sum = m.saturating_add(n).saturating_add(1);
686 let mut range = PhysFrame::range(start, end);
687 let mut range2 = PhysFrame::range(start, end);
688
689 range.nth_back(m);
692 assert_eq!(range.nth_back(n), range2.nth_back(sum));
693 }
694
695 #[kani::proof]
696 #[kani::unwind(1)]
697 fn phys_frame_range_inclusive_nth_back_0() {
698 let start = kani::any::<PhysFrame>();
699 let end = kani::any::<PhysFrame>();
700 let mut range = PhysFrame::range_inclusive(start, end);
701 let mut range2 = PhysFrame::range_inclusive(start, end);
702
703 assert_eq!(range.next_back(), range2.nth_back(0));
705 assert_eq!(range.next_back(), range2.nth_back(0));
706 }
707
708 #[kani::proof]
709 #[kani::unwind(1)]
710 fn phys_frame_range_inclusive_nth_back() {
711 let start = kani::any::<PhysFrame>();
712 let end = kani::any::<PhysFrame>();
713 let m = kani::any::<usize>();
714 let n = kani::any::<usize>();
715 let sum = m.saturating_add(n).saturating_add(1);
716 let mut range = PhysFrame::range_inclusive(start, end);
717 let mut range2 = PhysFrame::range_inclusive(start, end);
718
719 range.nth_back(m);
722 assert_eq!(range.nth_back(n), range2.nth_back(sum));
723 }
724}