procfs_core/process/
pagemap.rsuse bitflags::bitflags;
use std::{fmt, mem::size_of};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
const fn genmask(high: usize, low: usize) -> u64 {
let mask_bits = size_of::<u64>() * 8;
(!0 - (1 << low) + 1) & (!0 >> (mask_bits - 1 - high))
}
const MAX_SWAPFILES_SHIFT: usize = 5;
bitflags! {
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct SwapPageFlags: u64 {
#[doc(hidden)]
const SWAP_TYPE = genmask(MAX_SWAPFILES_SHIFT - 1, 0);
#[doc(hidden)]
const SWAP_OFFSET = genmask(54, MAX_SWAPFILES_SHIFT);
const SOFT_DIRTY = 1 << 55;
const MMAP_EXCLUSIVE = 1 << 56;
const FILE = 1 << 61;
#[doc(hidden)]
const SWAP = 1 << 62;
const PRESENT = 1 << 63;
}
}
impl SwapPageFlags {
pub fn get_swap_type(&self) -> u64 {
(*self & Self::SWAP_TYPE).bits()
}
pub fn get_swap_offset(&self) -> u64 {
(*self & Self::SWAP_OFFSET).bits() >> MAX_SWAPFILES_SHIFT
}
}
bitflags! {
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct MemoryPageFlags: u64 {
#[doc(hidden)]
const PFN = genmask(54, 0);
const SOFT_DIRTY = 1 << 55;
const MMAP_EXCLUSIVE = 1 << 56;
const FILE = 1 << 61;
#[doc(hidden)]
const SWAP = 1 << 62;
const PRESENT = 1 << 63;
}
}
impl MemoryPageFlags {
pub fn get_page_frame_number(&self) -> Pfn {
Pfn((*self & Self::PFN).bits())
}
}
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Pfn(pub u64);
impl fmt::UpperHex for Pfn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let val = self.0;
fmt::UpperHex::fmt(&val, f)
}
}
impl fmt::LowerHex for Pfn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let val = self.0;
fmt::LowerHex::fmt(&val, f)
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum PageInfo {
MemoryPage(MemoryPageFlags),
SwapPage(SwapPageFlags),
}
impl PageInfo {
pub fn parse_info(info: u64) -> Self {
let flags = MemoryPageFlags::from_bits_retain(info);
if flags.contains(MemoryPageFlags::SWAP) {
Self::SwapPage(SwapPageFlags::from_bits_retain(info))
} else {
Self::MemoryPage(flags)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_genmask() {
let mask = genmask(3, 1);
assert_eq!(mask, 0b1110);
let mask = genmask(3, 0);
assert_eq!(mask, 0b1111);
let mask = genmask(63, 62);
assert_eq!(mask, 0b11 << 62);
}
#[test]
fn test_page_info() {
let pagemap_entry: u64 = 0b1000000110000000000000000000000000000000000000000000000000000011;
let info = PageInfo::parse_info(pagemap_entry);
if let PageInfo::MemoryPage(memory_flags) = info {
assert!(memory_flags
.contains(MemoryPageFlags::PRESENT | MemoryPageFlags::MMAP_EXCLUSIVE | MemoryPageFlags::SOFT_DIRTY));
assert_eq!(memory_flags.get_page_frame_number(), Pfn(0b11));
} else {
panic!("Wrong SWAP decoding");
}
let pagemap_entry: u64 = 0b1100000110000000000000000000000000000000000000000000000001100010;
let info = PageInfo::parse_info(pagemap_entry);
if let PageInfo::SwapPage(swap_flags) = info {
assert!(
swap_flags.contains(SwapPageFlags::PRESENT | SwapPageFlags::MMAP_EXCLUSIVE | SwapPageFlags::SOFT_DIRTY)
);
assert_eq!(swap_flags.get_swap_type(), 0b10);
assert_eq!(swap_flags.get_swap_offset(), 0b11);
} else {
panic!("Wrong SWAP decoding");
}
}
}