1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
// SPDX-License-Identifier: GPL-2.0
//! Types and functions to work with pointers and addresses.
use core::fmt::Debug;
use core::mem::align_of;
use core::num::NonZero;
use crate::build_assert;
/// Type representing an alignment, which is always a power of two.
///
/// It is used to validate that a given value is a valid alignment, and to perform masking and
/// alignment operations.
///
/// This is a temporary substitute for the [`Alignment`] nightly type from the standard library,
/// and to be eventually replaced by it.
///
/// [`Alignment`]: https://github.com/rust-lang/rust/issues/102070
///
/// # Invariants
///
/// An alignment is always a power of two.
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Alignment(NonZero<usize>);
impl Alignment {
/// Validates that `ALIGN` is a power of two at build-time, and returns an [`Alignment`] of the
/// same value.
///
/// A build error is triggered if `ALIGN` is not a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// let v = Alignment::new::<16>();
/// assert_eq!(v.as_usize(), 16);
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> Self {
build_assert!(
ALIGN.is_power_of_two(),
"Provided alignment is not a power of two."
);
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
Self(unsafe { NonZero::new_unchecked(ALIGN) })
}
/// Validates that `align` is a power of two at runtime, and returns an
/// [`Alignment`] of the same value.
///
/// Returns [`None`] if `align` is not a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new_checked(16), Some(Alignment::new::<16>()));
/// assert_eq!(Alignment::new_checked(15), None);
/// assert_eq!(Alignment::new_checked(1), Some(Alignment::new::<1>()));
/// assert_eq!(Alignment::new_checked(0), None);
/// ```
#[inline(always)]
pub const fn new_checked(align: usize) -> Option<Self> {
if align.is_power_of_two() {
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
Some(Self(unsafe { NonZero::new_unchecked(align) }))
} else {
None
}
}
/// Returns the alignment of `T`.
///
/// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
#[inline(always)]
pub const fn of<T>() -> Self {
#![allow(clippy::incompatible_msrv)]
// This cannot panic since alignments are always powers of two.
//
// We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
const { Alignment::new_checked(align_of::<T>()).unwrap() }
}
/// Returns this alignment as a [`usize`].
///
/// It is guaranteed to be a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new::<16>().as_usize(), 16);
/// ```
#[inline(always)]
pub const fn as_usize(self) -> usize {
self.as_nonzero().get()
}
/// Returns this alignment as a [`NonZero`].
///
/// It is guaranteed to be a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new::<16>().as_nonzero().get(), 16);
/// ```
#[inline(always)]
pub const fn as_nonzero(self) -> NonZero<usize> {
// Allow the compiler to know that the value is indeed a power of two. This can help
// optimize some operations down the line, like e.g. replacing divisions by bit shifts.
if !self.0.is_power_of_two() {
// SAFETY: Per the invariants, `self.0` is always a power of two so this block will
// never be reached.
unsafe { core::hint::unreachable_unchecked() }
}
self.0
}
/// Returns the base-2 logarithm of the alignment.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::of::<u8>().log2(), 0);
/// assert_eq!(Alignment::new::<16>().log2(), 4);
/// ```
#[inline(always)]
pub const fn log2(self) -> u32 {
self.0.ilog2()
}
/// Returns the mask for this alignment.
///
/// This is equivalent to `!(self.as_usize() - 1)`.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new::<0x10>().mask(), !0xf);
/// ```
#[inline(always)]
pub const fn mask(self) -> usize {
// No underflow can occur as the alignment is guaranteed to be a power of two, and thus is
// non-zero.
!(self.as_usize() - 1)
}
}
/// Trait for items that can be aligned against an [`Alignment`].
pub trait Alignable: Sized {
/// Aligns `self` down to `alignment`.
///
/// # Examples
///
/// ```
/// use kernel::ptr::{Alignable, Alignment};
///
/// assert_eq!(0x2f_usize.align_down(Alignment::new::<0x10>()), 0x20);
/// assert_eq!(0x30usize.align_down(Alignment::new::<0x10>()), 0x30);
/// assert_eq!(0xf0u8.align_down(Alignment::new::<0x1000>()), 0x0);
/// ```
fn align_down(self, alignment: Alignment) -> Self;
/// Aligns `self` up to `alignment`, returning `None` if aligning would result in an overflow.
///
/// # Examples
///
/// ```
/// use kernel::ptr::{Alignable, Alignment};
///
/// assert_eq!(0x4fusize.align_up(Alignment::new::<0x10>()), Some(0x50));
/// assert_eq!(0x40usize.align_up(Alignment::new::<0x10>()), Some(0x40));
/// assert_eq!(0x0usize.align_up(Alignment::new::<0x10>()), Some(0x0));
/// assert_eq!(u8::MAX.align_up(Alignment::new::<0x10>()), None);
/// assert_eq!(0x10u8.align_up(Alignment::new::<0x100>()), None);
/// assert_eq!(0x0u8.align_up(Alignment::new::<0x100>()), Some(0x0));
/// ```
fn align_up(self, alignment: Alignment) -> Option<Self>;
}
/// Implement [`Alignable`] for unsigned integer types.
macro_rules! impl_alignable_uint {
($($t:ty),*) => {
$(
impl Alignable for $t {
#[inline(always)]
fn align_down(self, alignment: Alignment) -> Self {
// The operands of `&` need to be of the same type so convert the alignment to
// `Self`. This means we need to compute the mask ourselves.
::core::num::NonZero::<Self>::try_from(alignment.as_nonzero())
.map(|align| self & !(align.get() - 1))
// An alignment larger than `Self` always aligns down to `0`.
.unwrap_or(0)
}
#[inline(always)]
fn align_up(self, alignment: Alignment) -> Option<Self> {
let aligned_down = self.align_down(alignment);
if self == aligned_down {
Some(aligned_down)
} else {
Self::try_from(alignment.as_usize())
.ok()
.and_then(|align| aligned_down.checked_add(align))
}
}
}
)*
};
}
impl_alignable_uint!(u8, u16, u32, u64, usize);
|