diff --git a/11_virtual_memory/README.md b/11_virtual_memory/README.md index df126ca8..390d7703 100644 --- a/11_virtual_memory/README.md +++ b/11_virtual_memory/README.md @@ -87,15 +87,19 @@ is hardcoded here (`64 KiB` page descriptors). The actual page tables are stored in a global instance of the `PageTables` struct: ```rust -// Two newtypes for added type safety, so that you cannot accidentally place a TableDescriptor into -// a PageDescriptor slot in `struct PageTables`, and vice versa. +/// A table descriptor for 64 KiB aperture. +/// +/// The output points to the next table. #[derive(Copy, Clone)] #[repr(transparent)] -struct RawTableDescriptor(u64); +struct TableDescriptor(u64); +/// A page descriptor with 64 KiB aperture. +/// +/// The output points to physical memory. #[derive(Copy, Clone)] #[repr(transparent)] -struct RawPageDescriptor(u64); +struct PageDescriptor(u64); /// Big monolithic struct for storing the page tables. Individual levels must be 64 KiB aligned, /// hence the "reverse" order of appearance. @@ -103,9 +107,9 @@ struct RawPageDescriptor(u64); #[repr(align(65536))] struct PageTables { // Page descriptors, covering 64 KiB windows per entry. - lvl3: [[RawPageDescriptor; 8192]; N], + lvl3: [[PageDescriptor; 8192]; N], // Table descriptors, covering 512 MiB windows. - lvl2: [RawTableDescriptor; N], + lvl2: [TableDescriptor; N], } /// Usually evaluates to 1 GiB for RPi3 and 4 GiB for RPi 4. @@ -115,8 +119,8 @@ const ENTRIES_512_MIB: usize = bsp::addr_space_size() >> FIVETWELVE_MIB_SHIFT; /// /// Supposed to land in `.bss`. Therefore, ensure that they boil down to all "0" entries. static mut TABLES: PageTables<{ ENTRIES_512_MIB }> = PageTables { - lvl3: [[RawPageDescriptor(0); 8192]; ENTRIES_512_MIB], - lvl2: [RawTableDescriptor(0); ENTRIES_512_MIB], + lvl3: [[PageDescriptor(0); 8192]; ENTRIES_512_MIB], + lvl2: [TableDescriptor(0); ENTRIES_512_MIB], }; ``` @@ -135,11 +139,11 @@ memory and device memory (which is not cached). fn set_up_mair() { // Define the memory types being mapped. MAIR_EL1.write( - // Attribute 1 - Cacheable normal DRAM + // Attribute 1 - Cacheable normal DRAM. MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - // Attribute 0 - Device + // Attribute 0 - Device. + MAIR_EL1::Attr0_HIGH::Device + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, ); @@ -303,7 +307,7 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ +// A level 3 page descriptor, as per AArch64 Reference Manual Figure D4-17. +register_bitfields! {u64, + STAGE1_PAGE_DESCRIPTOR [ -+ /// Privileged execute-never ++ /// Privileged execute-never. + PXN OFFSET(53) NUMBITS(1) [ + False = 0, + True = 1 @@ -312,19 +316,19 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + /// Physical address of the next page table (lvl2) or the page descriptor (lvl3). + OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] + -+ /// Access flag ++ /// Access flag. + AF OFFSET(10) NUMBITS(1) [ + False = 0, + True = 1 + ], + -+ /// Shareability field ++ /// Shareability field. + SH OFFSET(8) NUMBITS(2) [ + OuterShareable = 0b10, + InnerShareable = 0b11 + ], + -+ /// Access Permissions ++ /// Access Permissions. + AP OFFSET(6) NUMBITS(2) [ + RW_EL1 = 0b00, + RW_EL1_EL0 = 0b01, @@ -332,7 +336,7 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + RO_EL1_EL0 = 0b11 + ], + -+ /// Memory attributes index into the MAIR_EL1 register ++ /// Memory attributes index into the MAIR_EL1 register. + AttrIndx OFFSET(2) NUMBITS(3) [], + + TYPE OFFSET(1) NUMBITS(1) [ @@ -418,7 +422,7 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + for register::FieldValue +{ + fn from(attribute_fields: AttributeFields) -> Self { -+ // Memory attributes ++ // Memory attributes. + let mut desc = match attribute_fields.mem_attributes { + MemAttributes::CacheableDRAM => { + STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable @@ -430,13 +434,13 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + } + }; + -+ // Access Permissions ++ // Access Permissions. + desc += match attribute_fields.acc_perms { + AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, + AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, + }; + -+ // Execute Never ++ // Execute Never. + desc += if attribute_fields.execute_never { + STAGE1_PAGE_DESCRIPTOR::PXN::True + } else { @@ -472,11 +476,11 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ +fn set_up_mair() { + // Define the memory types being mapped. + MAIR_EL1.write( -+ // Attribute 1 - Cacheable normal DRAM ++ // Attribute 1 - Cacheable normal DRAM. + MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc + + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc + -+ // Attribute 0 - Device ++ // Attribute 0 - Device. + + MAIR_EL1::Attr0_HIGH::Device + + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, + ); @@ -560,7 +564,7 @@ diff -uNr 10_privilege_level/src/arch/aarch64/mmu.rs 11_virtual_memory/src/arch/ + // 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 ++ // Force MMU init to complete before next instruction. + barrier::isb(barrier::SY); + + Ok(()) diff --git a/11_virtual_memory/src/arch/aarch64/mmu.rs b/11_virtual_memory/src/arch/aarch64/mmu.rs index 34d5f71e..7cee795f 100644 --- a/11_virtual_memory/src/arch/aarch64/mmu.rs +++ b/11_virtual_memory/src/arch/aarch64/mmu.rs @@ -35,7 +35,7 @@ register_bitfields! {u64, // A level 3 page descriptor, as per AArch64 Reference Manual Figure D4-17. register_bitfields! {u64, STAGE1_PAGE_DESCRIPTOR [ - /// Privileged execute-never + /// Privileged execute-never. PXN OFFSET(53) NUMBITS(1) [ False = 0, True = 1 @@ -44,19 +44,19 @@ register_bitfields! {u64, /// Physical address of the next page table (lvl2) or the page descriptor (lvl3). OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] - /// Access flag + /// Access flag. AF OFFSET(10) NUMBITS(1) [ False = 0, True = 1 ], - /// Shareability field + /// Shareability field. SH OFFSET(8) NUMBITS(2) [ OuterShareable = 0b10, InnerShareable = 0b11 ], - /// Access Permissions + /// Access Permissions. AP OFFSET(6) NUMBITS(2) [ RW_EL1 = 0b00, RW_EL1_EL0 = 0b01, @@ -64,7 +64,7 @@ register_bitfields! {u64, RO_EL1_EL0 = 0b11 ], - /// Memory attributes index into the MAIR_EL1 register + /// Memory attributes index into the MAIR_EL1 register. AttrIndx OFFSET(2) NUMBITS(3) [], TYPE OFFSET(1) NUMBITS(1) [ @@ -150,7 +150,7 @@ impl convert::From for register::FieldValue { fn from(attribute_fields: AttributeFields) -> Self { - // Memory attributes + // Memory attributes. let mut desc = match attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => { STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable @@ -162,13 +162,13 @@ impl convert::From } }; - // Access Permissions + // Access Permissions. desc += match attribute_fields.acc_perms { AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, }; - // Execute Never + // Execute Never. desc += if attribute_fields.execute_never { STAGE1_PAGE_DESCRIPTOR::PXN::True } else { @@ -204,11 +204,11 @@ mod mair { fn set_up_mair() { // Define the memory types being mapped. MAIR_EL1.write( - // Attribute 1 - Cacheable normal DRAM + // Attribute 1 - Cacheable normal DRAM. MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - // Attribute 0 - Device + // Attribute 0 - Device. + MAIR_EL1::Attr0_HIGH::Device + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, ); @@ -292,7 +292,7 @@ impl interface::mm::MMU for MMU { // 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 + // Force MMU init to complete before next instruction. barrier::isb(barrier::SY); Ok(()) diff --git a/12_cpu_exceptions_part1/README.md b/12_cpu_exceptions_part1/README.md index fda1281f..6a1569da 100644 --- a/12_cpu_exceptions_part1/README.md +++ b/12_cpu_exceptions_part1/README.md @@ -474,7 +474,7 @@ diff -uNr 11_virtual_memory/src/arch/aarch64/exception.rs 12_cpu_exceptions_part +// Assembly counterpart to this file. +global_asm!(include_str!("exception.S")); + -+/// Wrapper struct for memory copy of SPSR_EL1 ++/// Wrapper struct for memory copy of SPSR_EL1. +#[repr(transparent)] +struct SpsrEL1(InMemoryRegister); + @@ -491,7 +491,7 @@ diff -uNr 11_virtual_memory/src/arch/aarch64/exception.rs 12_cpu_exceptions_part + spsr_el1: SpsrEL1, +} + -+/// Wrapper struct for pretty printing ESR_EL1 ++/// Wrapper struct for pretty printing ESR_EL1. +struct EsrEL1; + +//-------------------------------------------------------------------------------------------------- @@ -537,7 +537,7 @@ diff -uNr 11_virtual_memory/src/arch/aarch64/exception.rs 12_cpu_exceptions_part +/// Asynchronous exception taken from the current EL, using SP of the current EL. +#[no_mangle] +unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { -+ let far_el1 = FAR_EL1.extract().get(); ++ let far_el1 = FAR_EL1.get(); + + // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, + // advance the exception link register for one instruction, so that execution can continue. @@ -697,7 +697,7 @@ diff -uNr 11_virtual_memory/src/arch/aarch64/exception.rs 12_cpu_exceptions_part +/// - The vector table and the symbol `__exception_vector_table_start` from the linker script must +/// adhere to the alignment and size constraints demanded by the AArch64 spec. +pub unsafe fn set_vbar_el1() { -+ // Provided by exception_vec_table.S. ++ // Provided by exception.S. + extern "C" { + static mut __exception_vector_start: u64; + } diff --git a/12_cpu_exceptions_part1/src/arch/aarch64/exception.rs b/12_cpu_exceptions_part1/src/arch/aarch64/exception.rs index fceea46f..30c986bf 100644 --- a/12_cpu_exceptions_part1/src/arch/aarch64/exception.rs +++ b/12_cpu_exceptions_part1/src/arch/aarch64/exception.rs @@ -11,7 +11,7 @@ use register::InMemoryRegister; // Assembly counterpart to this file. global_asm!(include_str!("exception.S")); -/// Wrapper struct for memory copy of SPSR_EL1 +/// Wrapper struct for memory copy of SPSR_EL1. #[repr(transparent)] struct SpsrEL1(InMemoryRegister); @@ -28,7 +28,7 @@ struct ExceptionContext { spsr_el1: SpsrEL1, } -/// Wrapper struct for pretty printing ESR_EL1 +/// Wrapper struct for pretty printing ESR_EL1. struct EsrEL1; //-------------------------------------------------------------------------------------------------- @@ -74,7 +74,7 @@ unsafe extern "C" fn current_el0_serror(e: &mut ExceptionContext) { /// Asynchronous exception taken from the current EL, using SP of the current EL. #[no_mangle] unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { - let far_el1 = FAR_EL1.extract().get(); + let far_el1 = FAR_EL1.get(); // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, // advance the exception link register for one instruction, so that execution can continue. @@ -234,7 +234,7 @@ impl fmt::Display for ExceptionContext { /// - The vector table and the symbol `__exception_vector_table_start` from the linker script must /// adhere to the alignment and size constraints demanded by the AArch64 spec. pub unsafe fn set_vbar_el1() { - // Provided by exception_vec_table.S. + // Provided by exception.S. extern "C" { static mut __exception_vector_start: u64; } diff --git a/12_cpu_exceptions_part1/src/arch/aarch64/mmu.rs b/12_cpu_exceptions_part1/src/arch/aarch64/mmu.rs index 34d5f71e..7cee795f 100644 --- a/12_cpu_exceptions_part1/src/arch/aarch64/mmu.rs +++ b/12_cpu_exceptions_part1/src/arch/aarch64/mmu.rs @@ -35,7 +35,7 @@ register_bitfields! {u64, // A level 3 page descriptor, as per AArch64 Reference Manual Figure D4-17. register_bitfields! {u64, STAGE1_PAGE_DESCRIPTOR [ - /// Privileged execute-never + /// Privileged execute-never. PXN OFFSET(53) NUMBITS(1) [ False = 0, True = 1 @@ -44,19 +44,19 @@ register_bitfields! {u64, /// Physical address of the next page table (lvl2) or the page descriptor (lvl3). OUTPUT_ADDR_64KiB OFFSET(16) NUMBITS(32) [], // [47:16] - /// Access flag + /// Access flag. AF OFFSET(10) NUMBITS(1) [ False = 0, True = 1 ], - /// Shareability field + /// Shareability field. SH OFFSET(8) NUMBITS(2) [ OuterShareable = 0b10, InnerShareable = 0b11 ], - /// Access Permissions + /// Access Permissions. AP OFFSET(6) NUMBITS(2) [ RW_EL1 = 0b00, RW_EL1_EL0 = 0b01, @@ -64,7 +64,7 @@ register_bitfields! {u64, RO_EL1_EL0 = 0b11 ], - /// Memory attributes index into the MAIR_EL1 register + /// Memory attributes index into the MAIR_EL1 register. AttrIndx OFFSET(2) NUMBITS(3) [], TYPE OFFSET(1) NUMBITS(1) [ @@ -150,7 +150,7 @@ impl convert::From for register::FieldValue { fn from(attribute_fields: AttributeFields) -> Self { - // Memory attributes + // Memory attributes. let mut desc = match attribute_fields.mem_attributes { MemAttributes::CacheableDRAM => { STAGE1_PAGE_DESCRIPTOR::SH::InnerShareable @@ -162,13 +162,13 @@ impl convert::From } }; - // Access Permissions + // Access Permissions. desc += match attribute_fields.acc_perms { AccessPermissions::ReadOnly => STAGE1_PAGE_DESCRIPTOR::AP::RO_EL1, AccessPermissions::ReadWrite => STAGE1_PAGE_DESCRIPTOR::AP::RW_EL1, }; - // Execute Never + // Execute Never. desc += if attribute_fields.execute_never { STAGE1_PAGE_DESCRIPTOR::PXN::True } else { @@ -204,11 +204,11 @@ mod mair { fn set_up_mair() { // Define the memory types being mapped. MAIR_EL1.write( - // Attribute 1 - Cacheable normal DRAM + // Attribute 1 - Cacheable normal DRAM. MAIR_EL1::Attr1_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc + MAIR_EL1::Attr1_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc - // Attribute 0 - Device + // Attribute 0 - Device. + MAIR_EL1::Attr0_HIGH::Device + MAIR_EL1::Attr0_LOW_DEVICE::Device_nGnRE, ); @@ -292,7 +292,7 @@ impl interface::mm::MMU for MMU { // 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 + // Force MMU init to complete before next instruction. barrier::isb(barrier::SY); Ok(())