1use core::fmt;
4
5use serde::{Deserialize, Serialize};
6
7use crate::error::{Error, Result};
10
11#[derive(
16 Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize,
17)]
18#[serde(transparent)]
19pub struct GuestAddress(pub u64);
20
21impl GuestAddress {
22 #[inline]
24 pub const fn raw(self) -> u64 {
25 self.0
26 }
27
28 pub fn align_down(self, align: u64) -> Result<Self> {
33 if !align.is_power_of_two() {
34 return Err(Error::InvalidArgument(format!(
35 "alignment must be a power of two: {align}"
36 )));
37 }
38 Ok(Self(self.0 & !(align - 1)))
39 }
40
41 #[inline]
43 #[must_use]
44 pub const fn saturating_add(self, offset: u64) -> Self {
45 Self(self.0.saturating_add(offset))
46 }
47}
48
49impl fmt::Display for GuestAddress {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(f, "{:#018x}", self.0)
52 }
53}
54
55impl From<u64> for GuestAddress {
56 #[inline]
57 fn from(value: u64) -> Self {
58 Self(value)
59 }
60}
61
62#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
64pub struct GuestRange {
65 pub base: GuestAddress,
67 pub size: u64,
69}
70
71impl GuestRange {
72 pub fn new(base: GuestAddress, size: u64) -> Result<Self> {
77 base.0.checked_add(size).ok_or_else(|| {
78 Error::InvalidArgument(format!("range overflow: base={base} size={size}"))
79 })?;
80 Ok(Self { base, size })
81 }
82
83 #[inline]
85 pub fn end(self) -> GuestAddress {
86 GuestAddress(self.base.0 + self.size)
87 }
88
89 #[inline]
91 pub fn contains(self, addr: GuestAddress) -> bool {
92 addr.0 >= self.base.0 && addr.0 < self.base.0 + self.size
93 }
94}
95
96#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
98#[allow(clippy::struct_excessive_bools)] pub struct Protection {
100 pub read: bool,
102 pub write: bool,
104 pub execute: bool,
106}
107
108impl Protection {
109 pub const READ: Self = Self::new(true, false, false);
111 pub const READ_WRITE: Self = Self::new(true, true, false);
113 pub const READ_EXECUTE: Self = Self::new(true, false, true);
115 pub const READ_WRITE_EXECUTE: Self = Self::new(true, true, true);
117
118 pub const fn new(read: bool, write: bool, execute: bool) -> Self {
120 Self {
121 read,
122 write,
123 execute,
124 }
125 }
126}
127
128#[derive(Debug)]
130#[non_exhaustive]
131pub struct GuestMemoryRegion {
132 pub range: GuestRange,
134 pub slot: u32,
136 pub protection: Protection,
138}
139
140impl GuestMemoryRegion {
141 pub fn new(range: GuestRange, slot: u32, protection: Protection) -> Self {
143 Self {
144 range,
145 slot,
146 protection,
147 }
148 }
149}
150
151pub trait GuestMemory: Send + Sync + fmt::Debug {
162 fn read(&self, addr: GuestAddress, buf: &mut [u8]) -> Result<()>;
168
169 fn write(&self, addr: GuestAddress, buf: &[u8]) -> Result<()>;
174
175 fn read_u16_le(&self, addr: GuestAddress) -> Result<u16> {
180 let mut b = [0u8; 2];
181 self.read(addr, &mut b)?;
182 Ok(u16::from_le_bytes(b))
183 }
184
185 fn read_u32_le(&self, addr: GuestAddress) -> Result<u32> {
190 let mut b = [0u8; 4];
191 self.read(addr, &mut b)?;
192 Ok(u32::from_le_bytes(b))
193 }
194
195 fn read_u64_le(&self, addr: GuestAddress) -> Result<u64> {
200 let mut b = [0u8; 8];
201 self.read(addr, &mut b)?;
202 Ok(u64::from_le_bytes(b))
203 }
204
205 fn write_u16_le(&self, addr: GuestAddress, value: u16) -> Result<()> {
210 self.write(addr, &value.to_le_bytes())
211 }
212
213 fn write_u32_le(&self, addr: GuestAddress, value: u32) -> Result<()> {
218 self.write(addr, &value.to_le_bytes())
219 }
220
221 fn write_u64_le(&self, addr: GuestAddress, value: u64) -> Result<()> {
226 self.write(addr, &value.to_le_bytes())
227 }
228}
229
230#[derive(Debug)]
237pub struct SliceGuestMemory {
238 base: GuestAddress,
239 bytes: parking_lot::RwLock<Vec<u8>>,
240}
241
242impl SliceGuestMemory {
243 #[must_use]
245 pub fn new(base: GuestAddress, size: usize) -> Self {
246 Self {
247 base,
248 bytes: parking_lot::RwLock::new(vec![0u8; size]),
249 }
250 }
251
252 #[must_use]
254 pub fn from_bytes(base: GuestAddress, bytes: Vec<u8>) -> Self {
255 Self {
256 base,
257 bytes: parking_lot::RwLock::new(bytes),
258 }
259 }
260
261 #[must_use]
263 pub fn base(&self) -> GuestAddress {
264 self.base
265 }
266
267 #[must_use]
269 pub fn size(&self) -> usize {
270 self.bytes.read().len()
271 }
272
273 fn offset_of(&self, addr: GuestAddress, len: usize) -> Result<usize> {
274 let base = self.base.raw();
275 let size = u64::try_from(self.bytes.read().len()).unwrap_or(u64::MAX);
276 let end = base.saturating_add(size);
277 let len_u64 = u64::try_from(len)
278 .map_err(|_| Error::MemoryOutOfRange(format!("addr {addr} + len {len} overflows")))?;
279 let req_end = addr
280 .raw()
281 .checked_add(len_u64)
282 .ok_or_else(|| Error::MemoryOutOfRange(format!("addr {addr} + len {len} overflows")))?;
283 if addr.raw() < base || req_end > end {
284 return Err(Error::MemoryOutOfRange(format!(
285 "addr {addr} + len {len} escapes [{base:#x}, {end:#x})"
286 )));
287 }
288 usize::try_from(addr.raw() - base).map_err(|_| {
289 Error::MemoryOutOfRange(format!("offset {} exceeds usize::MAX", addr.raw() - base))
290 })
291 }
292}
293
294impl GuestMemory for SliceGuestMemory {
295 fn read(&self, addr: GuestAddress, buf: &mut [u8]) -> Result<()> {
296 let off = self.offset_of(addr, buf.len())?;
297 let bytes = self.bytes.read();
298 buf.copy_from_slice(&bytes[off..off + buf.len()]);
299 Ok(())
300 }
301
302 fn write(&self, addr: GuestAddress, buf: &[u8]) -> Result<()> {
303 let off = self.offset_of(addr, buf.len())?;
304 let mut bytes = self.bytes.write();
305 bytes[off..off + buf.len()].copy_from_slice(buf);
306 Ok(())
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use super::*;
313
314 #[test]
315 fn align_down_rejects_non_power_of_two() {
316 let addr = GuestAddress(0x1234);
317 assert!(addr.align_down(7).is_err());
318 }
319
320 #[test]
321 fn align_down_rounds() {
322 let addr = GuestAddress(0x1234);
323 assert_eq!(addr.align_down(0x1000).unwrap().raw(), 0x1000);
324 }
325
326 #[test]
327 fn range_overflow_is_rejected() {
328 let err = GuestRange::new(GuestAddress(u64::MAX - 0x100), 0x200).unwrap_err();
329 matches!(err, Error::InvalidArgument(_));
330 }
331
332 #[test]
333 fn range_contains_endpoints() {
334 let r = GuestRange::new(GuestAddress(0x1000), 0x1000).unwrap();
335 assert!(r.contains(GuestAddress(0x1000)));
336 assert!(r.contains(GuestAddress(0x1FFF)));
337 assert!(!r.contains(GuestAddress(0x2000)));
338 }
339
340 #[test]
341 fn protection_constants_round_trip() {
342 let p = Protection::READ_WRITE;
343 assert!(p.read && p.write && !p.execute);
344 }
345
346 #[test]
347 fn slice_guest_memory_round_trips_typed_writes() {
348 let mem = SliceGuestMemory::new(GuestAddress(0x4000_0000), 0x1000);
349 mem.write_u32_le(GuestAddress(0x4000_0010), 0xDEAD_BEEF)
350 .unwrap();
351 assert_eq!(
352 mem.read_u32_le(GuestAddress(0x4000_0010)).unwrap(),
353 0xDEAD_BEEF
354 );
355 mem.write_u16_le(GuestAddress(0x4000_0020), 0xABCD).unwrap();
356 assert_eq!(mem.read_u16_le(GuestAddress(0x4000_0020)).unwrap(), 0xABCD);
357 }
358
359 #[test]
360 fn slice_guest_memory_rejects_below_base() {
361 let mem = SliceGuestMemory::new(GuestAddress(0x4000_0000), 0x1000);
362 let mut buf = [0u8; 4];
363 let err = mem.read(GuestAddress(0x3FFF_FFFF), &mut buf).unwrap_err();
364 assert!(matches!(err, Error::MemoryOutOfRange(_)));
365 }
366
367 #[test]
368 fn slice_guest_memory_rejects_straddling_top() {
369 let mem = SliceGuestMemory::new(GuestAddress(0x4000_0000), 0x10);
370 let mut buf = [0u8; 8];
371 let err = mem.read(GuestAddress(0x4000_000C), &mut buf).unwrap_err();
372 assert!(matches!(err, Error::MemoryOutOfRange(_)));
373 }
374
375 #[test]
376 fn slice_guest_memory_rejects_overflow() {
377 let mem = SliceGuestMemory::new(GuestAddress(u64::MAX - 0x10), 0x10);
378 let mut buf = [0u8; 0x100];
379 let err = mem
380 .read(GuestAddress(u64::MAX - 0x8), &mut buf)
381 .unwrap_err();
382 assert!(matches!(err, Error::MemoryOutOfRange(_)));
383 }
384}