mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 07:06:47 +00:00
mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存 (#346)
* mmio buddy新增guard,把映射的职责交由其守卫进行处理,并且守卫被drop的时候自动释放内存
This commit is contained in:
parent
8d94ea66a3
commit
2dd9f0c750
@ -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,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,
|
||||
|
@ -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);
|
||||
|
@ -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,10 +593,10 @@ 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
|
||||
@ -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::<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总线域物理地址转换为存储器域物理地址
|
||||
let paddr = PciArch::address_pci_to_physical(pci_address); //PCI总线域物理地址转换为存储器域物理地址
|
||||
|
||||
let space_guard: Arc<MMIOSpaceGuard>;
|
||||
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::<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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user