1 // Copyright 2017 The Chromium OS Authors. All rights reserved. 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, Ord, Ordering, PartialEq, PartialOrd}; 8 use std::fmt::{self, Display}; 9 use std::ops::{BitAnd, BitOr}; 10 11 use serde::{Deserialize, Serialize}; 12 13 /// Represents an Address in the guest's memory. 14 #[derive(Clone, Copy, Debug, Deserialize, Serialize)] 15 pub struct GuestAddress(pub u64); 16 17 impl GuestAddress { 18 /// Returns the offset from this address to the given base address. 19 /// 20 /// # Examples 21 /// 22 /// ``` 23 /// # use vm_memory::GuestAddress; 24 /// let base = GuestAddress(0x100); 25 /// let addr = GuestAddress(0x150); 26 /// assert_eq!(addr.offset_from(base), 0x50u64); 27 /// ``` offset_from(self, base: GuestAddress) -> u6428 pub fn offset_from(self, base: GuestAddress) -> u64 { 29 self.0 - base.0 30 } 31 32 /// Returns the address as a u64 offset from 0x0. 33 /// Use this when a raw number is needed to pass to the kernel. offset(self) -> u6434 pub fn offset(self) -> u64 { 35 self.0 36 } 37 38 /// Returns the result of the add or None if there is overflow. checked_add(self, other: u64) -> Option<GuestAddress>39 pub fn checked_add(self, other: u64) -> Option<GuestAddress> { 40 self.0.checked_add(other).map(GuestAddress) 41 } 42 43 /// Returns the result of the base address + the size. 44 /// Only use this when `offset` is guaranteed not to overflow. unchecked_add(self, offset: u64) -> GuestAddress45 pub fn unchecked_add(self, offset: u64) -> GuestAddress { 46 GuestAddress(self.0 + offset) 47 } 48 49 /// Returns the result of the subtraction of None if there is underflow. checked_sub(self, other: u64) -> Option<GuestAddress>50 pub fn checked_sub(self, other: u64) -> Option<GuestAddress> { 51 self.0.checked_sub(other).map(GuestAddress) 52 } 53 54 /// Returns the bitwise and of the address with the given mask. mask(self, mask: u64) -> GuestAddress55 pub fn mask(self, mask: u64) -> GuestAddress { 56 GuestAddress(self.0 & mask as u64) 57 } 58 } 59 60 impl BitAnd<u64> for GuestAddress { 61 type Output = GuestAddress; 62 bitand(self, other: u64) -> GuestAddress63 fn bitand(self, other: u64) -> GuestAddress { 64 GuestAddress(self.0 & other as u64) 65 } 66 } 67 68 impl BitOr<u64> for GuestAddress { 69 type Output = GuestAddress; 70 bitor(self, other: u64) -> GuestAddress71 fn bitor(self, other: u64) -> GuestAddress { 72 GuestAddress(self.0 | other as u64) 73 } 74 } 75 76 impl PartialEq for GuestAddress { eq(&self, other: &GuestAddress) -> bool77 fn eq(&self, other: &GuestAddress) -> bool { 78 self.0 == other.0 79 } 80 } 81 impl Eq for GuestAddress {} 82 83 impl Ord for GuestAddress { cmp(&self, other: &GuestAddress) -> Ordering84 fn cmp(&self, other: &GuestAddress) -> Ordering { 85 self.0.cmp(&other.0) 86 } 87 } 88 89 impl PartialOrd for GuestAddress { partial_cmp(&self, other: &GuestAddress) -> Option<Ordering>90 fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> { 91 Some(self.cmp(other)) 92 } 93 } 94 95 impl Display for GuestAddress { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result96 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 97 write!(f, "{:#x}", self.0) 98 } 99 } 100 101 #[cfg(test)] 102 mod tests { 103 use super::*; 104 105 #[test] equals()106 fn equals() { 107 let a = GuestAddress(0x300); 108 let b = GuestAddress(0x300); 109 let c = GuestAddress(0x301); 110 assert_eq!(a, b); 111 assert_eq!(b, a); 112 assert_ne!(a, c); 113 assert_ne!(c, a); 114 } 115 116 #[test] 117 #[allow(clippy::eq_op)] 118 #[allow(clippy::nonminimal_bool)] cmp()119 fn cmp() { 120 let a = GuestAddress(0x300); 121 let b = GuestAddress(0x301); 122 assert!(a < b); 123 assert!(b > a); 124 assert!(!(a < a)); 125 assert!(a >= a); 126 } 127 128 #[test] mask()129 fn mask() { 130 let a = GuestAddress(0x5050); 131 assert_eq!(GuestAddress(0x5000), a & 0xff00u64); 132 assert_eq!(GuestAddress(0x5055), a | 0x0005u64); 133 } 134 135 #[test] add_sub()136 fn add_sub() { 137 let a = GuestAddress(0x50); 138 let b = GuestAddress(0x60); 139 assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60)); 140 assert_eq!(0x10, b.offset_from(a)); 141 } 142 143 #[test] checked_add_overflow()144 fn checked_add_overflow() { 145 let a = GuestAddress(0xffffffffffffff55); 146 assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2)); 147 assert!(a.checked_add(0xf0).is_none()); 148 } 149 } 150