Skip to main content

globally_ordered_mock_mmio/
mmio_operand_value.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Converts an [`MmioOperand`] to an integer value.
6
7use mmio::{Mmio, MmioError, MmioOperand};
8
9/// Numeric type guaranteed to be large enough to store any MMIO operand value.
10pub type MmioOperandValue = u64;
11
12/// Returns the numerical value for any [`MmioOperand`].
13pub fn mmio_operand_to_u64<T: MmioOperand>(operand_value: T) -> MmioOperandValue {
14    let mut value_extractor = MmioWriteOperandValueExtractor::new();
15    T::try_store(&mut value_extractor, 0, operand_value)
16        .expect("MmioWriteOperandValueExtractor failed to intercept the write operation");
17    value_extractor.operand_value()
18}
19
20/// [`Mmio`] implementation that captures the integer value
21/// behind an [`MmioOperand`].
22///
23/// The implementation is limited to the methods used by
24/// [`MmioOperand::try_store`]. All other methods panic.
25struct MmioWriteOperandValueExtractor {
26    operand_value: MmioOperandValue,
27}
28
29impl MmioWriteOperandValueExtractor {
30    /// Creates an extractor that has not captured any value yet.
31    fn new() -> Self {
32        Self { operand_value: 0 }
33    }
34
35    /// Returns the value captured by the most recent store operation.
36    ///
37    /// Returns zero if no store operation was performed.
38    fn operand_value(&self) -> MmioOperandValue {
39        self.operand_value
40    }
41}
42
43impl Mmio for MmioWriteOperandValueExtractor {
44    fn len(&self) -> usize {
45        core::mem::size_of::<MmioOperandValue>()
46    }
47
48    fn align_offset(&self, _align: usize) -> usize {
49        0
50    }
51
52    fn try_load8(&self, _offset: usize) -> Result<u8, MmioError> {
53        unimplemented!("MmioOperand::try_store never performs load operations")
54    }
55
56    fn try_load16(&self, _offset: usize) -> Result<u16, MmioError> {
57        unimplemented!("MmioOperand::try_store never performs load operations")
58    }
59
60    fn try_load32(&self, _offset: usize) -> Result<u32, MmioError> {
61        unimplemented!("MmioOperand::try_store never performs load operations")
62    }
63
64    fn try_load64(&self, _offset: usize) -> Result<u64, MmioError> {
65        unimplemented!("MmioOperand::try_store never performs load operations")
66    }
67
68    fn try_store8(&mut self, _offset: usize, value: u8) -> Result<(), MmioError> {
69        self.operand_value = u64::from(value);
70        Ok(())
71    }
72
73    fn try_store16(&mut self, _offset: usize, value: u16) -> Result<(), MmioError> {
74        self.operand_value = u64::from(value);
75        Ok(())
76    }
77
78    fn try_store32(&mut self, _offset: usize, value: u32) -> Result<(), MmioError> {
79        self.operand_value = u64::from(value);
80        Ok(())
81    }
82
83    fn try_store64(&mut self, _offset: usize, value: u64) -> Result<(), MmioError> {
84        self.operand_value = value;
85        Ok(())
86    }
87
88    fn write_barrier(&self) {
89        unimplemented!("MmioOperand::try_store never issues write barriers")
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[fuchsia::test]
98    fn test_mmio_operand_to_u64_u8() {
99        assert_eq!(mmio_operand_to_u64(0x5au8), 0x5a);
100    }
101
102    #[fuchsia::test]
103    fn test_mmio_operand_to_u64_u16() {
104        assert_eq!(mmio_operand_to_u64(0x1234u16), 0x1234);
105    }
106
107    #[fuchsia::test]
108    fn test_mmio_operand_to_u64_u32() {
109        assert_eq!(mmio_operand_to_u64(0x1234_5678u32), 0x1234_5678);
110    }
111
112    #[fuchsia::test]
113    fn test_mmio_operand_to_u64_u64() {
114        assert_eq!(mmio_operand_to_u64(0x1234_5678_9abc_def0u64), 0x1234_5678_9abc_def0);
115    }
116
117    #[fuchsia::test]
118    fn test_extractor_captures_stores_of_every_size() {
119        let mut extractor = MmioWriteOperandValueExtractor::new();
120        assert_eq!(extractor.operand_value(), 0);
121
122        extractor.try_store8(0x10, 0x42).unwrap();
123        assert_eq!(extractor.operand_value(), 0x42);
124
125        extractor.try_store16(0x20, 0x1234).unwrap();
126        assert_eq!(extractor.operand_value(), 0x1234);
127
128        extractor.try_store32(0x30, 0x1234_5678).unwrap();
129        assert_eq!(extractor.operand_value(), 0x1234_5678);
130
131        extractor.try_store64(0x40, 0x0123_4567_89ab_cdef).unwrap();
132        assert_eq!(extractor.operand_value(), 0x0123_4567_89ab_cdef);
133    }
134
135    #[fuchsia::test]
136    fn test_extractor_covers_the_largest_operand() {
137        // `MmioOperand::try_store()` rejects offsets past the reported length.
138        // The extractor must accept the offset used by `mmio_operand_to_u64()`
139        // for the largest supported operand.
140        let extractor = MmioWriteOperandValueExtractor::new();
141        assert_eq!(extractor.len(), core::mem::size_of::<u64>());
142        assert_eq!(extractor.align_offset(4), 0);
143    }
144}