// Copyright 2017 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! Represents an address in the guest's memory space. use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::fmt::{self, Display}; use std::ops::{BitAnd, BitOr}; /// Represents an Address in the guest's memory. #[derive(Clone, Copy, Debug)] pub struct GuestAddress(pub u64); impl GuestAddress { /// Returns the offset from this address to the given base address. /// /// # Examples /// /// ``` /// # use sys_util::GuestAddress; /// let base = GuestAddress(0x100); /// let addr = GuestAddress(0x150); /// assert_eq!(addr.offset_from(base), 0x50u64); /// ``` pub fn offset_from(self, base: GuestAddress) -> u64 { self.0 - base.0 } /// Returns the address as a u64 offset from 0x0. /// Use this when a raw number is needed to pass to the kernel. pub fn offset(self) -> u64 { self.0 } /// Returns the result of the add or None if there is overflow. pub fn checked_add(self, other: u64) -> Option { self.0.checked_add(other).map(GuestAddress) } /// Returns the result of the base address + the size. /// Only use this when `offset` is guaranteed not to overflow. pub fn unchecked_add(self, offset: u64) -> GuestAddress { GuestAddress(self.0 + offset) } /// Returns the result of the subtraction of None if there is underflow. pub fn checked_sub(self, other: u64) -> Option { self.0.checked_sub(other).map(GuestAddress) } /// Returns the bitwise and of the address with the given mask. pub fn mask(self, mask: u64) -> GuestAddress { GuestAddress(self.0 & mask as u64) } } impl BitAnd for GuestAddress { type Output = GuestAddress; fn bitand(self, other: u64) -> GuestAddress { GuestAddress(self.0 & other as u64) } } impl BitOr for GuestAddress { type Output = GuestAddress; fn bitor(self, other: u64) -> GuestAddress { GuestAddress(self.0 | other as u64) } } impl PartialEq for GuestAddress { fn eq(&self, other: &GuestAddress) -> bool { self.0 == other.0 } } impl Eq for GuestAddress {} impl Ord for GuestAddress { fn cmp(&self, other: &GuestAddress) -> Ordering { self.0.cmp(&other.0) } } impl PartialOrd for GuestAddress { fn partial_cmp(&self, other: &GuestAddress) -> Option { Some(self.cmp(other)) } } impl Display for GuestAddress { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self.0) } } #[cfg(test)] mod tests { use super::*; #[test] fn equals() { let a = GuestAddress(0x300); let b = GuestAddress(0x300); let c = GuestAddress(0x301); assert_eq!(a, b); assert_eq!(b, a); assert_ne!(a, c); assert_ne!(c, a); } #[test] fn cmp() { let a = GuestAddress(0x300); let b = GuestAddress(0x301); assert!(a < b); assert!(b > a); assert!(!(a < a)); } #[test] fn mask() { let a = GuestAddress(0x5050); assert_eq!(GuestAddress(0x5000), a & 0xff00u64); assert_eq!(GuestAddress(0x5055), a | 0x0005u64); } #[test] fn add_sub() { let a = GuestAddress(0x50); let b = GuestAddress(0x60); assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60)); assert_eq!(0x10, b.offset_from(a)); } #[test] fn checked_add_overflow() { let a = GuestAddress(0xffffffffffffff55); assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2)); assert!(a.checked_add(0xf0).is_none()); } }