x86/bits32/
paging.rs

1//! Description of the data-structures for IA-32 paging mode.
2
3use bitflags::*;
4
5use core::convert::{From, Into};
6use core::fmt;
7use core::hash::{Hash, Hasher};
8use core::ops;
9
10macro_rules! check_flag {
11    ($doc:meta, $fun:ident, $flag:expr) => {
12        #[$doc]
13        pub fn $fun(self) -> bool {
14            self.flags().contains($flag)
15        }
16    };
17}
18
19/// Align address downwards.
20///
21/// Returns the greatest x with alignment `align` so that x <= addr.
22/// The alignment must be a power of 2.
23#[inline(always)]
24fn align_down(addr: u32, align: u32) -> u32 {
25    addr & !(align - 1)
26}
27
28/// Align address upwards.
29///
30/// Returns the smallest x with alignment `align` so that x >= addr.
31/// The alignment must be a power of 2.
32#[inline(always)]
33fn align_up(addr: u32, align: u32) -> u32 {
34    let align_mask = align - 1;
35    if addr & align_mask == 0 {
36        addr
37    } else {
38        (addr | align_mask) + 1
39    }
40}
41
42/// A wrapper for a physical address.
43#[repr(transparent)]
44#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
45pub struct PAddr(pub u32);
46
47impl PAddr {
48    /// Convert to `u32`
49    pub fn as_u32(self) -> u32 {
50        self.0
51    }
52
53    /// Convert to `usize`
54    pub fn as_usize(self) -> usize {
55        self.0 as usize
56    }
57
58    /// Convert to mutable pointer.
59    pub fn as_mut_ptr<T>(self) -> *mut T {
60        self.0 as *mut T
61    }
62
63    /// Convert to pointer.
64    pub fn as_ptr<T>(self) -> *const T {
65        self.0 as *const T
66    }
67
68    /// Physical Address zero.
69    pub const fn zero() -> Self {
70        PAddr(0)
71    }
72
73    /// Is zero?
74    pub fn is_zero(self) -> bool {
75        self == PAddr::zero()
76    }
77
78    fn align_up<U>(self, align: U) -> Self
79    where
80        U: Into<u32>,
81    {
82        PAddr(align_up(self.0, align.into()))
83    }
84
85    fn align_down<U>(self, align: U) -> Self
86    where
87        U: Into<u32>,
88    {
89        PAddr(align_down(self.0, align.into()))
90    }
91
92    /// Offset within the 4 KiB page.
93    pub fn base_page_offset(self) -> u32 {
94        self.0 & (BASE_PAGE_SIZE as u32 - 1)
95    }
96
97    /// Offset within the 4 MiB page.
98    pub fn large_page_offset(self) -> u32 {
99        self.0 & (LARGE_PAGE_SIZE as u32 - 1)
100    }
101
102    /// Return address of nearest 4 KiB page (lower or equal than self).
103    pub fn align_down_to_base_page(self) -> Self {
104        self.align_down(BASE_PAGE_SIZE as u32)
105    }
106
107    /// Return address of nearest 4 MiB page (lower or equal than self).
108    pub fn align_down_to_large_page(self) -> Self {
109        self.align_down(LARGE_PAGE_SIZE as u32)
110    }
111
112    /// Return address of nearest 4 KiB page (higher or equal than self).
113    pub fn align_up_to_base_page(self) -> Self {
114        self.align_up(BASE_PAGE_SIZE as u32)
115    }
116
117    /// Return address of nearest 4 MiB page (higher or equal than self).
118    pub fn align_up_to_large_page(self) -> Self {
119        self.align_up(LARGE_PAGE_SIZE as u32)
120    }
121
122    /// Is this address aligned to a 4 KiB page?
123    pub fn is_base_page_aligned(self) -> bool {
124        self.align_down(BASE_PAGE_SIZE as u32) == self
125    }
126
127    /// Is this address aligned to a 4 MiB page?
128    pub fn is_large_page_aligned(self) -> bool {
129        self.align_down(LARGE_PAGE_SIZE as u32) == self
130    }
131
132    /// Is this address aligned to `align`?
133    ///
134    /// # Note
135    /// `align` must be a power of two.
136    pub fn is_aligned<U>(self, align: U) -> bool
137    where
138        U: Into<u32> + Copy,
139    {
140        if !align.into().is_power_of_two() {
141            return false;
142        }
143
144        self.align_down(align) == self
145    }
146}
147
148impl From<u32> for PAddr {
149    fn from(num: u32) -> Self {
150        PAddr(num)
151    }
152}
153
154impl From<usize> for PAddr {
155    fn from(num: usize) -> Self {
156        PAddr(num as u32)
157    }
158}
159
160impl From<i32> for PAddr {
161    fn from(num: i32) -> Self {
162        PAddr(num as u32)
163    }
164}
165
166#[allow(clippy::clippy::from_over_into)]
167impl Into<u32> for PAddr {
168    fn into(self) -> u32 {
169        self.0
170    }
171}
172
173#[allow(clippy::clippy::from_over_into)]
174impl Into<usize> for PAddr {
175    fn into(self) -> usize {
176        self.0 as usize
177    }
178}
179
180impl ops::Add for PAddr {
181    type Output = PAddr;
182
183    fn add(self, rhs: PAddr) -> Self::Output {
184        PAddr(self.0 + rhs.0)
185    }
186}
187
188impl ops::Add<u32> for PAddr {
189    type Output = PAddr;
190
191    fn add(self, rhs: u32) -> Self::Output {
192        PAddr::from(self.0 + rhs)
193    }
194}
195
196impl ops::Add<usize> for PAddr {
197    type Output = PAddr;
198
199    fn add(self, rhs: usize) -> Self::Output {
200        PAddr::from(self.0 + rhs as u32)
201    }
202}
203
204impl ops::AddAssign for PAddr {
205    fn add_assign(&mut self, other: PAddr) {
206        *self = PAddr::from(self.0 + other.0);
207    }
208}
209
210impl ops::AddAssign<u32> for PAddr {
211    fn add_assign(&mut self, offset: u32) {
212        *self = PAddr::from(self.0 + offset);
213    }
214}
215
216impl ops::Sub for PAddr {
217    type Output = PAddr;
218
219    fn sub(self, rhs: PAddr) -> Self::Output {
220        PAddr::from(self.0 - rhs.0)
221    }
222}
223
224impl ops::Sub<u32> for PAddr {
225    type Output = PAddr;
226
227    fn sub(self, rhs: u32) -> Self::Output {
228        PAddr::from(self.0 - rhs)
229    }
230}
231
232impl ops::Sub<usize> for PAddr {
233    type Output = PAddr;
234
235    fn sub(self, rhs: usize) -> Self::Output {
236        PAddr::from(self.0 - rhs as u32)
237    }
238}
239
240impl ops::Rem for PAddr {
241    type Output = PAddr;
242
243    fn rem(self, rhs: PAddr) -> Self::Output {
244        PAddr(self.0 % rhs.0)
245    }
246}
247
248impl ops::Rem<u32> for PAddr {
249    type Output = u32;
250
251    fn rem(self, rhs: u32) -> Self::Output {
252        self.0 % rhs
253    }
254}
255
256impl ops::Rem<usize> for PAddr {
257    type Output = u32;
258
259    fn rem(self, rhs: usize) -> Self::Output {
260        self.0 % (rhs as u32)
261    }
262}
263
264impl ops::BitAnd for PAddr {
265    type Output = Self;
266
267    fn bitand(self, rhs: Self) -> Self {
268        PAddr(self.0 & rhs.0)
269    }
270}
271
272impl ops::BitAnd<u32> for PAddr {
273    type Output = u32;
274
275    fn bitand(self, rhs: u32) -> Self::Output {
276        Into::<u32>::into(self) & rhs
277    }
278}
279
280impl ops::BitOr for PAddr {
281    type Output = PAddr;
282
283    fn bitor(self, rhs: PAddr) -> Self::Output {
284        PAddr(self.0 | rhs.0)
285    }
286}
287
288impl ops::BitOr<u32> for PAddr {
289    type Output = u32;
290
291    fn bitor(self, rhs: u32) -> Self::Output {
292        self.0 | rhs
293    }
294}
295
296impl ops::Shr<u32> for PAddr {
297    type Output = u32;
298
299    fn shr(self, rhs: u32) -> Self::Output {
300        self.0 >> rhs
301    }
302}
303
304impl fmt::Binary for PAddr {
305    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306        self.0.fmt(f)
307    }
308}
309
310impl fmt::Display for PAddr {
311    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312        self.0.fmt(f)
313    }
314}
315
316impl fmt::Debug for PAddr {
317    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318        write!(f, "{:#x}", self.0)
319    }
320}
321
322impl fmt::LowerHex for PAddr {
323    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
324        self.0.fmt(f)
325    }
326}
327
328impl fmt::Octal for PAddr {
329    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330        self.0.fmt(f)
331    }
332}
333
334impl fmt::UpperHex for PAddr {
335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336        self.0.fmt(f)
337    }
338}
339
340impl fmt::Pointer for PAddr {
341    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
342        use core::fmt::LowerHex;
343        self.0.fmt(f)
344    }
345}
346
347#[allow(clippy::clippy::derive_hash_xor_eq)]
348impl Hash for PAddr {
349    fn hash<H: Hasher>(&self, state: &mut H) {
350        self.0.hash(state);
351    }
352}
353
354/// A wrapper for an IO address (IOVA / DMA Address for devices)
355#[repr(transparent)]
356#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
357pub struct IOAddr(pub u32);
358
359impl IOAddr {
360    /// Convert to `u32`
361    pub fn as_u32(self) -> u32 {
362        self.0
363    }
364
365    /// Convert to `usize`
366    pub fn as_usize(self) -> usize {
367        self.0 as usize
368    }
369
370    /// IO Address zero.
371    pub const fn zero() -> Self {
372        IOAddr(0)
373    }
374
375    /// Is zero?
376    pub fn is_zero(self) -> bool {
377        self == IOAddr::zero()
378    }
379
380    fn align_up<U>(self, align: U) -> Self
381    where
382        U: Into<u32>,
383    {
384        IOAddr(align_up(self.0, align.into()))
385    }
386
387    fn align_down<U>(self, align: U) -> Self
388    where
389        U: Into<u32>,
390    {
391        IOAddr(align_down(self.0, align.into()))
392    }
393
394    /// Offset within the 4 KiB page.
395    pub fn base_page_offset(self) -> u32 {
396        self.0 & (BASE_PAGE_SIZE as u32 - 1)
397    }
398
399    /// Offset within the 4 MiB page.
400    pub fn large_page_offset(self) -> u32 {
401        self.0 & (LARGE_PAGE_SIZE as u32 - 1)
402    }
403
404    /// Return address of nearest 4 KiB page (lower or equal than self).
405    pub fn align_down_to_base_page(self) -> Self {
406        self.align_down(BASE_PAGE_SIZE as u32)
407    }
408
409    /// Return address of nearest 4 MiB page (lower or equal than self).
410    pub fn align_down_to_large_page(self) -> Self {
411        self.align_down(LARGE_PAGE_SIZE as u32)
412    }
413
414    /// Return address of nearest 4 KiB page (higher or equal than self).
415    pub fn align_up_to_base_page(self) -> Self {
416        self.align_up(BASE_PAGE_SIZE as u32)
417    }
418
419    /// Return address of nearest 4 MiB page (higher or equal than self).
420    pub fn align_up_to_large_page(self) -> Self {
421        self.align_up(LARGE_PAGE_SIZE as u32)
422    }
423
424    /// Is this address aligned to a 4 KiB page?
425    pub fn is_base_page_aligned(self) -> bool {
426        self.align_down(BASE_PAGE_SIZE as u32) == self
427    }
428
429    /// Is this address aligned to a 4 MiB page?
430    pub fn is_large_page_aligned(self) -> bool {
431        self.align_down(LARGE_PAGE_SIZE as u32) == self
432    }
433
434    /// Is this address aligned to `align`?
435    ///
436    /// # Note
437    /// `align` must be a power of two.
438    pub fn is_aligned<U>(self, align: U) -> bool
439    where
440        U: Into<u32> + Copy,
441    {
442        if !align.into().is_power_of_two() {
443            return false;
444        }
445
446        self.align_down(align) == self
447    }
448}
449
450impl From<u32> for IOAddr {
451    fn from(num: u32) -> Self {
452        IOAddr(num)
453    }
454}
455
456impl From<usize> for IOAddr {
457    fn from(num: usize) -> Self {
458        IOAddr(num as u32)
459    }
460}
461
462impl From<i32> for IOAddr {
463    fn from(num: i32) -> Self {
464        IOAddr(num as u32)
465    }
466}
467
468#[allow(clippy::clippy::from_over_into)]
469impl Into<u32> for IOAddr {
470    fn into(self) -> u32 {
471        self.0
472    }
473}
474
475#[allow(clippy::clippy::from_over_into)]
476impl Into<usize> for IOAddr {
477    fn into(self) -> usize {
478        self.0 as usize
479    }
480}
481
482impl ops::Add for IOAddr {
483    type Output = IOAddr;
484
485    fn add(self, rhs: IOAddr) -> Self::Output {
486        IOAddr(self.0 + rhs.0)
487    }
488}
489
490impl ops::Add<u32> for IOAddr {
491    type Output = IOAddr;
492
493    fn add(self, rhs: u32) -> Self::Output {
494        IOAddr::from(self.0 + rhs)
495    }
496}
497
498impl ops::Add<usize> for IOAddr {
499    type Output = IOAddr;
500
501    fn add(self, rhs: usize) -> Self::Output {
502        IOAddr::from(self.0 + rhs as u32)
503    }
504}
505
506impl ops::AddAssign for IOAddr {
507    fn add_assign(&mut self, other: IOAddr) {
508        *self = IOAddr::from(self.0 + other.0);
509    }
510}
511
512impl ops::AddAssign<u32> for IOAddr {
513    fn add_assign(&mut self, offset: u32) {
514        *self = IOAddr::from(self.0 + offset);
515    }
516}
517
518impl ops::Sub for IOAddr {
519    type Output = IOAddr;
520
521    fn sub(self, rhs: IOAddr) -> Self::Output {
522        IOAddr::from(self.0 - rhs.0)
523    }
524}
525
526impl ops::Sub<u32> for IOAddr {
527    type Output = IOAddr;
528
529    fn sub(self, rhs: u32) -> Self::Output {
530        IOAddr::from(self.0 - rhs)
531    }
532}
533
534impl ops::Sub<usize> for IOAddr {
535    type Output = IOAddr;
536
537    fn sub(self, rhs: usize) -> Self::Output {
538        IOAddr::from(self.0 - rhs as u32)
539    }
540}
541
542impl ops::Rem for IOAddr {
543    type Output = IOAddr;
544
545    fn rem(self, rhs: IOAddr) -> Self::Output {
546        IOAddr(self.0 % rhs.0)
547    }
548}
549
550impl ops::Rem<u32> for IOAddr {
551    type Output = u32;
552
553    fn rem(self, rhs: u32) -> Self::Output {
554        self.0 % rhs
555    }
556}
557
558impl ops::Rem<usize> for IOAddr {
559    type Output = u32;
560
561    fn rem(self, rhs: usize) -> Self::Output {
562        self.0 % (rhs as u32)
563    }
564}
565
566impl ops::BitAnd for IOAddr {
567    type Output = Self;
568
569    fn bitand(self, rhs: Self) -> Self {
570        IOAddr(self.0 & rhs.0)
571    }
572}
573
574impl ops::BitAnd<u32> for IOAddr {
575    type Output = u32;
576
577    fn bitand(self, rhs: u32) -> Self::Output {
578        Into::<u32>::into(self) & rhs
579    }
580}
581
582impl ops::BitOr for IOAddr {
583    type Output = IOAddr;
584
585    fn bitor(self, rhs: IOAddr) -> Self::Output {
586        IOAddr(self.0 | rhs.0)
587    }
588}
589
590impl ops::BitOr<u32> for IOAddr {
591    type Output = u32;
592
593    fn bitor(self, rhs: u32) -> Self::Output {
594        self.0 | rhs
595    }
596}
597
598impl ops::Shr<u32> for IOAddr {
599    type Output = u32;
600
601    fn shr(self, rhs: u32) -> Self::Output {
602        self.0 >> rhs
603    }
604}
605
606impl fmt::Binary for IOAddr {
607    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
608        self.0.fmt(f)
609    }
610}
611
612impl fmt::Display for IOAddr {
613    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
614        self.0.fmt(f)
615    }
616}
617
618impl fmt::Debug for IOAddr {
619    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
620        write!(f, "{:#x}", self.0)
621    }
622}
623
624impl fmt::LowerHex for IOAddr {
625    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
626        self.0.fmt(f)
627    }
628}
629
630impl fmt::Octal for IOAddr {
631    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
632        self.0.fmt(f)
633    }
634}
635
636impl fmt::UpperHex for IOAddr {
637    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
638        self.0.fmt(f)
639    }
640}
641
642impl fmt::Pointer for IOAddr {
643    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
644        use core::fmt::LowerHex;
645        self.0.fmt(f)
646    }
647}
648
649#[allow(clippy::clippy::derive_hash_xor_eq)]
650impl Hash for IOAddr {
651    fn hash<H: Hasher>(&self, state: &mut H) {
652        self.0.hash(state);
653    }
654}
655
656/// A wrapper for a virtual address.
657#[repr(transparent)]
658#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
659pub struct VAddr(pub u32);
660
661impl VAddr {
662    /// Convert from `u32`
663    pub const fn from_u32(v: u32) -> Self {
664        VAddr(v)
665    }
666
667    /// Convert from `usize`
668    pub const fn from_usize(v: usize) -> Self {
669        VAddr(v as u32)
670    }
671
672    /// Convert to `u32`
673    pub const fn as_u32(self) -> u32 {
674        self.0
675    }
676
677    /// Convert to `usize`
678    pub const fn as_usize(self) -> usize {
679        self.0 as usize
680    }
681
682    /// Convert to mutable pointer.
683    pub fn as_mut_ptr<T>(self) -> *mut T {
684        self.0 as *mut T
685    }
686
687    /// Convert to pointer.
688    pub fn as_ptr<T>(self) -> *const T {
689        self.0 as *const T
690    }
691
692    /// Virtual Address zero.
693    pub const fn zero() -> Self {
694        VAddr(0)
695    }
696
697    /// Is zero?
698    pub fn is_zero(self) -> bool {
699        self == VAddr::zero()
700    }
701
702    fn align_up<U>(self, align: U) -> Self
703    where
704        U: Into<u32>,
705    {
706        VAddr(align_up(self.0, align.into()))
707    }
708
709    fn align_down<U>(self, align: U) -> Self
710    where
711        U: Into<u32>,
712    {
713        VAddr(align_down(self.0, align.into()))
714    }
715
716    /// Offset within the 4 KiB page.
717    pub fn base_page_offset(self) -> u32 {
718        self.0 & (BASE_PAGE_SIZE as u32 - 1)
719    }
720
721    /// Offset within the 4 MiB page.
722    pub fn large_page_offset(self) -> u32 {
723        self.0 & (LARGE_PAGE_SIZE as u32 - 1)
724    }
725
726    /// Return address of nearest 4 KiB page (lower or equal than self).
727    pub fn align_down_to_base_page(self) -> Self {
728        self.align_down(BASE_PAGE_SIZE as u32)
729    }
730
731    /// Return address of nearest 4 MiB page (lower or equal than self).
732    pub fn align_down_to_large_page(self) -> Self {
733        self.align_down(LARGE_PAGE_SIZE as u32)
734    }
735
736    /// Return address of nearest 4 KiB page (higher or equal than self).
737    pub fn align_up_to_base_page(self) -> Self {
738        self.align_up(BASE_PAGE_SIZE as u32)
739    }
740
741    /// Return address of nearest 4 MiB page (higher or equal than self).
742    pub fn align_up_to_large_page(self) -> Self {
743        self.align_up(LARGE_PAGE_SIZE as u32)
744    }
745
746    /// Is this address aligned to a 4 KiB page?
747    pub fn is_base_page_aligned(self) -> bool {
748        self.align_down(BASE_PAGE_SIZE as u32) == self
749    }
750
751    /// Is this address aligned to a 4 MiB page?
752    pub fn is_large_page_aligned(self) -> bool {
753        self.align_down(LARGE_PAGE_SIZE as u32) == self
754    }
755
756    /// Is this address aligned to `align`?
757    ///
758    /// # Note
759    /// `align` must be a power of two.
760    pub fn is_aligned<U>(self, align: U) -> bool
761    where
762        U: Into<u32> + Copy,
763    {
764        if !align.into().is_power_of_two() {
765            return false;
766        }
767
768        self.align_down(align) == self
769    }
770}
771
772impl From<u32> for VAddr {
773    fn from(num: u32) -> Self {
774        VAddr(num)
775    }
776}
777
778impl From<i32> for VAddr {
779    fn from(num: i32) -> Self {
780        VAddr(num as u32)
781    }
782}
783
784#[allow(clippy::clippy::from_over_into)]
785impl Into<u32> for VAddr {
786    fn into(self) -> u32 {
787        self.0
788    }
789}
790
791impl From<usize> for VAddr {
792    fn from(num: usize) -> Self {
793        VAddr(num as u32)
794    }
795}
796
797#[allow(clippy::clippy::from_over_into)]
798impl Into<usize> for VAddr {
799    fn into(self) -> usize {
800        self.0 as usize
801    }
802}
803
804impl ops::Add for VAddr {
805    type Output = VAddr;
806
807    fn add(self, rhs: VAddr) -> Self::Output {
808        VAddr(self.0 + rhs.0)
809    }
810}
811
812impl ops::Add<u32> for VAddr {
813    type Output = VAddr;
814
815    fn add(self, rhs: u32) -> Self::Output {
816        VAddr(self.0 + rhs)
817    }
818}
819
820impl ops::Add<usize> for VAddr {
821    type Output = VAddr;
822
823    fn add(self, rhs: usize) -> Self::Output {
824        VAddr::from(self.0 + rhs as u32)
825    }
826}
827
828impl ops::AddAssign for VAddr {
829    fn add_assign(&mut self, other: VAddr) {
830        *self = VAddr::from(self.0 + other.0);
831    }
832}
833
834impl ops::AddAssign<u32> for VAddr {
835    fn add_assign(&mut self, offset: u32) {
836        *self = VAddr::from(self.0 + offset);
837    }
838}
839
840impl ops::AddAssign<usize> for VAddr {
841    fn add_assign(&mut self, offset: usize) {
842        *self = VAddr::from(self.0 + offset as u32);
843    }
844}
845
846impl ops::Sub for VAddr {
847    type Output = VAddr;
848
849    fn sub(self, rhs: VAddr) -> Self::Output {
850        VAddr::from(self.0 - rhs.0)
851    }
852}
853
854impl ops::Sub<u32> for VAddr {
855    type Output = VAddr;
856
857    fn sub(self, rhs: u32) -> Self::Output {
858        VAddr::from(self.0 - rhs)
859    }
860}
861
862impl ops::Sub<usize> for VAddr {
863    type Output = VAddr;
864
865    fn sub(self, rhs: usize) -> Self::Output {
866        VAddr::from(self.0 - rhs as u32)
867    }
868}
869
870impl ops::Rem for VAddr {
871    type Output = VAddr;
872
873    fn rem(self, rhs: VAddr) -> Self::Output {
874        VAddr(self.0 % rhs.0)
875    }
876}
877
878impl ops::Rem<u32> for VAddr {
879    type Output = u32;
880
881    fn rem(self, rhs: Self::Output) -> Self::Output {
882        self.0 % rhs
883    }
884}
885
886impl ops::Rem<usize> for VAddr {
887    type Output = usize;
888
889    fn rem(self, rhs: Self::Output) -> Self::Output {
890        self.as_usize() % rhs
891    }
892}
893
894impl ops::BitAnd for VAddr {
895    type Output = Self;
896
897    fn bitand(self, rhs: Self) -> Self::Output {
898        VAddr(self.0 & rhs.0)
899    }
900}
901
902impl ops::BitAnd<u32> for VAddr {
903    type Output = VAddr;
904
905    fn bitand(self, rhs: u32) -> Self::Output {
906        VAddr(self.0 & rhs)
907    }
908}
909
910impl ops::BitAnd<usize> for VAddr {
911    type Output = VAddr;
912
913    fn bitand(self, rhs: usize) -> Self::Output {
914        VAddr(self.0 & rhs as u32)
915    }
916}
917
918impl ops::BitAnd<i32> for VAddr {
919    type Output = VAddr;
920
921    fn bitand(self, rhs: i32) -> Self::Output {
922        VAddr(self.0 & rhs as u32)
923    }
924}
925
926impl ops::BitOr for VAddr {
927    type Output = VAddr;
928
929    fn bitor(self, rhs: VAddr) -> VAddr {
930        VAddr(self.0 | rhs.0)
931    }
932}
933
934impl ops::BitOr<u32> for VAddr {
935    type Output = VAddr;
936
937    fn bitor(self, rhs: u32) -> Self::Output {
938        VAddr(self.0 | rhs)
939    }
940}
941
942impl ops::BitOr<usize> for VAddr {
943    type Output = VAddr;
944
945    fn bitor(self, rhs: usize) -> Self::Output {
946        VAddr(self.0 | rhs as u32)
947    }
948}
949
950impl ops::Shr<u32> for VAddr {
951    type Output = u32;
952
953    fn shr(self, rhs: u32) -> Self::Output {
954        self.0 >> rhs as u32
955    }
956}
957
958impl ops::Shr<usize> for VAddr {
959    type Output = u32;
960
961    fn shr(self, rhs: usize) -> Self::Output {
962        self.0 >> rhs as u32
963    }
964}
965
966impl ops::Shr<i32> for VAddr {
967    type Output = u32;
968
969    fn shr(self, rhs: i32) -> Self::Output {
970        self.0 >> rhs as u32
971    }
972}
973
974impl fmt::Binary for VAddr {
975    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
976        self.0.fmt(f)
977    }
978}
979
980impl fmt::Display for VAddr {
981    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
982        write!(f, "{:#x}", self.0)
983    }
984}
985
986impl fmt::Debug for VAddr {
987    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
988        write!(f, "{:#x}", self.0)
989    }
990}
991
992impl fmt::LowerHex for VAddr {
993    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
994        self.0.fmt(f)
995    }
996}
997
998impl fmt::Octal for VAddr {
999    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1000        self.0.fmt(f)
1001    }
1002}
1003
1004impl fmt::UpperHex for VAddr {
1005    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1006        self.0.fmt(f)
1007    }
1008}
1009
1010impl fmt::Pointer for VAddr {
1011    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1012        use core::fmt::LowerHex;
1013        self.0.fmt(f)
1014    }
1015}
1016
1017#[allow(clippy::clippy::derive_hash_xor_eq)]
1018impl Hash for VAddr {
1019    fn hash<H: Hasher>(&self, state: &mut H) {
1020        self.0.hash(state);
1021    }
1022}
1023
1024/// Log2 of base page size (12 bits).
1025pub const BASE_PAGE_SHIFT: usize = 12;
1026
1027/// Size of a base page (4 KiB)
1028pub const BASE_PAGE_SIZE: usize = 4096;
1029
1030/// Size of a large page (4 MiB)
1031pub const LARGE_PAGE_SIZE: usize = 1024 * 1024 * 4;
1032
1033/// Size of a cache-line
1034pub const CACHE_LINE_SIZE: usize = 64;
1035
1036/// A type wrapping a base page with a 4 KiB buffer.
1037pub struct Page([u8; BASE_PAGE_SIZE]);
1038
1039/// A type wrapping a large page with a 4 MiB buffer.
1040pub struct LargePage([u8; LARGE_PAGE_SIZE]);
1041
1042/// Mask to find the physical address of an entry in a page-table.
1043const ADDRESS_MASK: u32 = !0xfff;
1044const ADDRESS_MASK_PSE: u32 = !0x3fffff;
1045
1046/// Page tables have 512 = 4096 / 32 entries.
1047pub const PAGE_SIZE_ENTRIES: usize = 1024;
1048
1049/// A page directory.
1050pub type PD = [PDEntry; PAGE_SIZE_ENTRIES];
1051
1052/// A page table.
1053pub type PT = [PTEntry; PAGE_SIZE_ENTRIES];
1054
1055/// Given virtual address calculate corresponding entry in PD.
1056#[inline]
1057pub fn pd_index(addr: VAddr) -> usize {
1058    ((addr >> 22usize) & 0b1111111111) as usize
1059}
1060
1061/// Given virtual address calculate corresponding entry in PT.
1062#[inline]
1063pub fn pt_index(addr: VAddr) -> usize {
1064    ((addr >> 12usize) & 0b1111111111) as usize
1065}
1066
1067bitflags! {
1068    /// PD configuration bits description.
1069    #[repr(transparent)]
1070    pub struct PDFlags: u32 {
1071        /// Present; must be 1 to map a 4-MByte page.
1072        const P       = bit!(0);
1073        /// Read/write; if 0, writes may not be allowed to the 4-MByte page referenced by this entry.
1074        const RW      = bit!(1);
1075        /// User/supervisor; if 0, user-mode accesses are not allowed to the 4-MByte page referenced by this entry.
1076        const US      = bit!(2);
1077        /// Page-level write-through.
1078        const PWT     = bit!(3);
1079        /// Page-level cache disable.
1080        const PCD     = bit!(4);
1081        /// Accessed; indicates whether software has accessed the 4-MByte page referenced by this entry.
1082        const A       = bit!(5);
1083        /// Dirty; indicates whether software has written to the 4-MByte page referenced by this entry.
1084        const D       = bit!(6);
1085        /// Page size; if set this entry maps a 4-MByte page; otherwise, this entry references a page directory.
1086        const PS      = bit!(7);
1087        /// Global; if CR4.PGE = 1, determines whether the translation is global; ignored otherwise.
1088        const G       = bit!(8);
1089        /// If the PAT is supported, indirectly determines the memory type used to access the 4-MByte page referenced by this entry;
1090        /// otherwise, reserved (must be 0)
1091        const PAT     = bit!(12);
1092    }
1093}
1094
1095/// A PD Entry consists of an address and a bunch of flags.
1096#[repr(transparent)]
1097#[derive(Clone, Copy)]
1098pub struct PDEntry(pub u32);
1099
1100impl fmt::Debug for PDEntry {
1101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1102        write!(f, "PDEntry {{ {:#x}, {:?} }}", self.address(), self.flags())
1103    }
1104}
1105
1106impl PDEntry {
1107    /// Creates a new PDEntry.
1108    ///
1109    /// # Arguments
1110    ///
1111    ///  * `pt` - The physical address of the page table.
1112    ///  * `flags`- Additional flags for the entry.
1113    ///
1114    /// # Implementation notes
1115    ///
1116    /// This doesn't support PSE-36 or PSE-40.
1117    pub fn new(pt: PAddr, flags: PDFlags) -> PDEntry {
1118        let mask = if flags.contains(PDFlags::PS) {
1119            ADDRESS_MASK_PSE
1120        } else {
1121            ADDRESS_MASK
1122        };
1123        let pt_val = pt & mask;
1124        assert!(pt_val == pt.into());
1125        assert!(pt % BASE_PAGE_SIZE == 0);
1126        PDEntry(pt_val | flags.bits)
1127    }
1128
1129    /// Retrieves the physical address in this entry.
1130    pub fn address(self) -> PAddr {
1131        if self.flags().contains(PDFlags::PS) {
1132            PAddr::from(self.0 & ADDRESS_MASK_PSE)
1133        } else {
1134            PAddr::from(self.0 & ADDRESS_MASK)
1135        }
1136    }
1137
1138    /// Returns the flags corresponding to this entry.
1139    pub fn flags(self) -> PDFlags {
1140        PDFlags::from_bits_truncate(self.0)
1141    }
1142
1143    check_flag!(
1144        doc = "Present; must be 1 to map a 4-MByte page.",
1145        is_present,
1146        PDFlags::P
1147    );
1148    check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 4-MByte page referenced by this entry.",
1149                is_writeable, PDFlags::RW);
1150    check_flag!(doc = "User/supervisor; if 0, user-mode accesses are not allowed to the 4-MByte page referenced by this entry.",
1151                is_user_mode_allowed, PDFlags::US);
1152    check_flag!(
1153        doc = "Page-level write-through.",
1154        is_page_write_through,
1155        PDFlags::PWT
1156    );
1157    check_flag!(
1158        doc = "Page-level cache disable.",
1159        is_page_level_cache_disabled,
1160        PDFlags::PCD
1161    );
1162    check_flag!(doc = "Accessed; indicates whether software has accessed the 4-MByte page referenced by this entry.",
1163                is_accessed, PDFlags::A);
1164    check_flag!(doc = "Dirty; indicates whether software has written to the 4-MByte page referenced by this entry.",
1165                is_dirty, PDFlags::D);
1166    check_flag!(doc = "Page size; if set this entry maps a 4-MByte page; otherwise, this entry references a page directory.",
1167                is_page, PDFlags::PS);
1168    check_flag!(doc = "Global; if CR4.PGE = 1, determines whether the translation is global; ignored otherwise.",
1169                is_global, PDFlags::G);
1170    check_flag!(doc = "If the PAT is supported, indirectly determines the memory type used to access the 4-MByte page referenced by this entry; otherwise, reserved (must be 0)",
1171                is_pat, PDFlags::PAT);
1172}
1173
1174bitflags! {
1175    /// PT Entry bits description.
1176    #[repr(transparent)]
1177    pub struct PTFlags: u32 {
1178        /// Present; must be 1 to map a 4-KByte page.
1179        const P       = bit!(0);
1180        /// Read/write; if 0, writes may not be allowed to the 4-KByte page referenced by this entry.
1181        const RW      = bit!(1);
1182        /// User/supervisor; if 0, user-mode accesses are not allowed to the 4-KByte page referenced by this entry.
1183        const US      = bit!(2);
1184        /// Page-level write-through.
1185        const PWT     = bit!(3);
1186        /// Page-level cache disable.
1187        const PCD     = bit!(4);
1188        /// Accessed; indicates whether software has accessed the 4-KByte page referenced by this entry.
1189        const A       = bit!(5);
1190        /// Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.
1191        const D       = bit!(6);
1192        /// If the PAT is supported, indirectly determines the memory type used to access the 4-KByte page referenced by this entry;
1193        /// otherwise, reserved (must be 0)
1194        const PAT     = bit!(7);
1195        /// Global; if CR4.PGE = 1, determines whether the translation is global; ignored otherwise.
1196        const G       = bit!(8);
1197    }
1198}
1199
1200/// A PT Entry consists of an address and a bunch of flags.
1201#[repr(transparent)]
1202#[derive(Clone, Copy)]
1203pub struct PTEntry(pub u32);
1204
1205impl fmt::Debug for PTEntry {
1206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1207        write!(f, "PTEntry {{ {:#x}, {:?} }}", self.address(), self.flags())
1208    }
1209}
1210
1211impl PTEntry {
1212    /// Creates a new PTEntry.
1213    ///
1214    /// # Arguments
1215    ///
1216    ///  * `page` - The physical address of the backing 4 KiB page.
1217    ///  * `flags`- Additional flags for the entry.
1218    pub fn new(page: PAddr, flags: PTFlags) -> PTEntry {
1219        let page_val = page & ADDRESS_MASK;
1220        assert!(page_val == page.into());
1221        assert!(page % BASE_PAGE_SIZE == 0);
1222        PTEntry(page_val | flags.bits)
1223    }
1224
1225    /// Retrieves the physical address in this entry.
1226    pub fn address(self) -> PAddr {
1227        PAddr::from(self.0 & ADDRESS_MASK)
1228    }
1229
1230    /// Returns the flags corresponding to this entry.
1231    pub fn flags(self) -> PTFlags {
1232        PTFlags::from_bits_truncate(self.0)
1233    }
1234
1235    check_flag!(
1236        doc = "Present; must be 1 to map a 4-KByte page.",
1237        is_present,
1238        PTFlags::P
1239    );
1240    check_flag!(doc = "Read/write; if 0, writes may not be allowed to the 4-KByte page referenced by this entry.",
1241                is_writeable, PTFlags::RW);
1242    check_flag!(doc = "User/supervisor; if 0, user-mode accesses are not allowed to the 4-KByte page referenced by this entry.",
1243                is_user_mode_allowed, PTFlags::US);
1244    check_flag!(
1245        doc = "Page-level write-through.",
1246        is_page_write_through,
1247        PTFlags::PWT
1248    );
1249    check_flag!(
1250        doc = "Page-level cache disable.",
1251        is_page_level_cache_disabled,
1252        PTFlags::PCD
1253    );
1254    check_flag!(doc = "Accessed; indicates whether software has accessed the 4-KByte page referenced by this entry.",
1255                is_accessed, PTFlags::A);
1256    check_flag!(doc = "Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.",
1257                is_dirty, PTFlags::D);
1258    check_flag!(doc = "If the PAT is supported, indirectly determines the memory type used to access the 4-KByte page referenced by this entry; otherwise, reserved (must be 0)",
1259                is_pat, PTFlags::PAT);
1260    check_flag!(doc = "Global; if CR4.PGE = 1, determines whether the translation is global; ignored otherwise.",
1261                is_global, PTFlags::G);
1262}
1263
1264#[cfg(all(test, feature = "utest"))]
1265mod test {
1266    use super::*;
1267
1268    #[test]
1269    fn paddr_align() {
1270        let base = PAddr::from(0x1000);
1271        assert_eq!(base.base_page_offset(), 0x0);
1272        assert_eq!(base.large_page_offset(), 0x1000);
1273        assert_eq!(base.align_down_to_base_page(), PAddr::from(0x1000));
1274        assert_eq!(base.align_down_to_large_page(), PAddr::from(0x0));
1275        assert_eq!(base.align_up_to_base_page(), PAddr::from(0x1000));
1276        assert_eq!(base.align_up_to_large_page(), PAddr::from(0x400000));
1277        assert!(base.is_base_page_aligned());
1278        assert!(!base.is_large_page_aligned());
1279        assert!(base.is_aligned(0x1u32));
1280        assert!(base.is_aligned(0x2u32));
1281        assert!(!base.is_aligned(0x3u32));
1282        assert!(base.is_aligned(0x4u32));
1283
1284        let base = PAddr::from(0x1001);
1285        assert_eq!(base.base_page_offset(), 0x1);
1286        assert_eq!(base.large_page_offset(), 0x1001);
1287        assert_eq!(base.align_down_to_base_page(), PAddr::from(0x1000));
1288        assert_eq!(base.align_down_to_large_page(), PAddr::from(0x0));
1289        assert_eq!(base.align_up_to_base_page(), PAddr::from(0x2000));
1290        assert_eq!(base.align_up_to_large_page(), PAddr::from(0x400000));
1291        assert!(!base.is_base_page_aligned());
1292        assert!(!base.is_large_page_aligned());
1293        assert!(base.is_aligned(0x1u32));
1294        assert!(!base.is_aligned(0x2u32));
1295        assert!(!base.is_aligned(0x3u32));
1296        assert!(!base.is_aligned(0x4u32));
1297
1298        let base = PAddr::from(0x400000);
1299        assert_eq!(base.base_page_offset(), 0x0);
1300        assert_eq!(base.large_page_offset(), 0x0);
1301        assert_eq!(base.align_down_to_base_page(), PAddr::from(0x400000));
1302        assert_eq!(base.align_down_to_large_page(), PAddr::from(0x400000));
1303        assert_eq!(base.align_up_to_base_page(), PAddr::from(0x400000));
1304        assert_eq!(base.align_up_to_large_page(), PAddr::from(0x400000));
1305        assert!(base.is_base_page_aligned());
1306        assert!(base.is_large_page_aligned());
1307        assert!(base.is_aligned(0x1u32));
1308        assert!(base.is_aligned(0x2u32));
1309        assert!(!base.is_aligned(0x3u32));
1310        assert!(base.is_aligned(0x4u32));
1311
1312        let base = PAddr::from(0x400002);
1313        assert_eq!(base.base_page_offset(), 0x2);
1314        assert_eq!(base.large_page_offset(), 0x2);
1315        assert_eq!(base.align_down_to_base_page(), PAddr::from(0x400000));
1316        assert_eq!(base.align_down_to_large_page(), PAddr::from(0x400000));
1317        assert_eq!(base.align_up_to_base_page(), PAddr::from(0x401000));
1318        assert_eq!(base.align_up_to_large_page(), PAddr::from(0x800000));
1319        assert!(!base.is_base_page_aligned());
1320        assert!(!base.is_large_page_aligned());
1321        assert!(base.is_aligned(0x1u32));
1322        assert!(base.is_aligned(0x2u32));
1323        assert!(!base.is_aligned(0x3u32));
1324        assert!(!base.is_aligned(0x4u32));
1325    }
1326
1327    #[test]
1328    fn ioaddr_align() {
1329        let base = IOAddr::from(0x1000);
1330        assert_eq!(base.base_page_offset(), 0x0);
1331        assert_eq!(base.large_page_offset(), 0x1000);
1332        assert_eq!(base.align_down_to_base_page(), IOAddr::from(0x1000));
1333        assert_eq!(base.align_down_to_large_page(), IOAddr::from(0x0));
1334        assert_eq!(base.align_up_to_base_page(), IOAddr::from(0x1000));
1335        assert_eq!(base.align_up_to_large_page(), IOAddr::from(0x400000));
1336        assert!(base.is_base_page_aligned());
1337        assert!(!base.is_large_page_aligned());
1338        assert!(base.is_aligned(0x1u32));
1339        assert!(base.is_aligned(0x2u32));
1340        assert!(!base.is_aligned(0x3u32));
1341        assert!(base.is_aligned(0x4u32));
1342
1343        let base = IOAddr::from(0x1001);
1344        assert_eq!(base.base_page_offset(), 0x1);
1345        assert_eq!(base.large_page_offset(), 0x1001);
1346        assert_eq!(base.align_down_to_base_page(), IOAddr::from(0x1000));
1347        assert_eq!(base.align_down_to_large_page(), IOAddr::from(0x0));
1348        assert_eq!(base.align_up_to_base_page(), IOAddr::from(0x2000));
1349        assert_eq!(base.align_up_to_large_page(), IOAddr::from(0x400000));
1350        assert!(!base.is_base_page_aligned());
1351        assert!(!base.is_large_page_aligned());
1352        assert!(base.is_aligned(0x1u32));
1353        assert!(!base.is_aligned(0x2u32));
1354        assert!(!base.is_aligned(0x3u32));
1355        assert!(!base.is_aligned(0x4u32));
1356
1357        let base = IOAddr::from(0x400000);
1358        assert_eq!(base.base_page_offset(), 0x0);
1359        assert_eq!(base.large_page_offset(), 0x0);
1360        assert_eq!(base.align_down_to_base_page(), IOAddr::from(0x400000));
1361        assert_eq!(base.align_down_to_large_page(), IOAddr::from(0x400000));
1362        assert_eq!(base.align_up_to_base_page(), IOAddr::from(0x400000));
1363        assert_eq!(base.align_up_to_large_page(), IOAddr::from(0x400000));
1364        assert!(base.is_base_page_aligned());
1365        assert!(base.is_large_page_aligned());
1366        assert!(base.is_aligned(0x1u32));
1367        assert!(base.is_aligned(0x2u32));
1368        assert!(!base.is_aligned(0x3u32));
1369        assert!(base.is_aligned(0x4u32));
1370
1371        let base = IOAddr::from(0x400002);
1372        assert_eq!(base.base_page_offset(), 0x2);
1373        assert_eq!(base.large_page_offset(), 0x2);
1374        assert_eq!(base.align_down_to_base_page(), IOAddr::from(0x400000));
1375        assert_eq!(base.align_down_to_large_page(), IOAddr::from(0x400000));
1376        assert_eq!(base.align_up_to_base_page(), IOAddr::from(0x401000));
1377        assert_eq!(base.align_up_to_large_page(), IOAddr::from(0x800000));
1378        assert!(!base.is_base_page_aligned());
1379        assert!(!base.is_large_page_aligned());
1380        assert!(base.is_aligned(0x1u32));
1381        assert!(base.is_aligned(0x2u32));
1382        assert!(!base.is_aligned(0x3u32));
1383        assert!(!base.is_aligned(0x4u32));
1384    }
1385
1386    #[test]
1387    fn vaddr_align() {
1388        let base = VAddr::from(0x1000);
1389        assert_eq!(base.base_page_offset(), 0x0);
1390        assert_eq!(base.large_page_offset(), 0x1000);
1391        assert_eq!(base.align_down_to_base_page(), VAddr::from(0x1000));
1392        assert_eq!(base.align_down_to_large_page(), VAddr::from(0x0));
1393        assert_eq!(base.align_up_to_base_page(), VAddr::from(0x1000));
1394        assert_eq!(base.align_up_to_large_page(), VAddr::from(0x400000));
1395        assert!(base.is_base_page_aligned());
1396        assert!(!base.is_large_page_aligned());
1397        assert!(base.is_aligned(0x1u32));
1398        assert!(base.is_aligned(0x2u32));
1399        assert!(!base.is_aligned(0x3u32));
1400        assert!(base.is_aligned(0x4u32));
1401
1402        let base = VAddr::from(0x1001);
1403        assert_eq!(base.base_page_offset(), 0x1);
1404        assert_eq!(base.large_page_offset(), 0x1001);
1405        assert_eq!(base.align_down_to_base_page(), VAddr::from(0x1000));
1406        assert_eq!(base.align_down_to_large_page(), VAddr::from(0x0));
1407        assert_eq!(base.align_up_to_base_page(), VAddr::from(0x2000));
1408        assert_eq!(base.align_up_to_large_page(), VAddr::from(0x400000));
1409        assert!(!base.is_base_page_aligned());
1410        assert!(!base.is_large_page_aligned());
1411        assert!(base.is_aligned(0x1u32));
1412        assert!(!base.is_aligned(0x2u32));
1413        assert!(!base.is_aligned(0x3u32));
1414        assert!(!base.is_aligned(0x4u32));
1415
1416        let base = VAddr::from(0x400000);
1417        assert_eq!(base.base_page_offset(), 0x0);
1418        assert_eq!(base.large_page_offset(), 0x0);
1419        assert_eq!(base.align_down_to_base_page(), VAddr::from(0x400000));
1420        assert_eq!(base.align_down_to_large_page(), VAddr::from(0x400000));
1421        assert_eq!(base.align_up_to_base_page(), VAddr::from(0x400000));
1422        assert_eq!(base.align_up_to_large_page(), VAddr::from(0x400000));
1423        assert!(base.is_base_page_aligned());
1424        assert!(base.is_large_page_aligned());
1425        assert!(base.is_aligned(0x1u32));
1426        assert!(base.is_aligned(0x2u32));
1427        assert!(!base.is_aligned(0x3u32));
1428        assert!(base.is_aligned(0x4u32));
1429
1430        let base = VAddr::from(0x400002);
1431        assert_eq!(base.base_page_offset(), 0x2);
1432        assert_eq!(base.large_page_offset(), 0x2);
1433        assert_eq!(base.align_down_to_base_page(), VAddr::from(0x400000));
1434        assert_eq!(base.align_down_to_large_page(), VAddr::from(0x400000));
1435        assert_eq!(base.align_up_to_base_page(), VAddr::from(0x401000));
1436        assert_eq!(base.align_up_to_large_page(), VAddr::from(0x800000));
1437        assert!(!base.is_base_page_aligned());
1438        assert!(!base.is_large_page_aligned());
1439        assert!(base.is_aligned(0x1u32));
1440        assert!(base.is_aligned(0x2u32));
1441        assert!(!base.is_aligned(0x3u32));
1442        assert!(!base.is_aligned(0x4u32));
1443    }
1444}