fake_mmio/inject/
after_store.rs1use std::ops::Range;
6
7use crate::inject::{
8 GenericVmoMemoryHandler, MaybeVmoMemoryHandler, VmoMemoryHandler, VmoOpHelper,
9};
10use crate::operand::MmioOperand;
11
12pub struct AfterStore<H, F> {
14 inner: H,
15 callback: F,
16}
17
18impl<H, F> AfterStore<H, F> {
19 pub fn new(inner: H, callback: F) -> Self {
21 Self { inner, callback }
22 }
23}
24
25impl<H: VmoMemoryHandler, F: Fn(Range<usize>)> GenericVmoMemoryHandler for AfterStore<H, F> {
26 fn load<T: MmioOperand>(&self, op: VmoOpHelper<'_, T>) -> T {
27 T::load(&self.inner, op)
28 }
29
30 fn store<T: MmioOperand>(&self, op: VmoOpHelper<'_, T>, value: T) {
31 let range = op.range();
32 T::store(&self.inner, op, value);
33 (self.callback)(range)
34 }
35}
36
37impl<H: MaybeVmoMemoryHandler, F> MaybeVmoMemoryHandler for AfterStore<H, F> {
38 fn get_handler(&self, range: Range<usize>) -> Option<&(impl VmoMemoryHandler + ?Sized)> {
39 self.inner.get_handler(range)
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use crate::CachedVmoMemory;
47 use crate::inject::passthrough::Passthrough;
48 use crate::inject::{DispatchNode, DispatchNodeHandler, VmoMemory};
49 use crate::operand::MmioOperand;
50 use crate::operand::tests::OperandCallable;
51 use mmio::MmioExt as _;
52 use mmio::region::MmioRegion;
53 use std::sync::{Arc, Mutex};
54
55 #[test]
56 fn test_after_store() {
57 let stores = Arc::new(Mutex::new(Vec::<Range<usize>>::new()));
58 let stores_clone = stores.clone();
59 let handler: DispatchNodeHandler =
60 DispatchNode::from(AfterStore::new(Passthrough, move |range| {
61 stores_clone.lock().unwrap().push(range);
62 }))
63 .into_handler();
64
65 let mut mmio = CachedVmoMemory::new_mapped(4096)
66 .expect("Failed to map VMO.")
67 .map(|vmo| VmoMemory::new(handler, vmo));
68
69 let _ = mmio.load::<u32>(0);
71 assert!(stores.lock().unwrap().is_empty());
72
73 struct StoreTester<'a>(&'a mut MmioRegion<VmoMemory<DispatchNodeHandler>>);
74
75 impl OperandCallable for StoreTester<'_> {
76 fn call<T: MmioOperand>(&mut self) {
77 let val = T::try_from(0x12).unwrap();
78 self.0.store::<T>(0, val);
79 assert_eq!(self.0.load::<T>(0), val);
80 }
81 }
82
83 StoreTester(&mut mmio).call_all();
84
85 let recorded = stores.lock().unwrap().clone();
86 assert_eq!(recorded, vec![0..1, 0..2, 0..4, 0..8]);
87 }
88}