• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
87 impl BitAnd<u64> for GuestAddress {
88     type Output = GuestAddress;
89 
bitand(self, other: u64) -> GuestAddress90     fn bitand(self, other: u64) -> GuestAddress {
91         GuestAddress(self.0 & other)
92     }
93 }
94 
95 impl BitOr<u64> for GuestAddress {
96     type Output = GuestAddress;
97 
bitor(self, other: u64) -> GuestAddress98     fn bitor(self, other: u64) -> GuestAddress {
99         GuestAddress(self.0 | other)
100     }
101 }
102 
103 impl PartialEq for GuestAddress {
eq(&self, other: &GuestAddress) -> bool104     fn eq(&self, other: &GuestAddress) -> bool {
105         self.0 == other.0
106     }
107 }
108 impl Eq for GuestAddress {}
109 
110 impl Ord for GuestAddress {
cmp(&self, other: &GuestAddress) -> Ordering111     fn cmp(&self, other: &GuestAddress) -> Ordering {
112         self.0.cmp(&other.0)
113     }
114 }
115 
116 impl PartialOrd for GuestAddress {
partial_cmp(&self, other: &GuestAddress) -> Option<Ordering>117     fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
118         Some(self.cmp(other))
119     }
120 }
121 
122 impl Display for GuestAddress {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result123     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124         write!(f, "{:#x}", self.0)
125     }
126 }
127 
128 #[cfg(test)]
129 mod tests {
130     use super::*;
131 
132     #[test]
equals()133     fn equals() {
134         let a = GuestAddress(0x300);
135         let b = GuestAddress(0x300);
136         let c = GuestAddress(0x301);
137         assert_eq!(a, b);
138         assert_eq!(b, a);
139         assert_ne!(a, c);
140         assert_ne!(c, a);
141     }
142 
143     #[test]
144     #[allow(clippy::eq_op)]
145     #[allow(clippy::nonminimal_bool)]
cmp()146     fn cmp() {
147         let a = GuestAddress(0x300);
148         let b = GuestAddress(0x301);
149         assert!(a < b);
150         assert!(b > a);
151         assert!(!(a < a));
152         assert!(a >= a);
153     }
154 
155     #[test]
mask()156     fn mask() {
157         let a = GuestAddress(0x5050);
158         assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
159         assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
160     }
161 
162     #[test]
add_sub()163     fn add_sub() {
164         let a = GuestAddress(0x50);
165         let b = GuestAddress(0x60);
166         assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
167         assert_eq!(0x10, b.offset_from(a));
168     }
169 
170     #[test]
checked_add_overflow()171     fn checked_add_overflow() {
172         let a = GuestAddress(0xffffffffffffff55);
173         assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
174         assert!(a.checked_add(0xf0).is_none());
175     }
176 
177     #[test]
align()178     fn align() {
179         assert_eq!(GuestAddress(12345).align(0), Some(GuestAddress(12345)));
180         assert_eq!(GuestAddress(12345).align(1), Some(GuestAddress(12345)));
181         assert_eq!(GuestAddress(12345).align(2), Some(GuestAddress(12346)));
182         assert_eq!(GuestAddress(0).align(4096), Some(GuestAddress(0)));
183         assert_eq!(GuestAddress(1).align(4096), Some(GuestAddress(4096)));
184         assert_eq!(GuestAddress(4095).align(4096), Some(GuestAddress(4096)));
185         assert_eq!(GuestAddress(4096).align(4096), Some(GuestAddress(4096)));
186         assert_eq!(GuestAddress(4097).align(4096), Some(GuestAddress(8192)));
187         assert_eq!(
188             GuestAddress(u64::MAX & !4095).align(4096),
189             Some(GuestAddress(u64::MAX & !4095)),
190         );
191         assert_eq!(GuestAddress(u64::MAX).align(2), None);
192     }
193 }
194