mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-30 12:23:56 +00:00
Implement a new set of physical page APIs
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
6e1c36965a
commit
cdac59beda
@ -11,7 +11,7 @@ use crate::{
|
||||
error::Error,
|
||||
mm::{
|
||||
dma::{dma_type, Daddr, DmaType},
|
||||
HasPaddr, Infallible, Paddr, UntypedSegment, VmIo, VmReader, VmWriter, PAGE_SIZE,
|
||||
DynUSegment, HasPaddr, Infallible, Paddr, UntypedMem, VmIo, VmReader, VmWriter, PAGE_SIZE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -34,7 +34,7 @@ pub struct DmaStream {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DmaStreamInner {
|
||||
vm_segment: UntypedSegment,
|
||||
segment: DynUSegment,
|
||||
start_daddr: Daddr,
|
||||
/// TODO: remove this field when on x86.
|
||||
#[allow(unused)]
|
||||
@ -55,16 +55,16 @@ pub enum DmaDirection {
|
||||
}
|
||||
|
||||
impl DmaStream {
|
||||
/// Establishes DMA stream mapping for a given [`UntypedSegment`].
|
||||
/// Establishes DMA stream mapping for a given [`DynUSegment`].
|
||||
///
|
||||
/// The method fails if the segment already belongs to a DMA mapping.
|
||||
pub fn map(
|
||||
vm_segment: UntypedSegment,
|
||||
segment: DynUSegment,
|
||||
direction: DmaDirection,
|
||||
is_cache_coherent: bool,
|
||||
) -> Result<Self, DmaError> {
|
||||
let frame_count = vm_segment.nbytes() / PAGE_SIZE;
|
||||
let start_paddr = vm_segment.start_paddr();
|
||||
let frame_count = segment.size() / PAGE_SIZE;
|
||||
let start_paddr = segment.start_paddr();
|
||||
if !check_and_insert_dma_mapping(start_paddr, frame_count) {
|
||||
return Err(DmaError::AlreadyMapped);
|
||||
}
|
||||
@ -88,7 +88,7 @@ impl DmaStream {
|
||||
DmaType::Iommu => {
|
||||
for i in 0..frame_count {
|
||||
let paddr = start_paddr + (i * PAGE_SIZE);
|
||||
// SAFETY: the `paddr` is restricted by the `start_paddr` and `frame_count` of the `vm_segment`.
|
||||
// SAFETY: the `paddr` is restricted by the `start_paddr` and `frame_count` of the `segment`.
|
||||
unsafe {
|
||||
iommu::map(paddr as Daddr, paddr).unwrap();
|
||||
}
|
||||
@ -99,7 +99,7 @@ impl DmaStream {
|
||||
|
||||
Ok(Self {
|
||||
inner: Arc::new(DmaStreamInner {
|
||||
vm_segment,
|
||||
segment,
|
||||
start_daddr,
|
||||
is_cache_coherent,
|
||||
direction,
|
||||
@ -107,24 +107,24 @@ impl DmaStream {
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the underlying [`UntypedSegment`].
|
||||
/// Gets the underlying [`DynUSegment`].
|
||||
///
|
||||
/// Usually, the CPU side should not access the memory
|
||||
/// after the DMA mapping is established because
|
||||
/// there is a chance that the device is updating
|
||||
/// the memory. Do this at your own risk.
|
||||
pub fn vm_segment(&self) -> &UntypedSegment {
|
||||
&self.inner.vm_segment
|
||||
pub fn segment(&self) -> &DynUSegment {
|
||||
&self.inner.segment
|
||||
}
|
||||
|
||||
/// Returns the number of frames.
|
||||
pub fn nframes(&self) -> usize {
|
||||
self.inner.vm_segment.nbytes() / PAGE_SIZE
|
||||
self.inner.segment.size() / PAGE_SIZE
|
||||
}
|
||||
|
||||
/// Returns the number of bytes.
|
||||
pub fn nbytes(&self) -> usize {
|
||||
self.inner.vm_segment.nbytes()
|
||||
self.inner.segment.size()
|
||||
}
|
||||
|
||||
/// Returns the DMA direction.
|
||||
@ -156,7 +156,7 @@ impl DmaStream {
|
||||
if self.inner.is_cache_coherent {
|
||||
return Ok(());
|
||||
}
|
||||
let start_va = crate::mm::paddr_to_vaddr(self.inner.vm_segment.paddr()) as *const u8;
|
||||
let start_va = crate::mm::paddr_to_vaddr(self.inner.segment.paddr()) as *const u8;
|
||||
// TODO: Query the CPU for the cache line size via CPUID, we use 64 bytes as the cache line size here.
|
||||
for i in _byte_range.step_by(64) {
|
||||
// TODO: Call the cache line flush command in the corresponding architecture.
|
||||
@ -176,8 +176,8 @@ impl HasDaddr for DmaStream {
|
||||
|
||||
impl Drop for DmaStreamInner {
|
||||
fn drop(&mut self) {
|
||||
let frame_count = self.vm_segment.nbytes() / PAGE_SIZE;
|
||||
let start_paddr = self.vm_segment.start_paddr();
|
||||
let frame_count = self.segment.size() / PAGE_SIZE;
|
||||
let start_paddr = self.segment.start_paddr();
|
||||
// Ensure that the addresses used later will not overflow
|
||||
start_paddr.checked_add(frame_count * PAGE_SIZE).unwrap();
|
||||
match dma_type() {
|
||||
@ -211,7 +211,7 @@ impl VmIo for DmaStream {
|
||||
if self.inner.direction == DmaDirection::ToDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
self.inner.vm_segment.read(offset, writer)
|
||||
self.inner.segment.read(offset, writer)
|
||||
}
|
||||
|
||||
/// Writes data from the buffer.
|
||||
@ -219,7 +219,7 @@ impl VmIo for DmaStream {
|
||||
if self.inner.direction == DmaDirection::FromDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
self.inner.vm_segment.write(offset, reader)
|
||||
self.inner.segment.write(offset, reader)
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ impl<'a> DmaStream {
|
||||
if self.inner.direction == DmaDirection::ToDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
Ok(self.inner.vm_segment.reader())
|
||||
Ok(self.inner.segment.reader())
|
||||
}
|
||||
|
||||
/// Returns a writer to write data into it.
|
||||
@ -237,13 +237,13 @@ impl<'a> DmaStream {
|
||||
if self.inner.direction == DmaDirection::FromDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
Ok(self.inner.vm_segment.writer())
|
||||
Ok(self.inner.segment.writer())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasPaddr for DmaStream {
|
||||
fn paddr(&self) -> Paddr {
|
||||
self.inner.vm_segment.start_paddr()
|
||||
self.inner.segment.start_paddr()
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,36 +373,35 @@ mod test {
|
||||
|
||||
#[ktest]
|
||||
fn streaming_map() {
|
||||
let vm_segment = FrameAllocOptions::new(1)
|
||||
.is_contiguous(true)
|
||||
.alloc_contiguous()
|
||||
let segment = FrameAllocOptions::new()
|
||||
.alloc_segment_with(1, |_| ())
|
||||
.unwrap();
|
||||
let dma_stream =
|
||||
DmaStream::map(vm_segment.clone(), DmaDirection::Bidirectional, true).unwrap();
|
||||
assert!(dma_stream.paddr() == vm_segment.paddr());
|
||||
DmaStream::map(segment.clone().into(), DmaDirection::Bidirectional, true).unwrap();
|
||||
assert!(dma_stream.paddr() == segment.start_paddr());
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
fn duplicate_map() {
|
||||
let vm_segment_parent = FrameAllocOptions::new(2)
|
||||
.is_contiguous(true)
|
||||
.alloc_contiguous()
|
||||
let segment_parent = FrameAllocOptions::new()
|
||||
.alloc_segment_with(2, |_| ())
|
||||
.unwrap();
|
||||
let vm_segment_child = vm_segment_parent.slice(&(0..PAGE_SIZE));
|
||||
let segment_child = segment_parent.slice(&(0..PAGE_SIZE));
|
||||
let dma_stream_parent =
|
||||
DmaStream::map(vm_segment_parent, DmaDirection::Bidirectional, false);
|
||||
let dma_stream_child = DmaStream::map(vm_segment_child, DmaDirection::Bidirectional, false);
|
||||
DmaStream::map(segment_parent.into(), DmaDirection::Bidirectional, false);
|
||||
let dma_stream_child =
|
||||
DmaStream::map(segment_child.into(), DmaDirection::Bidirectional, false);
|
||||
assert!(dma_stream_parent.is_ok());
|
||||
assert!(dma_stream_child.is_err());
|
||||
}
|
||||
|
||||
#[ktest]
|
||||
fn read_and_write() {
|
||||
let vm_segment = FrameAllocOptions::new(2)
|
||||
.is_contiguous(true)
|
||||
.alloc_contiguous()
|
||||
let segment = FrameAllocOptions::new()
|
||||
.alloc_segment_with(2, |_| ())
|
||||
.unwrap();
|
||||
let dma_stream = DmaStream::map(vm_segment, DmaDirection::Bidirectional, false).unwrap();
|
||||
let dma_stream =
|
||||
DmaStream::map(segment.into(), DmaDirection::Bidirectional, false).unwrap();
|
||||
|
||||
let buf_write = vec![1u8; 2 * PAGE_SIZE];
|
||||
dma_stream.write_bytes(0, &buf_write).unwrap();
|
||||
@ -414,11 +413,11 @@ mod test {
|
||||
|
||||
#[ktest]
|
||||
fn reader_and_writer() {
|
||||
let vm_segment = FrameAllocOptions::new(2)
|
||||
.is_contiguous(true)
|
||||
.alloc_contiguous()
|
||||
let segment = FrameAllocOptions::new()
|
||||
.alloc_segment_with(2, |_| ())
|
||||
.unwrap();
|
||||
let dma_stream = DmaStream::map(vm_segment, DmaDirection::Bidirectional, false).unwrap();
|
||||
let dma_stream =
|
||||
DmaStream::map(segment.into(), DmaDirection::Bidirectional, false).unwrap();
|
||||
|
||||
let buf_write = vec![1u8; PAGE_SIZE];
|
||||
let mut writer = dma_stream.writer().unwrap();
|
||||
|
Reference in New Issue
Block a user