Skip to content

Commit a8a0dd4

Browse files
committed
feat(mapper): add MappedPageTable::range_iter
1 parent 5385a35 commit a8a0dd4

File tree

2 files changed

+404
-0
lines changed

2 files changed

+404
-0
lines changed
Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
use core::convert::TryFrom;
2+
use core::fmt;
3+
use core::ops::{Add, AddAssign, Sub, SubAssign};
4+
5+
use crate::structures::paging::frame::PhysFrameRangeInclusive;
6+
use crate::structures::paging::mapper::{
7+
PageTableFrameMapping, PageTableWalkError, PageTableWalker,
8+
};
9+
use crate::structures::paging::page::{AddressNotAligned, PageRangeInclusive};
10+
use crate::structures::paging::{
11+
MappedPageTable, Page, PageSize, PageTable, PageTableFlags, PageTableIndex, PhysFrame,
12+
Size1GiB, Size2MiB, Size4KiB,
13+
};
14+
15+
#[derive(Debug)]
16+
pub struct MappedPageRangeInclusive<S: PageSize> {
17+
pub page_range: PageRangeInclusive<S>,
18+
pub frame_range: PhysFrameRangeInclusive<S>,
19+
pub flags: PageTableFlags,
20+
}
21+
22+
impl<S: PageSize> TryFrom<(MappedPage<S>, MappedPage<S>)> for MappedPageRangeInclusive<S> {
23+
type Error = TryFromMappedPageError;
24+
25+
fn try_from((start, end): (MappedPage<S>, MappedPage<S>)) -> Result<Self, Self::Error> {
26+
if start.flags != end.flags {
27+
return Err(TryFromMappedPageError);
28+
}
29+
30+
Ok(Self {
31+
page_range: PageRangeInclusive {
32+
start: start.page,
33+
end: end.page,
34+
},
35+
frame_range: PhysFrameRangeInclusive {
36+
start: start.frame,
37+
end: end.frame,
38+
},
39+
flags: start.flags,
40+
})
41+
}
42+
}
43+
44+
#[derive(Debug)]
45+
pub enum MappedPageRangeInclusiveItem {
46+
Size4KiB(MappedPageRangeInclusive<Size4KiB>),
47+
Size2MiB(MappedPageRangeInclusive<Size2MiB>),
48+
Size1GiB(MappedPageRangeInclusive<Size1GiB>),
49+
}
50+
51+
impl TryFrom<(MappedPageItem, MappedPageItem)> for MappedPageRangeInclusiveItem {
52+
type Error = TryFromMappedPageError;
53+
54+
fn try_from((start, end): (MappedPageItem, MappedPageItem)) -> Result<Self, Self::Error> {
55+
match (start, end) {
56+
(MappedPageItem::Size4KiB(start), MappedPageItem::Size4KiB(end)) => {
57+
let range = MappedPageRangeInclusive::try_from((start, end))?;
58+
Ok(Self::Size4KiB(range))
59+
}
60+
(MappedPageItem::Size2MiB(start), MappedPageItem::Size2MiB(end)) => {
61+
let range = MappedPageRangeInclusive::try_from((start, end))?;
62+
Ok(Self::Size2MiB(range))
63+
}
64+
(MappedPageItem::Size1GiB(start), MappedPageItem::Size1GiB(end)) => {
65+
let range = MappedPageRangeInclusive::try_from((start, end))?;
66+
Ok(Self::Size1GiB(range))
67+
}
68+
(_, _) => Err(TryFromMappedPageError),
69+
}
70+
}
71+
}
72+
73+
#[derive(PartialEq, Eq, Clone, Debug)]
74+
pub struct TryFromMappedPageError;
75+
76+
impl fmt::Display for TryFromMappedPageError {
77+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78+
f.write_str("provided mapped pages were not compatible")
79+
}
80+
}
81+
82+
#[derive(Clone, Debug)]
83+
pub struct MappedPageTableRangeInclusiveIter<'a, P: PageTableFrameMapping> {
84+
inner: MappedPageTableIter<'a, P>,
85+
start: Option<MappedPageItem>,
86+
end: Option<MappedPageItem>,
87+
}
88+
89+
impl<'a, P: PageTableFrameMapping> MappedPageTable<'a, P> {
90+
pub fn range_iter(&'a self) -> MappedPageTableRangeInclusiveIter<'a, &'a P> {
91+
MappedPageTableRangeInclusiveIter {
92+
inner: self.iter(),
93+
start: None,
94+
end: None,
95+
}
96+
}
97+
}
98+
99+
impl<'a, P: PageTableFrameMapping> Iterator for MappedPageTableRangeInclusiveIter<'a, P> {
100+
type Item = MappedPageRangeInclusiveItem;
101+
102+
fn next(&mut self) -> Option<Self::Item> {
103+
if self.start.is_none() {
104+
self.start = self.inner.next();
105+
self.end = self.start;
106+
}
107+
108+
let Some(start) = &mut self.start else {
109+
return None;
110+
};
111+
let end = self.end.as_mut().unwrap();
112+
113+
for mapped_page in self.inner.by_ref() {
114+
if mapped_page == *end + 1 {
115+
*end = mapped_page;
116+
continue;
117+
}
118+
119+
let range = MappedPageRangeInclusiveItem::try_from((*start, *end)).unwrap();
120+
*start = mapped_page;
121+
*end = mapped_page;
122+
return Some(range);
123+
}
124+
125+
let range = MappedPageRangeInclusiveItem::try_from((*start, *end)).unwrap();
126+
self.start = None;
127+
self.end = None;
128+
Some(range)
129+
}
130+
}
131+
132+
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
133+
pub struct MappedPage<S: PageSize> {
134+
pub page: Page<S>,
135+
pub frame: PhysFrame<S>,
136+
pub flags: PageTableFlags,
137+
}
138+
139+
impl<S: PageSize> Add<u64> for MappedPage<S> {
140+
type Output = Self;
141+
142+
fn add(self, rhs: u64) -> Self::Output {
143+
Self {
144+
page: self.page + rhs,
145+
frame: self.frame + rhs,
146+
flags: self.flags,
147+
}
148+
}
149+
}
150+
151+
impl<S: PageSize> Sub<u64> for MappedPage<S> {
152+
type Output = Self;
153+
154+
fn sub(self, rhs: u64) -> Self::Output {
155+
Self {
156+
page: self.page - rhs,
157+
frame: self.frame - rhs,
158+
flags: self.flags,
159+
}
160+
}
161+
}
162+
163+
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
164+
pub enum MappedPageItem {
165+
Size4KiB(MappedPage<Size4KiB>),
166+
Size2MiB(MappedPage<Size2MiB>),
167+
Size1GiB(MappedPage<Size1GiB>),
168+
}
169+
170+
impl Add<u64> for MappedPageItem {
171+
type Output = Self;
172+
173+
fn add(self, rhs: u64) -> Self::Output {
174+
match self {
175+
Self::Size4KiB(mapped_page) => Self::Size4KiB(mapped_page + rhs),
176+
Self::Size2MiB(mapped_page) => Self::Size2MiB(mapped_page + rhs),
177+
Self::Size1GiB(mapped_page) => Self::Size1GiB(mapped_page + rhs),
178+
}
179+
}
180+
}
181+
182+
impl AddAssign<u64> for MappedPageItem {
183+
fn add_assign(&mut self, rhs: u64) {
184+
*self = *self + rhs;
185+
}
186+
}
187+
188+
impl Sub<u64> for MappedPageItem {
189+
type Output = Self;
190+
191+
fn sub(self, rhs: u64) -> Self::Output {
192+
match self {
193+
Self::Size4KiB(mapped_page) => Self::Size4KiB(mapped_page - rhs),
194+
Self::Size2MiB(mapped_page) => Self::Size2MiB(mapped_page - rhs),
195+
Self::Size1GiB(mapped_page) => Self::Size1GiB(mapped_page - rhs),
196+
}
197+
}
198+
}
199+
200+
impl SubAssign<u64> for MappedPageItem {
201+
fn sub_assign(&mut self, rhs: u64) {
202+
*self = *self - rhs;
203+
}
204+
}
205+
206+
#[derive(Clone, Debug)]
207+
pub struct MappedPageTableIter<'a, P: PageTableFrameMapping> {
208+
page_table_walker: PageTableWalker<P>,
209+
level_4_table: &'a PageTable,
210+
p4_index: u16,
211+
p3_index: u16,
212+
p2_index: u16,
213+
p1_index: u16,
214+
}
215+
216+
impl<'a, P: PageTableFrameMapping> MappedPageTable<'a, P> {
217+
pub fn iter(&'a self) -> MappedPageTableIter<'a, &'a P> {
218+
let page_table_walker = unsafe { PageTableWalker::new(self.page_table_frame_mapping()) };
219+
MappedPageTableIter {
220+
page_table_walker,
221+
level_4_table: self.level_4_table(),
222+
p4_index: 0,
223+
p3_index: 0,
224+
p2_index: 0,
225+
p1_index: 0,
226+
}
227+
}
228+
}
229+
230+
impl<'a, P: PageTableFrameMapping> MappedPageTableIter<'a, P> {
231+
fn p4_index(&self) -> Option<PageTableIndex> {
232+
if self.p4_index >= 512 {
233+
return None;
234+
}
235+
236+
Some(PageTableIndex::new(self.p4_index))
237+
}
238+
239+
fn p3_index(&self) -> Option<PageTableIndex> {
240+
if self.p3_index >= 512 {
241+
return None;
242+
}
243+
244+
Some(PageTableIndex::new(self.p3_index))
245+
}
246+
247+
fn p2_index(&self) -> Option<PageTableIndex> {
248+
if self.p2_index >= 512 {
249+
return None;
250+
}
251+
252+
Some(PageTableIndex::new(self.p2_index))
253+
}
254+
255+
fn p1_index(&self) -> Option<PageTableIndex> {
256+
if self.p1_index >= 512 {
257+
return None;
258+
}
259+
260+
Some(PageTableIndex::new(self.p1_index))
261+
}
262+
263+
fn increment_p4_index(&mut self) -> Option<()> {
264+
if self.p4_index >= 511 {
265+
self.p4_index += 1;
266+
return None;
267+
}
268+
269+
self.p4_index += 1;
270+
self.p3_index = 0;
271+
self.p2_index = 0;
272+
self.p1_index = 0;
273+
Some(())
274+
}
275+
276+
fn increment_p3_index(&mut self) -> Option<()> {
277+
if self.p3_index == 511 {
278+
self.increment_p4_index()?;
279+
return None;
280+
}
281+
282+
self.p3_index += 1;
283+
self.p2_index = 0;
284+
self.p1_index = 0;
285+
Some(())
286+
}
287+
288+
fn increment_p2_index(&mut self) -> Option<()> {
289+
if self.p2_index == 511 {
290+
self.increment_p3_index()?;
291+
return None;
292+
}
293+
294+
self.p2_index += 1;
295+
self.p1_index = 0;
296+
Some(())
297+
}
298+
299+
fn increment_p1_index(&mut self) -> Option<()> {
300+
if self.p1_index == 511 {
301+
self.increment_p2_index()?;
302+
return None;
303+
}
304+
305+
self.p1_index += 1;
306+
Some(())
307+
}
308+
309+
fn next_forward(&mut self) -> Option<MappedPageItem> {
310+
let p4 = self.level_4_table;
311+
312+
let p3 = loop {
313+
match self.page_table_walker.next_table(&p4[self.p4_index()?]) {
314+
Ok(page_table) => break page_table,
315+
Err(PageTableWalkError::NotMapped) => self.increment_p4_index()?,
316+
Err(PageTableWalkError::MappedToHugePage) => {
317+
panic!("level 4 entry has huge page bit set")
318+
}
319+
}
320+
};
321+
322+
let p2 = loop {
323+
match self.page_table_walker.next_table(&p3[self.p3_index()?]) {
324+
Ok(page_table) => break page_table,
325+
Err(PageTableWalkError::NotMapped) => self.increment_p3_index()?,
326+
Err(PageTableWalkError::MappedToHugePage) => {
327+
let page =
328+
Page::from_page_table_indices_1gib(self.p4_index()?, self.p3_index()?);
329+
let entry = &p3[self.p3_index()?];
330+
let frame = PhysFrame::containing_address(entry.addr());
331+
let flags = entry.flags();
332+
let mapped_page = MappedPageItem::Size1GiB(MappedPage { page, frame, flags });
333+
334+
self.increment_p3_index();
335+
return Some(mapped_page);
336+
}
337+
}
338+
};
339+
340+
let p1 = loop {
341+
match self.page_table_walker.next_table(&p2[self.p2_index()?]) {
342+
Ok(page_table) => break page_table,
343+
Err(PageTableWalkError::NotMapped) => self.increment_p2_index()?,
344+
Err(PageTableWalkError::MappedToHugePage) => {
345+
let page = Page::from_page_table_indices_2mib(
346+
self.p4_index()?,
347+
self.p3_index()?,
348+
self.p2_index()?,
349+
);
350+
let entry = &p2[self.p2_index()?];
351+
let frame = PhysFrame::containing_address(entry.addr());
352+
let flags = entry.flags();
353+
let mapped_page = MappedPageItem::Size2MiB(MappedPage { page, frame, flags });
354+
355+
self.increment_p2_index();
356+
return Some(mapped_page);
357+
}
358+
}
359+
};
360+
361+
loop {
362+
let p1_entry = &p1[self.p1_index()?];
363+
364+
if p1_entry.is_unused() {
365+
self.increment_p1_index()?;
366+
continue;
367+
}
368+
369+
let frame = match PhysFrame::from_start_address(p1_entry.addr()) {
370+
Ok(frame) => frame,
371+
Err(AddressNotAligned) => {
372+
// Invalid frame address
373+
self.increment_p1_index()?;
374+
continue;
375+
}
376+
};
377+
378+
let page = Page::from_page_table_indices(
379+
self.p4_index()?,
380+
self.p3_index()?,
381+
self.p2_index()?,
382+
self.p1_index()?,
383+
);
384+
let flags = p1_entry.flags();
385+
let mapped_page = MappedPageItem::Size4KiB(MappedPage { page, frame, flags });
386+
387+
self.increment_p1_index();
388+
return Some(mapped_page);
389+
}
390+
}
391+
}
392+
393+
impl<'a, P: PageTableFrameMapping> Iterator for MappedPageTableIter<'a, P> {
394+
type Item = MappedPageItem;
395+
396+
fn next(&mut self) -> Option<Self::Item> {
397+
self.next_forward().or_else(|| self.next_forward())
398+
}
399+
}

0 commit comments

Comments
 (0)