Skip to main content

kernel/lib/addr/
virt_addr.rs

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