// SPDX-License-Identifier: MIT OR Apache-2.0 // // Copyright (c) 2018-2021 Andre Richter //! Memory Management. pub mod mmu; use crate::common; use core::{ fmt, marker::PhantomData, ops::{AddAssign, RangeInclusive, SubAssign}, }; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. pub trait AddressType: Copy + Clone + PartialOrd + PartialEq {} /// Zero-sized type to mark a physical address. #[derive(Copy, Clone, PartialOrd, PartialEq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. #[derive(Copy, Clone, PartialOrd, PartialEq)] pub enum Virtual {} /// Generic address type. #[derive(Copy, Clone, PartialOrd, PartialEq)] pub struct Address { value: usize, _address_type: PhantomData ATYPE>, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- impl AddressType for Physical {} impl AddressType for Virtual {} impl Address { /// Create an instance. pub const fn new(value: usize) -> Self { Self { value, _address_type: PhantomData, } } /// Align down. pub const fn align_down(self, alignment: usize) -> Self { let aligned = common::align_down(self.value, alignment); Self { value: aligned, _address_type: PhantomData, } } /// Converts `Address` into an usize. pub const fn into_usize(self) -> usize { self.value } } impl core::ops::Add for Address { type Output = Self; fn add(self, other: usize) -> Self { Self { value: self.value + other, _address_type: PhantomData, } } } impl AddAssign for Address { fn add_assign(&mut self, other: Self) { *self = Self { value: self.value + other.into_usize(), _address_type: PhantomData, }; } } impl core::ops::Sub for Address { type Output = Self; fn sub(self, other: usize) -> Self { Self { value: self.value - other, _address_type: PhantomData, } } } impl SubAssign for Address { fn sub_assign(&mut self, other: Self) { *self = Self { value: self.value - other.into_usize(), _address_type: PhantomData, }; } } impl fmt::Display for Address { // Don't expect to see physical addresses greater than 40 bit. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let q3: u8 = ((self.value >> 32) & 0xff) as u8; let q2: u16 = ((self.value >> 16) & 0xffff) as u16; let q1: u16 = (self.value & 0xffff) as u16; write!(f, "0x")?; write!(f, "{:02x}_", q3)?; write!(f, "{:04x}_", q2)?; write!(f, "{:04x}", q1) } } impl fmt::Display for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let q4: u16 = ((self.value >> 48) & 0xffff) as u16; let q3: u16 = ((self.value >> 32) & 0xffff) as u16; let q2: u16 = ((self.value >> 16) & 0xffff) as u16; let q1: u16 = (self.value & 0xffff) as u16; write!(f, "0x")?; write!(f, "{:04x}_", q4)?; write!(f, "{:04x}_", q3)?; write!(f, "{:04x}_", q2)?; write!(f, "{:04x}", q1) } } /// Zero out an inclusive memory range. /// /// # Safety /// /// - `range.start` and `range.end` must be valid. /// - `range.start` and `range.end` must be `T` aligned. pub unsafe fn zero_volatile(range: RangeInclusive<*mut T>) where T: From, { let mut ptr = *range.start(); let end_inclusive = *range.end(); while ptr <= end_inclusive { core::ptr::write_volatile(ptr, T::from(0)); ptr = ptr.offset(1); } } //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- #[cfg(test)] mod tests { use super::*; use test_macros::kernel_test; /// Check `zero_volatile()`. #[kernel_test] fn zero_volatile_works() { let mut x: [usize; 3] = [10, 11, 12]; let x_range = x.as_mut_ptr_range(); let x_range_inclusive = RangeInclusive::new(x_range.start, unsafe { x_range.end.offset(-1) }); unsafe { zero_volatile(x_range_inclusive) }; assert_eq!(x, [0, 0, 0]); } /// Check `bss` section layout. #[kernel_test] fn bss_section_is_sane() { use crate::bsp::memory::bss_range_inclusive; use core::mem; let start = *bss_range_inclusive().start() as usize; let end = *bss_range_inclusive().end() as usize; assert_eq!(start % mem::size_of::(), 0); assert_eq!(end % mem::size_of::(), 0); assert!(end >= start); } }