Browse Source

mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存 (#346)

* mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存
LoGin 1 year ago
parent
commit
2dd9f0c750

+ 5 - 2
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<PciRoot, PciError> 转换结果或出错原因

+ 7 - 4
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<PciRoot, PciError> {
@@ -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,

+ 2 - 2
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);

+ 51 - 83
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<Arc<MMIOSpaceGuard>>, //映射后的虚拟地址,为方便访问数据这里转化成指针
     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;
+
+        let size = (bus_number_double as usize) * (PAGE_2M_SIZE as usize);
         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);
-            };
+            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());
 
-            //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);
+            assert!(space_guard.map_phys::<MMArch>(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<u8, PciError> {
 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<u8> 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<MMIOSpaceGuard>,
     },
     /// 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<u64> {
-        if let Self::Memory { virtaddress, .. } = self {
-            Some(*virtaddress)
+    pub fn virtual_address(&self) -> Option<VirtAddr> {
+        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总线域物理地址转换为存储器域物理地址
-            unsafe {
-                let vaddr_ptr = &mut virtaddress as *mut u64;
-                let mut virtsize: u64 = 0;
-                let virtsize_ptr = &mut virtsize as *mut u64;
+            let paddr = PciArch::address_pci_to_physical(pci_address); //PCI总线域物理地址转换为存储器域物理地址
 
+            let space_guard: Arc<MMIOSpaceGuard>;
+            unsafe {
                 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::<MMArch>(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 {

+ 9 - 10
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::<MsixEntry>();
-                    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::<MsixEntry>();
-                        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::<MsixEntry>();
-                    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::<MsixEntry>();
-                    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::<PendingEntry>();
-                    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);
                 }

+ 5 - 5
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<T>(
     //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::<T>() != 0 {
+    if vaddr.data() % align_of::<T>() != 0 {
         return Err(VirtioPciError::Misaligned {
             vaddr,
             alignment: align_of::<T>(),
         });
     }
-    let vaddr = NonNull::new(vaddr as *mut u8).unwrap();
+    let vaddr = NonNull::new(vaddr.data() as *mut u8).unwrap();
     Ok(vaddr.cast())
 }
 

+ 104 - 28
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<i32, SystemError> {
+    pub fn create_mmio(&self, size: usize) -> Result<MMIOSpaceGuard, SystemError> {
         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<i32, SystemError> {
+    fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
         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<Arch: MemoryManagementArch>(
+        &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());

+ 14 - 0
kernel/src/mm/mod.rs

@@ -152,6 +152,20 @@ impl core::ops::AddAssign<PhysAddr> for PhysAddr {
     }
 }
 
+impl core::ops::BitOrAssign<usize> for PhysAddr {
+    #[inline(always)]
+    fn bitor_assign(&mut self, rhs: usize) {
+        self.0 |= rhs;
+    }
+}
+
+impl core::ops::BitOrAssign<PhysAddr> for PhysAddr {
+    #[inline(always)]
+    fn bitor_assign(&mut self, rhs: PhysAddr) {
+        self.0 |= rhs.0;
+    }
+}
+
 impl core::ops::Sub<usize> for PhysAddr {
     type Output = Self;
 

+ 1 - 0
kernel/src/mm/page.rs

@@ -689,6 +689,7 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
     ///
     /// ## 返回值
     /// 如果取消成功,返回刷新器,否则返回None
+    #[allow(dead_code)]
     pub unsafe fn unmap(&mut self, virt: VirtAddr, unmap_parents: bool) -> Option<PageFlush<Arch>> {
         let (paddr, _, flusher) = self.unmap_phys(virt, unmap_parents)?;
         self.frame_allocator.free_one(paddr);