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