Skip to content

Commit 8d1d2e8

Browse files
committed
Turn PFN into a concrete type
1 parent 9b6f434 commit 8d1d2e8

File tree

7 files changed

+78
-61
lines changed

7 files changed

+78
-61
lines changed

examples/kpagecount.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@ fn main() {
3333

3434
// Physical memory is divided into pages of `page_size` bytes (usually 4kiB)
3535
// Each page is referenced by its Page Fram Number (PFN)
36-
let start_pfn = map.address.0 / page_size;
37-
let end_pfn = map.address.1 / page_size;
36+
let (start_pfn, end_pfn) = map.get_range();
3837

3938
let page_references = kpagecount
40-
.get_count_in_range(start_pfn..end_pfn)
39+
.get_count_in_range(start_pfn, end_pfn)
4140
.expect("Can't read from /proc/kpagecount");
4241

4342
// find the page with most references

examples/pfn.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,17 @@ fn main() {
4444
match page_info {
4545
procfs::process::PageInfo::MemoryPage(memory_page) => {
4646
let pfn = memory_page.get_page_frame_number();
47-
let pa = pfn * page_size;
47+
let pa = pfn.0 * page_size;
4848
println!("virt_mem: 0x{:x}, pfn: 0x{:x}, phys_addr: 0x{:x}", va, pfn, pa);
4949
}
50-
procfs::process::PageInfo::SwapPage(_) => (), // page is in swap
50+
procfs::process::PageInfo::SwapPage(swap_page_flags) => {
51+
let swap_type = swap_page_flags.get_swap_type();
52+
let swap_offset = swap_page_flags.get_swap_offset();
53+
println!(
54+
"virt_mem: 0x{:x}, swap: {:}, offset: 0x{:x}",
55+
va, swap_type, swap_offset
56+
);
57+
}
5158
}
5259
}
5360
}

examples/process_kpageflags.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn main() {
7777
match page_info {
7878
procfs::process::PageInfo::MemoryPage(memory_page) => {
7979
let pfn = memory_page.get_page_frame_number();
80-
let phys_addr = pfn * page_size;
80+
let phys_addr = pfn.0 * page_size;
8181

8282
let physical_page_info = kpageflags.get_info(pfn).expect("Can't get kpageflags info");
8383

@@ -86,7 +86,15 @@ fn main() {
8686
virt_mem, pfn, phys_addr, physical_page_info
8787
);
8888
}
89-
procfs::process::PageInfo::SwapPage(_) => (), // page is in swap
89+
procfs::process::PageInfo::SwapPage(swap_page_flags) => {
90+
let swap_type = swap_page_flags.get_swap_type();
91+
let swap_offset = swap_page_flags.get_swap_offset();
92+
93+
println!(
94+
"Found page\nvirt_mem: 0x{:x}, swap_type: {:}, swap_offset: 0x{:x}, flags: {:?}",
95+
virt_mem, swap_type, swap_offset, swap_page_flags
96+
);
97+
}
9098
}
9199
}
92100
}

src/iomem.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
33
use std::io::{BufRead, BufReader};
44

55
use super::{FileWrapper, ProcResult};
6-
use crate::split_into_num;
6+
use crate::{process::Pfn, split_into_num};
77

88
/// Reads and parses the `/proc/iomem`, returning an error if there are problems.
99
///
@@ -50,4 +50,15 @@ impl PhysicalMemoryMap {
5050
},
5151
))
5252
}
53+
54+
/// Get the PFN range for the mapping
55+
///
56+
/// First element of the tuple (start) is included.
57+
/// Second element (end) is excluded
58+
pub fn get_range(&self) -> (Pfn, Pfn) {
59+
let start = self.address.0 / crate::page_size();
60+
let end = (self.address.1 + 1) / crate::page_size();
61+
62+
(Pfn(start), Pfn(end))
63+
}
5364
}

src/kpagecount.rs

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::{
22
io::{BufReader, Read, Seek, SeekFrom},
33
mem::size_of,
4-
ops::{Bound, Range, RangeBounds},
54
path::Path,
65
};
76

8-
use crate::FileWrapper;
7+
use crate::{process::Pfn, FileWrapper};
98

109
use super::ProcResult;
1110

@@ -41,40 +40,25 @@ impl KPageCount {
4140
/// Return Err if pfn is not in RAM. See [crate::iomem()] for a list of valid physical RAM addresses
4241
///
4342
/// See [crate::process::Process::pagemap] and [crate::process::MemoryPageFlags::get_page_frame_number]
44-
pub fn get_count_at_pfn(&mut self, pfn: u64) -> ProcResult<u64> {
45-
self.get_count_in_range(pfn..pfn + 1).map(|mut vec| vec.pop().unwrap())
43+
pub fn get_count_at_pfn(&mut self, pfn: Pfn) -> ProcResult<u64> {
44+
self.get_count_in_range(pfn, Pfn(pfn.0 + 1))
45+
.map(|mut vec| vec.pop().unwrap())
4646
}
4747

48-
/// Get the number of references to physical memory at for PFNs within range `page_range`
48+
/// Get the number of references to physical memory at for PFNs within `start` and `end` PFNs, `end` is excluded
4949
///
5050
/// Return Err if any pfn is not in RAM. See [crate::iomem()] for a list of valid physical RAM addresses
5151
///
5252
/// See [crate::process::Process::pagemap] and [crate::process::MemoryPageFlags::get_page_frame_number]
53-
pub fn get_count_in_range(&mut self, page_range: Range<u64>) -> ProcResult<Vec<u64>> {
54-
// `start` is always included
55-
let start = match page_range.start_bound() {
56-
Bound::Included(v) => *v,
57-
Bound::Excluded(v) => *v + 1,
58-
Bound::Unbounded => 0,
59-
};
53+
pub fn get_count_in_range(&mut self, start: Pfn, end: Pfn) -> ProcResult<Vec<u64>> {
54+
let mut result = Vec::with_capacity((end.0 - start.0) as usize);
6055

61-
// `end` is always excluded
62-
let end = match page_range.end_bound() {
63-
Bound::Included(v) => *v + 1,
64-
Bound::Excluded(v) => *v,
65-
Bound::Unbounded => std::u64::MAX,
66-
};
67-
68-
let mut result: Vec<u64> = Vec::new();
69-
70-
let start_position = start * size_of::<u64>() as u64;
56+
let start_position = start.0 * size_of::<u64>() as u64;
7157
self.reader.seek(SeekFrom::Start(start_position))?;
7258

73-
for _pfn in start..end {
59+
for _pfn in start.0..end.0 {
7460
// Each entry is a 64 bits counter
75-
// 64 bits or 8 Bytes
76-
const ENTRY_SIZE: usize = 8;
77-
let mut buf = [0; ENTRY_SIZE];
61+
let mut buf = [0; size_of::<u64>()];
7862

7963
self.reader.read_exact(&mut buf)?;
8064
let page_references: u64 = u64::from_le_bytes(buf);

src/kpageflags.rs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use crate::{FileWrapper, ProcResult};
1+
use crate::{process::Pfn, FileWrapper, ProcResult};
22

33
use bitflags::bitflags;
44
use std::{
55
io::{BufReader, Read, Seek, SeekFrom},
66
mem::size_of,
7-
ops::{Bound, RangeBounds},
87
path::Path,
98
};
109

@@ -116,36 +115,22 @@ impl KPageFlags {
116115
///
117116
/// Return Err if the PFN is not in RAM (see [crate::iomem()]):
118117
/// Io(Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }, None)
119-
pub fn get_info(&mut self, page_index: u64) -> ProcResult<PhysicalPageFlags> {
120-
self.get_range_info(page_index..page_index + 1)
118+
pub fn get_info(&mut self, pfn: Pfn) -> ProcResult<PhysicalPageFlags> {
119+
self.get_range_info(pfn, Pfn(pfn.0 + 1))
121120
.map(|mut vec| vec.pop().unwrap())
122121
}
123122

124-
/// Retrieve information in the page table entry for the PFNs within range `page_range`.
123+
/// Retrieve information in the page table entry for the PFNs within range `start` (included) and `end` (excluded) PFNs.
125124
///
126125
/// Return Err if any PFN is not in RAM (see [crate::iomem()]):
127126
/// Io(Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }, None)
128-
pub fn get_range_info(&mut self, page_range: impl RangeBounds<u64>) -> ProcResult<Vec<PhysicalPageFlags>> {
129-
// `start` is always included
130-
let start = match page_range.start_bound() {
131-
Bound::Included(v) => *v,
132-
Bound::Excluded(v) => *v + 1,
133-
Bound::Unbounded => 0,
134-
};
135-
136-
// `end` is always excluded
137-
let end = match page_range.end_bound() {
138-
Bound::Included(v) => *v + 1,
139-
Bound::Excluded(v) => *v,
140-
Bound::Unbounded => std::u64::MAX / crate::page_size(),
141-
};
142-
143-
let start_position = start * size_of::<u64>() as u64;
127+
pub fn get_range_info(&mut self, start: Pfn, end: Pfn) -> ProcResult<Vec<PhysicalPageFlags>> {
128+
let start_position = start.0 * size_of::<PhysicalPageFlags>() as u64;
144129
self.reader.seek(SeekFrom::Start(start_position))?;
145130

146-
let mut page_infos = Vec::with_capacity((end - start) as usize);
147-
for _ in start..end {
148-
let mut info_bytes = [0; size_of::<u64>()];
131+
let mut page_infos = Vec::with_capacity((end.0 - start.0) as usize);
132+
for _ in start.0..end.0 {
133+
let mut info_bytes = [0; size_of::<PhysicalPageFlags>()];
149134
self.reader.read_exact(&mut info_bytes)?;
150135
page_infos.push(PhysicalPageFlags::parse_info(u64::from_ne_bytes(info_bytes)));
151136
}

src/process/pagemap.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{FileWrapper, ProcResult};
22

33
use bitflags::bitflags;
44
use std::{
5+
fmt,
56
io::{BufReader, Read, Seek, SeekFrom},
67
mem::size_of,
78
ops::{Bound, RangeBounds},
@@ -78,8 +79,30 @@ bitflags! {
7879

7980
impl MemoryPageFlags {
8081
/// Returns the page frame number recorded in this entry.
81-
pub fn get_page_frame_number(&self) -> u64 {
82-
(*self & Self::PFN).bits()
82+
pub fn get_page_frame_number(&self) -> Pfn {
83+
Pfn((*self & Self::PFN).bits())
84+
}
85+
}
86+
87+
/// A Page Frame Number, representing a 4 kiB physical memory page
88+
///
89+
/// See also [crate::iomem()]
90+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
91+
pub struct Pfn(pub u64);
92+
93+
impl fmt::UpperHex for Pfn {
94+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95+
let val = self.0;
96+
97+
fmt::UpperHex::fmt(&val, f)
98+
}
99+
}
100+
101+
impl fmt::LowerHex for Pfn {
102+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103+
let val = self.0;
104+
105+
fmt::LowerHex::fmt(&val, f)
83106
}
84107
}
85108

@@ -177,7 +200,7 @@ mod tests {
177200
if let PageInfo::MemoryPage(memory_flags) = info {
178201
assert!(memory_flags
179202
.contains(MemoryPageFlags::PRESENT | MemoryPageFlags::MMAP_EXCLUSIVE | MemoryPageFlags::SOFT_DIRTY));
180-
assert_eq!(memory_flags.get_page_frame_number(), 0b11);
203+
assert_eq!(memory_flags.get_page_frame_number(), Pfn(0b11));
181204
} else {
182205
panic!("Wrong SWAP decoding");
183206
}

0 commit comments

Comments
 (0)