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] 20 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] 26 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 32 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] 59 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] 86 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] 115 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