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, no_init::pseudo_map_phys, 19 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> = if zero { 81 vec![0u8; size] 82 } else { 83 let mut v = Vec::with_capacity(size); 84 unsafe { 85 v.set_len(size); 86 } 87 v 88 }; 89 90 assert!(space.len() == size); 91 let (ptr, len, cap) = space.into_raw_parts(); 92 if !ptr.is_null() { 93 let vaddr = VirtAddr::new(ptr as usize); 94 let len = len as usize; 95 let cap = cap as usize; 96 let mut guard = C_ALLOCATION_MAP.lock(); 97 if unlikely(guard.contains_key(&vaddr)) { 98 drop(guard); 99 unsafe { 100 drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap)); 101 } 102 panic!( 103 "do_kmalloc: vaddr {:?} already exists in C Allocation Map, query size: {size}, zero: {zero}", 104 vaddr 105 ); 106 } 107 // 插入到C Allocation Map中 108 guard.insert(vaddr, (vaddr, len, cap)); 109 return vaddr.data(); 110 } else { 111 return SystemError::ENOMEM.to_posix_errno() as i64 as usize; 112 } 113 } 114 115 #[no_mangle] 116 pub unsafe extern "C" fn kfree(vaddr: usize) -> usize { 117 let vaddr = VirtAddr::new(vaddr); 118 let mut guard = C_ALLOCATION_MAP.lock(); 119 let p = guard.remove(&vaddr); 120 drop(guard); 121 122 if p.is_none() { 123 kerror!("kfree: vaddr {:?} not found in C Allocation Map", vaddr); 124 return SystemError::EINVAL.to_posix_errno() as i64 as usize; 125 } 126 let (vaddr, len, cap) = p.unwrap(); 127 drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap)); 128 return 0; 129 } 130 131 #[no_mangle] 132 pub unsafe extern "C" fn rs_unmap_at_low_addr() -> usize { 133 LowAddressRemapping::unmap_at_low_address(true); 134 return 0; 135 } 136