1use core::fmt;
2
3use ax_memory_addr::{AddrRange, MemoryAddr};
4
5use crate::{MappingBackend, MappingError, MappingResult};
6
7#[derive(Clone)]
13pub struct MemoryArea<B: MappingBackend> {
14 va_range: AddrRange<B::Addr>,
15 flags: B::Flags,
16 reported_flags: B::Flags,
17 max_flags: B::Flags,
18 backend: B,
19}
20
21impl<B: MappingBackend> MemoryArea<B> {
22 pub fn try_new(
26 start: B::Addr,
27 size: usize,
28 flags: B::Flags,
29 backend: B,
30 ) -> MappingResult<Self> {
31 Self::try_new_with_reported_flags(start, size, flags, flags, backend)
32 }
33
34 pub fn try_new_with_reported_flags(
36 start: B::Addr,
37 size: usize,
38 flags: B::Flags,
39 reported_flags: B::Flags,
40 backend: B,
41 ) -> MappingResult<Self> {
42 let va_range = ax_memory_addr::AddrRange::try_from_start_size(start, size)
43 .ok_or(MappingError::InvalidParam)?;
44 if va_range.is_empty() {
45 return Err(MappingError::InvalidParam);
46 }
47 Ok(Self {
48 va_range,
49 flags,
50 reported_flags,
51 max_flags: flags,
52 backend,
53 })
54 }
55
56 pub fn new(start: B::Addr, size: usize, flags: B::Flags, backend: B) -> Self {
62 Self::new_with_reported_flags(start, size, flags, flags, backend)
63 }
64
65 pub fn new_with_reported_flags(
74 start: B::Addr,
75 size: usize,
76 flags: B::Flags,
77 reported_flags: B::Flags,
78 backend: B,
79 ) -> Self {
80 Self {
81 va_range: AddrRange::from_start_size(start, size),
82 flags,
83 reported_flags,
84 max_flags: flags,
85 backend,
86 }
87 }
88
89 pub fn new_with_permissions(
91 start: B::Addr,
92 size: usize,
93 flags: B::Flags,
94 reported_flags: B::Flags,
95 max_flags: B::Flags,
96 backend: B,
97 ) -> Self {
98 Self {
99 va_range: AddrRange::from_start_size(start, size),
100 flags,
101 reported_flags,
102 max_flags,
103 backend,
104 }
105 }
106
107 pub fn try_new_with_permissions(
114 start: B::Addr,
115 size: usize,
116 flags: B::Flags,
117 reported_flags: B::Flags,
118 max_flags: B::Flags,
119 backend: B,
120 ) -> MappingResult<Self> {
121 let va_range =
122 AddrRange::try_from_start_size(start, size).ok_or(MappingError::InvalidParam)?;
123 if va_range.is_empty() {
124 return Err(MappingError::InvalidParam);
125 }
126 Ok(Self {
127 va_range,
128 flags,
129 reported_flags,
130 max_flags,
131 backend,
132 })
133 }
134
135 pub const fn va_range(&self) -> AddrRange<B::Addr> {
137 self.va_range
138 }
139
140 pub const fn flags(&self) -> B::Flags {
142 self.flags
143 }
144
145 pub const fn reported_flags(&self) -> B::Flags {
147 self.reported_flags
148 }
149
150 pub const fn max_flags(&self) -> B::Flags {
152 self.max_flags
153 }
154
155 pub const fn start(&self) -> B::Addr {
157 self.va_range.start
158 }
159
160 pub const fn end(&self) -> B::Addr {
162 self.va_range.end
163 }
164
165 pub fn size(&self) -> usize {
167 self.va_range.size()
168 }
169
170 pub const fn backend(&self) -> &B {
172 &self.backend
173 }
174}
175
176impl<B: MappingBackend> MemoryArea<B> {
177 pub(crate) fn replace_backend(&mut self, backend: B) -> B {
178 core::mem::replace(&mut self.backend, backend)
179 }
180
181 pub(crate) fn set_flags_with_reported_flags(
183 &mut self,
184 new_flags: B::Flags,
185 new_reported_flags: B::Flags,
186 ) {
187 self.flags = new_flags;
188 self.reported_flags = new_reported_flags;
189 }
190
191 pub(crate) fn map_area(
193 &self,
194 context: &mut B::MutationContext,
195 page_table: &mut B::PageTable,
196 ) -> MappingResult {
197 self.backend
198 .map(self.start(), self.size(), self.flags, context, page_table)
199 .then_some(())
200 .ok_or(MappingError::BadState)
201 }
202
203 pub(crate) fn validate_map(&self, page_table: &B::PageTable) -> MappingResult {
204 self.backend
205 .validate_map(self.start(), self.size(), self.flags, page_table)
206 .then_some(())
207 .ok_or(MappingError::BadState)
208 }
209
210 pub(crate) fn unmap_area(
212 &self,
213 context: &mut B::MutationContext,
214 page_table: &mut B::PageTable,
215 ) -> MappingResult {
216 self.unmap_range(self.start(), self.size(), context, page_table)
217 }
218
219 pub(crate) fn unmap_range(
224 &self,
225 start: B::Addr,
226 size: usize,
227 context: &mut B::MutationContext,
228 page_table: &mut B::PageTable,
229 ) -> MappingResult {
230 debug_assert!(
231 self.va_range
232 .contains_range(AddrRange::from_start_size(start, size))
233 );
234 self.backend
235 .unmap(start, size, context, page_table)
236 .then_some(())
237 .ok_or(MappingError::BadState)
238 }
239
240 pub(crate) fn validate_unmap_range(
242 &self,
243 start: B::Addr,
244 size: usize,
245 page_table: &B::PageTable,
246 ) -> MappingResult {
247 debug_assert!(
248 self.va_range
249 .contains_range(AddrRange::from_start_size(start, size))
250 );
251 self.backend
252 .validate_unmap(start, size, page_table)
253 .then_some(())
254 .ok_or(MappingError::BadState)
255 }
256
257 pub(crate) fn protect_range(
259 &self,
260 start: B::Addr,
261 size: usize,
262 new_flags: B::Flags,
263 context: &mut B::MutationContext,
264 page_table: &mut B::PageTable,
265 ) -> MappingResult {
266 debug_assert!(
267 self.va_range
268 .contains_range(AddrRange::from_start_size(start, size))
269 );
270 self.backend
271 .protect(start, size, new_flags, context, page_table)
272 .then_some(())
273 .ok_or(MappingError::BadState)
274 }
275
276 pub(crate) fn shrink_left_metadata(&mut self, new_size: usize) -> MappingResult {
279 if new_size == 0 || new_size >= self.size() {
280 return Err(MappingError::InvalidParam);
281 }
282
283 let old_size = self.size();
284 let unmap_size = old_size - new_size;
285 let new_start = self
286 .va_range
287 .start
288 .checked_add(unmap_size)
289 .ok_or(MappingError::InvalidParam)?;
290 if !self.backend.shrink_left(unmap_size) {
291 return Err(MappingError::BadState);
292 }
293 self.va_range.start = new_start;
294 Ok(())
295 }
296
297 pub(crate) fn shrink_right_metadata(&mut self, new_size: usize) -> MappingResult {
300 if new_size == 0 || new_size >= self.size() {
301 return Err(MappingError::InvalidParam);
302 }
303 let old_size = self.size();
304 let unmap_size = old_size - new_size;
305
306 let new_end = self
307 .va_range
308 .end
309 .checked_sub(unmap_size)
310 .ok_or(MappingError::InvalidParam)?;
311 if !self.backend.shrink_right(unmap_size) {
312 return Err(MappingError::BadState);
313 }
314 self.va_range.end = new_end;
315 Ok(())
316 }
317
318 pub(crate) fn grow_right(
321 &mut self,
322 additional_size: usize,
323 context: &mut B::MutationContext,
324 page_table: &mut B::PageTable,
325 ) -> MappingResult {
326 if additional_size == 0
327 || !self.end().is_aligned_4k()
328 || !additional_size.is_multiple_of(ax_memory_addr::PAGE_SIZE_4K)
329 {
330 return Err(MappingError::InvalidParam);
331 }
332 let map_start = self.end();
333 let new_end = self
334 .va_range
335 .end
336 .checked_add(additional_size)
337 .ok_or(MappingError::InvalidParam)?;
338 if !self
339 .backend
340 .validate_map(map_start, additional_size, self.flags, page_table)
341 {
342 return Err(MappingError::BadState);
343 }
344 if !self
345 .backend
346 .map(map_start, additional_size, self.flags, context, page_table)
347 {
348 return Err(
353 if self
354 .backend
355 .unmap(map_start, additional_size, context, page_table)
356 {
357 MappingError::BadState
358 } else {
359 MappingError::NeedsRepair
360 },
361 );
362 }
363 self.va_range.end = new_end;
364 Ok(())
365 }
366
367 pub(crate) fn split(&mut self, pos: B::Addr) -> MappingResult<Option<Self>> {
375 if self.start() < pos && pos < self.end() {
376 let align_diff = pos.sub_addr(self.start());
377
378 let right = self
379 .backend
380 .split(align_diff)
381 .ok_or(MappingError::BadState)?;
382
383 let mut new_area = Self::new_with_reported_flags(
384 pos,
385 self.end()
386 .checked_sub_addr(pos)
387 .ok_or(MappingError::InvalidParam)?,
388 self.flags,
389 self.reported_flags,
390 right,
391 );
392 new_area.max_flags = self.max_flags;
393 self.va_range.end = pos;
394 Ok(Some(new_area))
395 } else {
396 Ok(None)
397 }
398 }
399}
400
401impl<B: MappingBackend> fmt::Debug for MemoryArea<B>
402where
403 B::Addr: fmt::Debug,
404 B::Flags: fmt::Debug + Copy,
405{
406 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407 f.debug_struct("MemoryArea")
408 .field("va_range", &self.va_range)
409 .field("flags", &self.flags)
410 .field("reported_flags", &self.reported_flags)
411 .field("max_flags", &self.max_flags)
412 .finish()
413 }
414}