vm_memory/
guest_address.rs

1// Copyright 2017 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Represents an address in the guest's memory space.
6
7use std::cmp::Eq;
8use std::cmp::Ord;
9use std::cmp::Ordering;
10use std::cmp::PartialEq;
11use std::cmp::PartialOrd;
12use std::fmt;
13use std::fmt::Debug;
14use std::fmt::Display;
15use std::fmt::Formatter;
16use std::ops::BitAnd;
17use std::ops::BitOr;
18
19use serde::Deserialize;
20use serde::Serialize;
21
22/// Represents an Address in the guest's memory.
23#[derive(Clone, Copy, Deserialize, Serialize)]
24pub struct GuestAddress(pub u64);
25
26impl Debug for GuestAddress {
27    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
28        write!(f, "GuestAddress({:#018x})", self.0)
29    }
30}
31
32impl GuestAddress {
33    /// Returns the offset from this address to the given base address.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// # use vm_memory::GuestAddress;
39    ///   let base = GuestAddress(0x100);
40    ///   let addr = GuestAddress(0x150);
41    ///   assert_eq!(addr.offset_from(base), 0x50u64);
42    /// ```
43    pub fn offset_from(self, base: GuestAddress) -> u64 {
44        self.0 - base.0
45    }
46
47    /// Returns the address as a u64 offset from 0x0.
48    /// Use this when a raw number is needed to pass to the kernel.
49    pub fn offset(self) -> u64 {
50        self.0
51    }
52
53    /// Returns the result of the add or None if there is overflow.
54    pub fn checked_add(self, other: u64) -> Option<GuestAddress> {
55        self.0.checked_add(other).map(GuestAddress)
56    }
57
58    /// Returns the result of the base address + the size.
59    /// Only use this when `offset` is guaranteed not to overflow.
60    #[inline]
61    pub fn unchecked_add(self, offset: u64) -> GuestAddress {
62        GuestAddress(self.0.wrapping_add(offset))
63    }
64
65    /// Returns the result of the subtraction of None if there is underflow.
66    pub fn checked_sub(self, other: u64) -> Option<GuestAddress> {
67        self.0.checked_sub(other).map(GuestAddress)
68    }
69
70    /// Returns the bitwise and of the address with the given mask.
71    pub fn mask(self, mask: u64) -> GuestAddress {
72        GuestAddress(self.0 & mask)
73    }
74
75    /// Returns the next highest address that is a multiple of `align`, or an unchanged copy of the
76    /// address if it's already a multiple of `align`.  Returns None on overflow.
77    ///
78    /// `align` must be a power of 2.
79    pub fn align(self, align: u64) -> Option<GuestAddress> {
80        if align <= 1 {
81            return Some(self);
82        }
83        self.checked_add(align - 1).map(|a| a & !(align - 1))
84    }
85
86    /// Returns the next lowest address that is a multiple of `align`, or an unchanged copy of the
87    /// address if it's already a multiple of `align`.
88    ///
89    /// `align` must be a power of 2.
90    pub fn align_down(self, align: u64) -> GuestAddress {
91        if align <= 1 {
92            return self;
93        }
94        self & !(align - 1)
95    }
96}
97
98impl BitAnd<u64> for GuestAddress {
99    type Output = GuestAddress;
100
101    fn bitand(self, other: u64) -> GuestAddress {
102        GuestAddress(self.0 & other)
103    }
104}
105
106impl BitOr<u64> for GuestAddress {
107    type Output = GuestAddress;
108
109    fn bitor(self, other: u64) -> GuestAddress {
110        GuestAddress(self.0 | other)
111    }
112}
113
114impl PartialEq for GuestAddress {
115    fn eq(&self, other: &GuestAddress) -> bool {
116        self.0 == other.0
117    }
118}
119impl Eq for GuestAddress {}
120
121impl Ord for GuestAddress {
122    fn cmp(&self, other: &GuestAddress) -> Ordering {
123        self.0.cmp(&other.0)
124    }
125}
126
127impl PartialOrd for GuestAddress {
128    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
129        Some(self.cmp(other))
130    }
131}
132
133impl Display for GuestAddress {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        write!(f, "{:#x}", self.0)
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn equals() {
145        let a = GuestAddress(0x300);
146        let b = GuestAddress(0x300);
147        let c = GuestAddress(0x301);
148        assert_eq!(a, b);
149        assert_eq!(b, a);
150        assert_ne!(a, c);
151        assert_ne!(c, a);
152    }
153
154    #[test]
155    #[allow(clippy::eq_op)]
156    #[allow(clippy::nonminimal_bool)]
157    fn cmp() {
158        let a = GuestAddress(0x300);
159        let b = GuestAddress(0x301);
160        assert!(a < b);
161        assert!(b > a);
162        assert!(!(a < a));
163        assert!(a >= a);
164    }
165
166    #[test]
167    fn mask() {
168        let a = GuestAddress(0x5050);
169        assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
170        assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
171    }
172
173    #[test]
174    fn add_sub() {
175        let a = GuestAddress(0x50);
176        let b = GuestAddress(0x60);
177        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
178        assert_eq!(0x10, b.offset_from(a));
179    }
180
181    #[test]
182    fn checked_add_overflow() {
183        let a = GuestAddress(0xffffffffffffff55);
184        assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
185        assert!(a.checked_add(0xf0).is_none());
186    }
187
188    #[test]
189    fn align() {
190        assert_eq!(GuestAddress(12345).align(0), Some(GuestAddress(12345)));
191        assert_eq!(GuestAddress(12345).align(1), Some(GuestAddress(12345)));
192        assert_eq!(GuestAddress(12345).align(2), Some(GuestAddress(12346)));
193        assert_eq!(GuestAddress(0).align(4096), Some(GuestAddress(0)));
194        assert_eq!(GuestAddress(1).align(4096), Some(GuestAddress(4096)));
195        assert_eq!(GuestAddress(4095).align(4096), Some(GuestAddress(4096)));
196        assert_eq!(GuestAddress(4096).align(4096), Some(GuestAddress(4096)));
197        assert_eq!(GuestAddress(4097).align(4096), Some(GuestAddress(8192)));
198        assert_eq!(
199            GuestAddress(u64::MAX & !4095).align(4096),
200            Some(GuestAddress(u64::MAX & !4095)),
201        );
202        assert_eq!(GuestAddress(u64::MAX).align(2), None);
203    }
204
205    #[test]
206    fn align_down() {
207        assert_eq!(GuestAddress(12345).align_down(0), GuestAddress(12345));
208        assert_eq!(GuestAddress(12345).align_down(1), GuestAddress(12345));
209        assert_eq!(GuestAddress(12345).align_down(2), GuestAddress(12344));
210        assert_eq!(GuestAddress(0).align_down(4096), GuestAddress(0));
211        assert_eq!(GuestAddress(1).align_down(4096), GuestAddress(0));
212        assert_eq!(GuestAddress(4095).align_down(4096), GuestAddress(0));
213        assert_eq!(GuestAddress(4096).align_down(4096), GuestAddress(4096));
214        assert_eq!(GuestAddress(4097).align_down(4096), GuestAddress(4096));
215        assert_eq!(
216            GuestAddress(u64::MAX & !4095).align_down(4096),
217            GuestAddress(u64::MAX & !4095),
218        );
219        assert_eq!(
220            GuestAddress(u64::MAX).align_down(2),
221            GuestAddress(u64::MAX - 1)
222        );
223    }
224}