diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3932d64b7..ce669fbd9d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,7 @@ jobs: continue-on-error: ${{ matrix.rust-toolchain == 'nightly' }} run: make clippy ARCH=aarch64 - name: Check code format + continue-on-error: ${{ matrix.rust-toolchain == 'nightly' }} run: cargo fmt --all -- --check build: diff --git a/modules/axmm/src/aspace.rs b/modules/axmm/src/aspace.rs index c1729c4d27..a758dcaead 100644 --- a/modules/axmm/src/aspace.rs +++ b/modules/axmm/src/aspace.rs @@ -1,8 +1,13 @@ use core::fmt; use axerrno::{ax_err, AxError, AxResult}; -use axhal::paging::{MappingFlags, PageTable}; -use memory_addr::{is_aligned_4k, pa, MemoryAddr, PhysAddr, VirtAddr, VirtAddrRange}; +use axhal::{ + mem::phys_to_virt, + paging::{MappingFlags, PageTable}, +}; +use memory_addr::{ + is_aligned_4k, pa, MemoryAddr, PageIter4K, PhysAddr, VirtAddr, VirtAddrRange, PAGE_SIZE_4K, +}; use crate::paging_err_to_ax_err; @@ -109,6 +114,64 @@ impl AddrSpace { Ok(()) } + /// To process data in this area with the given function. + /// + /// Now it supports reading and writing data in the given interval. + fn process_area_data(&self, start: VirtAddr, size: usize, mut f: F) -> AxResult + where + F: FnMut(VirtAddr, usize, usize), + { + if !self.contains_range(start, size) { + return ax_err!(InvalidInput, "address out of range"); + } + let mut cnt = 0; + // If start is aligned to 4K, start_align_down will be equal to start_align_up. + let end_align_up = (start + size).align_up_4k(); + for vaddr in PageIter4K::new(start.align_down_4k(), end_align_up) + .expect("Failed to create page iterator") + { + let (mut paddr, _, _) = self.pt.query(vaddr).map_err(|_| AxError::BadAddress)?; + + let mut copy_size = (size - cnt).min(PAGE_SIZE_4K); + + if copy_size == 0 { + break; + } + if vaddr == start.align_down_4k() && start.align_offset_4k() != 0 { + let align_offset = start.align_offset_4k(); + copy_size = copy_size.min(PAGE_SIZE_4K - align_offset); + paddr += align_offset; + } + f(phys_to_virt(paddr), cnt, copy_size); + cnt += copy_size; + } + Ok(()) + } + + /// To read data from the address space. + /// + /// # Arguments + /// + /// * `start` - The start virtual address to read. + /// * `buf` - The buffer to store the data. + pub fn read(&self, start: VirtAddr, buf: &mut [u8]) -> AxResult { + self.process_area_data(start, buf.len(), |src, offset, read_size| unsafe { + core::ptr::copy_nonoverlapping(src.as_ptr(), buf.as_mut_ptr().add(offset), read_size); + }) + } + + /// To write data to the address space. + /// + /// # Arguments + /// + /// * `start_vaddr` - The start virtual address to write. + /// * `buf` - The buffer to write to the address space. + pub fn write(&self, start: VirtAddr, buf: &[u8]) -> AxResult { + self.process_area_data(start, buf.len(), |dst, offset, write_size| unsafe { + core::ptr::copy_nonoverlapping(buf.as_ptr().add(offset), dst.as_mut_ptr(), write_size); + }) + } + /// Updates mapping within the specified virtual address range. /// /// Returns an error if the address range is out of the address space or not