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