1use core::fmt::{Debug, Formatter};
18use core::ops::Deref;
19use core::iter::Step;
20use core::fmt;
21#[cfg(feature = "full")] use core::slice;
22#[cfg(feature = "full")] use core::ops::Range;
23#[cfg(feature = "full")] use core::marker::PhantomData;
24#[cfg(feature = "full")] use core::mem::{ManuallyDrop, MaybeUninit};
25#[cfg(feature = "full")] use core::ptr::addr_of;
26#[cfg(feature = "full")] use crate::allocator::{DynPmm, Pmm};
27
28mod type_ops;
29
30pub mod asan;
31
32pub const PAGE_SIZE: usize = const {
34 if cfg!(doc) { 0 }
35 else if cfg!(target_arch = "x86_64") { 4096 }
36 else { panic!("unsupported arch") }
37};
38
39const PAGE_MAP_OFFSET: usize = 0xffff_8000_0000_0000;
40
41#[derive(Debug, Copy, Clone, Eq, Ord, Hash, PartialOrd, PartialEq)]
42#[must_use = "must be explicitly deallocated to not leak memory"]
43pub struct RawPage {
44 inner: VirtualAddress,
45}
46
47impl RawPage {
48 #[track_caller]
49 pub fn new(addr: usize) -> Self {
50 if addr % PAGE_SIZE != 0 { panic!("unaligned `RawPage`") };
51 RawPage { inner: VirtualAddress::new(addr) }
52 }
53}
54
55impl const Deref for RawPage {
56 type Target = VirtualAddress;
57
58 fn deref(&self) -> &Self::Target {
59 &self.inner
60 }
61}
62
63#[derive(Debug, Copy, Clone, Eq, Ord, Hash, PartialOrd, PartialEq)]
64#[must_use = "must be explicitly deallocated to not leak memory"]
65pub struct RawFrame {
66 inner: PhysicalAddress,
67}
68
69impl RawFrame {
70 #[track_caller]
71 pub const fn new(addr: usize) -> Self {
72 if addr % PAGE_SIZE != 0 { panic!("unaligned `RawFrame`") };
73 RawFrame { inner: PhysicalAddress::new(addr) }
74 }
75
76 pub const fn checked_sub(self, count: usize) -> Option<Self> {
77 self.addr.checked_sub(count * PAGE_SIZE)
78 .map(RawFrame::new)
79 }
80}
81
82impl const Deref for RawFrame {
83 type Target = PhysicalAddress;
84
85 fn deref(&self) -> &Self::Target {
86 &self.inner
87 }
88}
89
90#[cfg(feature = "full")]
92#[repr(C)]
93pub struct Frames<const RAM: bool, T = MaybeUninit<u8>> {
94 raw: Range<RawFrame>,
95 pmm: DynPmm<'static, RAM>,
96 _phantom: PhantomData<[T]>,
97}
98
99#[cfg(feature = "full")]
100impl<const RAM: bool, T> Debug for Frames<RAM, T> {
101 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
102 f.debug_struct("Frames")
103 .field("raw", &self.raw)
104 .field("pmm", &self.pmm)
105 .finish()
106 }
107}
108
109#[cfg(feature = "full")]
110impl<const RAM: bool, T> Frames<RAM, T> {
111 pub fn pmm(&self) -> &DynPmm<'static, RAM> { &self.pmm }
112
113 pub fn count(&self) -> usize {
114 self.raw.end - self.raw.start
115 }
116
117 pub fn base(&self) -> RawFrame {
118 self.raw.start
119 }
120
121 pub fn as_frame_range(&self) -> Range<RawFrame> {
122 self.raw.clone()
123 }
124
125 pub unsafe fn base_raw(self: *const Self) -> RawFrame {
126 unsafe { *addr_of!((*self).raw.start) }
127 }
128
129 pub(crate) fn into_raw(self) -> (Range<RawFrame>, DynPmm<'static, RAM>) {
130 let this = ManuallyDrop::new(self);
131 (this.raw.clone(), this.pmm)
132 }
133
134 pub unsafe fn from_raw(raw: Range<RawFrame>, pmm: DynPmm<'static, RAM>) -> Self {
135 Self {
136 raw,
137 pmm,
138 _phantom: PhantomData
139 }
140 }
141}
142
143#[cfg(feature = "full")]
144impl<T> Frames<false, T> {
145 pub(crate) unsafe fn from_raw_tuple<const RAM: bool>((raw, pmm): (Range<RawFrame>, DynPmm<'static, RAM>)) -> Self {
146 Self {
147 raw,
148 pmm: pmm.into(),
149 _phantom: PhantomData
150 }
151 }
152}
153
154#[cfg(feature = "full")]
155impl<const RAM: bool, T> Frames<RAM, MaybeUninit<T>> {
156 pub fn cast<U>(self) -> Frames<RAM, MaybeUninit<U>> {
157 let (raw, pmm) = self.into_raw();
158 Frames {
159 raw,
160 pmm,
161 _phantom: PhantomData
162 }
163 }
164}
165
166#[cfg(feature = "full")]
167impl<T> Frames<true, MaybeUninit<T>> {
168 pub fn write_filled(&mut self, value: T) -> &mut [T] where T: Clone {
169 self.get_mut().write_filled(value)
170 }
171
172 pub fn write_filled_with(&mut self, f: impl FnMut(usize) -> T) -> &mut [T] {
173 self.get_mut().write_with(f)
174 }
175
176 pub fn into_filed(mut self, value: T) -> Frames<true, T> where T: Clone {
177 self.write_filled(value);
178 let (raw, pmm) = self.into_raw();
179 Frames {
180 raw,
181 pmm,
182 _phantom: PhantomData
183 }
184 }
185
186 pub fn into_filed_with(mut self, f: impl FnMut(usize) -> T) -> Frames<true, T> {
187 self.write_filled_with(f);
188 let (raw, pmm) = self.into_raw();
189 Frames {
190 raw,
191 pmm,
192 _phantom: PhantomData
193 }
194 }
195}
196
197#[cfg(feature = "full")]
198impl<T> Frames<true, T> {
199 pub fn get(&self) -> &[T] {
200 assert!(align_of::<T>() <= 4096);
201 let base = self.raw.start.to_virtual().as_ptr();
202 unsafe {
203 slice::from_raw_parts(base.cast_const().cast(), self.count() * PAGE_SIZE / size_of::<T>())
204 }
205 }
206
207 pub fn get_mut(&mut self) -> &mut [T] {
208 assert!(align_of::<T>() <= 4096);
209 let base = self.raw.start.to_virtual().as_ptr();
210 unsafe {
211 slice::from_raw_parts_mut(base.cast(), self.count() * PAGE_SIZE / size_of::<T>())
212 }
213 }
214}
215
216#[cfg(feature = "full")]
217impl<const RAM: bool, T> Drop for Frames<RAM, T> {
218 fn drop(&mut self) {
219 unsafe {
220 self.pmm.deallocate_raw(self.raw.start, self.raw.clone().count().try_into().unwrap());
221 }
222 }
223}
224
225#[derive(Debug, Copy, Clone, Eq, Ord, Hash, PartialOrd, PartialEq)]
227#[repr(transparent)]
228pub struct PhysicalAddress {
229 pub addr: usize
231}
232
233#[derive(Debug, Copy, Clone, Eq, Ord, Hash, PartialOrd, PartialEq)]
235#[repr(transparent)]
236pub struct VirtualAddress {
237 pub addr: usize
239}
240
241impl PhysicalAddress {
242 #[track_caller]
244 pub const fn new(addr: usize) -> Self {
245 Self { addr }
246 }
247
248 pub const fn to_virtual(self) -> VirtualAddress {
253 VirtualAddress::new(self.addr + PAGE_MAP_OFFSET)
254 }
255
256 pub const fn align_down_to_frame(self) -> RawFrame {
258 let aligned = PhysicalAddress {
259 addr: self.addr & !(PAGE_SIZE - 1)
260 };
261 RawFrame { inner: aligned }
262 }
263
264 pub const fn align_up_to_frame(self) -> RawFrame {
266 let a: PhysicalAddress = self + PAGE_SIZE - 1usize;
267 a.align_down_to_frame()
268 }
269
270 #[cfg_attr(debug_assertions, track_caller)]
276 pub const fn aligned_to(self, align: usize) -> bool {
277 #[cfg(debug_assertions)] if !align.is_power_of_two() { panic!("alignment must be power of 2") }
278 self.addr & (align - 1) == 0
279 }
280}
281
282impl VirtualAddress {
283 pub const fn is_higher_half(self) -> bool {
285 (self.addr as isize) < 0
286 }
287
288 #[track_caller]
290 pub const fn new(addr: usize) -> Self {
291 Self { addr }
292 }
293
294 #[inline]
296 pub const fn as_ptr(self) -> *mut u8 {
297 self.addr as _
298 }
299
300 pub const fn align_down_to_page(self) -> RawPage {
302 let aligned = VirtualAddress {
303 addr: self.addr & !(PAGE_SIZE - 1)
304 };
305 RawPage { inner: aligned }
306 }
307
308 pub const fn align_up_to_page(self) -> RawPage {
310 let a: VirtualAddress = self + PAGE_SIZE - 1usize;
311 a.align_down_to_page()
312 }
313
314 #[cfg_attr(debug_assertions, track_caller)]
320 pub const fn aligned_to(self, align: usize) -> bool {
321 #[cfg(debug_assertions)] if !align.is_power_of_two() { panic!("alignment must be power of 2") }
322 self.addr & (align - 1) == 0
323 }
324
325 pub const fn saturating_add(self, rhs: usize) -> Self {
327 VirtualAddress::new(self.addr.saturating_add(rhs))
328 }
329
330 pub const fn saturating_sub(self, rhs: usize) -> Self {
332 VirtualAddress::new(self.addr.saturating_sub(rhs))
333 }
334
335 pub const fn to_physical(self) -> PhysicalAddress {
341 PhysicalAddress::new(self.addr - PAGE_MAP_OFFSET)
342 }
343}
344
345impl<T: ?Sized> From<*mut T> for VirtualAddress {
346 fn from(value: *mut T) -> Self {
347 VirtualAddress { addr: value as *mut u8 as usize }
348 }
349}
350
351impl<T: ?Sized> From<*const T> for VirtualAddress {
352 fn from(value: *const T) -> Self {
353 VirtualAddress { addr: value as *const u8 as usize }
354 }
355}
356
357impl const From<RawFrame> for PhysicalAddress {
358 fn from(value: RawFrame) -> Self {
359 value.inner
360 }
361}
362
363impl const From<RawPage> for VirtualAddress {
364 fn from(value: RawPage) -> Self {
365 value.inner
366 }
367}
368
369impl Step for PhysicalAddress {
370 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
371 Step::steps_between(&start.addr, &end.addr)
372 }
373
374 fn forward_checked(start: Self, count: usize) -> Option<Self> {
375 Some(PhysicalAddress::new(
376 Step::forward_checked(start.addr, count)?
377 ))
378 }
379
380 fn backward_checked(start: Self, count: usize) -> Option<Self> {
381 Some(PhysicalAddress::new(
382 Step::backward_checked(start.addr, count)?
383 ))
384 }
385}
386
387impl Step for VirtualAddress {
388 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
389 Step::steps_between(&start.addr, &end.addr)
390 }
391
392 fn forward_checked(start: Self, count: usize) -> Option<Self> {
393 Some(VirtualAddress::new(
394 Step::forward_checked(start.addr, count)?
395 ))
396 }
397
398 fn backward_checked(start: Self, count: usize) -> Option<Self> {
399 Some(VirtualAddress::new(
400 Step::backward_checked(start.addr, count)?
401 ))
402 }
403}
404
405impl Step for RawFrame {
406 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
407 Step::steps_between(&(start.addr / PAGE_SIZE), &(end.addr / PAGE_SIZE))
408 }
409
410 fn forward_checked(start: Self, count: usize) -> Option<Self> {
411 Some(RawFrame::new(
412 Step::forward_checked(start.addr, count.checked_mul(PAGE_SIZE)?)?
413 ))
414 }
415
416 fn backward_checked(start: Self, count: usize) -> Option<Self> {
417 Some(RawFrame::new(
418 Step::backward_checked(start.addr, count.checked_mul(PAGE_SIZE)?)?
419 ))
420 }
421}
422
423impl Step for RawPage {
424 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
425 Step::steps_between(&start.addr, &end.addr)
426 }
427
428 fn forward_checked(start: Self, count: usize) -> Option<Self> {
429 Some(RawPage::new(
430 Step::forward_checked(start.addr, count.checked_mul(PAGE_SIZE)?)?
431 ))
432 }
433
434 fn backward_checked(start: Self, count: usize) -> Option<Self> {
435 Some(RawPage::new(
436 Step::backward_checked(start.addr, count.checked_mul(PAGE_SIZE)?)?
437 ))
438 }
439}
440
441impl fmt::LowerHex for VirtualAddress {
442 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
443 fmt::LowerHex::fmt(&self.addr, f)
444 }
445}
446
447impl fmt::LowerHex for PhysicalAddress {
448 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
449 fmt::LowerHex::fmt(&self.addr, f)
450 }
451}
452
453impl fmt::LowerHex for RawPage {
454 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
455 fmt::LowerHex::fmt(&self.addr, f)
456 }
457}
458
459impl fmt::LowerHex for RawFrame {
460 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
461 fmt::LowerHex::fmt(&self.addr, f)
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use super::*;
468
469 #[test]
470 fn align_down() {
471 let unaligned: VirtualAddress = VirtualAddress { addr: 0x1567 };
472 let aligned = unaligned.align_down::<4096>();
473 assert_eq!(aligned.addr, 0x1000);
474
475 let unaligned: VirtualAddress = VirtualAddress { addr: 0x2000 };
476 let aligned = unaligned.align_down::<4096>();
477 assert_eq!(aligned.addr, 0x2000);
478
479 let unaligned: PhysicalAddress = PhysicalAddress { addr: 0x1567 };
480 let aligned = unaligned.align_down::<4096>();
481 assert_eq!(aligned.addr, 0x1000);
482
483 let unaligned: PhysicalAddress = PhysicalAddress { addr: 0x2000 };
484 let aligned = unaligned.align_down::<4096>();
485 assert_eq!(aligned.addr, 0x2000);
486 }
487
488 #[test]
489 fn align_up() {
490 let unaligned: VirtualAddress = VirtualAddress { addr: 0x1567 };
491 let aligned = unaligned.align_up::<4096>();
492 assert_eq!(aligned.addr, 0x2000);
493
494 let unaligned: VirtualAddress = VirtualAddress { addr: 0x2000 };
495 let aligned = unaligned.align_up::<4096>();
496 assert_eq!(aligned.addr, 0x2000);
497
498 let unaligned: PhysicalAddress = PhysicalAddress { addr: 0x1567 };
499 let aligned = unaligned.align_up::<4096>();
500 assert_eq!(aligned.addr, 0x2000);
501
502 let unaligned: PhysicalAddress = PhysicalAddress { addr: 0x2000 };
503 let aligned = unaligned.align_up::<4096>();
504 assert_eq!(aligned.addr, 0x2000);
505 }
506}