Implement a new set of physical page APIs

This commit is contained in:
Zhang Junyang
2024-12-24 18:20:55 +08:00
committed by Tate, Hongliang Tian
parent 6e1c36965a
commit cdac59beda
56 changed files with 882 additions and 995 deletions

View File

@ -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();