qemu_plugin/memory/
mod.rs

1//! Memory-related functionality for QEMU plugins
2
3#[cfg(not(any(
4    feature = "plugin-api-v0",
5    feature = "plugin-api-v1",
6    feature = "plugin-api-v2",
7    feature = "plugin-api-v3",
8)))]
9use crate::Error;
10#[cfg(not(feature = "plugin-api-v0"))]
11use crate::Result;
12#[cfg(not(any(
13    feature = "plugin-api-v0",
14    feature = "plugin-api-v1",
15    feature = "plugin-api-v2",
16    feature = "plugin-api-v3",
17    feature = "plugin-api-v4"
18)))]
19use crate::sys::qemu_plugin_hwaddr_operation_result;
20#[cfg(not(any(
21    feature = "plugin-api-v0",
22    feature = "plugin-api-v1",
23    feature = "plugin-api-v2",
24    feature = "plugin-api-v3"
25)))]
26use crate::sys::{GByteArray, qemu_plugin_mem_value, qemu_plugin_mem_value_type};
27use crate::sys::{qemu_plugin_hwaddr, qemu_plugin_meminfo_t};
28use std::marker::PhantomData;
29
30#[derive(Debug, Clone)]
31/// Wrapper structure for a `qemu_plugin_meminfo_t`
32///
33/// # Safety
34///
35/// This structure is safe to use during the invocation of the callback which receives it as an
36/// argument. The structure is always opaque, and therefore may not be accessed directly.
37pub struct MemoryInfo<'a> {
38    memory_info: qemu_plugin_meminfo_t,
39    marker: PhantomData<&'a ()>,
40}
41
42impl<'a> From<qemu_plugin_meminfo_t> for MemoryInfo<'a> {
43    fn from(info: qemu_plugin_meminfo_t) -> Self {
44        Self {
45            memory_info: info,
46            marker: PhantomData,
47        }
48    }
49}
50
51impl<'a> MemoryInfo<'a> {
52    /// Returns the size of the access in base-2, e.g. 0 for byte, 1 for 16-bit, 2 for
53    /// 32-bit, etc.
54    pub fn size_shift(&self) -> usize {
55        (unsafe { crate::sys::qemu_plugin_mem_size_shift(self.memory_info) }) as usize
56    }
57
58    /// Returns whether the access was sign extended
59    pub fn sign_extended(&self) -> bool {
60        unsafe { crate::sys::qemu_plugin_mem_is_sign_extended(self.memory_info) }
61    }
62
63    /// Returns whether the access was big-endian
64    pub fn big_endian(&self) -> bool {
65        unsafe { crate::sys::qemu_plugin_mem_is_big_endian(self.memory_info) }
66    }
67
68    /// Returns whether the access was a store
69    pub fn is_store(&self) -> bool {
70        unsafe { crate::sys::qemu_plugin_mem_is_store(self.memory_info) }
71    }
72
73    /// Return a handle to query details about the physical address backing the virtual address
74    /// in system emulation. In user-mode, this method always returns `None`.
75    pub fn hwaddr(&'a self, vaddr: u64) -> Option<HwAddr<'a>> {
76        let hwaddr = unsafe { crate::sys::qemu_plugin_get_hwaddr(self.memory_info, vaddr) };
77        if hwaddr.is_null() {
78            None
79        } else {
80            Some(HwAddr::from(hwaddr))
81        }
82    }
83
84    /// Return last value loaded/stored
85    #[cfg(not(any(
86        feature = "plugin-api-v0",
87        feature = "plugin-api-v1",
88        feature = "plugin-api-v2",
89        feature = "plugin-api-v3"
90    )))]
91    pub fn value(&self) -> MemValue {
92        let qemu_mem_value = unsafe { crate::sys::qemu_plugin_mem_get_value(self.memory_info) };
93        MemValue::from(qemu_mem_value)
94    }
95}
96
97#[cfg(not(any(
98    feature = "plugin-api-v0",
99    feature = "plugin-api-v1",
100    feature = "plugin-api-v2",
101    feature = "plugin-api-v3"
102)))]
103#[derive(Clone)]
104/// Memory value loaded/stored (in memory callback)
105///
106/// Wrapper structure for a `qemu_plugin_mem_value`
107pub enum MemValue {
108    /// 8-bit value
109    U8(u8),
110    /// 16-bit value
111    U16(u16),
112    /// 32-bit value
113    U32(u32),
114    /// 64-bit value
115    U64(u64),
116    /// 128-bit value
117    U128(u128),
118}
119
120#[cfg(not(any(
121    feature = "plugin-api-v0",
122    feature = "plugin-api-v1",
123    feature = "plugin-api-v2",
124    feature = "plugin-api-v3"
125)))]
126impl From<qemu_plugin_mem_value> for MemValue {
127    fn from(value: qemu_plugin_mem_value) -> Self {
128        unsafe {
129            match value.type_ {
130                qemu_plugin_mem_value_type::QEMU_PLUGIN_MEM_VALUE_U8 => Self::U8(value.data.u8_),
131                qemu_plugin_mem_value_type::QEMU_PLUGIN_MEM_VALUE_U16 => Self::U16(value.data.u16_),
132                qemu_plugin_mem_value_type::QEMU_PLUGIN_MEM_VALUE_U32 => Self::U32(value.data.u32_),
133                qemu_plugin_mem_value_type::QEMU_PLUGIN_MEM_VALUE_U64 => Self::U64(value.data.u64_),
134                qemu_plugin_mem_value_type::QEMU_PLUGIN_MEM_VALUE_U128 => {
135                    let high = value.data.u128_.high as u128;
136                    let low = value.data.u128_.low as u128;
137                    Self::U128(high << 64 | low)
138                }
139            }
140        }
141    }
142}
143
144#[derive(Debug, Clone)]
145/// Wrapper structure for a `qemu_plugin_hwaddr *`
146///
147/// # Safety
148///
149/// This structure is safe to use as long as the pointer is valid. The pointer is
150/// always opaque, and therefore may not be dereferenced.
151pub struct HwAddr<'a> {
152    hwaddr: usize,
153    marker: PhantomData<&'a ()>,
154}
155
156impl<'a> From<*mut qemu_plugin_hwaddr> for HwAddr<'a> {
157    fn from(hwaddr: *mut qemu_plugin_hwaddr) -> Self {
158        Self {
159            hwaddr: hwaddr as usize,
160            marker: PhantomData,
161        }
162    }
163}
164
165impl<'a> HwAddr<'a> {
166    /// Returns whether the memory operation is to MMIO. Returns false if the operation is to
167    /// RAM.
168    pub fn is_io(&self) -> bool {
169        unsafe { crate::sys::qemu_plugin_hwaddr_is_io(self.hwaddr as *mut qemu_plugin_hwaddr) }
170    }
171
172    #[cfg(not(feature = "plugin-api-v0"))]
173    /// Returns the physical address for the memory operation
174    pub fn hwaddr(&self) -> u64 {
175        unsafe { crate::sys::qemu_plugin_hwaddr_phys_addr(self.hwaddr as *mut qemu_plugin_hwaddr) }
176    }
177
178    #[cfg(not(feature = "plugin-api-v0"))]
179    /// Returns a string representing the device
180    pub fn device_name(&self) -> Result<Option<String>> {
181        let device_name = unsafe {
182            crate::sys::qemu_plugin_hwaddr_device_name(self.hwaddr as *mut qemu_plugin_hwaddr)
183        };
184
185        if device_name.is_null() {
186            Ok(None)
187        } else {
188            let device_name_string = unsafe {
189                use std::ffi::CStr;
190                CStr::from_ptr(device_name)
191            }
192            .to_str()?
193            .to_string();
194            // NOTE: The string is static, so we do not free it
195            Ok(Some(device_name_string))
196        }
197    }
198}
199
200#[cfg(not(any(
201    feature = "plugin-api-v0",
202    feature = "plugin-api-v1",
203    feature = "plugin-api-v2",
204    feature = "plugin-api-v3"
205)))]
206/// Read memory from a virtual address. The address must be valid and mapped.
207pub fn qemu_plugin_read_memory_vaddr(addr: u64, buf: &mut [u8]) -> Result<()> {
208    let mut buf = GByteArray {
209        data: buf.as_mut_ptr(),
210        len: buf.len() as u32,
211    };
212
213    if unsafe {
214        crate::sys::qemu_plugin_read_memory_vaddr(
215            addr,
216            &mut buf as *mut GByteArray,
217            buf.len as usize,
218        )
219    } {
220        Ok(())
221    } else {
222        Err(Error::VaddrReadError { addr, len: buf.len })
223    }
224}
225
226#[cfg(not(any(
227    feature = "plugin-api-v0",
228    feature = "plugin-api-v1",
229    feature = "plugin-api-v2",
230    feature = "plugin-api-v3",
231    feature = "plugin-api-v4"
232)))]
233/// Write memory to a virtual address. The address must be valid and mapped.
234pub fn qemu_plugin_write_memory_vaddr(addr: u64, buf: &mut [u8]) -> Result<()> {
235    let mut buf = GByteArray {
236        data: buf.as_mut_ptr(),
237        len: buf.len() as u32,
238    };
239
240    if unsafe { crate::sys::qemu_plugin_write_memory_vaddr(addr, &mut buf as *mut GByteArray) } {
241        Ok(())
242    } else {
243        Err(Error::VaddrWriteError { addr, len: buf.len })
244    }
245}
246
247#[cfg(not(any(
248    feature = "plugin-api-v0",
249    feature = "plugin-api-v1",
250    feature = "plugin-api-v2",
251    feature = "plugin-api-v3",
252    feature = "plugin-api-v4"
253)))]
254#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
255/// The result of a hardware operation
256pub enum HwaddrOperationResult {
257    #[error("Operation completed successfully")]
258    /// Operation completed successfully
259    Ok = 0,
260    #[error("Unspecified error")]
261    /// Unspecified error
262    Error = 1,
263    #[error("Device error")]
264    /// Device error
265    DeviceError = 2,
266    #[error("Access denied")]
267    /// Access denied
268    AccessDenied = 3,
269    /// Invalid address
270    #[error("Invalid address")]
271    InvalidAddress = 4,
272    /// Invalid address space
273    #[error("Invalid address space")]
274    InvalidAddressSpace = 5,
275}
276
277#[cfg(not(any(
278    feature = "plugin-api-v0",
279    feature = "plugin-api-v1",
280    feature = "plugin-api-v2",
281    feature = "plugin-api-v3",
282    feature = "plugin-api-v4"
283)))]
284impl From<qemu_plugin_hwaddr_operation_result> for HwaddrOperationResult {
285    fn from(value: qemu_plugin_hwaddr_operation_result) -> Self {
286        match value {
287            qemu_plugin_hwaddr_operation_result::QEMU_PLUGIN_HWADDR_OPERATION_OK => Self::Ok,
288            qemu_plugin_hwaddr_operation_result::QEMU_PLUGIN_HWADDR_OPERATION_ERROR => Self::Error,
289            qemu_plugin_hwaddr_operation_result::QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR => Self::DeviceError,
290            qemu_plugin_hwaddr_operation_result::QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED => Self::AccessDenied,
291            qemu_plugin_hwaddr_operation_result::QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS => Self::InvalidAddress,
292            qemu_plugin_hwaddr_operation_result::QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE => Self::InvalidAddressSpace,
293        }
294    }
295}
296
297#[cfg(not(any(
298    feature = "plugin-api-v0",
299    feature = "plugin-api-v1",
300    feature = "plugin-api-v2",
301    feature = "plugin-api-v3",
302    feature = "plugin-api-v4"
303)))]
304/// Read memory from a hardware address. The address must be valid and mapped.
305pub fn qemu_plugin_read_memory_hwaddr(addr: u64, buf: &mut [u8]) -> Result<()> {
306    let mut buf = GByteArray {
307        data: buf.as_mut_ptr(),
308        len: buf.len() as u32,
309    };
310
311    match unsafe {
312        crate::sys::qemu_plugin_read_memory_hwaddr(
313            addr,
314            &mut buf as *mut GByteArray,
315            buf.len as usize,
316        )
317    }
318    .into()
319    {
320        HwaddrOperationResult::Ok => Ok(()),
321        error => Err(Error::HwaddrReadError {
322            addr,
323            len: buf.len,
324            result: error,
325        }),
326    }
327}
328
329#[cfg(not(any(
330    feature = "plugin-api-v0",
331    feature = "plugin-api-v1",
332    feature = "plugin-api-v2",
333    feature = "plugin-api-v3",
334    feature = "plugin-api-v4"
335)))]
336/// Read memory from a virtual address. The address must be valid and mapped.
337pub fn qemu_plugin_write_memory_hwaddr(addr: u64, buf: &mut [u8]) -> Result<()> {
338    let mut buf = GByteArray {
339        data: buf.as_mut_ptr(),
340        len: buf.len() as u32,
341    };
342
343    match unsafe { crate::sys::qemu_plugin_write_memory_hwaddr(addr, &mut buf as *mut GByteArray) }
344        .into()
345    {
346        HwaddrOperationResult::Ok => Ok(()),
347        error => Err(Error::HwaddrWriteError {
348            addr,
349            len: buf.len,
350            result: error,
351        }),
352    }
353}
354
355#[cfg(not(any(
356    feature = "plugin-api-v0",
357    feature = "plugin-api-v1",
358    feature = "plugin-api-v2",
359    feature = "plugin-api-v3",
360    feature = "plugin-api-v4"
361)))]
362/// Translate a virtual address to a hardware address. If the address is not
363/// mapped, an error is returned.
364pub fn qemu_plugin_translate_vaddr(vaddr: u64) -> Result<u64> {
365    let mut hwaddr: u64 = 0;
366    if unsafe { crate::sys::qemu_plugin_translate_vaddr(vaddr, &mut hwaddr as *mut _) } {
367        Ok(hwaddr)
368    } else {
369        Err(Error::VaddrTranslateError { vaddr })
370    }
371}