// SPDX-License-Identifier: MIT OR Apache-2.0 // // Copyright (c) 2018-2021 Andre Richter //! BSP Memory Management Unit. use super::map as memory_map; use crate::memory::mmu::*; use core::ops::RangeInclusive; //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- const NUM_MEM_RANGES: usize = 2; /// The virtual memory layout. /// /// The layout must contain only special ranges, aka anything that is _not_ normal cacheable DRAM. /// It is agnostic of the paging granularity that the architecture's MMU will use. pub static LAYOUT: KernelVirtualLayout<{ NUM_MEM_RANGES }> = KernelVirtualLayout::new( memory_map::END_INCLUSIVE, [ TranslationDescriptor { name: "Kernel code and RO data", virtual_range: ro_range_inclusive, physical_range_translation: Translation::Identity, attribute_fields: AttributeFields { mem_attributes: MemAttributes::CacheableDRAM, acc_perms: AccessPermissions::ReadOnly, execute_never: false, }, }, TranslationDescriptor { name: "Device MMIO", virtual_range: mmio_range_inclusive, physical_range_translation: Translation::Identity, attribute_fields: AttributeFields { mem_attributes: MemAttributes::Device, acc_perms: AccessPermissions::ReadWrite, execute_never: true, }, }, ], ); //-------------------------------------------------------------------------------------------------- // Private Code //-------------------------------------------------------------------------------------------------- fn ro_range_inclusive() -> RangeInclusive { // Notice the subtraction to turn the exclusive end into an inclusive end. #[allow(clippy::range_minus_one)] RangeInclusive::new(super::ro_start(), super::ro_end() - 1) } fn mmio_range_inclusive() -> RangeInclusive { RangeInclusive::new(memory_map::mmio::START, memory_map::mmio::END_INCLUSIVE) } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- /// Return the address space size in bytes. /// /// Guarantees size to be a power of two. pub const fn addr_space_size() -> usize { let size = memory_map::END_INCLUSIVE + 1; assert!(size.is_power_of_two()); size } /// Return a reference to the virtual memory layout. pub fn virt_mem_layout() -> &'static KernelVirtualLayout<{ NUM_MEM_RANGES }> { &LAYOUT } //-------------------------------------------------------------------------------------------------- // Testing //-------------------------------------------------------------------------------------------------- #[cfg(test)] mod tests { use super::*; use test_macros::kernel_test; /// Check alignment of the kernel's virtual memory layout sections. #[kernel_test] fn virt_mem_layout_sections_are_64KiB_aligned() { const SIXTYFOUR_KIB: usize = 65536; for i in LAYOUT.inner().iter() { let start: usize = *(i.virtual_range)().start(); let end: usize = *(i.virtual_range)().end() + 1; assert_eq!(start % SIXTYFOUR_KIB, 0); assert_eq!(end % SIXTYFOUR_KIB, 0); assert!(end >= start); } } /// Ensure the kernel's virtual memory layout is free of overlaps. #[kernel_test] fn virt_mem_layout_has_no_overlaps() { let layout = virt_mem_layout().inner(); for (i, first) in layout.iter().enumerate() { for second in layout.iter().skip(i + 1) { let first_range = first.virtual_range; let second_range = second.virtual_range; assert!(!first_range().contains(second_range().start())); assert!(!first_range().contains(second_range().end())); assert!(!second_range().contains(first_range().start())); assert!(!second_range().contains(first_range().end())); } } } }