starnix_types/
user_buffer.rs1use super::PAGE_SIZE;
6use smallvec::SmallVec;
7use starnix_uapi::errors::{Errno, errno, error};
8use starnix_uapi::user_address::{UserAddress, UserAddress32, UserRef};
9use std::sync::LazyLock;
10use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
11
12pub type UserBuffers = SmallVec<[UserBuffer; 1]>;
13pub type UserBuffers32 = SmallVec<[UserBuffer32; 1]>;
14
15#[derive(
17 Debug, Default, Clone, Copy, PartialEq, Eq, IntoBytes, KnownLayout, FromBytes, Immutable,
18)]
19#[repr(C)]
20pub struct UserBuffer {
21 pub address: UserAddress,
22 pub length: usize,
23}
24
25pub static MAX_RW_COUNT: LazyLock<usize> = LazyLock::new(|| ((1 << 31) - *PAGE_SIZE) as usize);
26#[derive(
28 Debug, Default, Clone, Copy, PartialEq, Eq, IntoBytes, KnownLayout, FromBytes, Immutable,
29)]
30#[repr(C)]
31#[repr(packed)]
32pub struct UserBuffer32 {
33 pub address: UserAddress32,
34 pub length: u32,
35}
36
37impl From<UserBuffer32> for UserBuffer {
38 fn from(ub32: UserBuffer32) -> Self {
39 UserBuffer { address: ub32.address.into(), length: ub32.length as usize }
40 }
41}
42
43impl UserBuffer {
44 pub fn cap_buffers_to_max_rw_count(
45 max_address: UserAddress,
46 buffers: &mut UserBuffers,
47 ) -> Result<usize, Errno> {
48 for buffer in buffers.iter() {
50 if buffer.address > max_address
51 || buffer.address.checked_add(buffer.length).ok_or_else(|| errno!(EINVAL))?
52 > max_address
53 {
54 return error!(EFAULT);
55 }
56 }
57 let max_rw_count = *MAX_RW_COUNT;
58 let mut total: usize = 0;
59 let mut offset = 0;
60 while offset < buffers.len() {
61 total = total.checked_add(buffers[offset].length).ok_or_else(|| errno!(EINVAL))?;
62 if total >= max_rw_count {
63 buffers[offset].length -= total - max_rw_count;
64 total = max_rw_count;
65 buffers.truncate(offset + 1);
66 break;
67 }
68 offset += 1;
69 }
70 Ok(total)
71 }
72
73 pub fn advance(&mut self, length: usize) -> Result<(), Errno> {
74 self.address = self.address.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
75 self.length = self.length.checked_sub(length).ok_or_else(|| errno!(EINVAL))?;
76 Ok(())
77 }
78
79 pub fn is_null(&self) -> bool {
81 self.address.is_null() && self.is_empty()
82 }
83
84 pub fn is_empty(&self) -> bool {
86 self.length == 0
87 }
88
89 pub fn contains(&self, address: UserAddress, length: usize) -> bool {
91 if let (Some(limit), Some(self_limit)) =
92 (address.checked_add(length), self.address.checked_add(self.length))
93 {
94 address >= self.address && limit <= self_limit
95 } else {
96 false
97 }
98 }
99}
100
101impl<T> TryInto<UserRef<T>> for UserBuffer {
102 type Error = Errno;
103
104 fn try_into(self) -> Result<UserRef<T>, Errno> {
106 if self.length < std::mem::size_of::<T>() {
107 return error!(EINVAL);
108 }
109 Ok(UserRef::new(self.address))
110 }
111}
112
113#[cfg(test)]
114mod test {
115 use super::*;
116 use smallvec::smallvec;
117
118 #[::fuchsia::test]
119 fn test_cap_buffers_to_max_rw_count_buffer_begin_past_max_address() {
120 let mut buffers =
121 smallvec![UserBuffer { address: UserAddress::const_from(50), length: 10 }];
122 assert_eq!(
123 error!(EFAULT),
124 UserBuffer::cap_buffers_to_max_rw_count(UserAddress::const_from(40), &mut buffers),
125 );
126 }
127
128 #[::fuchsia::test]
129 fn test_cap_buffers_to_max_rw_count_buffer_end_past_max_address() {
130 let mut buffers =
131 smallvec![UserBuffer { address: UserAddress::const_from(50), length: 10 }];
132 assert_eq!(
133 error!(EFAULT),
134 UserBuffer::cap_buffers_to_max_rw_count(UserAddress::const_from(55), &mut buffers),
135 );
136 }
137
138 #[::fuchsia::test]
139 fn test_cap_buffers_to_max_rw_count_buffer_overflow_u64() {
140 let mut buffers =
141 smallvec![UserBuffer { address: UserAddress::const_from(u64::MAX - 10), length: 20 }];
142 assert_eq!(
143 error!(EINVAL),
144 UserBuffer::cap_buffers_to_max_rw_count(
145 UserAddress::const_from(u64::MAX),
146 &mut buffers
147 ),
148 );
149 }
150
151 #[::fuchsia::test]
152 fn test_cap_buffers_to_max_rw_count_shorten_buffer() {
153 let mut buffers = smallvec![UserBuffer {
154 address: UserAddress::const_from(0),
155 length: *MAX_RW_COUNT + 10
156 }];
157 let total = UserBuffer::cap_buffers_to_max_rw_count(
158 UserAddress::const_from(u64::MAX),
159 &mut buffers,
160 )
161 .unwrap();
162 assert_eq!(total, *MAX_RW_COUNT);
163 assert_eq!(
164 buffers.as_slice(),
165 &[UserBuffer { address: UserAddress::const_from(0), length: *MAX_RW_COUNT }]
166 );
167 }
168
169 #[::fuchsia::test]
170 fn test_cap_buffers_to_max_rw_count_drop_buffer() {
171 let mut buffers = smallvec![
172 UserBuffer { address: UserAddress::const_from(0), length: *MAX_RW_COUNT },
173 UserBuffer { address: UserAddress::const_from(1 << 33), length: 20 }
174 ];
175 let total = UserBuffer::cap_buffers_to_max_rw_count(
176 UserAddress::const_from(u64::MAX),
177 &mut buffers,
178 )
179 .unwrap();
180 assert_eq!(total, *MAX_RW_COUNT);
181 assert_eq!(
182 buffers.as_slice(),
183 &[UserBuffer { address: UserAddress::const_from(0), length: *MAX_RW_COUNT }]
184 );
185 }
186
187 #[::fuchsia::test]
188 fn test_cap_buffers_to_max_rw_count_drop_and_shorten_buffer() {
189 let mut buffers = smallvec![
190 UserBuffer { address: UserAddress::const_from(0), length: *MAX_RW_COUNT - 10 },
191 UserBuffer { address: UserAddress::const_from(1 << 33), length: 20 },
192 UserBuffer { address: UserAddress::const_from(2 << 33), length: 20 }
193 ];
194 let total = UserBuffer::cap_buffers_to_max_rw_count(
195 UserAddress::const_from(u64::MAX),
196 &mut buffers,
197 )
198 .unwrap();
199 assert_eq!(total, *MAX_RW_COUNT);
200 assert_eq!(
201 buffers.as_slice(),
202 &[
203 UserBuffer { address: UserAddress::const_from(0), length: *MAX_RW_COUNT - 10 },
204 UserBuffer { address: UserAddress::const_from(1 << 33), length: 10 },
205 ]
206 );
207 }
208}