From 2dd9f0c7503d1a325713764fedbce06fcab3a06b Mon Sep 17 00:00:00 2001 From: LoGin Date: Mon, 28 Aug 2023 15:54:52 +0800 Subject: [PATCH] =?UTF-8?q?mmio=20buddy=E6=96=B0=E5=A2=9Eguard=EF=BC=8C?= =?UTF-8?q?=E6=8A=8A=E6=98=A0=E5=B0=84=E7=9A=84=E8=81=8C=E8=B4=A3=E4=BA=A4?= =?UTF-8?q?=E7=94=B1=E5=85=B6=E5=AE=88=E5=8D=AB=E8=BF=9B=E8=A1=8C=E5=A4=84?= =?UTF-8?q?=E7=90=86=EF=BC=8C=E5=B9=B6=E4=B8=94=E5=AE=88=E5=8D=AB=E8=A2=AB?= =?UTF-8?q?drop=E7=9A=84=E6=97=B6=E5=80=99=E8=87=AA=E5=8A=A8=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E5=86=85=E5=AD=98=20(#346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存 --- kernel/src/arch/mod.rs | 7 +- kernel/src/arch/x86_64/pci/pci.rs | 11 +- kernel/src/driver/disk/ahci/mod.rs | 4 +- kernel/src/driver/pci/pci.rs | 136 +++++++++------------- kernel/src/driver/pci/pci_irq.rs | 19 ++- kernel/src/driver/virtio/transport_pci.rs | 10 +- kernel/src/mm/mmio_buddy.rs | 132 ++++++++++++++++----- kernel/src/mm/mod.rs | 14 +++ kernel/src/mm/page.rs | 1 + 9 files changed, 199 insertions(+), 135 deletions(-) diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index fd04262c..c66f65d2 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -2,7 +2,10 @@ pub mod x86_64; #[cfg(target_arch = "x86_64")] pub use self::x86_64::*; //公开x86_64架构下的函数,使外界接口统一 -use crate::driver::pci::pci::{BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber}; +use crate::{ + driver::pci::pci::{BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber}, + mm::PhysAddr, +}; /// TraitPciArch Pci架构相关函数,任何架构都应独立实现trait里的函数 pub trait TraitPciArch { @@ -19,7 +22,7 @@ pub trait TraitPciArch { /// @brief PCI域地址到存储器域地址的转换,x86_64架构为一一对应 /// @param address PCI域地址 /// @return usize 转换结果 - fn address_pci_to_physical(pci_address: PciAddr) -> usize; + fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr; /// @brief 获取Segement的root地址,x86_64架构为acpi mcfg表中读取 /// @param segement 组id /// @return Result 转换结果或出错原因 diff --git a/kernel/src/arch/x86_64/pci/pci.rs b/kernel/src/arch/x86_64/pci/pci.rs index 2f4d4d4c..3b4affb4 100644 --- a/kernel/src/arch/x86_64/pci/pci.rs +++ b/kernel/src/arch/x86_64/pci/pci.rs @@ -7,6 +7,7 @@ use crate::driver::pci::pci::{ use crate::include::bindings::bindings::{ acpi_get_MCFG, acpi_iter_SDT, acpi_system_description_table_header_t, io_in32, io_out32, }; +use crate::mm::PhysAddr; use core::ffi::c_void; use core::ptr::NonNull; @@ -40,8 +41,8 @@ impl TraitPciArch for X86_64PciArch { } } - fn address_pci_to_physical(pci_address: PciAddr) -> usize { - return pci_address.data(); + fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr { + return PhysAddr::new(pci_address.data()); } fn ecam_root(segement: SegmentGroupNumber) -> Result { @@ -61,8 +62,10 @@ impl TraitPciArch for X86_64PciArch { for segmentgroupconfiguration in outcome { if segmentgroupconfiguration.segement_group_number == segement { return Ok(PciRoot { - physical_address_base: segmentgroupconfiguration.base_address, - mmio_base: None, + physical_address_base: PhysAddr::new( + segmentgroupconfiguration.base_address as usize, + ), + mmio_guard: None, segement_group_number: segement, bus_begin: segmentgroupconfiguration.bus_begin, bus_end: segmentgroupconfiguration.bus_end, diff --git a/kernel/src/driver/disk/ahci/mod.rs b/kernel/src/driver/disk/ahci/mod.rs index 4f4729be..15255821 100644 --- a/kernel/src/driver/disk/ahci/mod.rs +++ b/kernel/src/driver/disk/ahci/mod.rs @@ -93,8 +93,8 @@ pub fn ahci_rust_init() -> Result<(), SystemError> { // 最后把这个引用列表放入到全局列表 let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock(); //这里两次unsafe转引用规避rust只能有一个可变引用的检查,提高运行速度 - let hba_mem = unsafe { (virtaddr as *mut HbaMem).as_mut().unwrap() }; - hba_mem_list.push(unsafe { (virtaddr as *mut HbaMem).as_mut().unwrap() }); + let hba_mem = unsafe { (virtaddr.data() as *mut HbaMem).as_mut().unwrap() }; + hba_mem_list.push(unsafe { (virtaddr.data() as *mut HbaMem).as_mut().unwrap() }); let pi = volatile_read!(hba_mem.pi); let hba_mem_index = hba_mem_list.len() - 1; drop(hba_mem_list); diff --git a/kernel/src/driver/pci/pci.rs b/kernel/src/driver/pci/pci.rs index f4adc08f..7922a83b 100644 --- a/kernel/src/driver/pci/pci.rs +++ b/kernel/src/driver/pci/pci.rs @@ -2,14 +2,15 @@ // 目前仅支持单主桥单Segment use super::pci_irq::{IrqType, PciIrqError}; -use crate::arch::{PciArch, TraitPciArch}; -use crate::include::bindings::bindings::{PAGE_2M_SIZE, VM_DONTCOPY, VM_IO}; +use crate::arch::{MMArch, PciArch, TraitPciArch}; +use crate::include::bindings::bindings::PAGE_2M_SIZE; use crate::libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use crate::mm::kernel_mapper::KernelMapper; -use crate::mm::mmio_buddy::mmio_pool; -use crate::mm::page::PageFlags; + +use crate::mm::mmio_buddy::{mmio_pool, MMIOSpaceGuard}; + use crate::mm::{PhysAddr, VirtAddr}; use crate::{kdebug, kerror, kinfo, kwarn}; +use alloc::sync::Arc; use alloc::vec::Vec; use alloc::{boxed::Box, collections::LinkedList}; use bitflags::bitflags; @@ -592,13 +593,13 @@ impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge { } /// 代表一个PCI segement greoup. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct PciRoot { - pub physical_address_base: u64, //物理地址,acpi获取 - pub mmio_base: Option<*mut u32>, //映射后的虚拟地址,为方便访问数据这里转化成指针 + pub physical_address_base: PhysAddr, //物理地址,acpi获取 + pub mmio_guard: Option>, //映射后的虚拟地址,为方便访问数据这里转化成指针 pub segement_group_number: SegmentGroupNumber, //segement greoup的id - pub bus_begin: u8, //该分组中的最小bus - pub bus_end: u8, //该分组中的最大bus + pub bus_begin: u8, //该分组中的最小bus + pub bus_end: u8, //该分组中的最大bus } ///线程间共享需要,该结构体只需要在初始化时写入数据,无需读写锁保证线程安全 unsafe impl Send for PciRoot {} @@ -608,8 +609,8 @@ impl Display for PciRoot { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, - "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:#x},mapped at {:#x}", - self.segement_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_base.unwrap() as usize + "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}", + self.segement_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_guard ) } } @@ -628,36 +629,18 @@ impl PciRoot { //kdebug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end); let bus_number = (self.bus_end - self.bus_begin) as u32 + 1; let bus_number_double = (bus_number - 1) / 2 + 1; //一个bus占据1MB空间,计算全部bus占据空间相对于2MB空间的个数 - let mut virtaddress: u64 = 0; - let vaddr_ptr = &mut virtaddress as *mut u64; - let mut virtsize: u64 = 0; - let virtsize_ptr = &mut virtsize as *mut u64; - let size = bus_number_double * PAGE_2M_SIZE; - unsafe { - if let Err(_) = mmio_pool().create_mmio( - size as usize, - (VM_IO | VM_DONTCOPY) as u64, - vaddr_ptr, - virtsize_ptr, - ) { - kerror!("Create mmio failed when initing ecam"); - return Err(PciError::CreateMmioError); - }; - //kdebug!("virtaddress={:#x},virtsize={:#x}",virtaddress,virtsize); - let vaddr = VirtAddr::new(virtaddress as usize); - let paddr = PhysAddr::new(self.physical_address_base as usize); - // kdebug!("pci root: map: vaddr={vaddr:?}, paddr={paddr:?}, size={size}"); - let page_flags = PageFlags::mmio_flags(); - let mut kernel_mapper = KernelMapper::lock(); - // todo: 添加错误处理代码。因为内核映射器可能是只读的,所以可能会出错 - assert!(kernel_mapper - .map_phys_with_size(vaddr, paddr, size as usize, page_flags, true) - .is_ok()); - drop(kernel_mapper); + let size = (bus_number_double as usize) * (PAGE_2M_SIZE as usize); + unsafe { + let space_guard = mmio_pool() + .create_mmio(size as usize) + .map_err(|_| PciError::CreateMmioError)?; + let space_guard = Arc::new(space_guard); + self.mmio_guard = Some(space_guard.clone()); + + assert!(space_guard.map_phys::(self.physical_address_base, size)); } - self.mmio_base = Some(virtaddress as *mut u32); - Ok(0) + return Ok(0); } /// @brief 获得要操作的寄存器相对于mmio_offset的偏移量 /// @param bus_device_function 在同一个group中pci设备的唯一标识符 @@ -681,7 +664,9 @@ impl PciRoot { let address = self.cam_offset(bus_device_function, register_offset); unsafe { // Right shift to convert from byte offset to word offset. - (self.mmio_base.unwrap().add((address >> 2) as usize)).read_volatile() + ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) + .add((address >> 2) as usize)) + .read_volatile() } } @@ -700,7 +685,9 @@ impl PciRoot { // resulting pointer is within the MMIO range of the CAM. unsafe { // Right shift to convert from byte offset to word offset. - (self.mmio_base.unwrap().add((address >> 2) as usize)).write_volatile(data) + ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) + .add((address >> 2) as usize)) + .write_volatile(data) } } /// @brief 返回迭代器,遍历pcie设备的external_capabilities @@ -1106,7 +1093,7 @@ fn pci_check_bus(bus: u8) -> Result { pub extern "C" fn rs_pci_init() { pci_init(); if PCI_ROOT_0.is_some() { - kdebug!("{}", PCI_ROOT_0.unwrap()); + kdebug!("{}", PCI_ROOT_0.as_ref().unwrap()); //以下为ecam的读取寄存器值测试,经测试可正常读取 // let bus_device_function = BusDeviceFunction { // bus: 0, @@ -1237,7 +1224,7 @@ impl TryFrom for MemoryBarType { /// Information about a PCI Base Address Register. /// BAR的三种类型 Memory/IO/Unused -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug)] pub enum BarInfo { /// The BAR is for a memory region. Memory { @@ -1251,7 +1238,7 @@ pub enum BarInfo { /// The size of the BAR in bytes. size: u32, /// The virtaddress for a memory bar(mapped). - virtaddress: u64, + mmio_guard: Arc, }, /// The BAR is for an I/O region. IO { @@ -1279,9 +1266,9 @@ impl BarInfo { ///@brief 得到某个bar的virtaddress(前提是他的类型为Memory Bar) ///@param self ///@return Option<(u64) 是Memory Bar返回映射的虚拟地址,不是则返回None - pub fn virtual_address(&self) -> Option { - if let Self::Memory { virtaddress, .. } = self { - Some(*virtaddress) + pub fn virtual_address(&self) -> Option { + if let Self::Memory { mmio_guard, .. } = self { + Some(mmio_guard.vaddr()) } else { None } @@ -1296,11 +1283,11 @@ impl Display for BarInfo { prefetchable, address, size, - virtaddress, + mmio_guard, } => write!( f, - "Memory space at {:#010x}, size {}, type {:?}, prefetchable {},mapped at {:#x}", - address, size, address_type, prefetchable, virtaddress + "Memory space at {:#010x}, size {}, type {:?}, prefetchable {}, mmio_guard: {:?}", + address, size, address_type, prefetchable, mmio_guard ), Self::IO { address, size } => { write!(f, "I/O space at {:#010x}, size {}", address, size) @@ -1315,7 +1302,7 @@ impl Display for BarInfo { pub trait PciDeviceBar {} ///一个普通PCI设备(非桥)有6个BAR寄存器,PciStandardDeviceBar存储其全部信息 -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug)] pub struct PciStandardDeviceBar { bar0: BarInfo, bar1: BarInfo, @@ -1378,7 +1365,6 @@ pub fn pci_bar_init( continue; } let bar_info; - let mut virtaddress: u64 = 0; let bar_orig = PciArch::read_config(&bus_device_function, BAR0_OFFSET + 4 * bar_index); PciArch::write_config( &bus_device_function, @@ -1414,45 +1400,27 @@ pub fn pci_bar_init( bar_index_ignore = bar_index + 1; //下个bar跳过,因为64位的memory bar覆盖了两个bar } let pci_address = PciAddr::new(address as usize); - address = PciArch::address_pci_to_physical(pci_address) as u64; //PCI总线域物理地址转换为存储器域物理地址 + let paddr = PciArch::address_pci_to_physical(pci_address); //PCI总线域物理地址转换为存储器域物理地址 + + let space_guard: Arc; unsafe { - let vaddr_ptr = &mut virtaddress as *mut u64; - let mut virtsize: u64 = 0; - let virtsize_ptr = &mut virtsize as *mut u64; - let size_want = size as usize; - - if let Err(_) = mmio_pool().create_mmio( - size_want, - (VM_IO | VM_DONTCOPY) as u64, - vaddr_ptr, - virtsize_ptr, - ) { - kerror!("Create mmio failed when initing pci bar"); - return Err(PciError::CreateMmioError); - }; - //kdebug!("virtaddress={:#x},virtsize={:#x}",virtaddress,virtsize); - let vaddr = VirtAddr::new(virtaddress as usize); - let paddr = PhysAddr::new(address as usize); - let page_flags = PageFlags::new() - .set_write(true) - .set_execute(true) - .set_page_cache_disable(true) - .set_page_write_through(true); - kdebug!("Pci bar init: vaddr={vaddr:?}, paddr={paddr:?}, size_want={size_want}, page_flags={page_flags:?}"); - let mut kernel_mapper = KernelMapper::lock(); - // todo: 添加错误处理代码。因为内核映射器可能是只读的,所以可能会出错 - assert!(kernel_mapper - .map_phys_with_size(vaddr, paddr, size_want, page_flags, true) - .is_ok()); - drop(kernel_mapper); + let tmp = mmio_pool() + .create_mmio(size_want) + .map_err(|_| PciError::CreateMmioError)?; + space_guard = Arc::new(tmp); + kdebug!("Pci bar init: mmio space: {space_guard:?}, paddr={paddr:?}, size_want={size_want}"); + assert!( + space_guard.map_phys::(paddr, size_want), + "pci_bar_init: map_phys failed" + ); } bar_info = BarInfo::Memory { address_type, prefetchable, address, size, - virtaddress, + mmio_guard: space_guard, }; } match bar_index { diff --git a/kernel/src/driver/pci/pci_irq.rs b/kernel/src/driver/pci/pci_irq.rs index 670f1289..823cfb84 100644 --- a/kernel/src/driver/pci/pci_irq.rs +++ b/kernel/src/driver/pci/pci_irq.rs @@ -506,10 +506,9 @@ pub trait PciInterrupt: PciDeviceStructure { let vaddr = msix_bar .virtual_address() .ok_or(PciError::PciIrqError(PciIrqError::BarGetVaddrFailed))? - as usize + msix_table_offset as usize + msg.irq_common_message.irq_index as usize * size_of::(); - let msix_entry = NonNull::new(vaddr as *mut MsixEntry).unwrap(); + let msix_entry = NonNull::new(vaddr.data() as *mut MsixEntry).unwrap(); unsafe { volwrite!(msix_entry, vector_control, 0); volwrite!(msix_entry, msg_data, msg_data); @@ -622,10 +621,10 @@ pub trait PciInterrupt: PciDeviceStructure { let vaddr = msix_bar .virtual_address() .ok_or(PciError::PciIrqError(PciIrqError::BarGetVaddrFailed)) - .unwrap() as usize + .unwrap() + msix_table_offset as usize + index as usize * size_of::(); - let msix_entry = NonNull::new(vaddr as *mut MsixEntry).unwrap(); + let msix_entry = NonNull::new(vaddr.data() as *mut MsixEntry).unwrap(); unsafe { volwrite!(msix_entry, vector_control, 0); volwrite!(msix_entry, msg_data, 0); @@ -747,10 +746,10 @@ pub trait PciInterrupt: PciDeviceStructure { .ok_or(PciError::PciIrqError(PciIrqError::PciBarNotInited)) .unwrap(); let msix_bar = pcistandardbar.get_bar(msix_table_bar).unwrap(); - let vaddr = msix_bar.virtual_address().unwrap() as usize + let vaddr = msix_bar.virtual_address().unwrap() + msix_table_offset as usize + irq_index as usize * size_of::(); - let msix_entry = NonNull::new(vaddr as *mut MsixEntry).unwrap(); + let msix_entry = NonNull::new(vaddr.data() as *mut MsixEntry).unwrap(); unsafe { volwrite!(msix_entry, vector_control, 1); } @@ -867,10 +866,10 @@ pub trait PciInterrupt: PciDeviceStructure { .ok_or(PciError::PciIrqError(PciIrqError::PciBarNotInited)) .unwrap(); let msix_bar = pcistandardbar.get_bar(msix_table_bar).unwrap(); - let vaddr = msix_bar.virtual_address().unwrap() as usize + let vaddr = msix_bar.virtual_address().unwrap() + msix_table_offset as usize + irq_index as usize * size_of::(); - let msix_entry = NonNull::new(vaddr as *mut MsixEntry).unwrap(); + let msix_entry = NonNull::new(vaddr.data() as *mut MsixEntry).unwrap(); unsafe { volwrite!(msix_entry, vector_control, 0); } @@ -981,10 +980,10 @@ pub trait PciInterrupt: PciDeviceStructure { .ok_or(PciError::PciIrqError(PciIrqError::PciBarNotInited)) .unwrap(); let pending_bar = pcistandardbar.get_bar(pending_table_bar).unwrap(); - let vaddr = pending_bar.virtual_address().unwrap() as usize + let vaddr = pending_bar.virtual_address().unwrap() + pending_table_offset as usize + (irq_index as usize / 64) * size_of::(); - let pending_entry = NonNull::new(vaddr as *mut PendingEntry).unwrap(); + let pending_entry = NonNull::new(vaddr.data() as *mut PendingEntry).unwrap(); let pending_entry = unsafe { volread!(pending_entry, entry) }; return Ok(pending_entry & (1 << (irq_index as u64 % 64)) != 0); } diff --git a/kernel/src/driver/virtio/transport_pci.rs b/kernel/src/driver/virtio/transport_pci.rs index fe44cbf4..d518bfd0 100644 --- a/kernel/src/driver/virtio/transport_pci.rs +++ b/kernel/src/driver/virtio/transport_pci.rs @@ -8,6 +8,7 @@ use crate::driver::pci::pci::{ use crate::libs::volatile::{ volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly, }; +use crate::mm::VirtAddr; use core::{ fmt::{self, Display, Formatter}, mem::{align_of, size_of}, @@ -18,7 +19,6 @@ use virtio_drivers::{ Error, Hal, PhysAddr, }; -type VirtAddr = usize; /// The PCI vendor ID for VirtIO devices. /// PCI Virtio设备的vendor ID const VIRTIO_VENDOR_ID: u16 = 0x1af4; @@ -437,7 +437,7 @@ impl Display for VirtioPciError { Self::BarOffsetOutOfRange => write!(f, "Capability offset greater than BAR length."), Self::Misaligned { vaddr, alignment } => write!( f, - "Virtual address {:#018x} was not aligned to a {} byte boundary as expected.", + "Virtual address {:?} was not aligned to a {} byte boundary as expected.", vaddr, alignment ), Self::BarGetVaddrFailed => write!(f, "Get bar virtaddress failed"), @@ -475,15 +475,15 @@ fn get_bar_region( //kdebug!("Chossed bar ={},used={}",struct_info.bar,struct_info.offset + struct_info.length); let vaddr = (bar_info .virtual_address() - .ok_or(VirtioPciError::BarGetVaddrFailed)?) as usize + .ok_or(VirtioPciError::BarGetVaddrFailed)?) + struct_info.offset as usize; - if vaddr % align_of::() != 0 { + if vaddr.data() % align_of::() != 0 { return Err(VirtioPciError::Misaligned { vaddr, alignment: align_of::(), }); } - let vaddr = NonNull::new(vaddr as *mut u8).unwrap(); + let vaddr = NonNull::new(vaddr.data() as *mut u8).unwrap(); Ok(vaddr.cast()) } diff --git a/kernel/src/mm/mmio_buddy.rs b/kernel/src/mm/mmio_buddy.rs index 71ca26fc..ea8ac9d9 100644 --- a/kernel/src/mm/mmio_buddy.rs +++ b/kernel/src/mm/mmio_buddy.rs @@ -11,9 +11,10 @@ use crate::{kerror, kinfo, kwarn}; use alloc::{collections::LinkedList, vec::Vec}; use core::mem; use core::mem::MaybeUninit; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; -use super::VirtAddr; +use super::page::PageFlags; +use super::{PhysAddr, VirtAddr}; // 最大的伙伴块的幂 const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT; @@ -474,20 +475,14 @@ impl MmioBuddyMemPool { /// @return Ok(i32) 成功返回0 /// /// @return Err(SystemError) 失败返回错误码 - pub fn create_mmio( - &self, - size: usize, - _vm_flags: vm_flags_t, - res_vaddr: *mut u64, - res_length: *mut u64, - ) -> Result { + pub fn create_mmio(&self, size: usize) -> Result { if size > PAGE_1G_SIZE || size == 0 { return Err(SystemError::EPERM); } - let retval: i32 = 0; // 计算前导0 #[cfg(target_arch = "x86_64")] let mut size_exp: u32 = 63 - size.leading_zeros(); + // 记录最终申请的空间大小 let mut new_size = size; // 对齐要申请的空间大小 @@ -502,21 +497,15 @@ impl MmioBuddyMemPool { } match self.mmio_buddy_query_addr_region(size_exp) { Ok(region) => { - // todo: 是否需要创建vma?或者用新重写的机制去做? - // kdebug!( - // "create_mmio: vaddr = {:?}, length = {}", - // region.vaddr, - // new_size - // ); - unsafe { *res_vaddr = region.vaddr.data() as u64 }; - unsafe { *res_length = new_size as u64 }; + let space_guard = + unsafe { MMIOSpaceGuard::from_raw(region.vaddr, new_size, false) }; + return Ok(space_guard); } Err(_) => { kerror!("failed to create mmio. pid = {:?}", current_pcb().pid); return Err(SystemError::ENOMEM); } } - return Ok(retval); } /// @brief 取消mmio的映射并将地址空间归还到buddy中 @@ -528,7 +517,7 @@ impl MmioBuddyMemPool { /// @return Ok(i32) 成功返回0 /// /// @return Err(SystemError) 失败返回错误码 - pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result { + fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result { assert!(vaddr.check_aligned(MMArch::PAGE_SIZE)); assert!(length & (MMArch::PAGE_SIZE - 1) == 0); if vaddr < self.pool_start_addr @@ -553,7 +542,7 @@ impl MmioBuddyMemPool { kernel_mapper .as_mut() .unwrap() - .unmap(vaddr + i * MMArch::PAGE_SIZE, true) + .unmap_phys(vaddr + i * MMArch::PAGE_SIZE, true) }; } @@ -614,6 +603,88 @@ fn exp2index(exp: u32) -> usize { return (exp - 12) as usize; } +#[derive(Debug)] +pub struct MMIOSpaceGuard { + vaddr: VirtAddr, + size: usize, + mapped: AtomicBool, +} + +impl MMIOSpaceGuard { + pub unsafe fn from_raw(vaddr: VirtAddr, size: usize, mapped: bool) -> Self { + // check size + assert!( + size & (MMArch::PAGE_SIZE - 1) == 0, + "MMIO space size must be page aligned" + ); + assert!(size.is_power_of_two(), "MMIO space size must be power of 2"); + assert!( + vaddr.check_aligned(size), + "MMIO space vaddr must be aligned with size" + ); + assert!( + vaddr.data() >= MMIO_BASE.data() && vaddr.data() + size <= MMIO_TOP.data(), + "MMIO space must be in MMIO region" + ); + + // 人工创建的MMIO空间,认为已经映射 + MMIOSpaceGuard { + vaddr, + size, + mapped: AtomicBool::new(mapped), + } + } + + pub fn vaddr(&self) -> VirtAddr { + self.vaddr + } + + pub fn size(&self) -> usize { + self.size + } + + /// 将物理地址填写到虚拟地址空间中 + /// + /// ## Safety + /// + /// 传入的物理地址【一定要是设备的物理地址】。 + /// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。 + pub unsafe fn map_phys( + &self, + paddr: PhysAddr, + length: usize, + ) -> bool { + if length > self.size { + return false; + } + + let check = self + .mapped + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst); + if check.is_err() { + return false; + } + + let flags = PageFlags::mmio_flags(); + let mut kernel_mapper = KernelMapper::lock(); + let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true); + if r.is_err() { + return false; + } + return true; + } +} + +impl Drop for MMIOSpaceGuard { + fn drop(&mut self) { + let _ = mmio_pool() + .release_mmio(self.vaddr, self.size) + .unwrap_or_else(|err| { + panic!("MMIO release failed: self: {self:?}, err msg: {:?}", err); + }); + } +} + pub fn mmio_init() { kdebug!("Initializing MMIO buddy memory pool..."); // 初始化mmio内存池 @@ -635,18 +706,23 @@ pub fn mmio_init() { /// /// @return int 错误码 #[no_mangle] -pub extern "C" fn mmio_create( +pub unsafe extern "C" fn mmio_create( size: u32, - vm_flags: vm_flags_t, + _vm_flags: vm_flags_t, res_vaddr: *mut u64, res_length: *mut u64, ) -> i32 { // kdebug!("mmio_create"); - if let Err(err) = mmio_pool().create_mmio(size as usize, vm_flags, res_vaddr, res_length) { - return err.to_posix_errno(); - } else { - return 0; + let r = mmio_pool().create_mmio(size as usize); + if r.is_err() { + return r.unwrap_err().to_posix_errno(); } + let space_guard = r.unwrap(); + *res_vaddr = space_guard.vaddr().data() as u64; + *res_length = space_guard.size() as u64; + // 由于space_guard drop的时候会自动释放内存,所以这里要忽略它的释放 + core::mem::forget(space_guard); + return 0; } /// @brief 取消mmio的映射并将地址空间归还到buddy中 @@ -659,7 +735,7 @@ pub extern "C" fn mmio_create( /// /// @return Err(i32) 失败返回错误码 #[no_mangle] -pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 { +pub unsafe extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 { return mmio_pool() .release_mmio(VirtAddr::new(vaddr as usize), length as usize) .unwrap_or_else(|err| err.to_posix_errno()); diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index cfe111f1..b3999169 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -152,6 +152,20 @@ impl core::ops::AddAssign for PhysAddr { } } +impl core::ops::BitOrAssign for PhysAddr { + #[inline(always)] + fn bitor_assign(&mut self, rhs: usize) { + self.0 |= rhs; + } +} + +impl core::ops::BitOrAssign for PhysAddr { + #[inline(always)] + fn bitor_assign(&mut self, rhs: PhysAddr) { + self.0 |= rhs.0; + } +} + impl core::ops::Sub for PhysAddr { type Output = Self; diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index 13023687..693cd62e 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -689,6 +689,7 @@ impl PageMapper { /// /// ## 返回值 /// 如果取消成功,返回刷新器,否则返回None + #[allow(dead_code)] pub unsafe fn unmap(&mut self, virt: VirtAddr, unmap_parents: bool) -> Option> { let (paddr, _, flusher) = self.unmap_phys(virt, unmap_parents)?; self.frame_allocator.free_one(paddr);