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