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