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 reported_flags: B::Flags,
16 backend: B,
17}
18
19impl<B: MappingBackend> MemoryArea<B> {
20 pub fn new(start: B::Addr, size: usize, flags: B::Flags, backend: B) -> Self {
26 Self::new_with_reported_flags(start, size, flags, flags, backend)
27 }
28
29 pub fn new_with_reported_flags(
38 start: B::Addr,
39 size: usize,
40 flags: B::Flags,
41 reported_flags: B::Flags,
42 backend: B,
43 ) -> Self {
44 Self {
45 va_range: AddrRange::from_start_size(start, size),
46 flags,
47 reported_flags,
48 backend,
49 }
50 }
51
52 pub const fn va_range(&self) -> AddrRange<B::Addr> {
54 self.va_range
55 }
56
57 pub const fn flags(&self) -> B::Flags {
59 self.flags
60 }
61
62 pub const fn reported_flags(&self) -> B::Flags {
64 self.reported_flags
65 }
66
67 pub const fn start(&self) -> B::Addr {
69 self.va_range.start
70 }
71
72 pub const fn end(&self) -> B::Addr {
74 self.va_range.end
75 }
76
77 pub fn size(&self) -> usize {
79 self.va_range.size()
80 }
81
82 pub const fn backend(&self) -> &B {
84 &self.backend
85 }
86}
87
88impl<B: MappingBackend> MemoryArea<B> {
89 pub(crate) fn set_flags_with_reported_flags(
91 &mut self,
92 new_flags: B::Flags,
93 new_reported_flags: B::Flags,
94 ) {
95 self.flags = new_flags;
96 self.reported_flags = new_reported_flags;
97 }
98
99 pub(crate) fn map_area(&self, page_table: &mut B::PageTable) -> MappingResult {
101 self.backend
102 .map(self.start(), self.size(), self.flags, page_table)
103 .then_some(())
104 .ok_or(MappingError::BadState)
105 }
106
107 pub(crate) fn unmap_area(&self, page_table: &mut B::PageTable) -> MappingResult {
109 self.backend
110 .unmap(self.start(), self.size(), page_table)
111 .then_some(())
112 .ok_or(MappingError::BadState)
113 }
114
115 pub(crate) fn protect_area(
117 &mut self,
118 new_flags: B::Flags,
119 page_table: &mut B::PageTable,
120 ) -> MappingResult {
121 self.backend
122 .protect(self.start(), self.size(), new_flags, page_table);
123 Ok(())
124 }
125
126 pub(crate) fn shrink_left(
135 &mut self,
136 new_size: usize,
137 page_table: &mut B::PageTable,
138 ) -> MappingResult {
139 assert!(new_size > 0 && new_size < self.size());
140
141 let old_size = self.size();
142 let unmap_size = old_size - new_size;
143
144 if !self.backend.unmap(self.start(), unmap_size, page_table) {
145 return Err(MappingError::BadState);
146 }
147 self.va_range.start = self.va_range.start.wrapping_add(unmap_size);
151 self.backend.shrink_left(unmap_size);
152 Ok(())
153 }
154
155 pub(crate) fn shrink_left_metadata(&mut self, new_size: usize) {
158 assert!(new_size > 0 && new_size < self.size());
159
160 let old_size = self.size();
161 let unmap_size = old_size - new_size;
162 self.va_range.start = self.va_range.start.wrapping_add(unmap_size);
163 self.backend.shrink_left(unmap_size);
164 }
165
166 pub(crate) fn shrink_right(
175 &mut self,
176 new_size: usize,
177 page_table: &mut B::PageTable,
178 ) -> MappingResult {
179 assert!(new_size > 0 && new_size < self.size());
180 let old_size = self.size();
181 let unmap_size = old_size - new_size;
182
183 let unmap_start = self.start().wrapping_add(new_size);
186
187 if !self.backend.unmap(unmap_start, unmap_size, page_table) {
188 return Err(MappingError::BadState);
189 }
190
191 self.va_range.end = self.va_range.end.wrapping_sub(unmap_size);
193 self.backend.shrink_right(unmap_size);
194 Ok(())
195 }
196
197 pub(crate) fn shrink_right_metadata(&mut self, new_size: usize) {
200 assert!(new_size > 0 && new_size < self.size());
201 let old_size = self.size();
202 let unmap_size = old_size - new_size;
203
204 self.va_range.end = self.va_range.end.wrapping_sub(unmap_size);
205 self.backend.shrink_right(unmap_size);
206 }
207
208 pub(crate) fn grow_right(
211 &mut self,
212 additional_size: usize,
213 page_table: &mut B::PageTable,
214 ) -> MappingResult {
215 assert!(additional_size > 0);
216 assert!(
217 self.end().is_aligned_4k()
218 && additional_size.is_multiple_of(ax_memory_addr::PAGE_SIZE_4K),
219 "grow_right: end and additional_size must be page-aligned"
220 );
221 let map_start = self.end();
222 let new_end = self
223 .va_range
224 .end
225 .checked_add(additional_size)
226 .ok_or(MappingError::InvalidParam)?;
227 if !self
228 .backend
229 .map(map_start, additional_size, self.flags, page_table)
230 {
231 return Err(MappingError::BadState);
232 }
233 self.va_range.end = new_end;
234 Ok(())
235 }
236
237 pub(crate) fn split(&mut self, pos: B::Addr) -> Option<Self> {
245 if self.start() < pos && pos < self.end() {
246 let align_diff = pos.sub_addr(self.start());
247
248 let right = self
249 .backend
250 .split(align_diff)
251 .expect("backend should be splittable");
252
253 let new_area = Self::new_with_reported_flags(
254 pos,
255 self.end().wrapping_sub_addr(pos),
258 self.flags,
259 self.reported_flags,
260 right,
261 );
262 self.va_range.end = pos;
263 Some(new_area)
264 } else {
265 None
266 }
267 }
268}
269
270impl<B: MappingBackend> fmt::Debug for MemoryArea<B>
271where
272 B::Addr: fmt::Debug,
273 B::Flags: fmt::Debug + Copy,
274{
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 f.debug_struct("MemoryArea")
277 .field("va_range", &self.va_range)
278 .field("flags", &self.flags)
279 .field("reported_flags", &self.reported_flags)
280 .finish()
281 }
282}