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#[derive(Clone, Copy)]
15pub struct Bit(usize);
16
17pub struct DevMem {
21 phys_addr: PhysAddr,
23 bit: Bit,
25 direction: FlipDirection,
27}
28
29impl DevMem {
30 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 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}