diff --git a/05_safe_globals/README.md b/05_safe_globals/README.md index 51fe8053..78984217 100644 --- a/05_safe_globals/README.md +++ b/05_safe_globals/README.md @@ -55,7 +55,7 @@ make qemu diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/src/arch/aarch64/sync.rs --- 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs +++ 05_safe_globals/src/arch/aarch64/sync.rs -@@ -0,0 +1,44 @@ +@@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter @@ -65,6 +65,10 @@ diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/ +use crate::interface; +use core::cell::UnsafeCell; + ++//-------------------------------------------------------------------------------------------------- ++// Arch-public ++//-------------------------------------------------------------------------------------------------- ++ +/// A pseudo-lock for teaching purposes. +/// +/// Used to introduce [interior mutability]. @@ -91,6 +95,10 @@ diff -uNr 04_zero_overhead_abstraction/src/arch/aarch64/sync.rs 05_safe_globals/ + } +} + ++//-------------------------------------------------------------------------------------------------- ++// OS interface implementations ++//-------------------------------------------------------------------------------------------------- ++ +impl interface::sync::Mutex for &NullLock { + type Data = T; + diff --git a/05_safe_globals/src/arch/aarch64/sync.rs b/05_safe_globals/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/05_safe_globals/src/arch/aarch64/sync.rs +++ b/05_safe_globals/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/06_drivers_gpio_uart/kernel b/06_drivers_gpio_uart/kernel index 1dfc7228..bb9ebb9f 100755 Binary files a/06_drivers_gpio_uart/kernel and b/06_drivers_gpio_uart/kernel differ diff --git a/06_drivers_gpio_uart/kernel8.img b/06_drivers_gpio_uart/kernel8.img index f5878447..8390c832 100755 Binary files a/06_drivers_gpio_uart/kernel8.img and b/06_drivers_gpio_uart/kernel8.img differ diff --git a/06_drivers_gpio_uart/src/arch/aarch64/sync.rs b/06_drivers_gpio_uart/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/06_drivers_gpio_uart/src/arch/aarch64/sync.rs +++ b/06_drivers_gpio_uart/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/07_uart_chainloader/kernel b/07_uart_chainloader/kernel index 210c2c01..d9c547fa 100755 Binary files a/07_uart_chainloader/kernel and b/07_uart_chainloader/kernel differ diff --git a/07_uart_chainloader/kernel8.img b/07_uart_chainloader/kernel8.img index 054d436b..88748df9 100755 Binary files a/07_uart_chainloader/kernel8.img and b/07_uart_chainloader/kernel8.img differ diff --git a/07_uart_chainloader/src/arch/aarch64/sync.rs b/07_uart_chainloader/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/07_uart_chainloader/src/arch/aarch64/sync.rs +++ b/07_uart_chainloader/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/08_timestamps/README.md b/08_timestamps/README.md index 315c19c6..5ee2f065 100644 --- a/08_timestamps/README.md +++ b/08_timestamps/README.md @@ -100,7 +100,7 @@ diff -uNr 07_uart_chainloader/Makefile 08_timestamps/Makefile diff -uNr 07_uart_chainloader/src/arch/aarch64/time.rs 08_timestamps/src/arch/aarch64/time.rs --- 07_uart_chainloader/src/arch/aarch64/time.rs +++ 08_timestamps/src/arch/aarch64/time.rs -@@ -0,0 +1,77 @@ +@@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter @@ -113,8 +113,16 @@ diff -uNr 07_uart_chainloader/src/arch/aarch64/time.rs 08_timestamps/src/arch/aa + +const NS_PER_S: u64 = 1_000_000_000; + ++//-------------------------------------------------------------------------------------------------- ++// Arch-public ++//-------------------------------------------------------------------------------------------------- ++ +pub struct Timer; + ++//-------------------------------------------------------------------------------------------------- ++// OS interface implementations ++//-------------------------------------------------------------------------------------------------- ++ +impl interface::time::Timer for Timer { + fn resolution(&self) -> Duration { + Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) diff --git a/08_timestamps/kernel b/08_timestamps/kernel index 080fe56a..c83e3f47 100755 Binary files a/08_timestamps/kernel and b/08_timestamps/kernel differ diff --git a/08_timestamps/kernel8.img b/08_timestamps/kernel8.img index c65aaf00..8e20b916 100755 Binary files a/08_timestamps/kernel8.img and b/08_timestamps/kernel8.img differ diff --git a/08_timestamps/src/arch/aarch64/sync.rs b/08_timestamps/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/08_timestamps/src/arch/aarch64/sync.rs +++ b/08_timestamps/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/08_timestamps/src/arch/aarch64/time.rs b/08_timestamps/src/arch/aarch64/time.rs index a6c9d50c..bbddd5e0 100644 --- a/08_timestamps/src/arch/aarch64/time.rs +++ b/08_timestamps/src/arch/aarch64/time.rs @@ -10,8 +10,16 @@ use cortex_a::regs::*; const NS_PER_S: u64 = 1_000_000_000; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + pub struct Timer; +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::time::Timer for Timer { fn resolution(&self) -> Duration { Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) diff --git a/09_hw_debug_JTAG/kernel b/09_hw_debug_JTAG/kernel index 952a835e..c83e3f47 100755 Binary files a/09_hw_debug_JTAG/kernel and b/09_hw_debug_JTAG/kernel differ diff --git a/09_hw_debug_JTAG/kernel8.img b/09_hw_debug_JTAG/kernel8.img index ff216356..8e20b916 100755 Binary files a/09_hw_debug_JTAG/kernel8.img and b/09_hw_debug_JTAG/kernel8.img differ diff --git a/09_hw_debug_JTAG/src/arch/aarch64/sync.rs b/09_hw_debug_JTAG/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/09_hw_debug_JTAG/src/arch/aarch64/sync.rs +++ b/09_hw_debug_JTAG/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/09_hw_debug_JTAG/src/arch/aarch64/time.rs b/09_hw_debug_JTAG/src/arch/aarch64/time.rs index a6c9d50c..bbddd5e0 100644 --- a/09_hw_debug_JTAG/src/arch/aarch64/time.rs +++ b/09_hw_debug_JTAG/src/arch/aarch64/time.rs @@ -10,8 +10,16 @@ use cortex_a::regs::*; const NS_PER_S: u64 = 1_000_000_000; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + pub struct Timer; +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::time::Timer for Timer { fn resolution(&self) -> Duration { Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) diff --git a/10_privilege_level/README.md b/10_privilege_level/README.md index 2339514a..e254ab0b 100644 --- a/10_privilege_level/README.md +++ b/10_privilege_level/README.md @@ -213,7 +213,7 @@ make chainbot diff -uNr 09_hw_debug_JTAG/src/arch/aarch64/exception.rs 10_privilege_level/src/arch/aarch64/exception.rs --- 09_hw_debug_JTAG/src/arch/aarch64/exception.rs +++ 10_privilege_level/src/arch/aarch64/exception.rs -@@ -0,0 +1,44 @@ +@@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter @@ -222,6 +222,10 @@ diff -uNr 09_hw_debug_JTAG/src/arch/aarch64/exception.rs 10_privilege_level/src/ + +use cortex_a::regs::*; + ++//-------------------------------------------------------------------------------------------------- ++// Arch-public ++//-------------------------------------------------------------------------------------------------- ++ +pub trait DaifField { + fn daif_field() -> register::Field; +} @@ -339,7 +343,7 @@ diff -uNr 09_hw_debug_JTAG/src/arch/aarch64.rs 10_privilege_level/src/arch/aarch +pub mod state { + use cortex_a::regs::*; + -+ /// The current privilege level. ++ /// The processing element's current privilege level. + pub fn current_privilege_level() -> &'static str { + let el = CurrentEL.read_as_enum(CurrentEL::EL); + match el { diff --git a/10_privilege_level/kernel b/10_privilege_level/kernel index e369ead6..9d4d1590 100755 Binary files a/10_privilege_level/kernel and b/10_privilege_level/kernel differ diff --git a/10_privilege_level/kernel8.img b/10_privilege_level/kernel8.img index aa01e32f..3f2d3ab9 100755 Binary files a/10_privilege_level/kernel8.img and b/10_privilege_level/kernel8.img differ diff --git a/10_privilege_level/src/arch/aarch64.rs b/10_privilege_level/src/arch/aarch64.rs index d20dfe4d..7427441a 100644 --- a/10_privilege_level/src/arch/aarch64.rs +++ b/10_privilege_level/src/arch/aarch64.rs @@ -108,7 +108,7 @@ pub fn wait_forever() -> ! { pub mod state { use cortex_a::regs::*; - /// The current privilege level. + /// The processing element's current privilege level. pub fn current_privilege_level() -> &'static str { let el = CurrentEL.read_as_enum(CurrentEL::EL); match el { diff --git a/10_privilege_level/src/arch/aarch64/exception.rs b/10_privilege_level/src/arch/aarch64/exception.rs index 27939b84..f8d33f94 100644 --- a/10_privilege_level/src/arch/aarch64/exception.rs +++ b/10_privilege_level/src/arch/aarch64/exception.rs @@ -6,6 +6,10 @@ use cortex_a::regs::*; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + pub trait DaifField { fn daif_field() -> register::Field; } diff --git a/10_privilege_level/src/arch/aarch64/sync.rs b/10_privilege_level/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/10_privilege_level/src/arch/aarch64/sync.rs +++ b/10_privilege_level/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/10_privilege_level/src/arch/aarch64/time.rs b/10_privilege_level/src/arch/aarch64/time.rs index a6c9d50c..bbddd5e0 100644 --- a/10_privilege_level/src/arch/aarch64/time.rs +++ b/10_privilege_level/src/arch/aarch64/time.rs @@ -10,8 +10,16 @@ use cortex_a::regs::*; const NS_PER_S: u64 = 1_000_000_000; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + pub struct Timer; +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::time::Timer for Timer { fn resolution(&self) -> Duration { Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) diff --git a/11_virtual_memory/README.md b/11_virtual_memory/README.md index bcecf698..3d1d11bd 100644 --- a/11_virtual_memory/README.md +++ b/11_virtual_memory/README.md @@ -262,10 +262,23 @@ make chainbot ## Diff to previous ```diff +diff -uNr 10_privilege_level/Makefile 11_virtual_memory/Makefile +--- 10_privilege_level/Makefile ++++ 11_virtual_memory/Makefile +@@ -17,7 +17,7 @@ + OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg + JTAG_BOOT_IMAGE = jtag_boot_rpi3.img + LINKER_FILE = src/bsp/rpi/link.ld +- RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 ++ RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C llvm-args=-ffixed-x18 + else ifeq ($(BSP),rpi4) + TARGET = aarch64-unknown-none-softfloat + OUTPUT = kernel8.img + diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/aarch64/mmu.rs --- 10_privilege_level/src/arch/aarch64/mmu.rs +++ 11_virtual_memory/src/arch/aarch64/mmu.rs -@@ -0,0 +1,309 @@ +@@ -0,0 +1,316 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter @@ -275,7 +288,7 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ +//! Static page tables, compiled on boot; Everything 64 KiB granule. + +use crate::{ -+ bsp, ++ bsp, interface, + memory::{AccessPermissions, AttributeFields, MemAttributes}, +}; +use core::convert; @@ -511,10 +524,7 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + let virt_addr = (l2_nr << FIVETWELVE_MIB_SHIFT) + (l3_nr << SIXTYFOUR_KIB_SHIFT); + + let (output_addr, attribute_fields) = -+ match bsp::virt_mem_layout().get_virt_addr_properties(virt_addr) { -+ Err(string) => return Err(string), -+ Ok((a, b)) => (a, b), -+ }; ++ bsp::virt_mem_layout().get_virt_addr_properties(virt_addr)?; + + *l3_entry = PageDescriptor::new(output_addr, attribute_fields).into(); + } @@ -538,42 +548,52 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + ); +} + -+/// Compile the page tables from the `BSP`-supplied `virt_mem_layout()`. -+/// -+/// # Safety -+/// -+/// - User must ensure that the hardware supports the paremeters being set here. -+pub unsafe fn init() -> Result<(), &'static str> { -+ // Fail early if translation granule is not supported. Both RPis support it, though. -+ if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported) { -+ return Err("64 KiB translation granule not supported"); -+ } ++//-------------------------------------------------------------------------------------------------- ++// Arch-public ++//-------------------------------------------------------------------------------------------------- + -+ // Prepare the memory attribute indirection register. -+ set_up_mair(); ++pub struct MMU; + -+ // Populate page tables. -+ if let Err(string) = populate_pt_entries() { -+ return Err(string); -+ } ++//-------------------------------------------------------------------------------------------------- ++// OS interface implementations ++//-------------------------------------------------------------------------------------------------- + -+ // Set the "Translation Table Base Register". -+ TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64()); ++impl interface::mm::MMU for MMU { ++ /// Compile the page tables from the `BSP`-supplied `virt_mem_layout()`. ++ /// ++ /// # Safety ++ /// ++ /// - User must ensure that the hardware supports the paremeters being set here. ++ unsafe fn init(&self) -> Result<(), &'static str> { ++ // Fail early if translation granule is not supported. Both RPis support it, though. ++ if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported) { ++ return Err("64 KiB translation granule not supported"); ++ } + -+ configure_translation_control(); ++ // Prepare the memory attribute indirection register. ++ set_up_mair(); + -+ // Switch the MMU on. -+ // -+ // First, force all previous changes to be seen before the MMU is enabled. -+ barrier::isb(barrier::SY); ++ // Populate page tables. ++ populate_pt_entries()?; + -+ // Enable the MMU and turn on data and instruction caching. -+ SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); ++ // Set the "Translation Table Base Register". ++ TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64()); + -+ // Force MMU init to complete before next instruction -+ barrier::isb(barrier::SY); ++ configure_translation_control(); + -+ Ok(()) ++ // Switch the MMU on. ++ // ++ // First, force all previous changes to be seen before the MMU is enabled. ++ barrier::isb(barrier::SY); ++ ++ // Enable the MMU and turn on data and instruction caching. ++ SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); ++ ++ // Force MMU init to complete before next instruction ++ barrier::isb(barrier::SY); ++ ++ Ok(()) ++ } +} diff -uNr 10_privilege_level/src/arch/aarch64.rs 11_virtual_memory/src/arch/aarch64.rs @@ -583,10 +603,27 @@ diff -uNr 10_privilege_level/src/arch/aarch64.rs 11_virtual_memory/src/arch/aarc //! AArch64. mod exception; -+pub mod mmu; ++mod mmu; pub mod sync; mod time; +@@ -77,6 +78,7 @@ + //-------------------------------------------------------------------------------------------------- + + static TIMER: time::Timer = time::Timer; ++static MMU: mmu::MMU = mmu::MMU; + + //-------------------------------------------------------------------------------------------------- + // Implementation of the kernel's architecture abstraction code +@@ -136,3 +138,8 @@ + println!(" FIQ: {}", to_mask_str(exception::is_masked::())); + } + } ++ ++/// Return a reference to an `interface::mm::MMU` implementation. ++pub fn mmu() -> &'static impl interface::mm::MMU { ++ &MMU ++} diff -uNr 10_privilege_level/src/bsp/rpi/link.ld 11_virtual_memory/src/bsp/rpi/link.ld --- 10_privilege_level/src/bsp/rpi/link.ld @@ -637,7 +674,7 @@ diff -uNr 10_privilege_level/src/bsp/rpi/memory_map.rs 11_virtual_memory/src/bsp diff -uNr 10_privilege_level/src/bsp/rpi/virt_mem_layout.rs 11_virtual_memory/src/bsp/rpi/virt_mem_layout.rs --- 10_privilege_level/src/bsp/rpi/virt_mem_layout.rs +++ 11_virtual_memory/src/bsp/rpi/virt_mem_layout.rs -@@ -0,0 +1,78 @@ +@@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter @@ -651,6 +688,10 @@ diff -uNr 10_privilege_level/src/bsp/rpi/virt_mem_layout.rs 11_virtual_memory/sr +use crate::memory::*; +use core::ops::RangeInclusive; + ++//-------------------------------------------------------------------------------------------------- ++// BSP-public ++//-------------------------------------------------------------------------------------------------- ++ +pub const NUM_MEM_RANGES: usize = 3; + +pub static LAYOUT: KernelVirtualLayout<{ NUM_MEM_RANGES }> = KernelVirtualLayout::new( @@ -760,6 +801,22 @@ diff -uNr 10_privilege_level/src/bsp.rs 11_virtual_memory/src/bsp.rs #[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))] mod rpi; +diff -uNr 10_privilege_level/src/interface.rs 11_virtual_memory/src/interface.rs +--- 10_privilege_level/src/interface.rs ++++ 11_virtual_memory/src/interface.rs +@@ -127,3 +127,11 @@ + fn spin_for(&self, duration: Duration); + } + } ++ ++/// Memory Management interfaces. ++pub mod mm { ++ pub trait MMU { ++ /// Called by the kernel early during init. ++ unsafe fn init(&self) -> Result<(), &'static str>; ++ } ++} + diff -uNr 10_privilege_level/src/main.rs 11_virtual_memory/src/main.rs --- 10_privilege_level/src/main.rs +++ 11_virtual_memory/src/main.rs @@ -780,7 +837,7 @@ diff -uNr 10_privilege_level/src/main.rs 11_virtual_memory/src/main.rs mod panic_wait; mod print; -@@ -46,8 +49,16 @@ +@@ -46,8 +49,18 @@ /// # Safety /// /// - Only a single core must be active and running this function. @@ -791,14 +848,16 @@ diff -uNr 10_privilege_level/src/main.rs 11_virtual_memory/src/main.rs +/// drivers (which currently employ NullLocks instead of spinlocks), will fail to work on +/// the RPi SoCs. unsafe fn kernel_init() -> ! { -+ if let Err(string) = arch::mmu::init() { ++ use interface::mm::MMU; ++ ++ if let Err(string) = arch::mmu().init() { + panic!("MMU: {}", string); + } + for i in bsp::device_drivers().iter() { if let Err(()) = i.init() { panic!("Error loading driver: {}", i.compatible()) -@@ -67,6 +78,9 @@ +@@ -67,6 +80,9 @@ println!("Booting on: {}", bsp::board_name()); @@ -808,7 +867,7 @@ diff -uNr 10_privilege_level/src/main.rs 11_virtual_memory/src/main.rs println!( "Current privilege level: {}", arch::state::current_privilege_level() -@@ -87,6 +101,13 @@ +@@ -87,6 +103,13 @@ println!("Timer test, spinning for 1 second"); arch::timer().spin_for(Duration::from_secs(1)); diff --git a/11_virtual_memory/kernel b/11_virtual_memory/kernel index 5d890884..46086de7 100755 Binary files a/11_virtual_memory/kernel and b/11_virtual_memory/kernel differ diff --git a/11_virtual_memory/kernel8.img b/11_virtual_memory/kernel8.img index 450ae8c1..646cdc21 100755 Binary files a/11_virtual_memory/kernel8.img and b/11_virtual_memory/kernel8.img differ diff --git a/11_virtual_memory/src/arch/aarch64.rs b/11_virtual_memory/src/arch/aarch64.rs index 97f45fad..6f0ee250 100644 --- a/11_virtual_memory/src/arch/aarch64.rs +++ b/11_virtual_memory/src/arch/aarch64.rs @@ -5,7 +5,7 @@ //! AArch64. mod exception; -pub mod mmu; +mod mmu; pub mod sync; mod time; @@ -78,6 +78,7 @@ unsafe fn el2_to_el1_transition() -> ! { //-------------------------------------------------------------------------------------------------- static TIMER: time::Timer = time::Timer; +static MMU: mmu::MMU = mmu::MMU; //-------------------------------------------------------------------------------------------------- // Implementation of the kernel's architecture abstraction code @@ -109,7 +110,7 @@ pub fn wait_forever() -> ! { pub mod state { use cortex_a::regs::*; - /// The current privilege level. + /// The processing element's current privilege level. pub fn current_privilege_level() -> &'static str { let el = CurrentEL.read_as_enum(CurrentEL::EL); match el { @@ -137,3 +138,8 @@ pub mod state { println!(" FIQ: {}", to_mask_str(exception::is_masked::())); } } + +/// Return a reference to an `interface::mm::MMU` implementation. +pub fn mmu() -> &'static impl interface::mm::MMU { + &MMU +} diff --git a/11_virtual_memory/src/arch/aarch64/exception.rs b/11_virtual_memory/src/arch/aarch64/exception.rs index 27939b84..f8d33f94 100644 --- a/11_virtual_memory/src/arch/aarch64/exception.rs +++ b/11_virtual_memory/src/arch/aarch64/exception.rs @@ -6,6 +6,10 @@ use cortex_a::regs::*; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + pub trait DaifField { fn daif_field() -> register::Field; } diff --git a/11_virtual_memory/src/arch/aarch64/mmu.rs b/11_virtual_memory/src/arch/aarch64/mmu.rs index bdceefd3..a81e68de 100644 --- a/11_virtual_memory/src/arch/aarch64/mmu.rs +++ b/11_virtual_memory/src/arch/aarch64/mmu.rs @@ -7,7 +7,7 @@ //! Static page tables, compiled on boot; Everything 64 KiB granule. use crate::{ - bsp, + bsp, interface, memory::{AccessPermissions, AttributeFields, MemAttributes}, }; use core::convert; @@ -243,10 +243,7 @@ unsafe fn populate_pt_entries() -> Result<(), &'static str> { let virt_addr = (l2_nr << FIVETWELVE_MIB_SHIFT) + (l3_nr << SIXTYFOUR_KIB_SHIFT); let (output_addr, attribute_fields) = - match bsp::virt_mem_layout().get_virt_addr_properties(virt_addr) { - Err(string) => return Err(string), - Ok((a, b)) => (a, b), - }; + bsp::virt_mem_layout().get_virt_addr_properties(virt_addr)?; *l3_entry = PageDescriptor::new(output_addr, attribute_fields).into(); } @@ -270,40 +267,50 @@ fn configure_translation_control() { ); } -/// Compile the page tables from the `BSP`-supplied `virt_mem_layout()`. -/// -/// # Safety -/// -/// - User must ensure that the hardware supports the paremeters being set here. -pub unsafe fn init() -> Result<(), &'static str> { - // Fail early if translation granule is not supported. Both RPis support it, though. - if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported) { - return Err("64 KiB translation granule not supported"); - } +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + +pub struct MMU; + +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + +impl interface::mm::MMU for MMU { + /// Compile the page tables from the `BSP`-supplied `virt_mem_layout()`. + /// + /// # Safety + /// + /// - User must ensure that the hardware supports the paremeters being set here. + unsafe fn init(&self) -> Result<(), &'static str> { + // Fail early if translation granule is not supported. Both RPis support it, though. + if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran64::Supported) { + return Err("64 KiB translation granule not supported"); + } - // Prepare the memory attribute indirection register. - set_up_mair(); + // Prepare the memory attribute indirection register. + set_up_mair(); - // Populate page tables. - if let Err(string) = populate_pt_entries() { - return Err(string); - } + // Populate page tables. + populate_pt_entries()?; - // Set the "Translation Table Base Register". - TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64()); + // Set the "Translation Table Base Register". + TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64()); - configure_translation_control(); + configure_translation_control(); - // Switch the MMU on. - // - // First, force all previous changes to be seen before the MMU is enabled. - barrier::isb(barrier::SY); + // Switch the MMU on. + // + // First, force all previous changes to be seen before the MMU is enabled. + barrier::isb(barrier::SY); - // Enable the MMU and turn on data and instruction caching. - SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); + // Enable the MMU and turn on data and instruction caching. + SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable); - // Force MMU init to complete before next instruction - barrier::isb(barrier::SY); + // Force MMU init to complete before next instruction + barrier::isb(barrier::SY); - Ok(()) + Ok(()) + } } diff --git a/11_virtual_memory/src/arch/aarch64/sync.rs b/11_virtual_memory/src/arch/aarch64/sync.rs index dfebc0e1..2f6900b0 100644 --- a/11_virtual_memory/src/arch/aarch64/sync.rs +++ b/11_virtual_memory/src/arch/aarch64/sync.rs @@ -7,6 +7,10 @@ use crate::interface; use core::cell::UnsafeCell; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + /// A pseudo-lock for teaching purposes. /// /// Used to introduce [interior mutability]. @@ -33,6 +37,10 @@ impl NullLock { } } +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::sync::Mutex for &NullLock { type Data = T; diff --git a/11_virtual_memory/src/arch/aarch64/time.rs b/11_virtual_memory/src/arch/aarch64/time.rs index a6c9d50c..bbddd5e0 100644 --- a/11_virtual_memory/src/arch/aarch64/time.rs +++ b/11_virtual_memory/src/arch/aarch64/time.rs @@ -10,8 +10,16 @@ use cortex_a::regs::*; const NS_PER_S: u64 = 1_000_000_000; +//-------------------------------------------------------------------------------------------------- +// Arch-public +//-------------------------------------------------------------------------------------------------- + pub struct Timer; +//-------------------------------------------------------------------------------------------------- +// OS interface implementations +//-------------------------------------------------------------------------------------------------- + impl interface::time::Timer for Timer { fn resolution(&self) -> Duration { Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64)) diff --git a/11_virtual_memory/src/bsp/rpi/virt_mem_layout.rs b/11_virtual_memory/src/bsp/rpi/virt_mem_layout.rs index 3b1b2014..0c05aa6d 100644 --- a/11_virtual_memory/src/bsp/rpi/virt_mem_layout.rs +++ b/11_virtual_memory/src/bsp/rpi/virt_mem_layout.rs @@ -11,6 +11,10 @@ use super::memory_map; use crate::memory::*; use core::ops::RangeInclusive; +//-------------------------------------------------------------------------------------------------- +// BSP-public +//-------------------------------------------------------------------------------------------------- + pub const NUM_MEM_RANGES: usize = 3; pub static LAYOUT: KernelVirtualLayout<{ NUM_MEM_RANGES }> = KernelVirtualLayout::new( diff --git a/11_virtual_memory/src/interface.rs b/11_virtual_memory/src/interface.rs index 55df89cb..24b3eb28 100644 --- a/11_virtual_memory/src/interface.rs +++ b/11_virtual_memory/src/interface.rs @@ -127,3 +127,11 @@ pub mod time { fn spin_for(&self, duration: Duration); } } + +/// Memory Management interfaces. +pub mod mm { + pub trait MMU { + /// Called by the kernel early during init. + unsafe fn init(&self) -> Result<(), &'static str>; + } +} diff --git a/11_virtual_memory/src/main.rs b/11_virtual_memory/src/main.rs index e0f6c3e4..c87cdeca 100644 --- a/11_virtual_memory/src/main.rs +++ b/11_virtual_memory/src/main.rs @@ -55,7 +55,9 @@ mod print; /// drivers (which currently employ NullLocks instead of spinlocks), will fail to work on /// the RPi SoCs. unsafe fn kernel_init() -> ! { - if let Err(string) = arch::mmu::init() { + use interface::mm::MMU; + + if let Err(string) = arch::mmu().init() { panic!("MMU: {}", string); }