x86_64/structures/paging/
frame.rs1use super::page::AddressNotAligned;
4use crate::structures::paging::page::{PageSize, Size4KiB};
5use crate::PhysAddr;
6use core::fmt;
7use core::marker::PhantomData;
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9
10#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[repr(C)]
13pub struct PhysFrame<S: PageSize = Size4KiB> {
14 pub(crate) start_address: PhysAddr,
16 size: PhantomData<S>,
17}
18
19impl<S: PageSize> PhysFrame<S> {
20 #[inline]
24 #[rustversion::attr(since(1.61), const)]
25 pub fn from_start_address(address: PhysAddr) -> Result<Self, AddressNotAligned> {
26 if !address.is_aligned_u64(S::SIZE) {
27 return Err(AddressNotAligned);
28 }
29
30 Ok(unsafe { PhysFrame::from_start_address_unchecked(address) })
32 }
33
34 #[inline]
40 #[rustversion::attr(since(1.61), const)]
41 pub unsafe fn from_start_address_unchecked(start_address: PhysAddr) -> Self {
42 PhysFrame {
43 start_address,
44 size: PhantomData,
45 }
46 }
47
48 #[inline]
50 #[rustversion::attr(since(1.61), const)]
51 pub fn containing_address(address: PhysAddr) -> Self {
52 PhysFrame {
53 start_address: address.align_down_u64(S::SIZE),
54 size: PhantomData,
55 }
56 }
57
58 #[inline]
60 #[rustversion::attr(since(1.61), const)]
61 pub fn start_address(self) -> PhysAddr {
62 self.start_address
63 }
64
65 #[inline]
67 #[rustversion::attr(since(1.61), const)]
68 pub fn size(self) -> u64 {
69 S::SIZE
70 }
71
72 #[inline]
74 #[rustversion::attr(since(1.61), const)]
75 pub fn range(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRange<S> {
76 PhysFrameRange { start, end }
77 }
78
79 #[inline]
81 #[rustversion::attr(since(1.61), const)]
82 pub fn range_inclusive(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRangeInclusive<S> {
83 PhysFrameRangeInclusive { start, end }
84 }
85}
86
87impl<S: PageSize> fmt::Debug for PhysFrame<S> {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 f.write_fmt(format_args!(
90 "PhysFrame[{}]({:#x})",
91 S::DEBUG_STR,
92 self.start_address().as_u64()
93 ))
94 }
95}
96
97impl<S: PageSize> Add<u64> for PhysFrame<S> {
98 type Output = Self;
99 #[inline]
100 fn add(self, rhs: u64) -> Self::Output {
101 PhysFrame::containing_address(self.start_address() + rhs * S::SIZE)
102 }
103}
104
105impl<S: PageSize> AddAssign<u64> for PhysFrame<S> {
106 #[inline]
107 fn add_assign(&mut self, rhs: u64) {
108 *self = *self + rhs;
109 }
110}
111
112impl<S: PageSize> Sub<u64> for PhysFrame<S> {
113 type Output = Self;
114 #[inline]
115 fn sub(self, rhs: u64) -> Self::Output {
116 PhysFrame::containing_address(self.start_address() - rhs * S::SIZE)
117 }
118}
119
120impl<S: PageSize> SubAssign<u64> for PhysFrame<S> {
121 #[inline]
122 fn sub_assign(&mut self, rhs: u64) {
123 *self = *self - rhs;
124 }
125}
126
127impl<S: PageSize> Sub<PhysFrame<S>> for PhysFrame<S> {
128 type Output = u64;
129 #[inline]
130 fn sub(self, rhs: PhysFrame<S>) -> Self::Output {
131 (self.start_address - rhs.start_address) / S::SIZE
132 }
133}
134
135#[derive(Clone, Copy, PartialEq, Eq, Hash)]
137#[repr(C)]
138pub struct PhysFrameRange<S: PageSize = Size4KiB> {
139 pub start: PhysFrame<S>,
141 pub end: PhysFrame<S>,
143}
144
145impl<S: PageSize> PhysFrameRange<S> {
146 #[inline]
148 pub fn is_empty(&self) -> bool {
149 self.start >= self.end
150 }
151
152 #[inline]
154 pub fn len(&self) -> u64 {
155 if !self.is_empty() {
156 self.end - self.start
157 } else {
158 0
159 }
160 }
161
162 #[inline]
164 pub fn size(&self) -> u64 {
165 S::SIZE * self.len()
166 }
167}
168
169impl<S: PageSize> Iterator for PhysFrameRange<S> {
170 type Item = PhysFrame<S>;
171
172 #[inline]
173 fn next(&mut self) -> Option<Self::Item> {
174 if self.start < self.end {
175 let frame = self.start;
176 self.start += 1;
177 Some(frame)
178 } else {
179 None
180 }
181 }
182}
183
184impl<S: PageSize> fmt::Debug for PhysFrameRange<S> {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 f.debug_struct("PhysFrameRange")
187 .field("start", &self.start)
188 .field("end", &self.end)
189 .finish()
190 }
191}
192
193#[derive(Clone, Copy, PartialEq, Eq, Hash)]
195#[repr(C)]
196pub struct PhysFrameRangeInclusive<S: PageSize = Size4KiB> {
197 pub start: PhysFrame<S>,
199 pub end: PhysFrame<S>,
201}
202
203impl<S: PageSize> PhysFrameRangeInclusive<S> {
204 #[inline]
206 pub fn is_empty(&self) -> bool {
207 self.start > self.end
208 }
209
210 #[inline]
212 pub fn len(&self) -> u64 {
213 if !self.is_empty() {
214 self.end - self.start + 1
215 } else {
216 0
217 }
218 }
219
220 #[inline]
222 pub fn size(&self) -> u64 {
223 S::SIZE * self.len()
224 }
225}
226
227impl<S: PageSize> Iterator for PhysFrameRangeInclusive<S> {
228 type Item = PhysFrame<S>;
229
230 #[inline]
231 fn next(&mut self) -> Option<Self::Item> {
232 if self.start <= self.end {
233 let frame = self.start;
234 self.start += 1;
235 Some(frame)
236 } else {
237 None
238 }
239 }
240}
241
242impl<S: PageSize> fmt::Debug for PhysFrameRangeInclusive<S> {
243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244 f.debug_struct("PhysFrameRangeInclusive")
245 .field("start", &self.start)
246 .field("end", &self.end)
247 .finish()
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 #[test]
255 pub fn test_frame_range_len() {
256 let start_addr = PhysAddr::new(0xdead_beaf);
257 let start = PhysFrame::<Size4KiB>::containing_address(start_addr);
258 let end = start + 50;
259
260 let range = PhysFrameRange { start, end };
261 assert_eq!(range.len(), 50);
262
263 let range_inclusive = PhysFrameRangeInclusive { start, end };
264 assert_eq!(range_inclusive.len(), 51);
265 }
266}