memflow/types/
address.rs

1/*!
2Abstraction over a address on the target system.
3*/
4
5use super::{PhysicalAddress, Pointer};
6use crate::types::ByteSwap;
7
8use core::convert::TryInto;
9use std::default::Default;
10use std::fmt;
11use std::hash;
12use std::ops;
13
14/// The largest target memory type
15/// The following core rule is defined for these memory types:
16///
17/// `PAGE_SIZE < usize <= umem`
18///
19/// Where `PAGE_SIZE` is any lowest granularity page size, `usize` is the standard size type, and
20/// `umem` is memflow's memory size type.
21///
22/// This means that `usize` can always be safely cast to `umem`, while anything to do with page
23/// sizes can be cast to `umem` safely,
24///
25#[cfg(feature = "64_bit_mem")]
26#[allow(non_camel_case_types)]
27pub type umem = u64;
28#[cfg(all(feature = "128_bit_mem", not(feature = "64_bit_mem")))]
29#[allow(non_camel_case_types)]
30pub type umem = u128;
31#[cfg(all(not(feature = "64_bit_mem"), not(feature = "128_bit_mem")))]
32#[allow(non_camel_case_types)]
33pub type umem = usize;
34#[cfg(feature = "64_bit_mem")]
35#[allow(non_camel_case_types)]
36pub type imem = i64;
37#[cfg(all(feature = "128_bit_mem", not(feature = "64_bit_mem")))]
38#[allow(non_camel_case_types)]
39pub type imem = i128;
40#[cfg(all(not(feature = "64_bit_mem"), not(feature = "128_bit_mem")))]
41#[allow(non_camel_case_types)]
42pub type imem = isize;
43
44pub const UMEM_BITS: u8 = core::mem::size_of::<umem>() as u8 * 8;
45
46// Enforce the `umem` >= `usize` condition. Whenever a real 128-bit architecture is here, `umem`
47// should be expanded to 128 bits.
48const _: [u8; (core::mem::size_of::<usize>() <= core::mem::size_of::<umem>()) as usize] = [0; 1];
49
50pub const fn clamp_to_usize(val: umem) -> usize {
51    let max = usize::MAX as umem;
52
53    let ret = if max < val { max } else { val };
54
55    ret as usize
56}
57
58pub const fn clamp_to_isize(val: imem) -> isize {
59    let max = isize::MAX as imem;
60    let min = isize::MIN as imem;
61
62    let ret = if max < val {
63        max
64    } else if min > val {
65        min
66    } else {
67        val
68    };
69
70    ret as isize
71}
72
73/// `PrimitiveAddress` describes the address of a target system.
74/// The current implementations include `u32`, `u64` and later eventually `u128`.
75/// This trait can be used to abstract objects over the target pointer width.
76pub trait PrimitiveAddress:
77    Copy
78    + Eq
79    + PartialEq
80    + Ord
81    + PartialOrd
82    + hash::Hash
83    + fmt::LowerHex
84    + fmt::UpperHex
85    + ByteSwap
86    + ops::Add<Output = Self>
87    + ops::Sub<Output = Self>
88{
89    fn null() -> Self;
90    fn invalid() -> Self;
91
92    fn min() -> Self;
93    fn max() -> Self;
94
95    fn from_umem(frm: umem) -> Self;
96    fn from_imem(frm: imem) -> Self;
97
98    fn wrapping_add(self, rhs: Self) -> Self;
99    fn wrapping_sub(self, rhs: Self) -> Self;
100    fn saturating_sub(self, rhs: Self) -> Self;
101    fn overflowing_shr(self, rhs: u32) -> (Self, bool);
102
103    fn to_umem(self) -> umem;
104    fn to_imem(self) -> imem;
105
106    #[inline]
107    fn is_null(self) -> bool {
108        self.eq(&Self::null())
109    }
110}
111
112#[macro_export]
113macro_rules! impl_primitive_address {
114    ($type_name:ident) => {
115        impl PrimitiveAddress for $type_name {
116            #[inline]
117            fn null() -> Self {
118                0 as $type_name
119            }
120
121            #[inline]
122            fn invalid() -> Self {
123                !Self::null()
124            }
125
126            #[inline]
127            fn min() -> Self {
128                Self::MIN
129            }
130
131            #[inline]
132            fn max() -> Self {
133                Self::MAX
134            }
135
136            #[inline]
137            fn from_umem(frm: umem) -> Self {
138                frm as Self
139            }
140
141            #[inline]
142            fn from_imem(frm: imem) -> Self {
143                frm as Self
144            }
145
146            #[inline]
147            fn wrapping_add(self, rhs: Self) -> Self {
148                self.wrapping_add(rhs)
149            }
150
151            #[inline]
152            fn wrapping_sub(self, rhs: Self) -> Self {
153                self.wrapping_sub(rhs)
154            }
155
156            #[inline]
157            fn saturating_sub(self, rhs: Self) -> Self {
158                self.saturating_sub(rhs)
159            }
160
161            #[inline]
162            fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
163                self.overflowing_shr(rhs)
164            }
165
166            #[inline]
167            fn to_umem(self) -> umem {
168                self as umem
169            }
170
171            #[inline]
172            fn to_imem(self) -> imem {
173                self as imem
174            }
175        }
176    };
177}
178
179impl_primitive_address!(u16);
180impl_primitive_address!(u32);
181impl_primitive_address!(u64);
182#[cfg(all(feature = "128_bit_mem", not(feature = "64_bit_mem")))]
183impl_primitive_address!(u128);
184
185/// This type represents a address on the target system.
186/// It internally holds a `umem` value but can also be used
187/// when working in 32-bit environments.
188///
189/// This type will not handle overflow for 32-bit or 64-bit addresses / lengths.
190#[repr(transparent)]
191#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
192#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
193#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
194pub struct Address(umem);
195
196impl Address {
197    /// A address with the value of zero.
198    ///
199    /// # Examples
200    ///
201    /// ```
202    /// use memflow::types::Address;
203    ///
204    /// println!("address: {}", Address::NULL);
205    /// ```
206    pub const NULL: Address = Address(0);
207
208    /// A address with an invalid value.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use memflow::types::Address;
214    ///
215    /// println!("address: {}", Address::INVALID);
216    /// ```
217    pub const INVALID: Address = Address(!0);
218
219    /// Returns an address with a value of zero.
220    ///
221    /// # Examples
222    ///
223    /// ```
224    /// use memflow::types::Address;
225    ///
226    /// println!("address: {}", Address::null());
227    /// ```
228    #[inline]
229    pub const fn null() -> Self {
230        Address::NULL
231    }
232
233    /// Creates a a bit mask.
234    /// This function accepts an (half-open) range excluding the end bit from the mask.
235    ///
236    /// # Examples
237    ///
238    /// ```
239    /// use memflow::types::Address;
240    ///
241    /// println!("mask: {}", Address::bit_mask(0..=11));
242    /// ```
243    pub fn bit_mask<T>(bits: ops::RangeInclusive<T>) -> Address
244    where
245        T: TryInto<u8> + Copy,
246    {
247        Address(
248            (!0 >> ((UMEM_BITS - 1) - (*bits.end()).try_into().ok().unwrap()))
249                & !((1 << (*bits.start()).try_into().ok().unwrap()) - 1),
250        )
251    }
252
253    /// Creates a a bit mask (const version with u8 range).
254    /// This function accepts an (half-open) range excluding the end bit from the mask.
255    ///
256    /// # Examples
257    ///
258    /// ```
259    /// use memflow::types::Address;
260    ///
261    /// println!("mask: {}", Address::bit_mask_u8(0..=11));
262    /// ```
263    pub const fn bit_mask_u8(bits: ops::RangeInclusive<u8>) -> Address {
264        Address((!0 >> (UMEM_BITS - 1 - *bits.end())) & !((1 << *bits.start()) - 1))
265    }
266
267    /// Checks wether the address is zero or not.
268    ///
269    /// # Examples
270    ///
271    /// ```
272    /// use memflow::types::Address;
273    ///
274    /// assert_eq!(Address::null().is_null(), true);
275    /// assert_eq!(Address::from(0x1000u64).is_null(), false);
276    /// ```
277    #[inline]
278    pub const fn is_null(self) -> bool {
279        self.0 == 0
280    }
281
282    /// Converts the address to an Option that is None when it is null
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// use memflow::types::Address;
288    ///
289    /// assert_eq!(Address::null().non_null(), None);
290    /// assert_eq!(Address::from(0x1000u64).non_null(), Some(Address::from(0x1000)));
291    /// ```
292    #[inline]
293    pub fn non_null(self) -> Option<Address> {
294        if self.is_null() {
295            None
296        } else {
297            Some(self)
298        }
299    }
300
301    /// Returns an address with a invalid value.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// use memflow::types::Address;
307    ///
308    /// println!("address: {}", Address::invalid());
309    /// ```
310    #[inline]
311    pub const fn invalid() -> Self {
312        Address::INVALID
313    }
314
315    /// Checks wether the address is valid or not.
316    ///
317    /// # Examples
318    ///
319    /// ```
320    /// use memflow::types::Address;
321    ///
322    /// assert_eq!(Address::invalid().is_valid(), false);
323    /// assert_eq!(Address::from(0x1000u64).is_valid(), true);
324    /// ```
325    #[inline]
326    pub const fn is_valid(self) -> bool {
327        self.0 != !0
328    }
329
330    /// Converts the address into a `u64` value.
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use memflow::types::{Address, umem};
336    ///
337    /// let addr = Address::from(0x1000u64);
338    /// let addr_umem: umem = addr.to_umem();
339    /// assert_eq!(addr_umem, 0x1000);
340    /// ```
341    #[inline]
342    pub const fn to_umem(self) -> umem {
343        self.0
344    }
345
346    /// Aligns the containing address to the given page size.
347    /// It returns the base address of the containing page.
348    ///
349    /// # Examples
350    ///
351    /// ```
352    /// use memflow::types::{Address, mem};
353    ///
354    /// let addr = Address::from(0x1234);
355    /// let aligned = addr.as_mem_aligned(mem::kb(4));
356    /// assert_eq!(aligned, Address::from(0x1000));
357    /// ```
358    pub const fn as_mem_aligned(self, mem_size: umem) -> Self {
359        Self(self.0 - self.0 % mem_size)
360    }
361
362    pub const fn as_page_aligned(self, page_size: usize) -> Self {
363        self.as_mem_aligned(page_size as umem)
364    }
365
366    /// Returns true or false wether the bit at the specified index is either 0 or 1.
367    /// An index of 0 will check the least significant bit.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// use memflow::types::Address;
373    ///
374    /// let addr = Address::from(2);
375    /// let bit = addr.bit_at(1);
376    /// assert_eq!(bit, true);
377    /// ```
378    pub const fn bit_at(self, idx: u8) -> bool {
379        (self.0 & (1 << idx)) != 0
380    }
381
382    /// Extracts the given range of bits by applying a corresponding bitmask.
383    /// This function accepts an (half-open) range excluding the end bit from the mask.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// use memflow::types::Address;
389    ///
390    /// let addr = Address::from(123456789);
391    /// println!("bits[0..2] = {}", addr.extract_bits(0..=2));
392    /// ```
393    pub fn extract_bits<T>(self, bits: ops::RangeInclusive<T>) -> Address
394    where
395        T: TryInto<u8> + Copy,
396    {
397        (self.0 & Address::bit_mask(bits).to_umem()).into()
398    }
399
400    /// Wrapping (modular) addition. Computes `self + rhs`,
401    /// wrapping around at the boundary of the type.
402    pub const fn wrapping_add(self, other: Self) -> Self {
403        Self(self.0.wrapping_add(other.0))
404    }
405
406    /// Wrapping (modular) subtraction. Computes `self - rhs`,
407    /// wrapping around at the boundary of the type.
408    pub const fn wrapping_sub(self, other: Self) -> Self {
409        Self(self.0.wrapping_sub(other.0))
410    }
411}
412
413/// Returns a address with a value of zero.
414///
415/// # Examples
416///
417/// ```
418/// use memflow::types::Address;
419///
420/// assert_eq!(Address::default().is_null(), true);
421/// ```
422impl Default for Address {
423    fn default() -> Self {
424        Self::null()
425    }
426}
427
428/// Implements byteswapping for the address
429impl ByteSwap for Address {
430    fn byte_swap(&mut self) {
431        self.0.byte_swap();
432    }
433}
434
435#[macro_export]
436macro_rules! impl_address_from {
437    ($type_name:ident) => {
438        impl From<$type_name> for Address {
439            fn from(item: $type_name) -> Self {
440                Self { 0: item as umem }
441            }
442        }
443
444        impl<T: ?Sized> From<Pointer<$type_name, T>> for Address {
445            #[inline(always)]
446            fn from(ptr: Pointer<$type_name, T>) -> Self {
447                Self {
448                    0: ptr.inner as umem,
449                }
450            }
451        }
452    };
453}
454
455// u16, u32, u64 is handled by the PrimitiveAddress implementation below.
456impl_address_from!(i8);
457impl_address_from!(u8);
458impl_address_from!(i16);
459//impl_address_from!(u16);
460impl_address_from!(i32);
461//impl_address_from!(u32);
462impl_address_from!(i64);
463//impl_address_from!(u64);
464impl_address_from!(usize);
465#[cfg(all(feature = "128_bit_mem", not(feature = "64_bit_mem")))]
466impl_address_from!(i128);
467
468/// Converts any `PrimitiveAddress` into an Address.
469impl<U: PrimitiveAddress> From<U> for Address {
470    #[inline(always)]
471    fn from(val: U) -> Self {
472        Self(val.to_umem())
473    }
474}
475
476/// Converts a `PhysicalAddress` into a `Address`.
477impl From<PhysicalAddress> for Address {
478    fn from(address: PhysicalAddress) -> Self {
479        address.address
480    }
481}
482
483/// Converts any `Pointer` into an Address.
484impl<U: PrimitiveAddress, T: ?Sized> From<Pointer<U, T>> for Address {
485    #[inline(always)]
486    fn from(ptr: Pointer<U, T>) -> Self {
487        Self(ptr.inner.to_umem())
488    }
489}
490
491#[macro_export]
492macro_rules! impl_address_arithmetic_unsigned {
493    ($type_name:ident) => {
494        impl ops::Add<$type_name> for Address {
495            type Output = Self;
496
497            fn add(self, other: $type_name) -> Self {
498                Self {
499                    0: self.0 + (other as umem),
500                }
501            }
502        }
503
504        impl ops::AddAssign<$type_name> for Address {
505            fn add_assign(&mut self, other: $type_name) {
506                *self = Self {
507                    0: self.0 + (other as umem),
508                }
509            }
510        }
511
512        impl ops::Sub<$type_name> for Address {
513            type Output = Address;
514
515            fn sub(self, other: $type_name) -> Address {
516                Self {
517                    0: self.0 - (other as umem),
518                }
519            }
520        }
521
522        impl ops::SubAssign<$type_name> for Address {
523            fn sub_assign(&mut self, other: $type_name) {
524                *self = Self {
525                    0: self.0 - (other as umem),
526                }
527            }
528        }
529    };
530}
531
532#[macro_export]
533macro_rules! impl_address_arithmetic_signed {
534    ($type_name:ident) => {
535        impl ops::Add<$type_name> for Address {
536            type Output = Self;
537
538            fn add(self, other: $type_name) -> Self {
539                if other >= 0 {
540                    Self {
541                        0: self.0 + (other as umem),
542                    }
543                } else {
544                    Self {
545                        0: self.0 - (-other as umem),
546                    }
547                }
548            }
549        }
550
551        impl ops::AddAssign<$type_name> for Address {
552            fn add_assign(&mut self, other: $type_name) {
553                if other >= 0 {
554                    *self = Self {
555                        0: self.0 + (other as umem),
556                    }
557                } else {
558                    *self = Self {
559                        0: self.0 - (-other as umem),
560                    }
561                }
562            }
563        }
564
565        impl ops::Sub<$type_name> for Address {
566            type Output = Address;
567
568            fn sub(self, other: $type_name) -> Address {
569                if other >= 0 {
570                    Self {
571                        0: self.0 - (other as umem),
572                    }
573                } else {
574                    Self {
575                        0: self.0 + (-other as umem),
576                    }
577                }
578            }
579        }
580
581        impl ops::SubAssign<$type_name> for Address {
582            fn sub_assign(&mut self, other: $type_name) {
583                if other >= 0 {
584                    *self = Self {
585                        0: self.0 - (other as umem),
586                    }
587                } else {
588                    *self = Self {
589                        0: self.0 + (-other as umem),
590                    }
591                }
592            }
593        }
594    };
595}
596
597impl_address_arithmetic_signed!(i8);
598impl_address_arithmetic_signed!(i16);
599impl_address_arithmetic_signed!(i32);
600impl_address_arithmetic_signed!(i64);
601#[cfg(all(feature = "128_bit_mem", not(feature = "64_bit_mem")))]
602impl_address_arithmetic_signed!(i128);
603impl_address_arithmetic_signed!(isize);
604impl_address_arithmetic_unsigned!(u8);
605impl_address_arithmetic_unsigned!(u16);
606impl_address_arithmetic_unsigned!(u32);
607impl_address_arithmetic_unsigned!(u64);
608#[cfg(all(feature = "128_bit_mem", not(feature = "64_bit_mem")))]
609impl_address_arithmetic_unsigned!(u128);
610impl_address_arithmetic_unsigned!(usize);
611
612/// Adds any compatible type reference to Address
613impl<'a, T: Into<umem> + Copy> ops::Add<&'a T> for Address {
614    type Output = Self;
615
616    fn add(self, other: &'a T) -> Self {
617        Self(self.0 + (*other).into())
618    }
619}
620
621/// Subtracts any compatible type reference to Address
622impl<'a, T: Into<umem> + Copy> ops::Sub<&'a T> for Address {
623    type Output = Self;
624
625    fn sub(self, other: &'a T) -> Self {
626        Self(self.0 - (*other).into())
627    }
628}
629
630/// Subtracts a `Address` from a `Address` resulting in a `umem`.
631///
632/// # Examples
633///
634/// ```
635/// use memflow::types::Address;
636///
637/// assert_eq!(Address::from(10) - 5, Address::from(5));
638/// ```
639impl ops::Sub for Address {
640    type Output = imem;
641
642    fn sub(self, other: Self) -> imem {
643        if self.0 > other.0 {
644            (self.0 - other.0) as imem
645        } else {
646            -((other.0 - self.0) as imem)
647        }
648    }
649}
650
651impl fmt::Debug for Address {
652    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
653        write!(f, "{:x}", self.0)
654    }
655}
656impl fmt::UpperHex for Address {
657    #[inline(always)]
658    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
659        write!(f, "{:X}", self.0)
660    }
661}
662impl fmt::LowerHex for Address {
663    #[inline(always)]
664    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
665        write!(f, "{:x}", self.0)
666    }
667}
668impl fmt::Display for Address {
669    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
670        write!(f, "{:x}", self.0)
671    }
672}
673
674#[cfg(test)]
675mod tests {
676    use super::super::size;
677    use super::*;
678
679    #[test]
680    fn test_null_valid() {
681        assert!(Address::null().is_null());
682        assert!(!Address::invalid().is_valid());
683    }
684
685    #[test]
686    fn test_from() {
687        assert_eq!(Address::from(1337_u32).to_umem(), 1337);
688        assert_eq!(Address::from(4321_u64).to_umem(), 4321);
689    }
690
691    #[test]
692    fn test_alignment() {
693        assert_eq!(
694            Address::from(0x1234_u64).as_page_aligned(size::kb(4)),
695            Address::from(0x1000_u64)
696        );
697        assert_eq!(
698            Address::from(0xFFF1_2345_u64).as_page_aligned(0x10000),
699            Address::from(0xFFF1_0000_u64)
700        );
701    }
702
703    #[test]
704    fn test_bits() {
705        assert!(Address::from(1_u64).bit_at(0));
706        assert!(!Address::from(1_u64).bit_at(1));
707        assert!(!Address::from(1_u64).bit_at(2));
708        assert!(!Address::from(1_u64).bit_at(3));
709
710        assert!(!Address::from(2_u64).bit_at(0));
711        assert!(Address::from(2_u64).bit_at(1));
712        assert!(!Address::from(2_u64).bit_at(2));
713        assert!(!Address::from(2_u64).bit_at(3));
714
715        assert!(Address::from(13_u64).bit_at(0));
716        assert!(!Address::from(13_u64).bit_at(1));
717        assert!(Address::from(13_u64).bit_at(2));
718        assert!(Address::from(13_u64).bit_at(3));
719    }
720
721    #[test]
722    fn test_bit_mask() {
723        assert_eq!(Address::bit_mask(0..=11).to_umem(), 0xfff);
724        assert_eq!(Address::bit_mask(12..=20).to_umem(), 0x001f_f000);
725        assert_eq!(Address::bit_mask(21..=29).to_umem(), 0x3fe0_0000);
726        assert_eq!(Address::bit_mask(30..=38).to_umem(), 0x007f_c000_0000);
727        assert_eq!(Address::bit_mask(39..=47).to_umem(), 0xff80_0000_0000);
728        assert_eq!(Address::bit_mask(12..=51).to_umem(), 0x000f_ffff_ffff_f000);
729    }
730
731    #[test]
732    fn test_bit_mask_u8() {
733        assert_eq!(Address::bit_mask_u8(0..=11).to_umem(), 0xfff);
734        assert_eq!(Address::bit_mask_u8(12..=20).to_umem(), 0x001f_f000);
735        assert_eq!(Address::bit_mask_u8(21..=29).to_umem(), 0x3fe0_0000);
736        assert_eq!(Address::bit_mask_u8(30..=38).to_umem(), 0x007f_c000_0000);
737        assert_eq!(Address::bit_mask_u8(39..=47).to_umem(), 0xff80_0000_0000);
738        assert_eq!(
739            Address::bit_mask_u8(12..=51).to_umem(),
740            0x000f_ffff_ffff_f000
741        );
742    }
743
744    #[test]
745    fn test_ops() {
746        assert_eq!(Address::from(10_u64) + 5usize, Address::from(15_u64));
747
748        assert_eq!(Address::from(10_u64) - Address::from(5_u64), 5);
749        assert_eq!(Address::from(100_u64) - 5usize, Address::from(95_u64));
750    }
751}