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