pull/73/head
Andre Richter 4 years ago
parent c1696d6b02
commit 5a793e5fcb
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -2,7 +2,7 @@
## tl;dr
The `MMU` is turned on; A simple scheme is used: static `64 KiB` page tables; For educational
The `MMU` is turned on; A simple scheme is used: static `64 KiB` translation tables; For educational
purposes, we write to a remapped `UART`.
## Table of Contents
@ -23,7 +23,8 @@ purposes, we write to a remapped `UART`.
## Introduction
Virtual memory is an immensely complex, but important and powerful topic. In this tutorial, we start
slow and easy by switching on the `MMU`, using static page tables and mapping everything at once.
slow and easy by switching on the `MMU`, using static translation tables and mapping everything at
once.
## MMU and paging theory
@ -90,7 +91,7 @@ RangeDescriptor {
`KernelVirtualLayout` itself implements the following method:
```rust
pub fn get_virt_addr_properties(
pub fn virt_addr_properties(
&self,
virt_addr: usize,
) -> Result<(usize, AttributeFields), &'static str>
@ -106,10 +107,10 @@ Due to this default return, it is technicall not needed to define normal cacheab
### AArch64: `_arch/aarch64/memory/mmu.rs`
This file contains the `AArch64` `MMU` driver. The paging granule is hardcoded here (`64 KiB` page
This file contains the `AArch64` `MMU` driver. The granule is hardcoded here (`64 KiB` page
descriptors).
The actual page tables are stored in a global instance of the `PageTables` struct:
The actual translation tables are stored in a global instance of the `TranslationTables` struct:
```rust
/// A table descriptor for 64 KiB aperture.
@ -126,11 +127,11 @@ struct TableDescriptor(u64);
#[repr(transparent)]
struct PageDescriptor(u64);
/// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned,
/// hence the "reverse" order of appearance.
/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB
/// aligned, hence the "reverse" order of appearance.
#[repr(C)]
#[repr(align(65536))]
struct PageTables<const N: usize> {
struct TranslationTables<const N: usize> {
/// Page descriptors, covering 64 KiB windows per entry.
lvl3: [[PageDescriptor; 8192]; N],
@ -141,24 +142,24 @@ struct PageTables<const N: usize> {
/// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4.
const ENTRIES_512_MIB: usize = bsp::memory::mmu::addr_space_size() >> FIVETWELVE_MIB_SHIFT;
/// The page tables.
/// The translation tables.
///
/// # Safety
///
/// - Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries.
static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables {
static mut TABLES: TranslationTables<{ ENTRIES_512_MIB }> = TranslationTables {
lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB],
lvl2: [TableDescriptor(0); ENTRIES_512_MIB],
};
```
They are populated using `bsp::memory::mmu::virt_mem_layout().get_virt_addr_properties()` and a
bunch of utility functions that convert our own descriptors to the actual `64 bit` integer entries
needed by the `MMU` hardware for the page table arrays.
They are populated using `bsp::memory::mmu::virt_mem_layout().virt_addr_properties()` and a bunch of
utility functions that convert our own descriptors to the actual `64 bit` integer entries needed by
the `MMU` hardware for the translation table arrays.
Each page table has an entry (`AttrIndex`) that indexes into the [MAIR_EL1] register, which holds
information about the cacheability of the respective page. We currently define normal cacheable
memory and device memory (which is not cached).
Each page descriptor has an entry (`AttrIndex`) that indexes into the [MAIR_EL1] register, which
holds information about the cacheability of the respective page. We currently define normal
cacheable memory and device memory (which is not cached).
[MAIR_EL1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500d/CIHDHJBB.html
@ -305,7 +306,7 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+
+//! Memory Management Unit Driver.
+//!
+//! Static page tables, compiled on boot; Everything 64 KiB granule.
+//! Static translation tables, compiled on boot; Everything 64 KiB granule.
+
+use super::{AccessPermissions, AttributeFields, MemAttributes};
+use crate::{bsp, memory};
@ -317,10 +318,10 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+// Private Definitions
+//--------------------------------------------------------------------------------------------------
+
+// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-15.
+// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15.
+register_bitfields! {u64,
+ STAGE1_TABLE_DESCRIPTOR [
+ /// Physical address of the next page table.
+ /// Physical address of the next descriptor.
+ NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
+
+ TYPE OFFSET(1) NUMBITS(1) [
@ -335,7 +336,7 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+ ]
+}
+
+// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-17.
+// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17.
+register_bitfields! {u64,
+ STAGE1_PAGE_DESCRIPTOR [
+ /// Privileged execute-never.
@ -344,7 +345,7 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+ True = 1
+ ],
+
+ /// Physical address of the next page table (lvl2) or the page descriptor (lvl3).
+ /// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3).
+ OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
+
+ /// Access flag.
@ -399,11 +400,11 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+#[repr(transparent)]
+struct PageDescriptor(u64);
+
+/// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned,
+/// hence the "reverse" order of appearance.
+/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB
+/// aligned, hence the "reverse" order of appearance.
+#[repr(C)]
+#[repr(align(65536))]
+struct PageTables<const N: usize> {
+struct TranslationTables<const N: usize> {
+ /// Page descriptors, covering 64 KiB windows per entry.
+ lvl3: [[PageDescriptor; 8192]; N],
+
@ -414,12 +415,12 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+/// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4.
+const ENTRIES_512_MIB: usize = bsp::memory::mmu::addr_space_size() >> FIVETWELVE_MIB_SHIFT;
+
+/// The page tables.
+/// The translation tables.
+///
+/// # Safety
+///
+/// - Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries.
+static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables {
+static mut TABLES: TranslationTables<{ ENTRIES_512_MIB }> = TranslationTables {
+ lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB],
+ lvl2: [TableDescriptor(0); ENTRIES_512_MIB],
+};
@ -536,12 +537,12 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+ );
+}
+
+/// Iterates over all static page table entries and fills them at once.
+/// Iterates over all static translation table entries and fills them at once.
+///
+/// # Safety
+///
+/// - Modifies a `static mut`. Ensure it only happens from here.
+unsafe fn populate_pt_entries() -> Result<(), &'static str> {
+unsafe fn populate_tt_entries() -> Result<(), &'static str> {
+ for (l2_nr, l2_entry) in TABLES.lvl2.iter_mut().enumerate() {
+ *l2_entry = TABLES.lvl3[l2_nr].base_addr_usize().into();
+
@ -549,7 +550,7 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+ let virt_addr = (l2_nr << FIVETWELVE_MIB_SHIFT) + (l3_nr << SIXTYFOUR_KIB_SHIFT);
+
+ let (output_addr, attribute_fields) =
+ bsp::memory::mmu::virt_mem_layout().get_virt_addr_properties(virt_addr)?;
+ bsp::memory::mmu::virt_mem_layout().virt_addr_properties(virt_addr)?;
+
+ *l3_entry = PageDescriptor::new(output_addr, attribute_fields);
+ }
@ -596,8 +597,8 @@ diff -uNr 10_privilege_level/src/_arch/aarch64/memory/mmu.rs 11_virtual_memory/s
+ // Prepare the memory attribute indirection register.
+ set_up_mair();
+
+ // Populate page tables.
+ populate_pt_entries()?;
+ // Populate translation tables.
+ populate_tt_entries()?;
+
+ // Set the "Translation Table Base Register".
+ TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64());
@ -880,7 +881,7 @@ diff -uNr 10_privilege_level/src/memory/mmu.rs 11_virtual_memory/src/memory/mmu.
+//! function.
+//!
+//! The `MMU` driver of the `arch` code uses `bsp::memory::mmu::virt_mem_layout()` to compile and
+//! install respective page tables.
+//! install respective translation tables.
+
+#[cfg(target_arch = "aarch64")]
+#[path = "../_arch/aarch64/memory/mmu.rs"]
@ -898,7 +899,7 @@ diff -uNr 10_privilege_level/src/memory/mmu.rs 11_virtual_memory/src/memory/mmu.
+
+ /// MMU functions.
+ pub trait MMU {
+ /// Called by the kernel during early init. Supposed to take the page tables from the
+ /// Called by the kernel during early init. Supposed to take the translation tables from the
+ /// `BSP`-supplied `virt_mem_layout()` and install/activate them for the respective MMU.
+ ///
+ /// # Safety
@ -1033,7 +1034,7 @@ diff -uNr 10_privilege_level/src/memory/mmu.rs 11_virtual_memory/src/memory/mmu.
+ ///
+ /// If the address is not found in `inner`, return an identity mapped default with normal
+ /// cacheable DRAM attributes.
+ pub fn get_virt_addr_properties(
+ pub fn virt_addr_properties(
+ &self,
+ virt_addr: usize,
+ ) -> Result<(usize, AttributeFields), &'static str> {

@ -4,7 +4,7 @@
//! Memory Management Unit Driver.
//!
//! Static page tables, compiled on boot; Everything 64 KiB granule.
//! Static translation tables, compiled on boot; Everything 64 KiB granule.
use super::{AccessPermissions, AttributeFields, MemAttributes};
use crate::{bsp, memory};
@ -16,10 +16,10 @@ use register::register_bitfields;
// Private Definitions
//--------------------------------------------------------------------------------------------------
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-15.
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15.
register_bitfields! {u64,
STAGE1_TABLE_DESCRIPTOR [
/// Physical address of the next page table.
/// Physical address of the next descriptor.
NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
TYPE OFFSET(1) NUMBITS(1) [
@ -34,7 +34,7 @@ register_bitfields! {u64,
]
}
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-17.
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17.
register_bitfields! {u64,
STAGE1_PAGE_DESCRIPTOR [
/// Privileged execute-never.
@ -43,7 +43,7 @@ register_bitfields! {u64,
True = 1
],
/// Physical address of the next page table (lvl2) or the page descriptor (lvl3).
/// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3).
OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
/// Access flag.
@ -98,11 +98,11 @@ struct TableDescriptor(u64);
#[repr(transparent)]
struct PageDescriptor(u64);
/// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned,
/// hence the "reverse" order of appearance.
/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB
/// aligned, hence the "reverse" order of appearance.
#[repr(C)]
#[repr(align(65536))]
struct PageTables<const N: usize> {
struct TranslationTables<const N: usize> {
/// Page descriptors, covering 64 KiB windows per entry.
lvl3: [[PageDescriptor; 8192]; N],
@ -113,12 +113,12 @@ struct PageTables<const N: usize> {
/// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4.
const ENTRIES_512_MIB: usize = bsp::memory::mmu::addr_space_size() >> FIVETWELVE_MIB_SHIFT;
/// The page tables.
/// The translation tables.
///
/// # Safety
///
/// - Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries.
static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables {
static mut TABLES: TranslationTables<{ ENTRIES_512_MIB }> = TranslationTables {
lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB],
lvl2: [TableDescriptor(0); ENTRIES_512_MIB],
};
@ -235,12 +235,12 @@ fn set_up_mair() {
);
}
/// Iterates over all static page table entries and fills them at once.
/// Iterates over all static translation table entries and fills them at once.
///
/// # Safety
///
/// - Modifies a `static mut`. Ensure it only happens from here.
unsafe fn populate_pt_entries() -> Result<(), &'static str> {
unsafe fn populate_tt_entries() -> Result<(), &'static str> {
for (l2_nr, l2_entry) in TABLES.lvl2.iter_mut().enumerate() {
*l2_entry = TABLES.lvl3[l2_nr].base_addr_usize().into();
@ -248,7 +248,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) =
bsp::memory::mmu::virt_mem_layout().get_virt_addr_properties(virt_addr)?;
bsp::memory::mmu::virt_mem_layout().virt_addr_properties(virt_addr)?;
*l3_entry = PageDescriptor::new(output_addr, attribute_fields);
}
@ -295,8 +295,8 @@ impl memory::mmu::interface::MMU for MemoryManagementUnit {
// Prepare the memory attribute indirection register.
set_up_mair();
// Populate page tables.
populate_pt_entries()?;
// Populate translation tables.
populate_tt_entries()?;
// Set the "Translation Table Base Register".
TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64());

@ -12,7 +12,7 @@
//! function.
//!
//! The `MMU` driver of the `arch` code uses `bsp::memory::mmu::virt_mem_layout()` to compile and
//! install respective page tables.
//! install respective translation tables.
#[cfg(target_arch = "aarch64")]
#[path = "../_arch/aarch64/memory/mmu.rs"]
@ -30,7 +30,7 @@ pub mod interface {
/// MMU functions.
pub trait MMU {
/// Called by the kernel during early init. Supposed to take the page tables from the
/// Called by the kernel during early init. Supposed to take the translation tables from the
/// `BSP`-supplied `virt_mem_layout()` and install/activate them for the respective MMU.
///
/// # Safety
@ -165,7 +165,7 @@ impl<const NUM_SPECIAL_RANGES: usize> KernelVirtualLayout<{ NUM_SPECIAL_RANGES }
///
/// If the address is not found in `inner`, return an identity mapped default with normal
/// cacheable DRAM attributes.
pub fn get_virt_addr_properties(
pub fn virt_addr_properties(
&self,
virt_addr: usize,
) -> Result<(usize, AttributeFields), &'static str> {

@ -4,7 +4,7 @@
//! Memory Management Unit Driver.
//!
//! Static page tables, compiled on boot; Everything 64 KiB granule.
//! Static translation tables, compiled on boot; Everything 64 KiB granule.
use super::{AccessPermissions, AttributeFields, MemAttributes};
use crate::{bsp, memory};
@ -16,10 +16,10 @@ use register::register_bitfields;
// Private Definitions
//--------------------------------------------------------------------------------------------------
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-15.
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15.
register_bitfields! {u64,
STAGE1_TABLE_DESCRIPTOR [
/// Physical address of the next page table.
/// Physical address of the next descriptor.
NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
TYPE OFFSET(1) NUMBITS(1) [
@ -34,7 +34,7 @@ register_bitfields! {u64,
]
}
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-17.
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17.
register_bitfields! {u64,
STAGE1_PAGE_DESCRIPTOR [
/// Privileged execute-never.
@ -43,7 +43,7 @@ register_bitfields! {u64,
True = 1
],
/// Physical address of the next page table (lvl2) or the page descriptor (lvl3).
/// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3).
OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
/// Access flag.
@ -98,11 +98,11 @@ struct TableDescriptor(u64);
#[repr(transparent)]
struct PageDescriptor(u64);
/// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned,
/// hence the "reverse" order of appearance.
/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB
/// aligned, hence the "reverse" order of appearance.
#[repr(C)]
#[repr(align(65536))]
struct PageTables<const N: usize> {
struct TranslationTables<const N: usize> {
/// Page descriptors, covering 64 KiB windows per entry.
lvl3: [[PageDescriptor; 8192]; N],
@ -113,12 +113,12 @@ struct PageTables<const N: usize> {
/// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4.
const ENTRIES_512_MIB: usize = bsp::memory::mmu::addr_space_size() >> FIVETWELVE_MIB_SHIFT;
/// The page tables.
/// The translation tables.
///
/// # Safety
///
/// - Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries.
static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables {
static mut TABLES: TranslationTables<{ ENTRIES_512_MIB }> = TranslationTables {
lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB],
lvl2: [TableDescriptor(0); ENTRIES_512_MIB],
};
@ -235,12 +235,12 @@ fn set_up_mair() {
);
}
/// Iterates over all static page table entries and fills them at once.
/// Iterates over all static translation table entries and fills them at once.
///
/// # Safety
///
/// - Modifies a `static mut`. Ensure it only happens from here.
unsafe fn populate_pt_entries() -> Result<(), &'static str> {
unsafe fn populate_tt_entries() -> Result<(), &'static str> {
for (l2_nr, l2_entry) in TABLES.lvl2.iter_mut().enumerate() {
*l2_entry = TABLES.lvl3[l2_nr].base_addr_usize().into();
@ -248,7 +248,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) =
bsp::memory::mmu::virt_mem_layout().get_virt_addr_properties(virt_addr)?;
bsp::memory::mmu::virt_mem_layout().virt_addr_properties(virt_addr)?;
*l3_entry = PageDescriptor::new(output_addr, attribute_fields);
}
@ -295,8 +295,8 @@ impl memory::mmu::interface::MMU for MemoryManagementUnit {
// Prepare the memory attribute indirection register.
set_up_mair();
// Populate page tables.
populate_pt_entries()?;
// Populate translation tables.
populate_tt_entries()?;
// Set the "Translation Table Base Register".
TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64());

@ -12,7 +12,7 @@
//! function.
//!
//! The `MMU` driver of the `arch` code uses `bsp::memory::mmu::virt_mem_layout()` to compile and
//! install respective page tables.
//! install respective translation tables.
#[cfg(target_arch = "aarch64")]
#[path = "../_arch/aarch64/memory/mmu.rs"]
@ -30,7 +30,7 @@ pub mod interface {
/// MMU functions.
pub trait MMU {
/// Called by the kernel during early init. Supposed to take the page tables from the
/// Called by the kernel during early init. Supposed to take the translation tables from the
/// `BSP`-supplied `virt_mem_layout()` and install/activate them for the respective MMU.
///
/// # Safety
@ -166,7 +166,7 @@ impl<const NUM_SPECIAL_RANGES: usize> KernelVirtualLayout<{ NUM_SPECIAL_RANGES }
///
/// If the address is not found in `inner`, return an identity mapped default with normal
/// cacheable DRAM attributes.
pub fn get_virt_addr_properties(
pub fn virt_addr_properties(
&self,
virt_addr: usize,
) -> Result<(usize, AttributeFields), &'static str> {

@ -788,7 +788,7 @@ diff -uNr 12_exceptions_part1_groundwork/Cargo.toml 13_integrated_testing/Cargo.
# Optional dependencies
cortex-a = { version = "3.0.x", optional = true }
-register = { version = "0.5.x", optional = true }
+register = { version = "0.5.x", features=["no_std_unit_tests"], optional = true }
+register = { version = "0.5.x", features = ["no_std_unit_tests"], optional = true }
+
+##--------------------------------------------------------------------------------------------------
+## Testing

@ -4,7 +4,7 @@
//! Memory Management Unit Driver.
//!
//! Static page tables, compiled on boot; Everything 64 KiB granule.
//! Static translation tables, compiled on boot; Everything 64 KiB granule.
use super::{AccessPermissions, AttributeFields, MemAttributes};
use crate::{bsp, memory};
@ -16,10 +16,10 @@ use register::register_bitfields;
// Private Definitions
//--------------------------------------------------------------------------------------------------
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-15.
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15.
register_bitfields! {u64,
STAGE1_TABLE_DESCRIPTOR [
/// Physical address of the next page table.
/// Physical address of the next descriptor.
NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
TYPE OFFSET(1) NUMBITS(1) [
@ -34,7 +34,7 @@ register_bitfields! {u64,
]
}
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-17.
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17.
register_bitfields! {u64,
STAGE1_PAGE_DESCRIPTOR [
/// Privileged execute-never.
@ -43,7 +43,7 @@ register_bitfields! {u64,
True = 1
],
/// Physical address of the next page table (lvl2) or the page descriptor (lvl3).
/// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3).
OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
/// Access flag.
@ -98,11 +98,11 @@ struct TableDescriptor(u64);
#[repr(transparent)]
struct PageDescriptor(u64);
/// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned,
/// hence the "reverse" order of appearance.
/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB
/// aligned, hence the "reverse" order of appearance.
#[repr(C)]
#[repr(align(65536))]
struct PageTables<const N: usize> {
struct TranslationTables<const N: usize> {
/// Page descriptors, covering 64 KiB windows per entry.
lvl3: [[PageDescriptor; 8192]; N],
@ -113,12 +113,12 @@ struct PageTables<const N: usize> {
/// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4.
const ENTRIES_512_MIB: usize = bsp::memory::mmu::addr_space_size() >> FIVETWELVE_MIB_SHIFT;
/// The page tables.
/// The translation tables.
///
/// # Safety
///
/// - Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries.
static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables {
static mut TABLES: TranslationTables<{ ENTRIES_512_MIB }> = TranslationTables {
lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB],
lvl2: [TableDescriptor(0); ENTRIES_512_MIB],
};
@ -235,12 +235,12 @@ fn set_up_mair() {
);
}
/// Iterates over all static page table entries and fills them at once.
/// Iterates over all static translation table entries and fills them at once.
///
/// # Safety
///
/// - Modifies a `static mut`. Ensure it only happens from here.
unsafe fn populate_pt_entries() -> Result<(), &'static str> {
unsafe fn populate_tt_entries() -> Result<(), &'static str> {
for (l2_nr, l2_entry) in TABLES.lvl2.iter_mut().enumerate() {
*l2_entry = TABLES.lvl3[l2_nr].base_addr_usize().into();
@ -248,7 +248,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) =
bsp::memory::mmu::virt_mem_layout().get_virt_addr_properties(virt_addr)?;
bsp::memory::mmu::virt_mem_layout().virt_addr_properties(virt_addr)?;
*l3_entry = PageDescriptor::new(output_addr, attribute_fields);
}
@ -295,8 +295,8 @@ impl memory::mmu::interface::MMU for MemoryManagementUnit {
// Prepare the memory attribute indirection register.
set_up_mair();
// Populate page tables.
populate_pt_entries()?;
// Populate translation tables.
populate_tt_entries()?;
// Set the "Translation Table Base Register".
TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64());

@ -12,7 +12,7 @@
//! function.
//!
//! The `MMU` driver of the `arch` code uses `bsp::memory::mmu::virt_mem_layout()` to compile and
//! install respective page tables.
//! install respective translation tables.
#[cfg(target_arch = "aarch64")]
#[path = "../_arch/aarch64/memory/mmu.rs"]
@ -30,7 +30,7 @@ pub mod interface {
/// MMU functions.
pub trait MMU {
/// Called by the kernel during early init. Supposed to take the page tables from the
/// Called by the kernel during early init. Supposed to take the translation tables from the
/// `BSP`-supplied `virt_mem_layout()` and install/activate them for the respective MMU.
///
/// # Safety
@ -165,7 +165,7 @@ impl<const NUM_SPECIAL_RANGES: usize> KernelVirtualLayout<{ NUM_SPECIAL_RANGES }
///
/// If the address is not found in `inner`, return an identity mapped default with normal
/// cacheable DRAM attributes.
pub fn get_virt_addr_properties(
pub fn virt_addr_properties(
&self,
virt_addr: usize,
) -> Result<(usize, AttributeFields), &'static str> {

@ -986,7 +986,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead
+ /// of `&mut self`.
+ #[allow(clippy::trivially_copy_pass_by_ref)]
+ pub fn get_pending_number<'irq_context>(
+ pub fn pending_irq_number<'irq_context>(
+ &self,
+ _ic: &exception::asynchronous::IRQContext<'irq_context>,
+ ) -> usize {
@ -997,7 +997,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2/gicc.rs 14_excep
+ ///
+ /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token.
+ ///
+ /// To be called after `get_pending_number()`.
+ /// To be called after `pending_irq_number()`.
+ ///
+ /// # Safety
+ ///
@ -1403,7 +1403,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/arm/gicv2.rs 14_exceptions
+ ) {
+ // Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register
+ // (IAR).
+ let irq_number = self.gicc.get_pending_number(ic);
+ let irq_number = self.gicc.pending_irq_number(ic);
+
+ // Guard against spurious interrupts.
+ if irq_number > GICv2::MAX_IRQ_NUMBER {
@ -1573,7 +1573,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
+ }
+
+ /// Query the list of pending IRQs.
+ fn get_pending(&self) -> PendingIRQs {
+ fn pending_irqs(&self) -> PendingIRQs {
+ let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32)
+ | u64::from(self.ro_registers.PENDING_1.get());
+
@ -1631,7 +1631,7 @@ diff -uNr 13_integrated_testing/src/bsp/device_driver/bcm/bcm2xxx_interrupt_cont
+ ) {
+ let mut r = &self.handler_table;
+ r.read(|table| {
+ for irq_number in self.get_pending() {
+ for irq_number in self.pending_irqs() {
+ match table[irq_number] {
+ None => panic!("No handler registered for IRQ {}", irq_number),
+ Some(descriptor) => {

@ -4,7 +4,7 @@
//! Memory Management Unit Driver.
//!
//! Static page tables, compiled on boot; Everything 64 KiB granule.
//! Static translation tables, compiled on boot; Everything 64 KiB granule.
use super::{AccessPermissions, AttributeFields, MemAttributes};
use crate::{bsp, memory};
@ -16,10 +16,10 @@ use register::register_bitfields;
// Private Definitions
//--------------------------------------------------------------------------------------------------
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-15.
// A table descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-15.
register_bitfields! {u64,
STAGE1_TABLE_DESCRIPTOR [
/// Physical address of the next page table.
/// Physical address of the next descriptor.
NEXT_LEVEL_TABLE_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
TYPE OFFSET(1) NUMBITS(1) [
@ -34,7 +34,7 @@ register_bitfields! {u64,
]
}
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D4-17.
// A level 3 page descriptor, as per ARMv8-A Architecture Reference Manual Figure D5-17.
register_bitfields! {u64,
STAGE1_PAGE_DESCRIPTOR [
/// Privileged execute-never.
@ -43,7 +43,7 @@ register_bitfields! {u64,
True = 1
],
/// Physical address of the next page table (lvl2) or the page descriptor (lvl3).
/// Physical address of the next table descriptor (lvl2) or the page descriptor (lvl3).
OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16]
/// Access flag.
@ -98,11 +98,11 @@ struct TableDescriptor(u64);
#[repr(transparent)]
struct PageDescriptor(u64);
/// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned,
/// hence the "reverse" order of appearance.
/// Big monolithic struct for storing the translation tables. Individual levels must be 64 KiB
/// aligned, hence the "reverse" order of appearance.
#[repr(C)]
#[repr(align(65536))]
struct PageTables<const N: usize> {
struct TranslationTables<const N: usize> {
/// Page descriptors, covering 64 KiB windows per entry.
lvl3: [[PageDescriptor; 8192]; N],
@ -113,12 +113,12 @@ struct PageTables<const N: usize> {
/// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4.
const ENTRIES_512_MIB: usize = bsp::memory::mmu::addr_space_size() >> FIVETWELVE_MIB_SHIFT;
/// The page tables.
/// The translation tables.
///
/// # Safety
///
/// - Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries.
static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables {
static mut TABLES: TranslationTables<{ ENTRIES_512_MIB }> = TranslationTables {
lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB],
lvl2: [TableDescriptor(0); ENTRIES_512_MIB],
};
@ -235,12 +235,12 @@ fn set_up_mair() {
);
}
/// Iterates over all static page table entries and fills them at once.
/// Iterates over all static translation table entries and fills them at once.
///
/// # Safety
///
/// - Modifies a `static mut`. Ensure it only happens from here.
unsafe fn populate_pt_entries() -> Result<(), &'static str> {
unsafe fn populate_tt_entries() -> Result<(), &'static str> {
for (l2_nr, l2_entry) in TABLES.lvl2.iter_mut().enumerate() {
*l2_entry = TABLES.lvl3[l2_nr].base_addr_usize().into();
@ -248,7 +248,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) =
bsp::memory::mmu::virt_mem_layout().get_virt_addr_properties(virt_addr)?;
bsp::memory::mmu::virt_mem_layout().virt_addr_properties(virt_addr)?;
*l3_entry = PageDescriptor::new(output_addr, attribute_fields);
}
@ -295,8 +295,8 @@ impl memory::mmu::interface::MMU for MemoryManagementUnit {
// Prepare the memory attribute indirection register.
set_up_mair();
// Populate page tables.
populate_pt_entries()?;
// Populate translation tables.
populate_tt_entries()?;
// Set the "Translation Table Base Register".
TTBR0_EL1.set_baddr(TABLES.lvl2.base_addr_u64());

@ -182,7 +182,7 @@ impl exception::asynchronous::interface::IRQManager for GICv2 {
) {
// Extract the highest priority pending IRQ number from the Interrupt Acknowledge Register
// (IAR).
let irq_number = self.gicc.get_pending_number(ic);
let irq_number = self.gicc.pending_irq_number(ic);
// Guard against spurious interrupts.
if irq_number > GICv2::MAX_IRQ_NUMBER {

@ -109,7 +109,7 @@ impl GICC {
/// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead
/// of `&mut self`.
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn get_pending_number<'irq_context>(
pub fn pending_irq_number<'irq_context>(
&self,
_ic: &exception::asynchronous::IRQContext<'irq_context>,
) -> usize {
@ -120,7 +120,7 @@ impl GICC {
///
/// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token.
///
/// To be called after `get_pending_number()`.
/// To be called after `pending_irq_number()`.
///
/// # Safety
///

@ -80,7 +80,7 @@ impl PeripheralIC {
}
/// Query the list of pending IRQs.
fn get_pending(&self) -> PendingIRQs {
fn pending_irqs(&self) -> PendingIRQs {
let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32)
| u64::from(self.ro_registers.PENDING_1.get());
@ -138,7 +138,7 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC {
) {
let mut r = &self.handler_table;
r.read(|table| {
for irq_number in self.get_pending() {
for irq_number in self.pending_irqs() {
match table[irq_number] {
None => panic!("No handler registered for IRQ {}", irq_number),
Some(descriptor) => {

@ -12,7 +12,7 @@
//! function.
//!
//! The `MMU` driver of the `arch` code uses `bsp::memory::mmu::virt_mem_layout()` to compile and
//! install respective page tables.
//! install respective translation tables.
#[cfg(target_arch = "aarch64")]
#[path = "../_arch/aarch64/memory/mmu.rs"]
@ -30,7 +30,7 @@ pub mod interface {
/// MMU functions.
pub trait MMU {
/// Called by the kernel during early init. Supposed to take the page tables from the
/// Called by the kernel during early init. Supposed to take the translation tables from the
/// `BSP`-supplied `virt_mem_layout()` and install/activate them for the respective MMU.
///
/// # Safety
@ -165,7 +165,7 @@ impl<const NUM_SPECIAL_RANGES: usize> KernelVirtualLayout<{ NUM_SPECIAL_RANGES }
///
/// If the address is not found in `inner`, return an identity mapped default with normal
/// cacheable DRAM attributes.
pub fn get_virt_addr_properties(
pub fn virt_addr_properties(
&self,
virt_addr: usize,
) -> Result<(usize, AttributeFields), &'static str> {

Loading…
Cancel
Save