1use core::fmt;
2
3use ax_memory_addr::{AddrRange, MemoryAddr};
4
5use crate::{MappingBackend, MappingError, MappingResult};
6
7pub struct MemoryArea<B: MappingBackend> {
13 va_range: AddrRange<B::Addr>,
14 flags: B::Flags,
15 backend: B,
16}
17
18impl<B: MappingBackend> MemoryArea<B> {
19 pub fn new(start: B::Addr, size: usize, flags: B::Flags, backend: B) -> Self {
25 Self {
26 va_range: AddrRange::from_start_size(start, size),
27 flags,
28 backend,
29 }
30 }
31
32 pub const fn va_range(&self) -> AddrRange<B::Addr> {
34 self.va_range
35 }
36
37 pub const fn flags(&self) -> B::Flags {
39 self.flags
40 }
41
42 pub const fn start(&self) -> B::Addr {
44 self.va_range.start
45 }
46
47 pub const fn end(&self) -> B::Addr {
49 self.va_range.end
50 }
51
52 pub fn size(&self) -> usize {
54 self.va_range.size()
55 }
56
57 pub const fn backend(&self) -> &B {
59 &self.backend
60 }
61}
62
63impl<B: MappingBackend> MemoryArea<B> {
64 pub(crate) fn set_flags(&mut self, new_flags: B::Flags) {
66 self.flags = new_flags;
67 }
68
69 pub(crate) fn map_area(&self, page_table: &mut B::PageTable) -> MappingResult {
71 self.backend
72 .map(self.start(), self.size(), self.flags, page_table)
73 .then_some(())
74 .ok_or(MappingError::BadState)
75 }
76
77 pub(crate) fn unmap_area(&self, page_table: &mut B::PageTable) -> MappingResult {
79 self.backend
80 .unmap(self.start(), self.size(), page_table)
81 .then_some(())
82 .ok_or(MappingError::BadState)
83 }
84
85 pub(crate) fn protect_area(
87 &mut self,
88 new_flags: B::Flags,
89 page_table: &mut B::PageTable,
90 ) -> MappingResult {
91 self.backend
92 .protect(self.start(), self.size(), new_flags, page_table);
93 Ok(())
94 }
95
96 pub(crate) fn shrink_left(
105 &mut self,
106 new_size: usize,
107 page_table: &mut B::PageTable,
108 ) -> MappingResult {
109 assert!(new_size > 0 && new_size < self.size());
110
111 let old_size = self.size();
112 let unmap_size = old_size - new_size;
113
114 if !self.backend.unmap(self.start(), unmap_size, page_table) {
115 return Err(MappingError::BadState);
116 }
117 self.va_range.start = self.va_range.start.wrapping_add(unmap_size);
121 self.backend.shrink_left(unmap_size);
122 Ok(())
123 }
124
125 pub(crate) fn shrink_left_metadata(&mut self, new_size: usize) {
128 assert!(new_size > 0 && new_size < self.size());
129
130 let old_size = self.size();
131 let unmap_size = old_size - new_size;
132 self.va_range.start = self.va_range.start.wrapping_add(unmap_size);
133 self.backend.shrink_left(unmap_size);
134 }
135
136 pub(crate) fn shrink_right(
145 &mut self,
146 new_size: usize,
147 page_table: &mut B::PageTable,
148 ) -> MappingResult {
149 assert!(new_size > 0 && new_size < self.size());
150 let old_size = self.size();
151 let unmap_size = old_size - new_size;
152
153 let unmap_start = self.start().wrapping_add(new_size);
156
157 if !self.backend.unmap(unmap_start, unmap_size, page_table) {
158 return Err(MappingError::BadState);
159 }
160
161 self.va_range.end = self.va_range.end.wrapping_sub(unmap_size);
163 self.backend.shrink_right(unmap_size);
164 Ok(())
165 }
166
167 pub(crate) fn shrink_right_metadata(&mut self, new_size: usize) {
170 assert!(new_size > 0 && new_size < self.size());
171 let old_size = self.size();
172 let unmap_size = old_size - new_size;
173
174 self.va_range.end = self.va_range.end.wrapping_sub(unmap_size);
175 self.backend.shrink_right(unmap_size);
176 }
177
178 pub(crate) fn grow_right(
181 &mut self,
182 additional_size: usize,
183 page_table: &mut B::PageTable,
184 ) -> MappingResult {
185 assert!(additional_size > 0);
186 assert!(
187 self.end().is_aligned_4k()
188 && additional_size.is_multiple_of(ax_memory_addr::PAGE_SIZE_4K),
189 "grow_right: end and additional_size must be page-aligned"
190 );
191 let map_start = self.end();
192 let new_end = self
193 .va_range
194 .end
195 .checked_add(additional_size)
196 .ok_or(MappingError::InvalidParam)?;
197 if !self
198 .backend
199 .map(map_start, additional_size, self.flags, page_table)
200 {
201 return Err(MappingError::BadState);
202 }
203 self.va_range.end = new_end;
204 Ok(())
205 }
206
207 pub(crate) fn split(&mut self, pos: B::Addr) -> Option<Self> {
215 if self.start() < pos && pos < self.end() {
216 let align_diff = pos.sub_addr(self.start());
217
218 let right = self
219 .backend
220 .split(align_diff)
221 .expect("backend should be splittable");
222
223 let new_area = Self::new(
224 pos,
225 self.end().wrapping_sub_addr(pos),
228 self.flags,
229 right,
230 );
231 self.va_range.end = pos;
232 Some(new_area)
233 } else {
234 None
235 }
236 }
237}
238
239impl<B: MappingBackend> fmt::Debug for MemoryArea<B>
240where
241 B::Addr: fmt::Debug,
242 B::Flags: fmt::Debug + Copy,
243{
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 f.debug_struct("MemoryArea")
246 .field("va_range", &self.va_range)
247 .field("flags", &self.flags)
248 .finish()
249 }
250}