swage_dev_mem/
dev_mem.rs

1use log::info;
2use std::{
3    fs::OpenOptions,
4    io::{Read, Seek, SeekFrom, Write},
5};
6
7use rand::Rng;
8use std::thread;
9use std::time::Duration;
10use swage_core::hammerer::Hammering;
11use swage_core::memory::{FlipDirection, PhysAddr};
12
13/// A bit position within a byte (0-7).
14#[derive(Clone, Copy)]
15pub struct Bit(usize);
16
17/// Hammerer that uses /dev/mem to directly flip bits.
18///
19/// Simulates bit flips by writing to physical memory through /dev/mem.
20pub struct DevMem {
21    /// Physical address to target
22    phys_addr: PhysAddr,
23    /// Bit position to flip
24    bit: Bit,
25    /// Direction of the bit flip
26    direction: FlipDirection,
27}
28
29impl DevMem {
30    /// Creates a new /dev/mem hammerer.
31    ///
32    /// # Arguments
33    ///
34    /// * `phys_addr` - Physical address to target
35    /// * `bit` - Bit position (0-7) to flip
36    /// * `direction` - Flip direction (0→1, 1→0, or any)
37    pub fn new(phys_addr: PhysAddr, bit: Bit, direction: FlipDirection) -> Self {
38        assert!(bit.0 < 8);
39        Self {
40            phys_addr,
41            bit,
42            direction,
43        }
44    }
45}
46
47impl Hammering for DevMem {
48    type Error = std::io::Error;
49    fn hammer(&self) -> Result<(), Self::Error> {
50        let mut dev_mem = OpenOptions::new().read(true).write(true).open("/dev/mem")?;
51        let mut value = [0u8; 1];
52        dev_mem.seek(SeekFrom::Start(self.phys_addr.as_usize() as u64))?;
53        // sleep for a random duration to simulate real hammering conditions
54        thread::sleep(Duration::from_millis(rand::rng().random_range(1000..7000)));
55        dev_mem.read_exact(&mut value)?;
56        let new_value = match self.direction {
57            FlipDirection::ZeroToOne => [value[0] | (1 << self.bit.0)],
58            FlipDirection::OneToZero => [value[0] & !(1 << self.bit.0)],
59            FlipDirection::Any => [value[0] ^ (1 << self.bit.0)],
60            FlipDirection::None | FlipDirection::Multiple(_) => {
61                unimplemented!("FlipDirection::None and ::Multiple not implemented")
62            }
63        };
64        if new_value != value {
65            info!(
66                "Flipping address {:p} from {} to {}",
67                self.phys_addr, value[0], new_value[0],
68            );
69            dev_mem.seek(SeekFrom::Current(-1))?;
70            dev_mem.write_all(&new_value)?;
71            dev_mem.flush()?;
72        }
73        Ok(())
74    }
75}
76
77impl From<usize> for Bit {
78    fn from(value: usize) -> Self {
79        Bit(value)
80    }
81}