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