• 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.
unchecked_add(self, offset: u64) -> GuestAddress60     pub fn unchecked_add(self, offset: u64) -> GuestAddress {
61         GuestAddress(self.0 + offset)
62     }
63 
64     /// Returns the result of the subtraction of None if there is underflow.
checked_sub(self, other: u64) -> Option<GuestAddress>65     pub fn checked_sub(self, other: u64) -> Option<GuestAddress> {
66         self.0.checked_sub(other).map(GuestAddress)
67     }
68 
69     /// Returns the bitwise and of the address with the given mask.
mask(self, mask: u64) -> GuestAddress70     pub fn mask(self, mask: u64) -> GuestAddress {
71         GuestAddress(self.0 & mask as u64)
72     }
73 
74     /// Returns the next highest address that is a multiple of `align`, or an unchanged copy of the
75     /// address if it's already a multiple of `align`.  Returns None on overflow.
76     ///
77     /// `align` must be a power of 2.
align(self, align: u64) -> Option<GuestAddress>78     pub fn align(self, align: u64) -> Option<GuestAddress> {
79         if align <= 1 {
80             return Some(self);
81         }
82         self.checked_add(align - 1).map(|a| a & !(align - 1))
83     }
84 }
85 
86 impl BitAnd<u64> for GuestAddress {
87     type Output = GuestAddress;
88 
bitand(self, other: u64) -> GuestAddress89     fn bitand(self, other: u64) -> GuestAddress {
90         GuestAddress(self.0 & other as u64)
91     }
92 }
93 
94 impl BitOr<u64> for GuestAddress {
95     type Output = GuestAddress;
96 
bitor(self, other: u64) -> GuestAddress97     fn bitor(self, other: u64) -> GuestAddress {
98         GuestAddress(self.0 | other as u64)
99     }
100 }
101 
102 impl PartialEq for GuestAddress {
eq(&self, other: &GuestAddress) -> bool103     fn eq(&self, other: &GuestAddress) -> bool {
104         self.0 == other.0
105     }
106 }
107 impl Eq for GuestAddress {}
108 
109 impl Ord for GuestAddress {
cmp(&self, other: &GuestAddress) -> Ordering110     fn cmp(&self, other: &GuestAddress) -> Ordering {
111         self.0.cmp(&other.0)
112     }
113 }
114 
115 impl PartialOrd for GuestAddress {
partial_cmp(&self, other: &GuestAddress) -> Option<Ordering>116     fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
117         Some(self.cmp(other))
118     }
119 }
120 
121 impl Display for GuestAddress {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result122     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123         write!(f, "{:#x}", self.0)
124     }
125 }
126 
127 #[cfg(test)]
128 mod tests {
129     use super::*;
130 
131     #[test]
equals()132     fn equals() {
133         let a = GuestAddress(0x300);
134         let b = GuestAddress(0x300);
135         let c = GuestAddress(0x301);
136         assert_eq!(a, b);
137         assert_eq!(b, a);
138         assert_ne!(a, c);
139         assert_ne!(c, a);
140     }
141 
142     #[test]
143     #[allow(clippy::eq_op)]
144     #[allow(clippy::nonminimal_bool)]
cmp()145     fn cmp() {
146         let a = GuestAddress(0x300);
147         let b = GuestAddress(0x301);
148         assert!(a < b);
149         assert!(b > a);
150         assert!(!(a < a));
151         assert!(a >= a);
152     }
153 
154     #[test]
mask()155     fn mask() {
156         let a = GuestAddress(0x5050);
157         assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
158         assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
159     }
160 
161     #[test]
add_sub()162     fn add_sub() {
163         let a = GuestAddress(0x50);
164         let b = GuestAddress(0x60);
165         assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
166         assert_eq!(0x10, b.offset_from(a));
167     }
168 
169     #[test]
checked_add_overflow()170     fn checked_add_overflow() {
171         let a = GuestAddress(0xffffffffffffff55);
172         assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
173         assert!(a.checked_add(0xf0).is_none());
174     }
175 
176     #[test]
align()177     fn align() {
178         assert_eq!(GuestAddress(12345).align(0), Some(GuestAddress(12345)));
179         assert_eq!(GuestAddress(12345).align(1), Some(GuestAddress(12345)));
180         assert_eq!(GuestAddress(12345).align(2), Some(GuestAddress(12346)));
181         assert_eq!(GuestAddress(0).align(4096), Some(GuestAddress(0)));
182         assert_eq!(GuestAddress(1).align(4096), Some(GuestAddress(4096)));
183         assert_eq!(GuestAddress(4095).align(4096), Some(GuestAddress(4096)));
184         assert_eq!(GuestAddress(4096).align(4096), Some(GuestAddress(4096)));
185         assert_eq!(GuestAddress(4097).align(4096), Some(GuestAddress(8192)));
186         assert_eq!(
187             GuestAddress(u64::MAX & !4095).align(4096),
188             Some(GuestAddress(u64::MAX & !4095)),
189         );
190         assert_eq!(GuestAddress(u64::MAX).align(2), None);
191     }
192 }
193