Skip to main content

page_walker/walkers/
copy.rs

1//! This modules implements the [`CopyFromWalker`] and [`CopyToWalker`] structs which are walkers used to copy data from and to a virtual address range.
2
3use core::marker::PhantomData;
4use core::ops::Range;
5use crate::address_space::PageTableMapper;
6use crate::{PageFormat, PteType};
7use num_traits::{FromPrimitive, PrimInt, Unsigned};
8
9/// The [`CopyFromWalker`] struct is an implementation of a [`crate::walker::PageWalker`] used to
10/// copy data from a given a virtual address range.
11///
12/// This is used by the [`AddressSpace::copy_from`] method.
13///
14/// [`AddressSpace::copy_from`]: `super::super::AddressSpace::copy_from`
15pub struct CopyFromWalker<'a, PTE, Mapper, Error>
16where
17    PTE: FromPrimitive + PrimInt + Unsigned,
18    Mapper: PageTableMapper<PTE, Error>,
19{
20    /// The page table mapper.
21    pub mapper: &'a Mapper,
22    /// The offset within the buffer.
23    pub offset: usize,
24    /// Storage for the copied data.
25    pub data: &'a mut [u8],
26    /// The page format.
27    pub format: &'a PageFormat<'a, PTE>,
28    /// A marker for Error.
29    pub error: PhantomData<Error>,
30}
31
32impl<'a, PTE, Mapper, Error> crate::PageWalker<PTE, Error> for CopyFromWalker<'a, PTE, Mapper, Error>
33where
34    PTE: FromPrimitive + PrimInt + Unsigned,
35    Mapper: PageTableMapper<PTE, Error>,
36{
37    /// Reads the PTE at the given physical address.
38    fn read_pte(&self, phys_addr: PTE) -> Result<PTE, Error> {
39        self.mapper.read_pte(phys_addr)
40    }
41
42    /// Maps the page and copies the data to the buffer.
43    fn handle_pte(&mut self, pte_type: PteType, range: Range<usize>, pte: &PTE) -> Result<(), Error> {
44        let level = match pte_type {
45            PteType::Page(level) => level,
46            _ => return Ok(()),
47        };
48
49        let level = &self.format.levels[level];
50
51        if !level.is_present(*pte) {
52            return Err(Mapper::PAGE_NOT_PRESENT);
53        }
54
55        // Get the physical address of the page.
56        let phys_addr = *pte & self.format.physical_mask;
57
58        // Get the page offset.
59        let offset = PTE::from_usize(range.start & (level.page_size() - 1)).unwrap();
60
61        // Determine how many bytes to copy.
62        let size = (self.data.len() - self.offset).min(level.page_size());
63
64        // Copy the bytes.
65        self.mapper.read_bytes(&mut self.data[self.offset..self.offset + size], phys_addr + offset)?;
66        self.offset += size;
67
68        Ok(())
69    }
70}
71
72/// The [`CopyToWalker`] struct is an implementation of a [`crate::walker::PageWalker`] used to
73/// copy data to a given a virtual address range.
74///
75/// This is used by the [`AddressSpace::copy_to`] method.
76///
77/// [`AddressSpace::copy_to`]: `super::super::AddressSpace::copy_to`
78pub struct CopyToWalker<'a, PTE, Mapper, Error>
79where
80    PTE: FromPrimitive + PrimInt + Unsigned,
81    Mapper: PageTableMapper<PTE, Error>,
82{
83    /// The page table mapper.
84    pub mapper: &'a mut Mapper,
85    /// The offset within the buffer.
86    pub offset: usize,
87    /// Storage for the data to copy.
88    pub data: &'a [u8],
89    /// The page format.
90    pub format: &'a PageFormat<'a, PTE>,
91    /// A marker for Error.
92    pub error: PhantomData<Error>,
93}
94
95impl<'a, PTE, Mapper, Error> crate::PageWalker<PTE, Error> for CopyToWalker<'a, PTE, Mapper, Error>
96where
97    PTE: FromPrimitive + PrimInt + Unsigned,
98    Mapper: PageTableMapper<PTE, Error>,
99{
100    /// Reads the PTE at the given physical address.
101    fn read_pte(&self, phys_addr: PTE) -> Result<PTE, Error> {
102        self.mapper.read_pte(phys_addr)
103    }
104
105    /// Maps the page and copies the data from the buffer.
106    fn handle_pte(&mut self, pte_type: PteType, range: Range<usize>, pte: &PTE) -> Result<(), Error> {
107        let level = match pte_type {
108            PteType::Page(level) => level,
109            _ => return Ok(()),
110        };
111
112        let level = &self.format.levels[level];
113
114        if !level.is_present(*pte) {
115            return Err(Mapper::PAGE_NOT_PRESENT);
116        }
117
118        // Get the physical address of the page.
119        let phys_addr = *pte & self.format.physical_mask;
120
121        // Get the page offset.
122        let offset = PTE::from_usize(range.start & (level.page_size() - 1)).unwrap();
123
124        // Determine how many bytes to copy.
125        let size = (self.data.len() - self.offset).min(level.page_size());
126
127        // Copy the bytes.
128        self.mapper.write_bytes(phys_addr + offset, &self.data[self.offset..self.offset + size])?;
129        self.offset += size;
130
131        Ok(())
132    }
133}