Skip to content

Commit 091b45d

Browse files
committed
feat(mapper): add MappedPageTable::display
1 parent 30f50f6 commit 091b45d

6 files changed

Lines changed: 804 additions & 3 deletions

File tree

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
//! Display adapters for [`MappedPageTable`].
2+
3+
use core::fmt::{self, Write};
4+
5+
use super::range_iter::{MappedPageRangeInclusive, MappedPageRangeInclusiveItem};
6+
use super::{MappedPageTable, PageTableFrameMapping};
7+
use crate::structures::paging::frame::PhysFrameRangeInclusive;
8+
use crate::structures::paging::page::PageRangeInclusive;
9+
use crate::structures::paging::{PageSize, PageTableFlags};
10+
11+
impl<P: PageTableFrameMapping> MappedPageTable<'_, P> {
12+
/// Display the page table mappings as a human-readable table.
13+
///
14+
/// This method returns an object that implements [`fmt::Display`].
15+
/// For details, see [`MappedPageTableDisplay`].
16+
///
17+
/// # Examples
18+
///
19+
/// ```
20+
/// use x86_64::structures::paging::MappedPageTable;
21+
///
22+
/// # let level_4_table = &mut x86_64::structures::paging::page_table::PageTable::new();
23+
/// # let phys_offset = x86_64::VirtAddr::zero();
24+
/// let page_table = unsafe { MappedPageTable::from_phys_offset(level_4_table, phys_offset) };
25+
///
26+
/// println!("{}", page_table.display());
27+
/// ```
28+
///
29+
/// [`MappedPageTableDisplay`]: Display
30+
pub fn display(&self) -> Display<'_, P> {
31+
Display { page_table: self }
32+
}
33+
}
34+
35+
/// [`Display`] adapter for [`MappedPageTable`].
36+
///
37+
/// This struct formats as a human-readable version of the page table mappings when used with [`format_args!`] and `{}`.
38+
/// It is created using [`MappedPageTable::display`].
39+
///
40+
/// This struct also supports formatting with the alternate (`#`) flag for aligned columns with table headers.
41+
///
42+
/// # Examples
43+
///
44+
/// ```
45+
/// use x86_64::structures::paging::MappedPageTable;
46+
///
47+
/// # let level_4_table = &mut x86_64::structures::paging::page_table::PageTable::new();
48+
/// # let phys_offset = x86_64::VirtAddr::zero();
49+
/// let page_table = unsafe { MappedPageTable::from_phys_offset(level_4_table, phys_offset) };
50+
///
51+
/// println!("{}", page_table.display());
52+
/// ```
53+
///
54+
/// This is how a formatted table looks like:
55+
///
56+
/// ```text
57+
/// 100000-101000 100000-101000 WRITABLE | ACCESSED | DIRTY
58+
/// 101000-103000 101000-103000 WRITABLE | ACCESSED
59+
/// 103000-105000 103000-105000 WRITABLE
60+
/// 105000-106000 105000-106000 WRITABLE | ACCESSED
61+
/// 106000-107000 106000-107000 WRITABLE
62+
/// 107000-10d000 107000-10d000 WRITABLE | ACCESSED
63+
/// 10d000-111000 10d000-111000 WRITABLE
64+
/// 111000-112000 111000-112000 WRITABLE | ACCESSED
65+
/// 112000-114000 112000-114000 WRITABLE
66+
/// 114000-118000 114000-118000 WRITABLE | ACCESSED
67+
/// 118000-119000 118000-119000 WRITABLE
68+
/// 119000-11a000 119000-11a000 WRITABLE | ACCESSED
69+
/// 11a000-11b000 11a000-11b000 WRITABLE
70+
/// 11b000-11c000 11b000-11c000 WRITABLE | ACCESSED | DIRTY
71+
/// 11c000-120000 11c000-120000 WRITABLE | ACCESSED
72+
/// 120000-121000 120000-121000 WRITABLE
73+
/// 121000-122000 121000-122000 WRITABLE | ACCESSED | DIRTY
74+
/// 122000-123000 122000-123000 WRITABLE
75+
/// 123000-124000 123000-124000 WRITABLE | ACCESSED | DIRTY
76+
/// 124000-125000 124000-125000 WRITABLE
77+
/// ffffff8000000000-ffffff8000001000 11f000-120000 WRITABLE | ACCESSED
78+
/// ffffff8000001000-ffffff8000002000 120000-121000 WRITABLE
79+
/// ffffffffc0000000-ffffffffc0001000 11e000-11f000 WRITABLE | ACCESSED
80+
/// ffffffffffe00000-ffffffffffe01000 11d000-11e000 WRITABLE | ACCESSED
81+
/// fffffffffffff000- 11c000-11d000 WRITABLE
82+
/// ```
83+
///
84+
/// This is how a table formatted with the alternate (`#`) flag looks like:
85+
///
86+
/// ```text
87+
/// size len virt phys flags
88+
/// 4KiB 1 100000- 101000 identity mapped WRITABLE | ACCESSED | DIRTY
89+
/// 4KiB 2 101000- 103000 identity mapped WRITABLE | ACCESSED
90+
/// 4KiB 2 103000- 105000 identity mapped WRITABLE
91+
/// 4KiB 1 105000- 106000 identity mapped WRITABLE | ACCESSED
92+
/// 4KiB 1 106000- 107000 identity mapped WRITABLE
93+
/// 4KiB 7 107000- 10e000 identity mapped WRITABLE | ACCESSED
94+
/// 4KiB 3 10e000- 111000 identity mapped WRITABLE
95+
/// 4KiB 1 111000- 112000 identity mapped WRITABLE | ACCESSED
96+
/// 4KiB 2 112000- 114000 identity mapped WRITABLE
97+
/// 4KiB 4 114000- 118000 identity mapped WRITABLE | ACCESSED
98+
/// 4KiB 1 118000- 119000 identity mapped WRITABLE
99+
/// 4KiB 1 119000- 11a000 identity mapped WRITABLE | ACCESSED
100+
/// 4KiB 1 11a000- 11b000 identity mapped WRITABLE
101+
/// 4KiB 1 11b000- 11c000 identity mapped WRITABLE | ACCESSED | DIRTY
102+
/// 4KiB 5 11c000- 121000 identity mapped WRITABLE | ACCESSED
103+
/// 4KiB 1 121000- 122000 identity mapped WRITABLE | ACCESSED | DIRTY
104+
/// 4KiB 1 122000- 123000 identity mapped WRITABLE
105+
/// 4KiB 1 123000- 124000 identity mapped WRITABLE | ACCESSED | DIRTY
106+
/// 4KiB 1 124000- 125000 identity mapped WRITABLE
107+
/// 4KiB 1 ffffff8000000000-ffffff8000001000 11f000- 120000 WRITABLE | ACCESSED
108+
/// 4KiB 1 ffffff8000001000-ffffff8000002000 120000- 121000 WRITABLE
109+
/// 4KiB 1 ffffffffc0000000-ffffffffc0001000 11e000- 11f000 WRITABLE | ACCESSED
110+
/// 4KiB 1 ffffffffffe00000-ffffffffffe01000 11d000- 11e000 WRITABLE | ACCESSED
111+
/// 4KiB 1 fffffffffffff000- 11c000- 11d000 WRITABLE
112+
/// ```
113+
///
114+
/// [`Display`]: fmt::Display
115+
pub struct Display<'a, P: PageTableFrameMapping> {
116+
page_table: &'a MappedPageTable<'a, P>,
117+
}
118+
119+
impl<P: PageTableFrameMapping + fmt::Debug> fmt::Debug for Display<'_, P> {
120+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121+
fmt::Debug::fmt(&self.page_table, f)
122+
}
123+
}
124+
125+
impl<P: PageTableFrameMapping> fmt::Display for Display<'_, P> {
126+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127+
let mut has_fields = false;
128+
129+
if f.alternate() {
130+
write!(f, "size {:>5} {:>33} {:>33} flags", "len", "virt", "phys")?;
131+
has_fields = true;
132+
}
133+
134+
for mapped_page_range in self.page_table.range_iter() {
135+
if has_fields {
136+
f.write_char('\n')?;
137+
}
138+
fmt::Display::fmt(&mapped_page_range.display(), f)?;
139+
140+
has_fields = true;
141+
}
142+
143+
Ok(())
144+
}
145+
}
146+
147+
/// A helper struct for formatting a [`MappedPageRangeInclusiveItem`] as a table row.
148+
struct MappedPageRangeInclusiveItemDisplay<'a> {
149+
item: &'a MappedPageRangeInclusiveItem,
150+
}
151+
152+
impl MappedPageRangeInclusiveItem {
153+
fn display(&self) -> MappedPageRangeInclusiveItemDisplay<'_> {
154+
MappedPageRangeInclusiveItemDisplay { item: self }
155+
}
156+
}
157+
158+
impl fmt::Display for MappedPageRangeInclusiveItemDisplay<'_> {
159+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160+
match self.item {
161+
MappedPageRangeInclusiveItem::Size4KiB(range) => fmt::Display::fmt(&range.display(), f),
162+
MappedPageRangeInclusiveItem::Size2MiB(range) => fmt::Display::fmt(&range.display(), f),
163+
MappedPageRangeInclusiveItem::Size1GiB(range) => fmt::Display::fmt(&range.display(), f),
164+
}
165+
}
166+
}
167+
168+
/// A helper struct for formatting a [`MappedPageRangeInclusive`] as a table row.
169+
struct MappedPageRangeInclusiveDisplay<'a, S: PageSize> {
170+
range: &'a MappedPageRangeInclusive<S>,
171+
}
172+
173+
impl<S: PageSize> MappedPageRangeInclusive<S> {
174+
fn display(&self) -> MappedPageRangeInclusiveDisplay<'_, S> {
175+
MappedPageRangeInclusiveDisplay { range: self }
176+
}
177+
}
178+
179+
impl<S: PageSize> fmt::Display for MappedPageRangeInclusiveDisplay<'_, S> {
180+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181+
if f.alternate() {
182+
let size = S::DEBUG_STR;
183+
write!(f, "{size} ")?;
184+
185+
let len = self.range.len();
186+
write!(f, "{len:5} ")?;
187+
}
188+
189+
let page_range = self.range.page_range();
190+
// Forward the formatter's options such as the alternate (`#`) flag.
191+
fmt::Pointer::fmt(&page_range.display(), f)?;
192+
f.write_char(' ')?;
193+
194+
if f.alternate() && self.range.is_identity_mapped() {
195+
write!(f, "{:>33}", "identity mapped")?;
196+
} else {
197+
let frame_range = self.range.frame_range();
198+
// Forward the formatter's options such as the alternate (`#`) flag.
199+
fmt::Pointer::fmt(&frame_range.display(), f)?;
200+
}
201+
f.write_char(' ')?;
202+
203+
// Every entry is present, don't print it explicitly.
204+
let flags = self.range.flags() - PageTableFlags::PRESENT;
205+
// Format the flags as `A | B` instead of `Flags(A | B)`.
206+
bitflags::parser::to_writer(&flags, &mut *f)?;
207+
208+
Ok(())
209+
}
210+
}
211+
212+
/// A helper type for formatting an address range as [`fmt::Pointer`].
213+
struct AddressRangeDisplay<T> {
214+
start: T,
215+
end: Option<T>,
216+
}
217+
218+
impl<S: PageSize> PageRangeInclusive<S> {
219+
fn display(&self) -> AddressRangeDisplay<u64> {
220+
let start = self.start.start_address().as_u64();
221+
let end = self.end.start_address().as_u64().checked_add(S::SIZE);
222+
AddressRangeDisplay { start, end }
223+
}
224+
}
225+
226+
impl<S: PageSize> PhysFrameRangeInclusive<S> {
227+
fn display(&self) -> AddressRangeDisplay<u64> {
228+
let start = self.start.start_address().as_u64();
229+
let end = self.end.start_address().as_u64().checked_add(S::SIZE);
230+
AddressRangeDisplay { start, end }
231+
}
232+
}
233+
234+
impl<T: fmt::LowerHex> fmt::Pointer for AddressRangeDisplay<T> {
235+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236+
let Self { start, end } = self;
237+
match (end, f.alternate()) {
238+
(Some(end), false) => write!(f, "{start:x}-{end:x}"),
239+
(Some(end), true) => write!(f, "{start:16x}-{end:16x}"),
240+
(None, false) => write!(f, "{start:x}-{:16}", ""),
241+
(None, true) => write!(f, "{start:16x}-{:16}", ""),
242+
}
243+
}
244+
}

0 commit comments

Comments
 (0)