procfs_core/process/
pagemap.rs1use bitflags::bitflags;
2use std::{fmt, mem::size_of};
3
4#[cfg(feature = "serde1")]
5use serde::{Deserialize, Serialize};
6
7const fn genmask(high: usize, low: usize) -> u64 {
8 let mask_bits = size_of::<u64>() * 8;
9 (!0 - (1 << low) + 1) & (!0 >> (mask_bits - 1 - high))
10}
11
12const MAX_SWAPFILES_SHIFT: usize = 5;
14
15bitflags! {
17 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
19 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
20 pub struct SwapPageFlags: u64 {
21 #[doc(hidden)]
23 const SWAP_TYPE = genmask(MAX_SWAPFILES_SHIFT - 1, 0);
24 #[doc(hidden)]
26 const SWAP_OFFSET = genmask(54, MAX_SWAPFILES_SHIFT);
27 const SOFT_DIRTY = 1 << 55;
29 const MMAP_EXCLUSIVE = 1 << 56;
31 const FILE = 1 << 61;
33 #[doc(hidden)]
35 const SWAP = 1 << 62;
36 const PRESENT = 1 << 63;
38 }
39}
40
41impl SwapPageFlags {
42 pub fn get_swap_type(&self) -> u64 {
44 (*self & Self::SWAP_TYPE).bits()
45 }
46
47 pub fn get_swap_offset(&self) -> u64 {
49 (*self & Self::SWAP_OFFSET).bits() >> MAX_SWAPFILES_SHIFT
50 }
51}
52
53bitflags! {
54 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
56 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
57 pub struct MemoryPageFlags: u64 {
58 #[doc(hidden)]
60 const PFN = genmask(54, 0);
61 const SOFT_DIRTY = 1 << 55;
63 const MMAP_EXCLUSIVE = 1 << 56;
65 const FILE = 1 << 61;
67 #[doc(hidden)]
69 const SWAP = 1 << 62;
70 const PRESENT = 1 << 63;
72 }
73}
74
75impl MemoryPageFlags {
76 pub fn get_page_frame_number(&self) -> Pfn {
78 Pfn((*self & Self::PFN).bits())
79 }
80}
81
82#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
84#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
85pub struct Pfn(pub u64);
86
87impl fmt::UpperHex for Pfn {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 let val = self.0;
90
91 fmt::UpperHex::fmt(&val, f)
92 }
93}
94
95impl fmt::LowerHex for Pfn {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 let val = self.0;
98
99 fmt::LowerHex::fmt(&val, f)
100 }
101}
102
103#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
105pub enum PageInfo {
106 MemoryPage(MemoryPageFlags),
108 SwapPage(SwapPageFlags),
110}
111
112impl PageInfo {
113 pub fn parse_info(info: u64) -> Self {
114 let flags = MemoryPageFlags::from_bits_retain(info);
115
116 if flags.contains(MemoryPageFlags::SWAP) {
117 Self::SwapPage(SwapPageFlags::from_bits_retain(info))
118 } else {
119 Self::MemoryPage(flags)
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_genmask() {
130 let mask = genmask(3, 1);
131 assert_eq!(mask, 0b1110);
132
133 let mask = genmask(3, 0);
134 assert_eq!(mask, 0b1111);
135
136 let mask = genmask(63, 62);
137 assert_eq!(mask, 0b11 << 62);
138 }
139
140 #[test]
141 fn test_page_info() {
142 let pagemap_entry: u64 = 0b1000000110000000000000000000000000000000000000000000000000000011;
143 let info = PageInfo::parse_info(pagemap_entry);
144 if let PageInfo::MemoryPage(memory_flags) = info {
145 assert!(memory_flags
146 .contains(MemoryPageFlags::PRESENT | MemoryPageFlags::MMAP_EXCLUSIVE | MemoryPageFlags::SOFT_DIRTY));
147 assert_eq!(memory_flags.get_page_frame_number(), Pfn(0b11));
148 } else {
149 panic!("Wrong SWAP decoding");
150 }
151
152 let pagemap_entry: u64 = 0b1100000110000000000000000000000000000000000000000000000001100010;
153 let info = PageInfo::parse_info(pagemap_entry);
154 if let PageInfo::SwapPage(swap_flags) = info {
155 assert!(
156 swap_flags.contains(SwapPageFlags::PRESENT | SwapPageFlags::MMAP_EXCLUSIVE | SwapPageFlags::SOFT_DIRTY)
157 );
158 assert_eq!(swap_flags.get_swap_type(), 0b10);
159 assert_eq!(swap_flags.get_swap_offset(), 0b11);
160 } else {
161 panic!("Wrong SWAP decoding");
162 }
163 }
164}