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] 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] 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] 66 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] 72 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 78 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] 107 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] 134 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] 163 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