xref: /aosp_15_r20/external/crosvm/vm_memory/src/guest_address.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
7 use std::cmp::Eq;
8 use std::cmp::Ord;
9 use std::cmp::Ordering;
10 use std::cmp::PartialEq;
11 use std::cmp::PartialOrd;
12 use std::fmt;
13 use std::fmt::Debug;
14 use std::fmt::Display;
15 use std::fmt::Formatter;
16 use std::ops::BitAnd;
17 use std::ops::BitOr;
18 
19 use serde::Deserialize;
20 use serde::Serialize;
21 
22 /// Represents an Address in the guest's memory.
23 #[derive(Clone, Copy, Deserialize, Serialize)]
24 pub struct GuestAddress(pub u64);
25 
26 impl Debug for GuestAddress {
fmt(&self, f: &mut Formatter) -> fmt::Result27     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
28         write!(f, "GuestAddress({:#018x})", self.0)
29     }
30 }
31 
32 impl 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     /// ```
offset_from(self, base: GuestAddress) -> u6443     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.
offset(self) -> u6449     pub fn offset(self) -> u64 {
50         self.0
51     }
52 
53     /// Returns the result of the add or None if there is overflow.
checked_add(self, other: u64) -> Option<GuestAddress>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]
unchecked_add(self, offset: u64) -> GuestAddress61     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.
checked_sub(self, other: u64) -> Option<GuestAddress>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.
mask(self, mask: u64) -> GuestAddress71     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.
align(self, align: u64) -> Option<GuestAddress>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.
align_down(self, align: u64) -> GuestAddress90     pub fn align_down(self, align: u64) -> GuestAddress {
91         if align <= 1 {
92             return self;
93         }
94         self & !(align - 1)
95     }
96 }
97 
98 impl BitAnd<u64> for GuestAddress {
99     type Output = GuestAddress;
100 
bitand(self, other: u64) -> GuestAddress101     fn bitand(self, other: u64) -> GuestAddress {
102         GuestAddress(self.0 & other)
103     }
104 }
105 
106 impl BitOr<u64> for GuestAddress {
107     type Output = GuestAddress;
108 
bitor(self, other: u64) -> GuestAddress109     fn bitor(self, other: u64) -> GuestAddress {
110         GuestAddress(self.0 | other)
111     }
112 }
113 
114 impl PartialEq for GuestAddress {
eq(&self, other: &GuestAddress) -> bool115     fn eq(&self, other: &GuestAddress) -> bool {
116         self.0 == other.0
117     }
118 }
119 impl Eq for GuestAddress {}
120 
121 impl Ord for GuestAddress {
cmp(&self, other: &GuestAddress) -> Ordering122     fn cmp(&self, other: &GuestAddress) -> Ordering {
123         self.0.cmp(&other.0)
124     }
125 }
126 
127 impl PartialOrd for GuestAddress {
partial_cmp(&self, other: &GuestAddress) -> Option<Ordering>128     fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
129         Some(self.cmp(other))
130     }
131 }
132 
133 impl Display for GuestAddress {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result134     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135         write!(f, "{:#x}", self.0)
136     }
137 }
138 
139 #[cfg(test)]
140 mod tests {
141     use super::*;
142 
143     #[test]
equals()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)]
cmp()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]
mask()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]
add_sub()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]
checked_add_overflow()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]
align()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]
align_down()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 }
225