blob: 1b78e7112270563002489be544c3715acfea137b [file] [log] [blame]
// 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<GuestAddress> {
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<GuestAddress> {
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<u64> for GuestAddress {
type Output = GuestAddress;
fn bitand(self, other: u64) -> GuestAddress {
GuestAddress(self.0 & other as u64)
}
}
impl BitOr<u64> 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<Ordering> {
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());
}
}