xref: /DragonOS/kernel/src/mm/c_adapter.rs (revision c75089286e9d49cef8d039446bf570c1bd4d2550)
1 //! 这是暴露给C的接口,用于在C语言中使用Rust的内存分配器。
2 
3 use core::intrinsics::unlikely;
4 
5 use alloc::vec::Vec;
6 use hashbrown::HashMap;
7 
8 use crate::{
9     arch::mm::LowAddressRemapping,
10     include::bindings::bindings::{gfp_t, PAGE_U_S},
11     kerror,
12     libs::{align::page_align_up, spinlock::SpinLock},
13     mm::MMArch,
14     syscall::SystemError,
15 };
16 
17 use super::{
18     allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, mmio_buddy::mmio_pool,
19     no_init::pseudo_map_phys, page::PageFlags, MemoryManagementArch, PhysAddr, VirtAddr,
20 };
21 
22 lazy_static! {
23     // 用于记录内核分配给C的空间信息
24     static ref C_ALLOCATION_MAP: SpinLock<HashMap<VirtAddr, (VirtAddr, usize, usize)>> = SpinLock::new(HashMap::new());
25 }
26 
27 /// [EXTERN TO C] Use pseudo mapper to map physical memory to virtual memory.
28 #[no_mangle]
29 pub unsafe extern "C" fn rs_pseudo_map_phys(vaddr: usize, paddr: usize, size: usize) {
30     let vaddr = VirtAddr::new(vaddr);
31     let paddr = PhysAddr::new(paddr);
32     let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
33     pseudo_map_phys(vaddr, paddr, count);
34 }
35 
36 /// [EXTERN TO C] Use kernel mapper to map physical memory to virtual memory.
37 #[no_mangle]
38 pub unsafe extern "C" fn rs_map_phys(vaddr: usize, paddr: usize, size: usize, flags: usize) {
39     let mut vaddr = VirtAddr::new(vaddr);
40     let mut paddr = PhysAddr::new(paddr);
41     let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
42     // kdebug!("rs_map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}");
43 
44     let mut page_flags: PageFlags<MMArch> = PageFlags::new().set_execute(true).set_write(true);
45     if flags & PAGE_U_S as usize != 0 {
46         page_flags = page_flags.set_user(true);
47     }
48 
49     let mut kernel_mapper = KernelMapper::lock();
50     let mut kernel_mapper = kernel_mapper.as_mut();
51     assert!(kernel_mapper.is_some());
52     for _i in 0..count.data() {
53         let flusher = kernel_mapper
54             .as_mut()
55             .unwrap()
56             .map_phys(vaddr, paddr, page_flags)
57             .unwrap();
58 
59         flusher.flush();
60 
61         vaddr += MMArch::PAGE_SIZE;
62         paddr += MMArch::PAGE_SIZE;
63     }
64 }
65 
66 #[no_mangle]
67 pub unsafe extern "C" fn kzalloc(size: usize, _gfp: gfp_t) -> usize {
68     // kdebug!("kzalloc: size: {size}");
69     return do_kmalloc(size, true);
70 }
71 
72 #[no_mangle]
73 pub unsafe extern "C" fn kmalloc(size: usize, _gfp: gfp_t) -> usize {
74     // kdebug!("kmalloc: size: {size}");
75     // 由于C代码不规范,因此都全部清空
76     return do_kmalloc(size, true);
77 }
78 
79 fn do_kmalloc(size: usize, _zero: bool) -> usize {
80     let space: Vec<u8> = vec![0u8; size];
81 
82     assert!(space.len() == size);
83     let (ptr, len, cap) = space.into_raw_parts();
84     if !ptr.is_null() {
85         let vaddr = VirtAddr::new(ptr as usize);
86         let len = len as usize;
87         let cap = cap as usize;
88         let mut guard = C_ALLOCATION_MAP.lock();
89         if unlikely(guard.contains_key(&vaddr)) {
90             drop(guard);
91             unsafe {
92                 drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap));
93             }
94             panic!(
95                 "do_kmalloc: vaddr {:?} already exists in C Allocation Map, query size: {size}, zero: {_zero}",
96                 vaddr
97             );
98         }
99         // 插入到C Allocation Map中
100         guard.insert(vaddr, (vaddr, len, cap));
101         return vaddr.data();
102     } else {
103         return SystemError::ENOMEM.to_posix_errno() as i64 as usize;
104     }
105 }
106 
107 #[no_mangle]
108 pub unsafe extern "C" fn kfree(vaddr: usize) -> usize {
109     let vaddr = VirtAddr::new(vaddr);
110     let mut guard = C_ALLOCATION_MAP.lock();
111     let p = guard.remove(&vaddr);
112     drop(guard);
113 
114     if p.is_none() {
115         kerror!("kfree: vaddr {:?} not found in C Allocation Map", vaddr);
116         return SystemError::EINVAL.to_posix_errno() as i64 as usize;
117     }
118     let (vaddr, len, cap) = p.unwrap();
119     drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap));
120     return 0;
121 }
122 
123 #[no_mangle]
124 pub unsafe extern "C" fn rs_unmap_at_low_addr() -> usize {
125     LowAddressRemapping::unmap_at_low_address(true);
126     return 0;
127 }
128 
129 /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
130 ///
131 /// @param size mmio区域的大小(字节)
132 ///
133 /// @param vm_flags 要把vma设置成的标志
134 ///
135 /// @param res_vaddr 返回值-分配得到的虚拟地址
136 ///
137 /// @param res_length 返回值-分配的虚拟地址空间长度
138 ///
139 /// @return int 错误码
140 #[no_mangle]
141 unsafe extern "C" fn rs_mmio_create(
142     size: u32,
143     _vm_flags: u64,
144     res_vaddr: *mut u64,
145     res_length: *mut u64,
146 ) -> i32 {
147     // kdebug!("mmio_create");
148     let r = mmio_pool().create_mmio(size as usize);
149     if r.is_err() {
150         return r.unwrap_err().to_posix_errno();
151     }
152     let space_guard = r.unwrap();
153     *res_vaddr = space_guard.vaddr().data() as u64;
154     *res_length = space_guard.size() as u64;
155     // 由于space_guard drop的时候会自动释放内存,所以这里要忽略它的释放
156     core::mem::forget(space_guard);
157     return 0;
158 }
159 
160 /// @brief 取消mmio的映射并将地址空间归还到buddy中
161 ///
162 /// @param vaddr 起始的虚拟地址
163 ///
164 /// @param length 要归还的地址空间的长度
165 ///
166 /// @return Ok(i32) 成功返回0
167 ///
168 /// @return Err(i32) 失败返回错误码
169 #[no_mangle]
170 pub unsafe extern "C" fn rs_mmio_release(vaddr: u64, length: u64) -> i32 {
171     return mmio_pool()
172         .release_mmio(VirtAddr::new(vaddr as usize), length as usize)
173         .unwrap_or_else(|err| err.to_posix_errno());
174 }
175