Skip to main content

kernel/lib/addr/
phys_addr.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Type for physical addresses
3//!
4//! Authors: MarioS271
5
6use crate::state::kstate::KSTATE;
7use core::fmt::{Debug, Display, LowerHex, UpperHex};
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9
10/// A type representing physical addresses in the CPU's physical address space
11#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[repr(transparent)]
13pub struct PhysAddr(u64);
14
15impl PhysAddr {
16    /// Creates a new `PhysAddr` from a raw `u64` address
17    pub const fn new(addr: u64) -> Self {
18        Self(addr)
19    }
20
21    /// Creates a new `PhysAddr` which points to 0
22    pub const fn null() -> Self {
23        Self(0)
24    }
25
26    /// Returns the address as a `u64`
27    pub fn as_u64(self) -> u64 {
28        self.0
29    }
30
31    /// Returns the address as a `usize`
32    pub fn as_usize(self) -> usize {
33        self.0 as usize
34    }
35
36    /// Returns the address as a `*const T` pointer
37    pub fn as_ptr<T>(self) -> *const T {
38        self.0 as *const T
39    }
40
41    /// Returns the address as a `*mut T` pointer
42    pub fn as_mut_ptr<T>(self) -> *mut T {
43        self.0 as *mut T
44    }
45
46    /// Returns the address as a `*const T` pointer with the HHDM offset added
47    pub fn as_hhdm_ptr<T>(self) -> *const T {
48        (self.0 + KSTATE.mm.hhdm_offset()) as *const T
49    }
50
51    /// Returns the address as a `*mut T` pointer with the HHDM offset added
52    pub fn as_mut_hhdm_ptr<T>(self) -> *mut T {
53        (self.0 + KSTATE.mm.hhdm_offset()) as *mut T
54    }
55
56    /// Returns a new address aligned to the next larger address which is aligned to `align`
57    ///
58    /// # Panics
59    /// In debug builds if `align` is not a power of two
60    pub fn align_up(self, align: u64) -> Self {
61        debug_assert!(align.is_power_of_two());
62        Self((self.0 + (align - 1)) & !(align - 1))
63    }
64
65    /// Returns a new address aligned to the next smaller address which is aligned to `align`
66    ///
67    /// # Panics
68    /// In debug builds if `align` is not a power of two
69    pub fn align_down(self, align: u64) -> Self {
70        debug_assert!(align.is_power_of_two());
71        Self(self.0 & !(align - 1))
72    }
73
74    /// Check whether the address is aligned to `align`
75    pub fn is_aligned(self, align: u64) -> bool {
76        self.0 & (align - 1) == 0
77    }
78}
79
80#[cfg(target_arch = "x86_64")]
81impl PhysAddr {
82    /// Returns a [`x86_64::PhysAddr`] with the same address value
83    pub fn as_x86_64(self) -> x86_64::PhysAddr {
84        x86_64::PhysAddr::new(self.0)
85    }
86}
87
88impl Add<u64> for PhysAddr {
89    type Output = Self;
90
91    /// `Add` trait for adding a `u64` to a `PhysAddr`, returns a new instance of `PhysAddr`
92    fn add(self, rhs: u64) -> Self::Output {
93        PhysAddr::new(self.0 + rhs)
94    }
95}
96impl Add<PhysAddr> for PhysAddr {
97    type Output = Self;
98
99    /// `Add` trait for adding a `PhysAddr` to a `PhysAddr`, returns a new instance of `PhysAddr`
100    fn add(self, rhs: PhysAddr) -> Self::Output {
101        PhysAddr::new(self.0 + rhs.0)
102    }
103}
104impl AddAssign<u64> for PhysAddr {
105    /// `AddAssign` trait for add-assigning a `u64` to a `PhysAddr`
106    fn add_assign(&mut self, rhs: u64) {
107        self.0 += rhs
108    }
109}
110impl AddAssign<PhysAddr> for PhysAddr {
111    /// `AddAssign` trait for add-assigning a `PhysAddr` to a `PhysAddr`
112    fn add_assign(&mut self, rhs: PhysAddr) {
113        self.0 += rhs.0
114    }
115}
116
117impl Sub<u64> for PhysAddr {
118    type Output = Self;
119
120    /// `Sub` trait for subtracting a `u64` from a `PhysAddr`, returns a new instance of `PhysAddr`
121    fn sub(self, rhs: u64) -> Self::Output {
122        PhysAddr::new(self.0 - rhs)
123    }
124}
125impl Sub<PhysAddr> for PhysAddr {
126    type Output = Self;
127
128    /// `Sub` trait for subtracting a `PhysAddr` from a `PhysAddr`, returns a new instance of `PhysAddr`
129    fn sub(self, rhs: PhysAddr) -> Self::Output {
130        PhysAddr::new(self.0 - rhs.0)
131    }
132}
133impl SubAssign<u64> for PhysAddr {
134    /// `SubAssign` trait for sub-assigning a `u64` from a `PhysAddr`
135    fn sub_assign(&mut self, rhs: u64) {
136        self.0 -= rhs
137    }
138}
139impl SubAssign<PhysAddr> for PhysAddr {
140    /// `SubAssign` trait for sub-assigning a `PhysAddr` from a `PhysAddr`
141    fn sub_assign(&mut self, rhs: PhysAddr) {
142        self.0 -= rhs.0
143    }
144}
145
146impl Display for PhysAddr {
147    /// Formats the address as `0x<hex>` (e.g. `0x1000`)
148    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149        write!(f, "{:#x}", self.0)
150    }
151}
152impl Debug for PhysAddr {
153    /// Formats the address as `PhysAddr(0x<hex>)` (e.g. `PhysAddr(0x1000)`)
154    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
155        write!(f, "PhysAddr({:#x})", self.0)
156    }
157}
158impl LowerHex for PhysAddr {
159    /// Delegates to the inner `u64` for `{:x}` / `{:#x}` to work
160    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161        LowerHex::fmt(&self.0, f)
162    }
163}
164impl UpperHex for PhysAddr {
165    /// Delegates to the inner `u64` for `{:X}` / `{:#X}` to work
166    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167        UpperHex::fmt(&self.0, f)
168    }
169}