xref: /DragonOS/kernel/src/libs/align.rs (revision c75089286e9d49cef8d039446bf570c1bd4d2550)
1 #![allow(dead_code)]
2 //! 这是一个关于对齐的库,提供了一些对齐的宏和函数、结构体
3 
4 use core::{alloc::GlobalAlloc, fmt::Debug, ptr::Unique};
5 
6 use crate::{arch::MMArch, mm::MemoryManagementArch, syscall::SystemError, KERNEL_ALLOCATOR};
7 
8 /// # AlignedBox
9 ///
10 /// 一个用于分配对齐内存的结构体。分配的内存地址符合`ALIGN`的要求。
11 /// 如果类型T的对齐要求大于`ALIGN`,则采用T的对齐要求。
12 ///
13 /// ## 说明
14 ///
15 /// `ALIGN`: 对齐要求,必须是2的幂次方,且不为0,否则编译时报错
16 pub struct AlignedBox<T, const ALIGN: usize> {
17     inner: Unique<T>,
18 }
19 
20 impl<T, const ALIGN: usize> AlignedBox<T, ALIGN> {
21     const LAYOUT: core::alloc::Layout = {
22         const fn max(a: usize, b: usize) -> usize {
23             if a > b {
24                 a
25             } else {
26                 b
27             }
28         }
29         let layout = core::alloc::Layout::from_size_align(
30             core::mem::size_of::<T>(),
31             max(ALIGN, core::mem::align_of::<T>()),
32         );
33 
34         if let Ok(layout) = layout {
35             layout
36         } else {
37             panic!("Check alignment failed at compile time.")
38         }
39     };
40 
41     /// 分配一个新的内存空间,并将其初始化为零。然后返回AlignedBox
42     ///
43     /// # Errors
44     ///
45     /// 如果分配失败,则返回`Err(SystemError::ENOMEM)`
46     #[inline(always)]
47     pub fn new_zeroed() -> Result<Self, SystemError>
48     where
49         T: SafeForZero,
50     {
51         let ptr = unsafe { KERNEL_ALLOCATOR.alloc_zeroed(Self::LAYOUT) };
52         if ptr.is_null() {
53             return Err(SystemError::ENOMEM);
54         } else {
55             return Ok(AlignedBox {
56                 inner: unsafe { Unique::new_unchecked(ptr.cast()) },
57             });
58         }
59     }
60 
61     pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
62         return AlignedBox {
63             inner: Unique::new_unchecked(ptr),
64         };
65     }
66 }
67 
68 impl<T, const ALIGN: usize> Debug for AlignedBox<T, ALIGN> {
69     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70         return write!(
71             f,
72             "AlignedBox<{:?}, {:?}>, ptr: {:p}, size: {:}",
73             core::any::type_name::<T>(),
74             core::mem::align_of::<T>(),
75             self.inner.as_ptr(),
76             core::mem::size_of::<T>()
77         );
78     }
79 }
80 
81 impl<T, const ALIGN: usize> Drop for AlignedBox<T, ALIGN> {
82     fn drop(&mut self) {
83         unsafe {
84             // 释放 Unique 智能指针所拥有的内存,并调用类型的析构函数以清理资源
85             core::ptr::drop_in_place(self.inner.as_ptr());
86             // dealloc memory space
87             KERNEL_ALLOCATOR.dealloc(self.inner.as_ptr().cast(), Self::LAYOUT);
88         }
89     }
90 }
91 
92 impl<T, const ALIGN: usize> core::ops::Deref for AlignedBox<T, ALIGN> {
93     type Target = T;
94 
95     fn deref(&self) -> &Self::Target {
96         unsafe { &*self.inner.as_ptr() }
97     }
98 }
99 
100 impl<T, const ALIGN: usize> core::ops::DerefMut for AlignedBox<T, ALIGN> {
101     fn deref_mut(&mut self) -> &mut Self::Target {
102         unsafe { &mut *self.inner.as_ptr() }
103     }
104 }
105 
106 impl<T: Clone + SafeForZero, const ALIGN: usize> Clone for AlignedBox<T, ALIGN> {
107     fn clone(&self) -> Self {
108         let mut new: AlignedBox<T, ALIGN> =
109             Self::new_zeroed().unwrap_or_else(|_| alloc::alloc::handle_alloc_error(Self::LAYOUT));
110         new.clone_from(self);
111         return new;
112     }
113 }
114 
115 /// 一个用于表明某个类型是安全的用于零初始化的 trait
116 ///
117 /// 该 trait 用于表明某个类型是安全的用于零初始化的,即该类型的所有位都可以被初始化为 0 而不会出现未定义行为。
118 pub unsafe trait SafeForZero {}
119 
120 unsafe impl<const NUM: usize> SafeForZero for [u8; NUM] {}
121 
122 /// 将给定的地址按照页面大小,向上对齐。
123 ///
124 /// 参数 `addr`:要对齐的地址。
125 ///
126 /// 返回值:对齐后的地址。
127 pub fn page_align_up(addr: usize) -> usize {
128     let page_size = MMArch::PAGE_SIZE;
129     return (addr + page_size - 1) & (!(page_size - 1));
130 }
131 
132 pub fn page_align_down(addr: usize) -> usize {
133     let page_size = MMArch::PAGE_SIZE;
134     return addr & (!(page_size - 1));
135 }
136 
137 /// ## 检查是否对齐
138 ///
139 /// 检查给定的值是否对齐到给定的对齐要求。
140 ///
141 /// ## 参数
142 /// - `value`:要检查的值
143 /// - `align`:对齐要求,必须是2的幂次方,且不为0,否则运行时panic
144 ///
145 /// ## 返回值
146 ///
147 /// 如果对齐则返回`true`,否则返回`false`
148 pub fn check_aligned(value: usize, align: usize) -> bool {
149     assert!(align != 0 && align.is_power_of_two());
150     return value & (align - 1) == 0;
151 }
152