1 //! 这是暴露给C的接口,用于在C语言中使用Rust的内存分配器。
2
3 use core::intrinsics::unlikely;
4
5 use alloc::vec::Vec;
6 use hashbrown::HashMap;
7 use log::error;
8 use system_error::SystemError;
9
10 use crate::libs::spinlock::SpinLock;
11
12 use super::{mmio_buddy::mmio_pool, VirtAddr};
13
14 lazy_static! {
15 // 用于记录内核分配给C的空间信息
16 static ref C_ALLOCATION_MAP: SpinLock<HashMap<VirtAddr, (VirtAddr, usize, usize)>> = SpinLock::new(HashMap::new());
17 }
18
19 #[no_mangle]
kzalloc(size: usize, _gfp: u64) -> usize20 pub unsafe extern "C" fn kzalloc(size: usize, _gfp: u64) -> usize {
21 // debug!("kzalloc: size: {size}");
22 return do_kmalloc(size, true);
23 }
24
25 #[no_mangle]
kmalloc(size: usize, _gfp: u64) -> usize26 pub unsafe extern "C" fn kmalloc(size: usize, _gfp: u64) -> usize {
27 // debug!("kmalloc: size: {size}");
28 // 由于C代码不规范,因此都全部清空
29 return do_kmalloc(size, true);
30 }
31
do_kmalloc(size: usize, _zero: bool) -> usize32 fn do_kmalloc(size: usize, _zero: bool) -> usize {
33 let space: Vec<u8> = vec![0u8; size];
34
35 assert!(space.len() == size);
36 let (ptr, len, cap) = space.into_raw_parts();
37 if !ptr.is_null() {
38 let vaddr = VirtAddr::new(ptr as usize);
39 let mut guard = C_ALLOCATION_MAP.lock();
40 if unlikely(guard.contains_key(&vaddr)) {
41 drop(guard);
42 unsafe {
43 drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap));
44 }
45 panic!(
46 "do_kmalloc: vaddr {:?} already exists in C Allocation Map, query size: {size}, zero: {_zero}",
47 vaddr
48 );
49 }
50 // 插入到C Allocation Map中
51 guard.insert(vaddr, (vaddr, len, cap));
52 return vaddr.data();
53 } else {
54 return SystemError::ENOMEM.to_posix_errno() as i64 as usize;
55 }
56 }
57
58 #[no_mangle]
kfree(vaddr: usize) -> usize59 pub unsafe extern "C" fn kfree(vaddr: usize) -> usize {
60 let vaddr = VirtAddr::new(vaddr);
61 let mut guard = C_ALLOCATION_MAP.lock();
62 let p = guard.remove(&vaddr);
63 drop(guard);
64
65 if p.is_none() {
66 error!("kfree: vaddr {:?} not found in C Allocation Map", vaddr);
67 return SystemError::EINVAL.to_posix_errno() as i64 as usize;
68 }
69 let (vaddr, len, cap) = p.unwrap();
70 drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap));
71 return 0;
72 }
73
74 /// @brief 创建一块mmio区域,并将vma绑定到initial_mm
75 ///
76 /// @param size mmio区域的大小(字节)
77 ///
78 /// @param vm_flags 要把vma设置成的标志
79 ///
80 /// @param res_vaddr 返回值-分配得到的虚拟地址
81 ///
82 /// @param res_length 返回值-分配的虚拟地址空间长度
83 ///
84 /// @return int 错误码
85 #[no_mangle]
rs_mmio_create( size: u32, _vm_flags: u64, res_vaddr: *mut u64, res_length: *mut u64, ) -> i3286 unsafe extern "C" fn rs_mmio_create(
87 size: u32,
88 _vm_flags: u64,
89 res_vaddr: *mut u64,
90 res_length: *mut u64,
91 ) -> i32 {
92 // debug!("mmio_create");
93 let r = mmio_pool().create_mmio(size as usize);
94 if let Err(e) = r {
95 return e.to_posix_errno();
96 }
97 let space_guard = r.unwrap();
98 *res_vaddr = space_guard.vaddr().data() as u64;
99 *res_length = space_guard.size() as u64;
100 // 由于space_guard drop的时候会自动释放内存,所以这里要忽略它的释放
101 core::mem::forget(space_guard);
102 return 0;
103 }
104
105 /// @brief 取消mmio的映射并将地址空间归还到buddy中
106 ///
107 /// @param vaddr 起始的虚拟地址
108 ///
109 /// @param length 要归还的地址空间的长度
110 ///
111 /// @return Ok(i32) 成功返回0
112 ///
113 /// @return Err(i32) 失败返回错误码
114 #[no_mangle]
rs_mmio_release(vaddr: u64, length: u64) -> i32115 pub unsafe extern "C" fn rs_mmio_release(vaddr: u64, length: u64) -> i32 {
116 return mmio_pool()
117 .release_mmio(VirtAddr::new(vaddr as usize), length as usize)
118 .unwrap_or_else(|err| err.to_posix_errno());
119 }
120