gdma_defs/
access.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Tools to help access queue entries.
5
6use crate::Wqe;
7use guestmem::AccessError;
8use guestmem::GuestMemory;
9use guestmem::MemoryRead;
10use guestmem::MemoryWrite;
11use std::num::Wrapping;
12
13#[derive(Clone)]
14pub struct WqeAccess<'a> {
15    wqe: &'a Wqe,
16    gm: &'a GuestMemory,
17    sgi: usize,
18    offset: usize,
19    remaining_len: usize,
20}
21
22impl Wqe {
23    pub fn access<'a>(&'a self, gm: &'a GuestMemory) -> WqeAccess<'a> {
24        let remaining_len = if self.header.params.sgl_direct() {
25            self.header.sgl_direct_len()
26        } else {
27            self.sgl()
28                .iter()
29                .map(|sge| Wrapping(sge.size as usize))
30                .sum::<Wrapping<usize>>()
31                .0
32        };
33        WqeAccess {
34            wqe: self,
35            gm,
36            sgi: 0,
37            offset: 0,
38            remaining_len,
39        }
40    }
41}
42
43impl WqeAccess<'_> {
44    fn access(
45        &mut self,
46        mut len: usize,
47        mut f: impl FnMut(usize, Result<u64, usize>) -> Result<(), AccessError>,
48    ) -> Result<&mut Self, AccessError> {
49        if self.wqe.header.params.sgl_direct() {
50            let avail = self.wqe.header.sgl_direct_len() - self.offset;
51            if avail < len {
52                return Err(AccessError::OutOfRange(avail, len));
53            }
54            let offset = self.wqe.header.sgl_offset() + self.offset;
55            f(len, Err(offset))?;
56            self.offset += len;
57            self.remaining_len -= len;
58        } else {
59            while len > 0 {
60                let sge = self.wqe.sgl().get(self.sgi).ok_or_else(|| {
61                    AccessError::OutOfRange(
62                        self.sgi,
63                        self.wqe.header.params.num_sgl_entries().into(),
64                    )
65                })?;
66                let gpa = sge.address.wrapping_add(self.offset as u64);
67                let this_len = (sge.size as usize - self.offset).min(len);
68                f(this_len, Ok(gpa))?;
69                self.offset += this_len;
70                self.remaining_len -= this_len;
71                len -= this_len;
72                if sge.size as usize == self.offset {
73                    self.offset = 0;
74                    self.sgi += 1;
75                }
76            }
77        }
78        Ok(self)
79    }
80}
81
82impl MemoryRead for WqeAccess<'_> {
83    fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError> {
84        let mut offset = 0;
85        self.access(data.len(), |len, r| {
86            match r {
87                Ok(gpa) => {
88                    self.gm
89                        .read_at(gpa, &mut data[offset..offset + len])
90                        .map_err(AccessError::Memory)?;
91                    offset += len;
92                }
93                Err(offset) => {
94                    data.copy_from_slice(&self.wqe.data[offset..offset + data.len()]);
95                }
96            }
97            Ok(())
98        })
99    }
100
101    fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError> {
102        self.access(len, |_, _| Ok(()))
103    }
104
105    fn len(&self) -> usize {
106        self.remaining_len
107    }
108}
109
110impl MemoryWrite for WqeAccess<'_> {
111    fn write(&mut self, data: &[u8]) -> Result<(), AccessError> {
112        let mut offset = 0;
113        self.access(data.len(), |len, r| {
114            match r {
115                Ok(gpa) => {
116                    self.gm
117                        .write_at(gpa, &data[offset..offset + len])
118                        .map_err(AccessError::Memory)?;
119                    offset += len;
120                }
121                Err(offset) => {
122                    // Can't receive into SGL direct.
123                    return Err(AccessError::OutOfRange(offset, 0));
124                }
125            }
126            Ok(())
127        })?;
128        Ok(())
129    }
130
131    fn fill(&mut self, _val: u8, _len: usize) -> Result<(), AccessError> {
132        unimplemented!()
133    }
134
135    fn len(&self) -> usize {
136        self.remaining_len
137    }
138}