You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
5.7 KiB
Rust
172 lines
5.7 KiB
Rust
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
//
|
|
// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
//! BSP Memory Management Unit.
|
|
|
|
use crate::{
|
|
common,
|
|
memory::{
|
|
mmu as kernel_mmu,
|
|
mmu::{
|
|
interface, AccessPermissions, AttributeFields, Granule64KiB, MemAttributes, Page,
|
|
PageSliceDescriptor, Physical, Virtual,
|
|
},
|
|
},
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Public Definitions
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to
|
|
/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`.
|
|
pub type KernelGranule = Granule64KiB;
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Private Code
|
|
//--------------------------------------------------------------------------------------------------
|
|
use interface::TranslationGranule;
|
|
|
|
/// Helper function for calculating the number of pages the given parameter spans.
|
|
const fn size_to_num_pages(size: usize) -> usize {
|
|
assert!(size > 0);
|
|
assert!(size % KernelGranule::SIZE == 0);
|
|
|
|
size >> KernelGranule::SHIFT
|
|
}
|
|
|
|
/// The boot core's stack.
|
|
fn virt_stack_page_desc() -> PageSliceDescriptor<Virtual> {
|
|
let num_pages = size_to_num_pages(super::boot_core_stack_size());
|
|
|
|
PageSliceDescriptor::from_addr(super::virt_boot_core_stack_start(), num_pages)
|
|
}
|
|
|
|
/// The Read-Only (RO) pages of the kernel binary.
|
|
fn virt_ro_page_desc() -> PageSliceDescriptor<Virtual> {
|
|
let num_pages = size_to_num_pages(super::ro_size());
|
|
|
|
PageSliceDescriptor::from_addr(super::virt_ro_start(), num_pages)
|
|
}
|
|
|
|
/// The data pages of the kernel binary.
|
|
fn virt_data_page_desc() -> PageSliceDescriptor<Virtual> {
|
|
let num_pages = size_to_num_pages(super::data_size());
|
|
|
|
PageSliceDescriptor::from_addr(super::virt_data_start(), num_pages)
|
|
}
|
|
|
|
// The binary is still identity mapped, so we don't need to convert in the following.
|
|
|
|
/// The boot core's stack.
|
|
fn phys_stack_page_desc() -> PageSliceDescriptor<Physical> {
|
|
virt_stack_page_desc().into()
|
|
}
|
|
|
|
/// The Read-Only (RO) pages of the kernel binary.
|
|
fn phys_ro_page_desc() -> PageSliceDescriptor<Physical> {
|
|
virt_ro_page_desc().into()
|
|
}
|
|
|
|
/// The data pages of the kernel binary.
|
|
fn phys_data_page_desc() -> PageSliceDescriptor<Physical> {
|
|
virt_data_page_desc().into()
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Public Code
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
/// Pointer to the last page of the physical address space.
|
|
pub fn phys_addr_space_end_page() -> *const Page<Physical> {
|
|
common::align_down(
|
|
super::phys_addr_space_end().into_usize(),
|
|
KernelGranule::SIZE,
|
|
) as *const Page<_>
|
|
}
|
|
|
|
/// Map the kernel binary.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// - Any miscalculation or attribute error will likely be fatal. Needs careful manual checking.
|
|
pub unsafe fn kernel_map_binary() -> Result<(), &'static str> {
|
|
kernel_mmu::kernel_map_pages_at(
|
|
"Kernel boot-core stack",
|
|
&phys_stack_page_desc(),
|
|
&virt_stack_page_desc(),
|
|
&AttributeFields {
|
|
mem_attributes: MemAttributes::CacheableDRAM,
|
|
acc_perms: AccessPermissions::ReadWrite,
|
|
execute_never: true,
|
|
},
|
|
)?;
|
|
|
|
kernel_mmu::kernel_map_pages_at(
|
|
"Kernel code and RO data",
|
|
&phys_ro_page_desc(),
|
|
&virt_ro_page_desc(),
|
|
&AttributeFields {
|
|
mem_attributes: MemAttributes::CacheableDRAM,
|
|
acc_perms: AccessPermissions::ReadOnly,
|
|
execute_never: false,
|
|
},
|
|
)?;
|
|
|
|
kernel_mmu::kernel_map_pages_at(
|
|
"Kernel data and bss",
|
|
&phys_data_page_desc(),
|
|
&virt_data_page_desc(),
|
|
&AttributeFields {
|
|
mem_attributes: MemAttributes::CacheableDRAM,
|
|
acc_perms: AccessPermissions::ReadWrite,
|
|
execute_never: true,
|
|
},
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// 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() {
|
|
for i in [virt_stack_page_desc, virt_ro_page_desc, virt_data_page_desc].iter() {
|
|
let start: usize = i().start_addr().into_usize();
|
|
let end: usize = i().end_addr().into_usize();
|
|
|
|
assert_eq!(start % KernelGranule::SIZE, 0);
|
|
assert_eq!(end % KernelGranule::SIZE, 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_stack_page_desc().into_usize_range_inclusive(),
|
|
virt_ro_page_desc().into_usize_range_inclusive(),
|
|
virt_data_page_desc().into_usize_range_inclusive(),
|
|
];
|
|
|
|
for (i, first_range) in layout.iter().enumerate() {
|
|
for second_range in layout.iter().skip(i + 1) {
|
|
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()));
|
|
}
|
|
}
|
|
}
|
|
}
|