// SPDX-License-Identifier: MIT OR Apache-2.0 // // Copyright (c) 2018-2023 Andre Richter //! Memory Management. pub mod mmu; use crate::{bsp, common}; use core::{ fmt, marker::PhantomData, ops::{Add, Sub}, }; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- /// Metadata trait for marking the type of an address. pub trait AddressType: Copy + Clone + PartialOrd + PartialEq + Ord + Eq {} /// Zero-sized type to mark a physical address. #[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Physical {} /// Zero-sized type to mark a virtual address. #[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub enum Virtual {} /// Generic address type. #[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] 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, } } /// Convert to usize. pub const fn as_usize(self) -> usize { self.value } /// Align down to page size. #[must_use] pub const fn align_down_page(self) -> Self { let aligned = common::align_down(self.value, bsp::memory::mmu::KernelGranule::SIZE); Self::new(aligned) } /// Align up to page size. #[must_use] pub const fn align_up_page(self) -> Self { let aligned = common::align_up(self.value, bsp::memory::mmu::KernelGranule::SIZE); Self::new(aligned) } /// Checks if the address is page aligned. pub const fn is_page_aligned(&self) -> bool { common::is_aligned(self.value, bsp::memory::mmu::KernelGranule::SIZE) } /// Return the address' offset into the corresponding page. pub const fn offset_into_page(&self) -> usize { self.value & bsp::memory::mmu::KernelGranule::MASK } } impl Add for Address { type Output = Self; #[inline(always)] fn add(self, rhs: usize) -> Self::Output { match self.value.checked_add(rhs) { None => panic!("Overflow on Address::add"), Some(x) => Self::new(x), } } } impl Sub> for Address { type Output = Self; #[inline(always)] fn sub(self, rhs: Address) -> Self::Output { match self.value.checked_sub(rhs.value) { None => panic!("Overflow on Address::sub"), Some(x) => Self::new(x), } } } 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) } } //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- #[cfg(test)] mod tests { use super::*; use test_macros::kernel_test; /// Sanity of [Address] methods. #[kernel_test] fn address_type_method_sanity() { let addr = Address::::new(bsp::memory::mmu::KernelGranule::SIZE + 100); assert_eq!( addr.align_down_page().as_usize(), bsp::memory::mmu::KernelGranule::SIZE ); assert_eq!( addr.align_up_page().as_usize(), bsp::memory::mmu::KernelGranule::SIZE * 2 ); assert!(!addr.is_page_aligned()); assert_eq!(addr.offset_into_page(), 100); } }