diff --git a/crate/aarch64/Cargo.toml b/crate/aarch64/Cargo.toml deleted file mode 100644 index 7514dd0e..00000000 --- a/crate/aarch64/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "aarch64" -version = "0.1.0" -authors = ["koumingyang <1761674434@qq.com>"] - -[dependencies] -register = "0.2.0" -bit_field = "0.9.0" -bitflags = "1.0.1" -usize_conversions = "0.2.0" -os_bootinfo = "0.2.0" -bare-metal = "0.2.0" - -[dependencies.ux] -default-features = false -version = "0.1.0" \ No newline at end of file diff --git a/crate/aarch64/src/addr.rs b/crate/aarch64/src/addr.rs deleted file mode 100644 index cf3f0923..00000000 --- a/crate/aarch64/src/addr.rs +++ /dev/null @@ -1,441 +0,0 @@ -use core::convert::{Into, TryInto}; -use core::fmt; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -use bit_field::BitField; -use usize_conversions::FromUsize; -use ux::*; - -#[derive(Debug)] -#[repr(u8)] -pub enum VirtAddrRange { - /// 0x0000000000000000 to 0x0000FFFFFFFFFFFF - BottomRange = 0, - /// 0xFFFF000000000000 to 0xFFFFFFFFFFFFFFFF. - TopRange = 1, -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct VirtAddr(u64); - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(transparent)] -pub struct PhysAddr(u64); - -#[derive(Debug)] -pub struct VirtAddrNotValid(u64); - -impl VirtAddr { - /// Creates a new canonical virtual address. - /// - /// This function performs sign extension of bit 47 to make the address canonical. Panics - /// if the bits in the range 48 to 64 contain data (i.e. are not null and no sign extension). - pub fn new(addr: u64) -> VirtAddr { - Self::try_new(addr).expect( - "invalid virtual address", - ) - } - - /// Tries to create a new canonical virtual address. - /// in aarch64, valid virtual address starts with 0x0000 or 0xffff. - pub fn try_new(addr: u64) -> Result { - match addr.get_bits(48..64) { - 0 | 0xffff => Ok(VirtAddr(addr)), // address is canonical - other => Err(VirtAddrNotValid(other)), - } - } - - pub fn new_unchecked(addr: u64) -> VirtAddr { - VirtAddr(addr) - } - - /// Creates a virtual address that points to `0`. - pub const fn zero() -> VirtAddr { - VirtAddr(0) - } - - /// Converts the address to an `u64`. - pub fn as_u64(self) -> u64 { - self.0 - } - - /// Creates a virtual address from the given pointer - pub fn from_ptr(ptr: *const T) -> Self { - use usize_conversions::FromUsize; - - Self::new(u64::from_usize(ptr as usize)) - } - - /// Converts the address to a raw pointer. - #[cfg(target_pointer_width = "64")] - pub fn as_ptr(self) -> *const T { - use usize_conversions::usize_from; - - usize_from(self.as_u64()) as *const T - } - - /// Converts the address to a mutable raw pointer. - #[cfg(target_pointer_width = "64")] - pub fn as_mut_ptr(self) -> *mut T { - self.as_ptr::() as *mut T - } - - /// Aligns the virtual address upwards to the given alignment. - /// - /// See the `align_up` function for more information. - pub fn align_up(self, align: U) -> Self - where - U: Into, - { - VirtAddr(align_up(self.0, align.into())) - } - - /// Aligns the virtual address downwards to the given alignment. - /// - /// See the `align_down` function for more information. - pub fn align_down(self, align: U) -> Self - where - U: Into, - { - VirtAddr(align_down(self.0, align.into())) - } - - /// Checks whether the virtual address has the demanded alignment. - pub fn is_aligned(self, align: U) -> bool - where - U: Into, - { - self.align_down(align) == self - } - - /// Returns the 12-bit page offset of this virtual address. - pub fn page_offset(&self) -> u12 { - u12::new((self.0 & 0xfff).try_into().unwrap()) - } - - /// Returns the VA range - pub fn va_range(&self) -> Result { - match self.va_range_bits() { - 0x0000 => Ok(VirtAddrRange::BottomRange), - 0xffff => Ok(VirtAddrRange::TopRange), - _ => Err(VirtAddrNotValid(self.0)), - } - } - - /// Returns the top 16 bits - pub fn va_range_bits(&self) -> u16 { - ((self.0 >> 48) & 0xffff) as u16 - } - - /// Returns the 9-bit level 1 page table index. - pub fn p1_index(&self) -> u9 { - u9::new(((self.0 >> 12) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 2 page table index. - pub fn p2_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 3 page table index. - pub fn p3_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap()) - } - - /// Returns the 9-bit level 4 page table index. - pub fn p4_index(&self) -> u9 { - u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap()) - } -} - -impl fmt::Debug for VirtAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VirtAddr({:#x})", self.0) - } -} - -impl Add for VirtAddr { - type Output = Self; - fn add(self, rhs: u64) -> Self::Output { - VirtAddr::new(self.0 + rhs) - } -} - -impl AddAssign for VirtAddr { - fn add_assign(&mut self, rhs: u64) { - *self = *self + rhs; - } -} - -impl Add for VirtAddr -where - u64: FromUsize, -{ - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - self + u64::from_usize(rhs) - } -} - -impl AddAssign for VirtAddr -where - u64: FromUsize, -{ - fn add_assign(&mut self, rhs: usize) { - self.add_assign(u64::from_usize(rhs)) - } -} - -impl Sub for VirtAddr { - type Output = Self; - fn sub(self, rhs: u64) -> Self::Output { - VirtAddr::new(self.0.checked_sub(rhs).unwrap()) - } -} - -impl SubAssign for VirtAddr { - fn sub_assign(&mut self, rhs: u64) { - *self = *self - rhs; - } -} - -impl Sub for VirtAddr -where - u64: FromUsize, -{ - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - self - u64::from_usize(rhs) - } -} - -impl SubAssign for VirtAddr -where - u64: FromUsize, -{ - fn sub_assign(&mut self, rhs: usize) { - self.sub_assign(u64::from_usize(rhs)) - } -} - -impl Sub for VirtAddr { - type Output = u64; - fn sub(self, rhs: VirtAddr) -> Self::Output { - self.as_u64().checked_sub(rhs.as_u64()).unwrap() - } -} - -/// A passed `u64` was not a valid physical address. -/// -/// This means that bits 52 to 64 are not were not all null. -#[derive(Debug)] -pub struct PhysAddrNotValid(u64); - -impl PhysAddr { - /// Creates a new physical address. - /// - /// Panics if a bit in the range 52 to 64 is set. - pub fn new(addr: u64) -> PhysAddr { - assert_eq!( - addr.get_bits(52..64), - 0, - "physical addresses must not have any bits in the range 52 to 64 set" - ); - PhysAddr(addr) - } - - /// Tries to create a new physical address. - /// - /// Fails if any bits in the range 52 to 64 are set. - pub fn try_new(addr: u64) -> Result { - match addr.get_bits(52..64) { - 0 => Ok(PhysAddr(addr)), // address is valid - other => Err(PhysAddrNotValid(other)), - } - } - - /// Converts the address to an `u64`. - pub fn as_u64(self) -> u64 { - self.0 - } - - /// Convenience method for checking if a physical address is null. - pub fn is_null(&self) -> bool { - self.0 == 0 - } - - /// Aligns the physical address upwards to the given alignment. - /// - /// See the `align_up` function for more information. - pub fn align_up(self, align: U) -> Self - where - U: Into, - { - PhysAddr(align_up(self.0, align.into())) - } - - /// Aligns the physical address downwards to the given alignment. - /// - /// See the `align_down` function for more information. - pub fn align_down(self, align: U) -> Self - where - U: Into, - { - PhysAddr(align_down(self.0, align.into())) - } - - /// Checks whether the physical address has the demanded alignment. - pub fn is_aligned(self, align: U) -> bool - where - U: Into, - { - self.align_down(align) == self - } -} - -impl fmt::Debug for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "PhysAddr({:#x})", self.0) - } -} - -impl fmt::Binary for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::LowerHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Octal for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::UpperHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Add for PhysAddr { - type Output = Self; - fn add(self, rhs: u64) -> Self::Output { - PhysAddr::new(self.0 + rhs) - } -} - -impl AddAssign for PhysAddr { - fn add_assign(&mut self, rhs: u64) { - *self = *self + rhs; - } -} - -impl Add for PhysAddr -where - u64: FromUsize, -{ - type Output = Self; - fn add(self, rhs: usize) -> Self::Output { - self + u64::from_usize(rhs) - } -} - -impl AddAssign for PhysAddr -where - u64: FromUsize, -{ - fn add_assign(&mut self, rhs: usize) { - self.add_assign(u64::from_usize(rhs)) - } -} - -impl Sub for PhysAddr { - type Output = Self; - fn sub(self, rhs: u64) -> Self::Output { - PhysAddr::new(self.0.checked_sub(rhs).unwrap()) - } -} - -impl SubAssign for PhysAddr { - fn sub_assign(&mut self, rhs: u64) { - *self = *self - rhs; - } -} - -impl Sub for PhysAddr -where - u64: FromUsize, -{ - type Output = Self; - fn sub(self, rhs: usize) -> Self::Output { - self - u64::from_usize(rhs) - } -} - -impl SubAssign for PhysAddr -where - u64: FromUsize, -{ - fn sub_assign(&mut self, rhs: usize) { - self.sub_assign(u64::from_usize(rhs)) - } -} - -impl Sub for PhysAddr { - type Output = u64; - fn sub(self, rhs: PhysAddr) -> Self::Output { - self.as_u64().checked_sub(rhs.as_u64()).unwrap() - } -} - -/// Align address downwards. -/// -/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be -/// a power of 2. -pub fn align_down(addr: u64, align: u64) -> u64 { - assert!(align.is_power_of_two(), "`align` must be a power of two"); - addr & !(align - 1) -} - -/// Align address upwards. -/// -/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be -/// a power of 2. -pub fn align_up(addr: u64, align: u64) -> u64 { - assert!(align.is_power_of_two(), "`align` must be a power of two"); - let align_mask = align - 1; - if addr & align_mask == 0 { - addr // already aligned - } else { - (addr | align_mask) + 1 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_align_up() { - // align 1 - assert_eq!(align_up(0, 1), 0); - assert_eq!(align_up(1234, 1), 1234); - assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff); - // align 2 - assert_eq!(align_up(0, 2), 0); - assert_eq!(align_up(1233, 2), 1234); - assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe); - // address 0 - assert_eq!(align_up(0, 128), 0); - assert_eq!(align_up(0, 1), 0); - assert_eq!(align_up(0, 2), 0); - assert_eq!(align_up(0, 0x8000000000000000), 0); - } -} diff --git a/crate/aarch64/src/asm.rs b/crate/aarch64/src/asm.rs deleted file mode 100644 index bada049c..00000000 --- a/crate/aarch64/src/asm.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Miscellaneous assembly instructions and functions - -use paging::PhysFrame; -use addr::{PhysAddr, VirtAddr}; -use regs::*; - -/// Returns the current stack pointer. -#[inline(always)] -pub fn sp() -> *const u8 { - let ptr: usize; - unsafe { - asm!("mov $0, sp" : "=r"(ptr)); - } - - ptr as *const u8 -} - -/// Returns the current point counter. -#[inline(always)] -pub unsafe fn get_pc() -> usize { - let pc: usize; - asm!("adr $0, ." : "=r"(pc)); - pc -} - -/// The classic no-op -#[inline] -pub fn nop() { - match () { - #[cfg(target_arch = "aarch64")] - () => unsafe { asm!("nop" :::: "volatile") }, - - #[cfg(not(target_arch = "aarch64"))] - () => unimplemented!(), - } -} - -/// Wait For Interrupt -#[inline] -pub fn wfi() { - match () { - #[cfg(target_arch = "aarch64")] - () => unsafe { asm!("wfi" :::: "volatile") }, - - #[cfg(not(target_arch = "aarch64"))] - () => unimplemented!(), - } -} - -/// Wait For Event -#[inline] -pub fn wfe() { - match () { - #[cfg(target_arch = "aarch64")] - () => unsafe { asm!("wfe" :::: "volatile") }, - - #[cfg(not(target_arch = "aarch64"))] - () => unimplemented!(), - } -} - -/// Exception return -/// -/// Will jump to wherever the corresponding link register points to, and -/// therefore never return. -#[inline] -pub fn eret() -> ! { - use core; - - match () { - #[cfg(target_arch = "aarch64")] - () => unsafe { - asm!("eret" :::: "volatile"); - core::intrinsics::unreachable() - }, - - #[cfg(not(target_arch = "aarch64"))] - () => unimplemented!(), - } -} - -/// Invalidate all TLB entries. -#[inline(always)] -pub fn tlb_invalidate_all() { - unsafe { - asm!( - "dsb ishst - tlbi vmalle1is - dsb ish - isb" - ); - } -} - -/// Invalidate TLB entries that would be used to translate the specified address. -#[inline(always)] -pub fn tlb_invalidate(vaddr: VirtAddr) { - unsafe { - asm!( - "dsb ishst - tlbi vaae1is, $0 - dsb ish - isb" :: "r"(vaddr.as_u64() >> 12) - ); - } -} - -/// Invalidate all instruction caches in Inner Shareable domain to Point of Unification. -#[inline(always)] -pub fn flush_icache_all() { - unsafe { - asm!( - "ic ialluis - dsb ish - isb" - ); - } -} - -/// Address Translate. -#[inline(always)] -pub fn address_translate(vaddr: usize) -> usize { - let paddr: usize; - unsafe { - asm!("at S1E1R, $1; mrs $0, par_el1" : "=r"(paddr) : "r"(vaddr)); - } - paddr -} - -/// Read TTBRx_EL1 as PhysFrame -pub fn ttbr_el1_read(which: u8) -> PhysFrame { - let baddr = match which { - 0 => TTBR0_EL1.get_baddr(), - 1 => TTBR1_EL1.get_baddr(), - _ => 0, - }; - PhysFrame::containing_address(PhysAddr::new(baddr)) -} - -/// Write TTBRx_EL1 from PhysFrame -pub fn ttbr_el1_write(which: u8, frame: PhysFrame) { - let baddr = frame.start_address().as_u64(); - match which { - 0 => TTBR0_EL1.set_baddr(baddr), - 1 => TTBR1_EL1.set_baddr(baddr), - _ => {} - }; -} - -/// write TTBRx_EL1 from PhysFrame and ASID -pub fn ttbr_el1_write_asid(which: u8, asid: u16, frame: PhysFrame) { - let baddr = frame.start_address().as_u64(); - match which { - 0 => TTBR0_EL1.write(TTBR0_EL1::ASID.val(asid as u64) + TTBR0_EL1::BADDR.val(baddr >> 1)), - 1 => TTBR1_EL1.write(TTBR1_EL1::ASID.val(asid as u64) + TTBR1_EL1::BADDR.val(baddr >> 1)), - _ => {} - }; -} diff --git a/crate/aarch64/src/barrier.rs b/crate/aarch64/src/barrier.rs deleted file mode 100644 index 32114806..00000000 --- a/crate/aarch64/src/barrier.rs +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -// Borrow implementations from the pending upstream ACLE implementation until it -// is merged. Afterwards, we'll probably just reexport them, hoping that the API -// doesn't change. -// -// https://github.com/rust-lang-nursery/stdsimd/pull/557 - -mod sealed { - pub trait Dmb { - unsafe fn __dmb(&self); - } - - pub trait Dsb { - unsafe fn __dsb(&self); - } - - pub trait Isb { - unsafe fn __isb(&self); - } -} - -macro_rules! dmb_dsb { - ($A:ident) => { - impl sealed::Dmb for $A { - #[inline(always)] - unsafe fn __dmb(&self) { - asm!(concat!("DMB ", stringify!($A)) : : : "memory" : "volatile") - } - } - impl sealed::Dsb for $A { - #[inline(always)] - unsafe fn __dsb(&self) { - asm!(concat!("DSB ", stringify!($A)) : : : "memory" : "volatile") - } - } - }; -} - -pub struct SY; -pub struct ISH; -pub struct ISHST; - -dmb_dsb!(SY); -dmb_dsb!(ISH); -dmb_dsb!(ISHST); - -impl sealed::Isb for SY { - #[inline(always)] - unsafe fn __isb(&self) { - asm!("ISB SY" : : : "memory" : "volatile") - } -} - -#[inline(always)] -pub unsafe fn dmb(arg: A) -where - A: sealed::Dmb, -{ - arg.__dmb() -} - -#[inline(always)] -pub unsafe fn dsb(arg: A) -where - A: sealed::Dsb, -{ - arg.__dsb() -} - -#[inline(always)] -pub unsafe fn isb(arg: A) -where - A: sealed::Isb, -{ - arg.__isb() -} diff --git a/crate/aarch64/src/lib.rs b/crate/aarch64/src/lib.rs deleted file mode 100644 index bb8bf725..00000000 --- a/crate/aarch64/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -//#![deny(warnings)] -#![feature(asm)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![feature(try_from)] - -extern crate bare_metal; -#[macro_use] -extern crate register; -#[macro_use] -extern crate bitflags; -extern crate bit_field; -extern crate os_bootinfo; -extern crate usize_conversions; - -/// Provides the non-standard-width integer types `u2`–`u63`. -/// -/// We use these integer types in various APIs, for example `u9` for page tables indices. -pub extern crate ux; - -pub use addr::{align_down, align_up, PhysAddr, VirtAddr}; - -pub mod asm; -pub mod addr; -pub mod paging; -pub mod barrier; -pub mod regs; - diff --git a/crate/aarch64/src/paging/frame_alloc.rs b/crate/aarch64/src/paging/frame_alloc.rs deleted file mode 100644 index f3ea4c8b..00000000 --- a/crate/aarch64/src/paging/frame_alloc.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Traits for abstracting away frame allocation and deallocation. - -use paging::{PageSize, PhysFrame}; - -/// A trait for types that can allocate a frame of memory. -pub trait FrameAllocator { - /// Allocate a frame of the appropriate size and return it if possible. - fn alloc(&mut self) -> Option>; -} - -/// A trait for types that can deallocate a frame of memory. -pub trait FrameDeallocator { - /// Deallocate the given frame of memory. - fn dealloc(&mut self, frame: PhysFrame); -} diff --git a/crate/aarch64/src/paging/memory_attribute.rs b/crate/aarch64/src/paging/memory_attribute.rs deleted file mode 100644 index 4a24071a..00000000 --- a/crate/aarch64/src/paging/memory_attribute.rs +++ /dev/null @@ -1,64 +0,0 @@ -//!Memory region attributes (D4.5, page 2174) - -use super::{PageTableAttribute, MEMORY_ATTRIBUTE}; -use regs::*; - -pub trait MairType { - const INDEX: u64; - - #[inline] - fn config_value() -> u64; - - #[inline] - fn attr_value() -> PageTableAttribute; -} - -pub enum MairDevice {} -pub enum MairNormal {} -pub enum MairNormalNonCacheable {} - -impl MairType for MairDevice { - const INDEX: u64 = 0; - - #[inline] - fn config_value() -> u64 { - (MAIR_ATTR::Attr_HIGH::Device + MAIR_ATTR::Attr_LOW_DEVICE::Device_nGnRE).value - } - - #[inline] - fn attr_value() -> PageTableAttribute { - MEMORY_ATTRIBUTE::SH::OuterShareable + MEMORY_ATTRIBUTE::AttrIndx.val(Self::INDEX) - } -} - -impl MairType for MairNormal { - const INDEX: u64 = 1; - - #[inline] - fn config_value() -> u64 { - (MAIR_ATTR::Attr_HIGH::Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc - + MAIR_ATTR::Attr_LOW_MEMORY::InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc) - .value - } - - #[inline] - fn attr_value() -> PageTableAttribute { - MEMORY_ATTRIBUTE::SH::InnerShareable + MEMORY_ATTRIBUTE::AttrIndx.val(Self::INDEX) - } -} - -impl MairType for MairNormalNonCacheable { - const INDEX: u64 = 2; - - #[inline] - fn config_value() -> u64 { - (MAIR_ATTR::Attr_HIGH::Memory_OuterNonCacheable - + MAIR_ATTR::Attr_LOW_MEMORY::InnerNonCacheable) - .value - } - - #[inline] - fn attr_value() -> PageTableAttribute { - MEMORY_ATTRIBUTE::SH::OuterShareable + MEMORY_ATTRIBUTE::AttrIndx.val(Self::INDEX) - } -} diff --git a/crate/aarch64/src/paging/mod.rs b/crate/aarch64/src/paging/mod.rs deleted file mode 100644 index 552d6f63..00000000 --- a/crate/aarch64/src/paging/mod.rs +++ /dev/null @@ -1,549 +0,0 @@ -//! Abstractions for page tables and other paging related structures. -//! -//! Page tables translate virtual memory “pages” to physical memory “frames”. - -pub use self::frame_alloc::*; -pub use self::page_table::*; -#[cfg(target_arch = "aarch64")] -pub use self::recursive::*; - -use core::fmt; -use core::marker::PhantomData; -use core::ops::{Add, AddAssign, Sub, SubAssign}; -use os_bootinfo; -use ux::*; -use addr::{PhysAddr, VirtAddr}; - -mod frame_alloc; -mod page_table; -mod recursive; - -pub mod memory_attribute; - -/// Trait for abstracting over the three possible block/page sizes on aarch64, 4KiB, 2MiB, 1GiB. -pub trait PageSize: Copy + Eq + PartialOrd + Ord { - /// The page size in bytes. - const SIZE: u64; - - /// A string representation of the page size for debug output. - const SIZE_AS_DEBUG_STR: &'static str; -} - -/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages. -pub trait NotGiantPageSize: PageSize {} - -/// A standard 4KiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size4KiB {} - -/// A “huge” 2MiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size2MiB {} - -/// A “giant” 1GiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum Size1GiB {} - -impl PageSize for Size4KiB { - const SIZE: u64 = 4096; - const SIZE_AS_DEBUG_STR: &'static str = "4KiB"; -} - -impl NotGiantPageSize for Size4KiB {} - -impl PageSize for Size2MiB { - const SIZE: u64 = Size4KiB::SIZE * 512; - const SIZE_AS_DEBUG_STR: &'static str = "2MiB"; -} - -impl NotGiantPageSize for Size2MiB {} - -impl PageSize for Size1GiB { - const SIZE: u64 = Size2MiB::SIZE * 512; - const SIZE_AS_DEBUG_STR: &'static str = "1GiB"; -} - -/// A virtual memory page. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(C)] -pub struct Page { - start_address: VirtAddr, - size: PhantomData, -} - -impl Page { - /// Returns the page that starts at the given virtual address. - /// - /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start). - pub fn from_start_address(address: VirtAddr) -> Result { - if !address.is_aligned(S::SIZE) { - return Err(()); - } - Ok(Page::containing_address(address)) - } - - /// Returns the page that contains the given virtual address. - pub fn containing_address(address: VirtAddr) -> Self { - Page { - start_address: address.align_down(S::SIZE), - size: PhantomData, - } - } - - /// Returns the start address of the page. - pub fn start_address(&self) -> VirtAddr { - self.start_address - } - - /// Returns the size the page (4KB, 2MB or 1GB). - pub const fn size(&self) -> u64 { - S::SIZE - } - - /// Returns the level 4 page table index of this page. - pub fn va_range_bits(&self) -> u16 { - self.start_address().va_range_bits() - } - - /// Returns the level 4 page table index of this page. - pub fn p4_index(&self) -> u9 { - self.start_address().p4_index() - } - - /// Returns the level 3 page table index of this page. - pub fn p3_index(&self) -> u9 { - self.start_address().p3_index() - } - - /// Returns a range of pages, exclusive `end`. - pub fn range(start: Self, end: Self) -> PageRange { - PageRange { start, end } - } - - /// Returns a range of pages, inclusive `end`. - pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive { - PageRangeInclusive { start, end } - } - - pub fn of_addr(address: usize) -> Self { - Self::containing_address(VirtAddr::new(address as u64)) - } - - pub fn range_of(begin: usize, end: usize) -> PageRange { - Self::range(Page::of_addr(begin), Page::of_addr(end - 1) + 1) - } -} - -impl Page { - /// Returns the level 2 page table index of this page. - pub fn p2_index(&self) -> u9 { - self.start_address().p2_index() - } -} - -impl Page { - /// Returns the 1GiB memory page with the specified page table indices. - pub fn from_page_table_indices_1gib(p4_index: u9, p3_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index)); - addr.set_bits(30..39, u64::from(p3_index)); - Page::containing_address(VirtAddr::new(addr)) - } -} - -impl Page { - /// Returns the 2MiB memory page with the specified page table indices. - pub fn from_page_table_indices_2mib(p4_index: u9, p3_index: u9, p2_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index)); - addr.set_bits(30..39, u64::from(p3_index)); - addr.set_bits(21..30, u64::from(p2_index)); - Page::containing_address(VirtAddr::new(addr)) - } -} - -impl Page { - /// Returns the 4KiB memory page with the specified page table indices. - pub fn from_page_table_indices(p4_index: u9, p3_index: u9, p2_index: u9, p1_index: u9) -> Self { - use bit_field::BitField; - - let mut addr = 0; - addr.set_bits(39..48, u64::from(p4_index)); - addr.set_bits(30..39, u64::from(p3_index)); - addr.set_bits(21..30, u64::from(p2_index)); - addr.set_bits(12..21, u64::from(p1_index)); - Page::containing_address(VirtAddr::new(addr)) - } - - /// Returns the level 1 page table index of this page. - pub fn p1_index(&self) -> u9 { - self.start_address().p1_index() - } -} - -impl fmt::Debug for Page { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "Page[{}]({:#x})", - S::SIZE_AS_DEBUG_STR, - self.start_address().as_u64() - )) - } -} - -impl Add for Page { - type Output = Self; - fn add(self, rhs: u64) -> Self::Output { - Page::containing_address(self.start_address() + rhs * u64::from(S::SIZE)) - } -} - -impl AddAssign for Page { - fn add_assign(&mut self, rhs: u64) { - *self = self.clone() + rhs; - } -} - -impl Sub for Page { - type Output = Self; - fn sub(self, rhs: u64) -> Self::Output { - Page::containing_address(self.start_address() - rhs * u64::from(S::SIZE)) - } -} - -impl SubAssign for Page { - fn sub_assign(&mut self, rhs: u64) { - *self = self.clone() - rhs; - } -} - -impl Sub for Page { - type Output = u64; - fn sub(self, rhs: Self) -> Self::Output { - (self.start_address - rhs.start_address) / S::SIZE - } -} - -/// A range of pages with exclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PageRange { - /// The start of the range, inclusive. - pub start: Page, - /// The end of the range, exclusive. - pub end: Page, -} - -impl PageRange { - /// Returns wether this range contains no pages. - pub fn is_empty(&self) -> bool { - !(self.start < self.end) - } -} - -impl Iterator for PageRange { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start < self.end { - let page = self.start.clone(); - self.start += 1; - Some(page) - } else { - None - } - } -} - -impl PageRange { - /// Converts the range of 2MiB pages to a range of 4KiB pages. - pub fn as_4kib_page_range(self) -> PageRange { - PageRange { - start: Page::containing_address(self.start.start_address()), - end: Page::containing_address(self.end.start_address()), - } - } -} - -impl fmt::Debug for PageRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PageRange") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// A range of pages with inclusive upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PageRangeInclusive { - /// The start of the range, inclusive. - pub start: Page, - /// The end of the range, inclusive. - pub end: Page, -} - -impl PageRangeInclusive { - /// Returns wether this range contains no pages. - pub fn is_empty(&self) -> bool { - !(self.start <= self.end) - } -} - -impl Iterator for PageRangeInclusive { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let page = self.start.clone(); - self.start += 1; - Some(page) - } else { - None - } - } -} - -impl fmt::Debug for PageRangeInclusive { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PageRangeInclusive") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// A physical memory frame. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -#[repr(C)] -pub struct PhysFrame { - start_address: PhysAddr, - size: PhantomData, -} - -impl PhysFrame { - /// Returns the frame that starts at the given virtual address. - /// - /// Returns an error if the address is not correctly aligned (i.e. is not a valid frame start). - pub fn from_start_address(address: PhysAddr) -> Result { - if !address.is_aligned(S::SIZE) { - return Err(()); - } - Ok(PhysFrame::containing_address(address)) - } - - /// Returns the frame that contains the given physical address. - pub fn containing_address(address: PhysAddr) -> Self { - PhysFrame { - start_address: address.align_down(S::SIZE), - size: PhantomData, - } - } - - /// Returns the start address of the frame. - pub fn start_address(&self) -> PhysAddr { - self.start_address - } - - /// Returns the size the frame (4KB, 2MB or 1GB). - pub fn size(&self) -> u64 { - S::SIZE - } - - /// Returns a range of frames, exclusive `end`. - pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange { - PhysFrameRange { start, end } - } - - /// Returns a range of frames, inclusive `end`. - pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive { - PhysFrameRangeInclusive { start, end } - } - - pub fn of_addr(address: usize) -> Self { - Self::containing_address(PhysAddr::new(address as u64)) - } - - pub fn range_of(begin: usize, end: usize) -> PhysFrameRange { - Self::range(Self::of_addr(begin), Self::of_addr(end - 1) + 1) - } -} - -impl fmt::Debug for PhysFrame { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "PhysFrame[{}]({:#x})", - S::SIZE_AS_DEBUG_STR, - self.start_address().as_u64() - )) - } -} - -impl Add for PhysFrame { - type Output = Self; - fn add(self, rhs: u64) -> Self::Output { - PhysFrame::containing_address(self.start_address() + rhs * u64::from(S::SIZE)) - } -} - -impl AddAssign for PhysFrame { - fn add_assign(&mut self, rhs: u64) { - *self = self.clone() + rhs; - } -} - -impl Sub for PhysFrame { - type Output = Self; - fn sub(self, rhs: u64) -> Self::Output { - PhysFrame::containing_address(self.start_address() - rhs * u64::from(S::SIZE)) - } -} - -impl SubAssign for PhysFrame { - fn sub_assign(&mut self, rhs: u64) { - *self = self.clone() - rhs; - } -} - -impl Sub> for PhysFrame { - type Output = u64; - fn sub(self, rhs: PhysFrame) -> Self::Output { - (self.start_address - rhs.start_address) / S::SIZE - } -} - -/// An range of physical memory frames, exclusive the upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PhysFrameRange { - /// The start of the range, inclusive. - pub start: PhysFrame, - /// The end of the range, exclusive. - pub end: PhysFrame, -} - -impl PhysFrameRange { - /// Returns whether the range contains no frames. - pub fn is_empty(&self) -> bool { - !(self.start < self.end) - } -} - -impl Iterator for PhysFrameRange { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start < self.end { - let frame = self.start.clone(); - self.start += 1; - Some(frame) - } else { - None - } - } -} - -impl From for PhysFrameRange { - fn from(range: os_bootinfo::FrameRange) -> Self { - PhysFrameRange { - start: PhysFrame::from_start_address(PhysAddr::new(range.start_addr())).unwrap(), - end: PhysFrame::from_start_address(PhysAddr::new(range.end_addr())).unwrap(), - } - } -} - -impl Into for PhysFrameRange { - fn into(self) -> os_bootinfo::FrameRange { - os_bootinfo::FrameRange::new( - self.start.start_address().as_u64(), - self.end.start_address().as_u64(), - ) - } -} - -impl fmt::Debug for PhysFrameRange { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PhysFrameRange") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -/// An range of physical memory frames, inclusive the upper bound. -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub struct PhysFrameRangeInclusive { - /// The start of the range, inclusive. - pub start: PhysFrame, - /// The start of the range, exclusive. - pub end: PhysFrame, -} - -impl PhysFrameRangeInclusive { - /// Returns whether the range contains no frames. - pub fn is_empty(&self) -> bool { - !(self.start <= self.end) - } -} - -impl Iterator for PhysFrameRangeInclusive { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let frame = self.start.clone(); - self.start += 1; - Some(frame) - } else { - None - } - } -} - -impl fmt::Debug for PhysFrameRangeInclusive { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("PhysFrameRangeInclusive") - .field("start", &self.start) - .field("end", &self.end) - .finish() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_page_ranges() { - let page_size = Size4KiB::SIZE; - let number = 1000; - - let start_addr = VirtAddr::new(0xdeadbeaf); - let start: Page = Page::containing_address(start_addr); - let end = start.clone() + number; - - let mut range = Page::range(start.clone(), end.clone()); - for i in 0..number { - assert_eq!( - range.next(), - Some(Page::containing_address(start_addr + page_size * i)) - ); - } - assert_eq!(range.next(), None); - - let mut range_inclusive = Page::range_inclusive(start, end); - for i in 0..=number { - assert_eq!( - range_inclusive.next(), - Some(Page::containing_address(start_addr + page_size * i)) - ); - } - assert_eq!(range_inclusive.next(), None); - } -} diff --git a/crate/aarch64/src/paging/page_table.rs b/crate/aarch64/src/paging/page_table.rs deleted file mode 100644 index 6d33fa6b..00000000 --- a/crate/aarch64/src/paging/page_table.rs +++ /dev/null @@ -1,267 +0,0 @@ -use core::fmt; -use core::ops::{Index, IndexMut}; - -use super::{PhysFrame, PageSize}; -use addr::PhysAddr; - -use usize_conversions::usize_from; -use ux::*; - -use register::FieldValue; -use register::cpu::RegisterReadWrite; - -/// Memory attribute fields mask -const MEMORY_ATTR_MASK: u64 = (MEMORY_ATTRIBUTE::SH.mask << MEMORY_ATTRIBUTE::SH.shift) - | (MEMORY_ATTRIBUTE::AttrIndx.mask << MEMORY_ATTRIBUTE::AttrIndx.shift); -/// Output address mask -const ADDR_MASK: u64 = 0x0000_ffff_ffff_f000; -/// Other flags mask -const FLAGS_MASK: u64 = !(MEMORY_ATTR_MASK | ADDR_MASK); - -/// Memory attribute fields -pub type PageTableAttribute = FieldValue; - -/// The error returned by the `PageTableEntry::frame` method. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum FrameError { - /// The entry does not have the `PRESENT` flag set, so it isn't currently mapped to a frame. - FrameNotPresent, - /// The entry does have the `HUGE_PAGE` flag set. The `frame` method has a standard 4KiB frame - /// as return type, so a huge frame can't be returned. - HugeFrame, -} - -/// A 64-bit page table entry. -#[derive(Clone)] -#[repr(transparent)] -pub struct PageTableEntry { - pub entry: u64, -} - -impl RegisterReadWrite for PageTableEntry { - #[inline] - fn get(&self) -> u64 { - self.entry - } - - #[inline] - fn set(&self, value: u64) { - unsafe { *(&self.entry as *const u64 as *mut u64) = value } - } -} - -impl PageTableEntry { - /// Returns whether this entry is zero. - #[inline] - pub fn is_unused(&self) -> bool { - self.entry == 0 - } - - /// Sets this entry to zero. - #[inline] - pub fn set_unused(&mut self) { - self.entry = 0; - } - - /// Returns the flags of this entry. - #[inline] - pub fn flags(&self) -> PageTableFlags { - PageTableFlags::from_bits_truncate(self.entry) - } - - /// Returns the physical address mapped by this entry, might be zero. - #[inline] - pub fn addr(&self) -> PhysAddr { - PhysAddr::new(self.entry & ADDR_MASK) - } - - /// Returns the memory attribute fields of this entry. - #[inline] - pub fn attr(&self) -> PageTableAttribute { - PageTableAttribute::new(MEMORY_ATTR_MASK, 0, self.entry & MEMORY_ATTR_MASK) - } - - /// Returns the physical frame mapped by this entry. - /// - /// Returns the following errors: - /// - /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set. - /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the - /// `addr` function must be used) - pub fn frame(&self) -> Result { - if !self.flags().contains(PageTableFlags::VALID) { - Err(FrameError::FrameNotPresent) - } else if !self.flags().contains(PageTableFlags::TABLE_OR_PAGE) { - // is a huge page (block) - Err(FrameError::HugeFrame) - } else { - Ok(PhysFrame::containing_address(self.addr())) - } - } - - /// Map the entry to the specified physical frame with the specified flags and memory attribute. - pub fn set_frame(&mut self, frame: PhysFrame, flags: PageTableFlags, attr: PageTableAttribute) { - // is not a block - assert!(flags.contains(PageTableFlags::TABLE_OR_PAGE)); - self.set(frame.start_address().as_u64() | flags.bits() | attr.value); - } - - /// The descriptor gives the base address of a block of memory, and the attributes for that - /// memory region. - pub fn set_block(&mut self, addr: PhysAddr, flags: PageTableFlags, attr: PageTableAttribute) { - // is a block - assert!(!flags.contains(PageTableFlags::TABLE_OR_PAGE)); - self.set(addr.align_down(S::SIZE).as_u64() | flags.bits() | attr.value); - } - - /// Map the entry to the specified physical address with the specified flags. - pub fn modify_addr(&mut self, addr: PhysAddr) { - self.entry = (self.entry & !ADDR_MASK) | addr.as_u64(); - } - - /// Sets the flags of this entry. - pub fn modify_flags(&mut self, flags: PageTableFlags) { - self.entry = (self.entry & !FLAGS_MASK) | flags.bits(); - } - - /// Sets the flags of this entry. - pub fn modify_attr(&mut self, attr: PageTableAttribute) { - self.entry = (self.entry & !MEMORY_ATTR_MASK) | attr.value; - } -} - -impl fmt::Debug for PageTableEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = f.debug_struct("PageTableEntry"); - f.field("value", &self.entry); - f.field("addr", &self.addr()); - f.field("flags", &self.flags()); - f.field("attr", &self.attr().value); - f.finish() - } -} - -register_bitfields! {u64, - // Memory attribute fields in the VMSAv8-64 translation table format descriptors (Page 2148~2152) - MEMORY_ATTRIBUTE [ - /// Shareability field - SH OFFSET(8) NUMBITS(2) [ - NonShareable = 0b00, - OuterShareable = 0b10, - InnerShareable = 0b11 - ], - - /// Memory attributes index into the MAIR_EL1 register - AttrIndx OFFSET(2) NUMBITS(3) [] - ] -} - -bitflags! { - /// Possible flags for a page table entry. - pub struct PageTableFlags: u64 { - /// identifies whether the descriptor is valid - const VALID = 1 << 0; - /// the descriptor type - /// 0, Block - /// 1, Table/Page - const TABLE_OR_PAGE = 1 << 1; - /// Access permission: accessable at EL0 - const AP_EL0 = 1 << 6; - /// Access permission: read-only - const AP_RO = 1 << 7; - /// Access flag - const AF = 1 << 10; - /// not global bit - const nG = 1 << 11; - /// Dirty Bit Modifier - const DBM = 1 << 51; - - /// A hint bit indicating that the translation table entry is one of a contiguous set or - /// entries - const Contiguous = 1 << 52; - /// Privileged Execute-never - const PXN = 1 << 53; - /// Execute-never/Unprivileged execute-never - const XN = 1 << 54; - - /// Software Dirty Bit Modifier - const WRITE = 1 << 51; - /// Software dirty bit - const DIRTY = 1 << 55; - /// Software swapped bit - const SWAPPED = 1 << 56; - /// Software writable shared bit for COW - const WRITABLE_SHARED = 1 << 57; - /// Software readonly shared bit for COW - const READONLY_SHARED = 1 << 58; - - /// Privileged Execute-never for table descriptors - const PXNTable = 1 << 59; - /// Execute-never/Unprivileged execute-never for table descriptors - const XNTable = 1 << 60; - } -} - -impl Default for PageTableFlags { - #[inline] - fn default() -> Self { - Self::VALID | Self::TABLE_OR_PAGE | Self::AF | Self::WRITE | Self::PXN | Self::XN - } -} - -/// The number of entries in a page table. -const ENTRY_COUNT: usize = 512; - -/// Represents a page table. -/// -/// Always page-sized. -/// -/// This struct implements the `Index` and `IndexMut` traits, so the entries can be accessed -/// through index operations. For example, `page_table[15]` returns the 15th page table entry. -#[repr(transparent)] -pub struct PageTable { - entries: [PageTableEntry; ENTRY_COUNT], -} - -impl PageTable { - /// Clears all entries. - pub fn zero(&mut self) { - for entry in self.entries.iter_mut() { - entry.set_unused(); - } - } -} - -impl Index for PageTable { - type Output = PageTableEntry; - - fn index(&self, index: usize) -> &Self::Output { - &self.entries[index] - } -} - -impl IndexMut for PageTable { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.entries[index] - } -} - -impl Index for PageTable { - type Output = PageTableEntry; - - fn index(&self, index: u9) -> &Self::Output { - &self.entries[usize_from(u16::from(index))] - } -} - -impl IndexMut for PageTable { - fn index_mut(&mut self, index: u9) -> &mut Self::Output { - &mut self.entries[usize_from(u16::from(index))] - } -} - -impl fmt::Debug for PageTable { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.entries[..].fmt(f) - } -} diff --git a/crate/aarch64/src/paging/recursive.rs b/crate/aarch64/src/paging/recursive.rs deleted file mode 100644 index a1633ff9..00000000 --- a/crate/aarch64/src/paging/recursive.rs +++ /dev/null @@ -1,425 +0,0 @@ -#![cfg(target_arch = "aarch64")] - -use paging::{ - frame_alloc::FrameAllocator, - page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}, - NotGiantPageSize, Page, PageSize, PhysFrame, Size4KiB, -}; -use paging::{page_table::PageTableFlags as Flags, PageTableAttribute, memory_attribute::*}; -use asm::{ttbr_el1_read, tlb_invalidate}; -use barrier; -use ux::u9; -use addr::{PhysAddr, VirtAddr}; - -/// This type represents a page whose mapping has changed in the page table. -/// -/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs -/// to be flushed from the TLB before it's accessed. This type is returned from function that -/// change the mapping of a page to ensure that the TLB flush is not forgotten. -#[derive(Debug)] -#[must_use = "Page Table changes must be flushed or ignored."] -pub struct MapperFlush(Page); - -impl MapperFlush { - /// Create a new flush promise - fn new(page: Page) -> Self { - MapperFlush(page) - } - - /// Flush the page from the TLB to ensure that the newest mapping is used. - pub fn flush(self) { - tlb_invalidate(self.0.start_address()); - } - - /// Don't flush the TLB and silence the “must be used” warning. - pub fn ignore(self) {} -} - -/// A trait for common page table operations. -pub trait Mapper { - /// Creates a new mapping in the page table. - /// - /// This function might need additional physical frames to create new page tables. These - /// frames are allocated from the `allocator` argument. At most three frames are required. - fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - attr: PageTableAttribute, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator; - - /// Removes a mapping from the page table and returns the frame that used to be mapped. - /// - /// Note that no page tables or pages are deallocated. - fn unmap(&mut self, page: Page) -> Result<(PhysFrame, MapperFlush), UnmapError>; - - /// Updates the flags of an existing mapping. - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError>; - - /// Return the frame that the specified page is mapped to. - fn translate_page(&self, page: Page) -> Option>; - - /// Maps the given frame to the virtual page with the same address. - fn identity_map( - &mut self, - frame: PhysFrame, - flags: PageTableFlags, - attr: PageTableAttribute, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - S: PageSize, - Self: Mapper, - { - let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64())); - self.map_to(page, frame, flags, attr, allocator) - } -} - -/// A recursive page table is a last level page table with an entry mapped to the table itself. -/// -/// This recursive mapping allows accessing all page tables in the hierarchy: -/// -/// - To access the level 4 page table, we “loop“ (i.e. follow the recursively mapped entry) four -/// times. -/// - To access a level 3 page table, we “loop” three times and then use the level 4 index. -/// - To access a level 2 page table, we “loop” two times, then use the level 4 index, then the -/// level 3 index. -/// - To access a level 1 page table, we “loop” once, then use the level 4 index, then the -/// level 3 index, then the level 2 index. -/// -/// This struct implements the `Mapper` trait. -#[derive(Debug)] -pub struct RecursivePageTable<'a> { - p4: &'a mut PageTable, - recursive_index: u9, -} - -/// An error indicating that the given page table is not recursively mapped. -/// -/// Returned from `RecursivePageTable::new`. -#[derive(Debug)] -pub struct NotRecursivelyMapped; - -/// This error is returned from `map_to` and similar methods. -#[derive(Debug)] -pub enum MapToError { - /// An additional frame was needed for the mapping process, but the frame allocator - /// returned `None`. - FrameAllocationFailed, - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of an already mapped huge page. - ParentEntryHugePage, - /// The given page is already mapped to a physical frame. - PageAlreadyMapped, -} - -/// An error indicating that an `unmap` call failed. -#[derive(Debug)] -pub enum UnmapError { - /// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the - /// given page is part of a huge page and can't be freed individually. - ParentEntryHugePage, - /// The given page is not mapped to a physical frame. - PageNotMapped, - /// The page table entry for the given page points to an invalid physical address. - InvalidFrameAddress(PhysAddr), -} - -/// An error indicating that an `update_flags` call failed. -#[derive(Debug)] -pub enum FlagUpdateError { - /// The given page is not mapped to a physical frame. - PageNotMapped, -} - -impl<'a> RecursivePageTable<'a> { - /// Creates a new RecursivePageTable from the passed level 4 PageTable. - /// - /// The page table must be recursively mapped, that means: - /// - /// - The page table must have one recursive entry, i.e. an entry that points to the table - /// itself. - /// - The reference must use that “loop”, i.e. be of the form `0o_xxx_xxx_xxx_xxx_0000` - /// where `xxx` is the recursive entry. - /// - The page table must be active, i.e. the CR3 register must contain its physical address. - /// - /// Otherwise `Err(NotRecursivelyMapped)` is returned. - pub fn new(table: &'a mut PageTable) -> Result { - let page = Page::containing_address(VirtAddr::new(table as *const _ as u64)); - let recursive_index = page.p4_index(); - - if page.p3_index() != recursive_index - || page.p2_index() != recursive_index - || page.p1_index() != recursive_index - { - return Err(NotRecursivelyMapped); - } - if Ok(ttbr_el1_read(page.start_address().va_range().unwrap() as u8)) != - table[recursive_index].frame() - { - return Err(NotRecursivelyMapped); - } - - Ok(RecursivePageTable { - p4: table, - recursive_index, - }) - } - - /// Creates a new RecursivePageTable without performing any checks. - /// - /// The `recursive_index` parameter must be the index of the recursively mapped entry. - pub unsafe fn new_unchecked(table: &'a mut PageTable, recursive_index: u9) -> Self { - RecursivePageTable { - p4: table, - recursive_index, - } - } - - /// Internal helper function to create the page table of the next level if needed. - /// - /// If the passed entry is unused, a new frame is allocated from the given allocator, zeroed, - /// and the entry is updated to that address. If the passed entry is already mapped, the next - /// table is returned directly. - /// - /// The `next_page_table` page must be the page of the next page table in the hierarchy. - /// - /// Returns `MapToError::FrameAllocationFailed` if the entry is unused and the allocator - /// returned `None`. Returns `MapToError::ParentEntryHugePage` if the `HUGE_PAGE` flag is set - /// in the passed entry. - unsafe fn create_next_table<'b, A>( - entry: &'b mut PageTableEntry, - next_table_page: Page, - allocator: &mut A, - ) -> Result<&'b mut PageTable, MapToError> - where - A: FrameAllocator, - { - /// This inner function is used to limit the scope of `unsafe`. - /// - /// This is a safe function, so we need to use `unsafe` blocks when we do something unsafe. - fn inner<'b, A>( - entry: &'b mut PageTableEntry, - next_table_page: Page, - allocator: &mut A, - ) -> Result<&'b mut PageTable, MapToError> - where - A: FrameAllocator, - { - let created; - - if entry.is_unused() { - if let Some(frame) = allocator.alloc() { - entry.set_frame(frame, Flags::default(), MairNormal::attr_value()); - created = true; - } else { - return Err(MapToError::FrameAllocationFailed); - } - } else { - created = false; - } - // is a huge page (block) - if !entry.flags().contains(Flags::TABLE_OR_PAGE) { - return Err(MapToError::ParentEntryHugePage); - } - - let page_table_ptr = next_table_page.start_address().as_mut_ptr(); - let page_table: &mut PageTable = unsafe { &mut *(page_table_ptr) }; - if created { - unsafe { barrier::dsb(barrier::ISHST); } - page_table.zero(); - } - Ok(page_table) - } - - inner(entry, next_table_page, allocator) - } - - pub fn p3_ptr(&self, page: Page) -> *mut PageTable { - self.p3_page(page).start_address().as_mut_ptr() - } - - pub fn p2_ptr(&self, page: Page) -> *mut PageTable { - self.p2_page(page).start_address().as_mut_ptr() - } - - pub fn p1_ptr(&self, page: Page) -> *mut PageTable { - self.p1_page(page).start_address().as_mut_ptr() - } - - fn p3_page(&self, page: Page) -> Page { - Page::from_page_table_indices( - self.recursive_index, - self.recursive_index, - self.recursive_index, - page.p4_index(), - ) - } - - fn p2_page(&self, page: Page) -> Page { - Page::from_page_table_indices( - self.recursive_index, - self.recursive_index, - page.p4_index(), - page.p3_index(), - ) - } - - fn p1_page(&self, page: Page) -> Page { - Page::from_page_table_indices( - self.recursive_index, - page.p4_index(), - page.p3_index(), - page.p2_index(), - ) - } -} - -impl<'a> Mapper for RecursivePageTable<'a> { - fn map_to( - &mut self, - page: Page, - frame: PhysFrame, - flags: PageTableFlags, - attr: PageTableAttribute, - allocator: &mut A, - ) -> Result, MapToError> - where - A: FrameAllocator, - { - let self_mut = unsafe { &mut *(self as *const _ as *mut Self) }; - let p4 = &mut self_mut.p4; - - let p3_page = self.p3_page(page); - let p3 = unsafe { Self::create_next_table(&mut p4[page.p4_index()], p3_page, allocator)? }; - - let p2_page = self.p2_page(page); - let p2 = unsafe { Self::create_next_table(&mut p3[page.p3_index()], p2_page, allocator)? }; - - let p1_page = self.p1_page(page); - let p1 = unsafe { Self::create_next_table(&mut p2[page.p2_index()], p1_page, allocator)? }; - - if !p1[page.p1_index()].is_unused() { - return Err(MapToError::PageAlreadyMapped); - } - p1[page.p1_index()].set_frame(frame, flags, attr); - - Ok(MapperFlush::new(page)) - } - - fn unmap( - &mut self, - page: Page, - ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let self_mut = unsafe { &mut *(self as *const _ as *mut Self) }; - let p4 = &mut self_mut.p4; - - let p4_entry = &p4[page.p4_index()]; - p4_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p3 = unsafe { &mut *(self.p3_ptr(page)) }; - let p3_entry = &p3[page.p3_index()]; - p3_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p2 = unsafe { &mut *(self.p2_ptr(page)) }; - let p2_entry = &p2[page.p2_index()]; - p2_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - let p1 = unsafe { &mut *(self.p1_ptr(page)) }; - let p1_entry = &mut p1[page.p1_index()]; - - let frame = p1_entry.frame().map_err(|err| match err { - FrameError::FrameNotPresent => UnmapError::PageNotMapped, - FrameError::HugeFrame => UnmapError::ParentEntryHugePage, - })?; - - p1_entry.set_unused(); - Ok((frame, MapperFlush::new(page))) - } - - fn update_flags( - &mut self, - page: Page, - flags: PageTableFlags, - ) -> Result, FlagUpdateError> { - let self_mut = unsafe { &mut *(self as *const _ as *mut Self) }; - let p4 = &mut self_mut.p4; - - if p4[page.p4_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p3 = unsafe { &mut *(self.p3_ptr(page)) }; - - if p3[page.p3_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p2 = unsafe { &mut *(self.p2_ptr(page)) }; - - if p2[page.p2_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - let p1 = unsafe { &mut *(self.p1_ptr(page)) }; - - if p1[page.p1_index()].is_unused() { - return Err(FlagUpdateError::PageNotMapped); - } - - p1[page.p1_index()].modify_flags(flags); - - Ok(MapperFlush::new(page)) - } - - fn translate_page(&self, page: Page) -> Option> { - let self_mut = unsafe { &mut *(self as *const _ as *mut Self) }; - let p4 = &mut self_mut.p4; - - if p4[page.p4_index()].is_unused() { - return None; - } - - let p3 = unsafe { &*(self.p3_ptr(page)) }; - let p3_entry = &p3[page.p3_index()]; - - if p3_entry.is_unused() { - return None; - } - - let p2 = unsafe { &*(self.p2_ptr(page)) }; - let p2_entry = &p2[page.p2_index()]; - - if p2_entry.is_unused() { - return None; - } - - let p1 = unsafe { &*(self.p1_ptr(page)) }; - let p1_entry = &p1[page.p1_index()]; - - if p1_entry.is_unused() { - return None; - } - - PhysFrame::from_start_address(p1_entry.addr()).ok() - } -} diff --git a/crate/aarch64/src/regs/cntfrq_el0.rs b/crate/aarch64/src/regs/cntfrq_el0.rs deleted file mode 100644 index df56ac9f..00000000 --- a/crate/aarch64/src/regs/cntfrq_el0.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Counter-timer Frequency register - EL0 -//! -//! This register is provided so that software can discover the frequency of the -//! system counter. It must be programmed with this value as part of system -//! initialization. The value of the register is not interpreted by hardware. - -use register::cpu::RegisterReadOnly; - -pub struct Reg; - -impl RegisterReadOnly for Reg { - sys_coproc_read_raw!(u32, "CNTFRQ_EL0"); -} - -pub static CNTFRQ_EL0: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/cnthctl_el2.rs b/crate/aarch64/src/regs/cnthctl_el2.rs deleted file mode 100644 index f5e3c2cd..00000000 --- a/crate/aarch64/src/regs/cnthctl_el2.rs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Counter-timer Hypervisor Control register - EL2 -//! -//! Controls the generation of an event stream from the physical counter, and -//! access from Non-secure EL1 to the physical counter and the Non-secure EL1 -//! physical timer. - -use register::cpu::RegisterReadWrite; - -// When HCR_EL2.E2H == 0: -// TODO: Figure out how we can differentiate depending on HCR_EL2.E2H state -// -// For now, implement the HCR_EL2.E2H == 0 version -register_bitfields! {u32, - CNTHCTL_EL2 [ - /// Traps Non-secure EL0 and EL1 accesses to the physical timer - /// registers to EL2. - /// - /// 0 From AArch64 state: Non-secure EL0 and EL1 accesses to the - /// CNTP_CTL_EL0, CNTP_CVAL_EL0, and CNTP_TVAL_EL0 are trapped to EL2, - /// unless it is trapped by CNTKCTL_EL1.EL0PTEN. - /// - /// From AArch32 state: Non-secure EL0 and EL1 accesses to the - /// CNTP_CTL, CNTP_CVAL, and CNTP_TVAL are trapped to EL2, unless it - /// is trapped by CNTKCTL_EL1.EL0PTEN or CNTKCTL.PL0PTEN. - /// - /// 1 This control does not cause any instructions to be trapped. - /// - /// If EL3 is implemented and EL2 is not implemented, behavior is as if - /// this bit is 1 other than for the purpose of a direct read. - EL1PCEN OFFSET(1) NUMBITS(1) [], - - /// Traps Non-secure EL0 and EL1 accesses to the physical counter - /// register to EL2. - /// - /// 0 From AArch64 state: Non-secure EL0 and EL1 accesses to the - /// CNTPCT_EL0 are trapped to EL2, unless it is trapped by - /// CNTKCTL_EL1.EL0PCTEN. - /// - /// From AArch32 state: Non-secure EL0 and EL1 accesses to the CNTPCT - /// are trapped to EL2, unless it is trapped by CNTKCTL_EL1.EL0PCTEN - /// or CNTKCTL.PL0PCTEN. - /// - /// 1 This control does not cause any instructions to be trapped. - /// - /// If EL3 is implemented and EL2 is not implemented, behavior is as if - /// this bit is 1 other than for the purpose of a direct read. - EL1PCTEN OFFSET(0) NUMBITS(1) [] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "CNTHCTL_EL2"); - sys_coproc_write_raw!(u32, "CNTHCTL_EL2"); -} - -#[allow(non_upper_case_globals)] -pub static CNTHCTL_EL2: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/cntp_ctl_el0.rs b/crate/aarch64/src/regs/cntp_ctl_el0.rs deleted file mode 100644 index 76991ebd..00000000 --- a/crate/aarch64/src/regs/cntp_ctl_el0.rs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Counter-timer Physical Timer Control register - EL0 -//! -//! Control register for the EL1 physical timer. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u32, - CNTP_CTL_EL0 [ - /// The status of the timer. This bit indicates whether the timer - /// condition is met: - /// - /// 0 Timer condition is not met. - /// 1 Timer condition is met. - /// - /// When the value of the ENABLE bit is 1, ISTATUS indicates whether the - /// timer condition is met. ISTATUS takes no account of the value of the - /// IMASK bit. If the value of ISTATUS is 1 and the value of IMASK is 0 - /// then the timer interrupt is asserted. - /// - /// When the value of the ENABLE bit is 0, the ISTATUS field is UNKNOWN. - /// - /// This bit is read-only. - ISTATUS OFFSET(2) NUMBITS(1) [], - - /// Timer interrupt mask bit. Permitted values are: - /// - /// 0 Timer interrupt is not masked by the IMASK bit. - /// 1 Timer interrupt is masked by the IMASK bit. - IMASK OFFSET(1) NUMBITS(1) [], - - /// Enables the timer. Permitted values are: - /// - /// 0 Timer disabled. - /// 1 Timer enabled. - ENABLE OFFSET(0) NUMBITS(1) [] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "CNTP_CTL_EL0"); - sys_coproc_write_raw!(u32, "CNTP_CTL_EL0"); -} - -pub static CNTP_CTL_EL0: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/cntp_tval_el0.rs b/crate/aarch64/src/regs/cntp_tval_el0.rs deleted file mode 100644 index bdf5f6a7..00000000 --- a/crate/aarch64/src/regs/cntp_tval_el0.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Counter-timer Physical Timer TimerValue register - EL0 -//! -//! Holds the timer value for the EL1 physical timer. - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "CNTP_TVAL_EL0"); - sys_coproc_write_raw!(u32, "CNTP_TVAL_EL0"); -} - -pub static CNTP_TVAL_EL0: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/cntpct_el0.rs b/crate/aarch64/src/regs/cntpct_el0.rs deleted file mode 100644 index b381d991..00000000 --- a/crate/aarch64/src/regs/cntpct_el0.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Counter-timer Physical Count register - EL0 -//! -//! Holds the 64-bit physical count value. - -use register::cpu::RegisterReadOnly; - -pub struct Reg; - -impl RegisterReadOnly for Reg { - sys_coproc_read_raw!(u64, "CNTPCT_EL0"); -} - -pub static CNTPCT_EL0: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/cntvoff_el2.rs b/crate/aarch64/src/regs/cntvoff_el2.rs deleted file mode 100644 index aff70749..00000000 --- a/crate/aarch64/src/regs/cntvoff_el2.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Counter-timer Virtual Offset register - EL2 -//! -//! Holds the 64-bit virtual offset. This is the offset between the physical -//! count value visible in CNTPCT_EL0 and the virtual count value visible in -//! CNTVCT_EL0. - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "CNTVOFF_EL2"); - sys_coproc_write_raw!(u64, "CNTVOFF_EL2"); -} - -pub static CNTVOFF_EL2: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/currentel.rs b/crate/aarch64/src/regs/currentel.rs deleted file mode 100644 index 91b8e0a6..00000000 --- a/crate/aarch64/src/regs/currentel.rs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Current Exception Level -//! -//! Holds the current Exception level. - -use register::cpu::RegisterReadOnly; - -register_bitfields! {u32, - CurrentEL [ - /// Current Exception level. Possible values of this field are: - /// - /// 00 EL0 - /// 01 EL1 - /// 10 EL2 - /// 11 EL3 - /// - /// When the HCR_EL2.NV bit is 1, Non-secure EL1 read accesses to the - /// CurrentEL register return the value of 0x2 in this field. - /// - /// This field resets to a value that is architecturally UNKNOWN. - EL OFFSET(2) NUMBITS(2) [ - EL0 = 0, - EL1 = 1, - EL2 = 2, - EL3 = 3 - ] - ] -} - -pub struct Reg; - -impl RegisterReadOnly for Reg { - sys_coproc_read_raw!(u32, "CurrentEL"); -} - -#[allow(non_upper_case_globals)] -pub static CurrentEL: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/daif.rs b/crate/aarch64/src/regs/daif.rs deleted file mode 100644 index bf810a2b..00000000 --- a/crate/aarch64/src/regs/daif.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Interrupt Mask Bits -//! -//! Allows access to the interrupt mask bits. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u32, - DAIF [ - /// Process state D mask. The possible values of this bit are: - /// - /// 0 Watchpoint, Breakpoint, and Software Step exceptions targeted at - /// the current Exception level are not masked. - /// - /// 1 Watchpoint, Breakpoint, and Software Step exceptions targeted at - /// the current Exception level are masked. - /// - /// When the target Exception level of the debug exception is higher - /// than the current Exception level, the exception is not masked by - /// this bit. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 1. - D OFFSET(9) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// SError interrupt mask bit. The possible values of this bit are: - /// - /// 0 Exception not masked. - /// 1 Exception masked. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 1 . - A OFFSET(8) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// IRQ mask bit. The possible values of this bit are: - /// - /// 0 Exception not masked. - /// 1 Exception masked. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 1 . - I OFFSET(7) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// FIQ mask bit. The possible values of this bit are: - /// - /// 0 Exception not masked. - /// 1 Exception masked. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 1 . - F OFFSET(6) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ] - ] -} - - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "DAIF"); - sys_coproc_write_raw!(u32, "DAIF"); -} - -pub static DAIF: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/elr_el2.rs b/crate/aarch64/src/regs/elr_el2.rs deleted file mode 100644 index 0786fbb1..00000000 --- a/crate/aarch64/src/regs/elr_el2.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Exception Link Register - EL2 -//! -//! When taking an exception to EL2, holds the address to return to. - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "ELR_EL2"); - sys_coproc_write_raw!(u64, "ELR_EL2"); -} - -pub static ELR_EL2: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/far_el1.rs b/crate/aarch64/src/regs/far_el1.rs deleted file mode 100644 index fc809fad..00000000 --- a/crate/aarch64/src/regs/far_el1.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Fault Address Register - EL1 -//! -//! Holds the faulting Virtual Address for all synchronous Instruction or Data -//! Abort, PC alignment fault and Watchpoint exceptions that are taken to EL1. - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "FAR_EL1"); - sys_coproc_write_raw!(u64, "FAR_EL1"); -} - -pub static FAR_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/hcr_el2.rs b/crate/aarch64/src/regs/hcr_el2.rs deleted file mode 100644 index 683bbef6..00000000 --- a/crate/aarch64/src/regs/hcr_el2.rs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Hypervisor Configuration Register - EL2 -//! -//! Provides configuration controls for virtualization, including defining -//! whether various Non-secure operations are trapped to EL2. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u64, - HCR_EL2 [ - /// Execution state control for lower Exception levels: - /// - /// 0 Lower levels are all AArch32. - /// 1 The Execution state for EL1 is AArch64. The Execution state for - /// EL0 is determined by the current value of PSTATE.nRW when - /// executing at EL0. - /// - /// If all lower Exception levels cannot use AArch32 then this bit is - /// RAO/WI. - /// - /// In an implementation that includes EL3, when SCR_EL3.NS==0, the PE - /// behaves as if this bit has the same value as the SCR_EL3.RW bit for - /// all purposes other than a direct read or write access of HCR_EL2. - /// - /// The RW bit is permitted to be cached in a TLB. - /// - /// When ARMv8.1-VHE is implemented, and the value of HCR_EL2.{E2H, TGE} - /// is {1, 1}, this field behaves as 1 for all purposes other than a - /// direct read of the value of this bit. - RW OFFSET(31) NUMBITS(1) [ - AllLowerELsAreAarch32 = 0, - EL1IsAarch64 = 1 - ], - - /// Default Cacheability. - /// - /// 0 This control has no effect on the Non-secure EL1&0 translation - /// regime. - /// - /// 1 In Non-secure state: - /// - When EL1 is using AArch64, the PE behaves as if the value of - /// the SCTLR_EL1.M field is 0 for all purposes other than - /// returning the value of a direct read of SCTLR_EL1. - /// - /// - When EL1 is using AArch32, the PE behaves as if the value of - /// the SCTLR.M field is 0 for all purposes other than returning - /// the value of a direct read of SCTLR. - /// - /// - The PE behaves as if the value of the HCR_EL2.VM field is 1 - /// for all purposes other than returning the value of a direct - /// read of HCR_EL2. - /// - /// - The memory type produced by stage 1 of the EL1&0 translation - /// regime is Normal Non-Shareable, Inner Write-Back Read-Allocate - /// Write-Allocate, Outer Write-Back Read-Allocate Write-Allocate. - /// - /// This field has no effect on the EL2, EL2&0, and EL3 translation - /// regimes. - /// - /// This field is permitted to be cached in a TLB. - /// - /// In an implementation that includes EL3, when the value of SCR_EL3.NS - /// is 0 the PE behaves as if this field is 0 for all purposes other - /// than a direct read or write access of HCR_EL2. - /// - /// When ARMv8.1-VHE is implemented, and the value of HCR_EL2.{E2H, TGE} - /// is {1, 1}, this field behaves as 0 for all purposes other than a - /// direct read of the value of this field. - DC OFFSET(12) NUMBITS(1) [], - - /// Set/Way Invalidation Override. Causes Non-secure EL1 execution of - /// the data cache invalidate by set/way instructions to perform a data - /// cache clean and invalidate by set/way: - /// - /// 0 This control has no effect on the operation of data cache - /// invalidate by set/way instructions. - /// - /// 1 Data cache invalidate by set/way instructions perform a data cache - /// clean and invalidate by set/way. - /// - /// When the value of this bit is 1: - /// - /// AArch32: DCISW performs the same invalidation as a DCCISW - /// instruction. - /// - /// AArch64: DC ISW performs the same invalidation as a DC CISW - /// instruction. - /// - /// This bit can be implemented as RES 1. - /// - /// In an implementation that includes EL3, when the value of SCR_EL3.NS - /// is 0 the PE behaves as if this field is 0 for all purposes other - /// than a direct read or write access of HCR_EL2. - /// - /// When HCR_EL2.TGE is 1, the PE ignores the value of this field for - /// all purposes other than a direct read of this field. - SWIO OFFSET(1) NUMBITS(1) [] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "HCR_EL2"); - sys_coproc_write_raw!(u64, "HCR_EL2"); -} - -pub static HCR_EL2: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/id_aa64mmfr0_el1.rs b/crate/aarch64/src/regs/id_aa64mmfr0_el1.rs deleted file mode 100644 index f75813ca..00000000 --- a/crate/aarch64/src/regs/id_aa64mmfr0_el1.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! AArch64 Memory Model Feature Register 0 - EL1 -//! -//! Provides information about the implemented memory model and memory -//! management support in AArch64 state. - -use register::cpu::RegisterReadOnly; - -register_bitfields! {u64, - ID_AA64MMFR0_EL1 [ - /// Support for 4KiB memory translation granule size. Defined values - /// are: - /// - /// 0000 4KiB granule supported. - /// 1111 4KiB granule not supported. - /// - /// All other values are reserved. - TGran4 OFFSET(28) NUMBITS(4) [ - Supported = 0b0000, - NotSupported = 0b1111 - ], - - /// Support for 64KiB memory translation granule size. Defined values - /// are: - /// - /// 0000 64KiB granule supported. - /// 1111 64KiB granule not supported. - /// - /// All other values are reserved. - TGran64 OFFSET(24) NUMBITS(4) [ - Supported = 0b0000, - NotSupported = 0b1111 - ], - - /// Physical Address range supported. Defined values are: - /// - /// 0000 32 bits, 4GiB. - /// 0001 36 bits, 64GiB. - /// 0010 40 bits, 1TiB. - /// 0011 42 bits, 4TiB. - /// 0100 44 bits, 16TiB. - /// 0101 48 bits, 256TiB. - /// 0110 52 bits, 4PiB. - /// - /// All other values are reserved. - /// - /// The value 0110 is permitted only if the implementation includes - /// ARMv8.2-LPA, otherwise it is reserved. - PARange OFFSET(0) NUMBITS(4) [ - Bits_32 = 0b0000, - Bits_36 = 0b0001, - Bits_40 = 0b0010, - Bits_42 = 0b0011, - Bits_44 = 0b0100, - Bits_48 = 0b0101, - Bits_52 = 0b0110 - ] - ] -} - -pub struct Reg; - -impl RegisterReadOnly for Reg { - sys_coproc_read_raw!(u64, "ID_AA64MMFR0_EL1"); -} - -pub static ID_AA64MMFR0_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/macros.rs b/crate/aarch64/src/regs/macros.rs deleted file mode 100644 index bd4439c5..00000000 --- a/crate/aarch64/src/regs/macros.rs +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -macro_rules! __read_raw { - ($width:ty, $asm_instr:tt, $asm_reg_name:tt) => { - /// Reads the raw bits of the CPU register. - #[inline] - fn get(&self) -> $width { - match () { - #[cfg(target_arch = "aarch64")] - () => { - let reg; - unsafe { - asm!(concat!($asm_instr, " $0, ", $asm_reg_name) : "=r"(reg) ::: "volatile"); - } - reg - } - - #[cfg(not(target_arch = "aarch64"))] - () => unimplemented!(), - } - } - }; -} - -macro_rules! __write_raw { - ($width:ty, $asm_instr:tt, $asm_reg_name:tt) => { - /// Writes raw bits to the CPU register. - #[cfg_attr(not(target_arch = "aarch64"), allow(unused_variables))] - #[inline] - fn set(&self, value: $width) { - match () { - #[cfg(target_arch = "aarch64")] - () => { - unsafe { - asm!(concat!($asm_instr, " ", $asm_reg_name, ", $0") :: "r"(value) :: "volatile") - } - } - - #[cfg(not(target_arch = "aarch64"))] - () => unimplemented!(), - } - } - }; -} - -/// Raw read from system coprocessor registers -macro_rules! sys_coproc_read_raw { - ($width:ty, $asm_reg_name:tt) => { - __read_raw!($width, "mrs", $asm_reg_name); - }; -} - -/// Raw write to system coprocessor registers -macro_rules! sys_coproc_write_raw { - ($width:ty, $asm_reg_name:tt) => { - __write_raw!($width, "msr", $asm_reg_name); - }; -} - -/// Raw read from (ordinary) registers -macro_rules! read_raw { - ($width:ty, $asm_reg_name:tt) => { - __read_raw!($width, "mov", $asm_reg_name); - }; -} -/// Raw write to (ordinary) registers -macro_rules! write_raw { - ($width:ty, $asm_reg_name:tt) => { - __write_raw!($width, "mov", $asm_reg_name); - }; -} diff --git a/crate/aarch64/src/regs/mair_el1.rs b/crate/aarch64/src/regs/mair_el1.rs deleted file mode 100644 index dbd7f9d8..00000000 --- a/crate/aarch64/src/regs/mair_el1.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Memory Attribute Indirection Register - EL1 -//! -//! Provides the memory attribute encodings corresponding to the possible -//! AttrIndx values in a Long-descriptor format translation table entry for -//! stage 1 translations at EL1. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u64, - MAIR_EL1 [ - /// Attribute 7 - Attr7 OFFSET(56) NUMBITS(8) [], - - /// Attribute 6 - Attr6 OFFSET(48) NUMBITS(8) [], - - /// Attribute 5 - Attr5 OFFSET(40) NUMBITS(8) [], - - /// Attribute 4 - Attr4 OFFSET(32) NUMBITS(8) [], - - /// Attribute 3 - Attr3 OFFSET(24) NUMBITS(8) [], - - /// Attribute 2 - Attr2 OFFSET(16) NUMBITS(8) [], - - /// Attribute 1 - Attr1 OFFSET(8) NUMBITS(8) [], - - /// Attribute 0 - Attr0 OFFSET(0) NUMBITS(8) [] - ] -} - -register_bitfields! {u64, - MAIR_ATTR [ - Attr_HIGH OFFSET(4) NUMBITS(4) [ - Device = 0b0000, - Memory_OuterNonCacheable = 0b0100, - Memory_OuterWriteThrough_NonTransient_ReadAlloc_WriteAlloc = 0b1011, - Memory_OuterWriteBack_NonTransient_ReadAlloc_WriteAlloc = 0b1111 - ], - Attr_LOW_DEVICE OFFSET(0) NUMBITS(4) [ - Device_nGnRnE = 0b0000, - Device_nGnRE = 0b0100, - Device_nGRE = 0b1000, - Device_GRE = 0b1100 - ], - Attr_LOW_MEMORY OFFSET(0) NUMBITS(4) [ - InnerNonCacheable = 0b0100, - InnerWriteThrough_NonTransient_ReadAlloc_WriteAlloc = 0b1011, - InnerWriteBack_NonTransient_ReadAlloc_WriteAlloc = 0b1111 - ] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "MAIR_EL1"); - sys_coproc_write_raw!(u64, "MAIR_EL1"); -} - -pub static MAIR_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/mod.rs b/crate/aarch64/src/regs/mod.rs deleted file mode 100644 index 11a6d3fb..00000000 --- a/crate/aarch64/src/regs/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Processor core registers - -#[macro_use] -mod macros; - -mod cntfrq_el0; -mod cnthctl_el2; -mod cntp_ctl_el0; -mod cntp_tval_el0; -mod cntpct_el0; -mod cntvoff_el2; -mod currentel; -mod daif; -mod elr_el2; -mod far_el1; -mod hcr_el2; -mod id_aa64mmfr0_el1; -mod mair_el1; -mod mpidr_el1; -mod sctlr_el1; -mod sp; -mod sp_el0; -mod sp_el1; -mod spsel; -mod spsr_el2; -mod tcr_el1; -mod ttbr0_el1; -mod ttbr1_el1; - -// Export only the R/W traits and the static reg definitions -pub use register::cpu::*; - -pub use self::cntfrq_el0::CNTFRQ_EL0; -pub use self::cnthctl_el2::CNTHCTL_EL2; -pub use self::cntp_ctl_el0::CNTP_CTL_EL0; -pub use self::cntp_tval_el0::CNTP_TVAL_EL0; -pub use self::cntpct_el0::CNTPCT_EL0; -pub use self::cntvoff_el2::CNTVOFF_EL2; -pub use self::currentel::CurrentEL; -pub use self::daif::DAIF; -pub use self::elr_el2::ELR_EL2; -pub use self::far_el1::FAR_EL1; -pub use self::hcr_el2::HCR_EL2; -pub use self::id_aa64mmfr0_el1::ID_AA64MMFR0_EL1; -pub use self::mair_el1::{MAIR_EL1, MAIR_ATTR}; -pub use self::mpidr_el1::MPIDR_EL1; -pub use self::sctlr_el1::SCTLR_EL1; -pub use self::sp::SP; -pub use self::sp_el0::SP_EL0; -pub use self::sp_el1::SP_EL1; -pub use self::spsel::SPSel; -pub use self::spsr_el2::SPSR_EL2; -pub use self::tcr_el1::TCR_EL1; -pub use self::ttbr0_el1::TTBR0_EL1; -pub use self::ttbr1_el1::TTBR1_EL1; diff --git a/crate/aarch64/src/regs/mpidr_el1.rs b/crate/aarch64/src/regs/mpidr_el1.rs deleted file mode 100644 index 6fbfea00..00000000 --- a/crate/aarch64/src/regs/mpidr_el1.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Multiprocessor Affinity Register - EL1 -//! -//! In a multiprocessor system, provides an additional PE -//! identification mechanism for scheduling purposes. - -use register::cpu::RegisterReadOnly; - -pub struct Reg; - -impl RegisterReadOnly for Reg { - sys_coproc_read_raw!(u64, "MPIDR_EL1"); -} - -pub static MPIDR_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/sctlr_el1.rs b/crate/aarch64/src/regs/sctlr_el1.rs deleted file mode 100644 index 1f463b42..00000000 --- a/crate/aarch64/src/regs/sctlr_el1.rs +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! System Control Register - EL1 -//! -//! Provides top level control of the system, including its memory system, at -//! EL1 and EL0. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u32, - SCTLR_EL1 [ - /// Instruction access Cacheability control, for accesses at EL0 and - /// EL1: - /// - /// 0 All instruction access to Normal memory from EL0 and EL1 are - /// Non-cacheable for all levels of instruction and unified cache. - /// - /// If the value of SCTLR_EL1.M is 0, instruction accesses from stage - /// 1 of the EL1&0 translation regime are to Normal, Outer Shareable, - /// Inner Non-cacheable, Outer Non-cacheable memory. - /// - /// 1 This control has no effect on the Cacheability of instruction - /// access to Normal memory from EL0 and EL1. - /// - /// If the value of SCTLR_EL1.M is 0, instruction accesses from stage - /// 1 of the EL1&0 translation regime are to Normal, Outer Shareable, - /// Inner Write-Through, Outer Write-Through memory. - /// - /// When the value of the HCR_EL2.DC bit is 1, then instruction access - /// to Normal memory from EL0 and EL1 are Cacheable regardless of the - /// value of the SCTLR_EL1.I bit. - /// - /// When ARMv8.1-VHE is implemented, and the value of HCR_EL2.{E2H, TGE} - /// is {1, 1}, this bit has no effect on the PE. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 0. - I OFFSET(12) NUMBITS(1) [ - NonCacheable = 0, - Cacheable = 1 - ], - - /// Cacheability control, for data accesses. - /// - /// 0 All data access to Normal memory from EL0 and EL1, and all Normal - /// memory accesses to the EL1&0 stage 1 translation tables, are - /// Non-cacheable for all levels of data and unified cache. - /// - /// 1 This control has no effect on the Cacheability of: - /// - Data access to Normal memory from EL0 and EL1. - /// - Normal memory accesses to the EL1&0 stage 1 translation - /// tables. - /// - /// When the value of the HCR_EL2.DC bit is 1, the PE ignores - /// SCLTR.C. This means that Non-secure EL0 and Non-secure EL1 data - /// accesses to Normal memory are Cacheable. - /// - /// When ARMv8.1-VHE is implemented, and the value of HCR_EL2.{E2H, TGE} - /// is {1, 1}, this bit has no effect on the PE. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 0. - C OFFSET(2) NUMBITS(1) [ - NonCacheable = 0, - Cacheable = 1 - ], - - /// MMU enable for EL1 and EL0 stage 1 address translation. Possible - /// values of this bit are: - /// - /// 0 EL1 and EL0 stage 1 address translation disabled. - /// See the SCTLR_EL1.I field for the behavior of instruction accesses - /// to Normal memory. - /// 1 EL1 and EL0 stage 1 address translation enabled. - M OFFSET(0) NUMBITS(1) [ - Disable = 0, - Enable = 1 - ] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "SCTLR_EL1"); - sys_coproc_write_raw!(u32, "SCTLR_EL1"); -} - -pub static SCTLR_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/sp.rs b/crate/aarch64/src/regs/sp.rs deleted file mode 100644 index f9f578be..00000000 --- a/crate/aarch64/src/regs/sp.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! The stack pointer - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - read_raw!(u64, "sp"); - write_raw!(u64, "sp"); -} - -pub static SP: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/sp_el0.rs b/crate/aarch64/src/regs/sp_el0.rs deleted file mode 100644 index aa82fdbc..00000000 --- a/crate/aarch64/src/regs/sp_el0.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! The stack pointer - EL0 -//! -//! Holds the stack pointer associated with EL0. At higher Exception levels, -//! this is used as the current stack pointer when the value of SPSel.SP is 0. - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "SP_EL0"); - sys_coproc_write_raw!(u64, "SP_EL0"); -} - -pub static SP_EL0: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/sp_el1.rs b/crate/aarch64/src/regs/sp_el1.rs deleted file mode 100644 index 4357412b..00000000 --- a/crate/aarch64/src/regs/sp_el1.rs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! The stack pointer - EL1 -//! -//! Holds the stack pointer associated with EL1. When executing at EL1, the -//! value of SPSel.SP determines the current stack pointer: -//! -//! SPSel.SP | current stack pointer -//! -------------------------------- -//! 0 | SP_EL0 -//! 1 | SP_EL1 - -use register::cpu::RegisterReadWrite; - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "SP_EL1"); - sys_coproc_write_raw!(u64, "SP_EL1"); -} - -pub static SP_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/spsel.rs b/crate/aarch64/src/regs/spsel.rs deleted file mode 100644 index 91e3694f..00000000 --- a/crate/aarch64/src/regs/spsel.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Stack Pointer Select -//! -//! Allows the Stack Pointer to be selected between SP_EL0 and SP_ELx. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u32, - SPSel [ - /// Stack pointer to use. Possible values of this bit are: - /// - /// 0 Use SP_EL0 at all Exception levels. - /// 1 Use SP_ELx for Exception level ELx. - /// - /// When this register has an architecturally-defined reset value, this - /// field resets to 1. - SP OFFSET(0) NUMBITS(1) [ - EL0 = 0, - ELx = 1 - ] - ] -} - - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "SPSEL"); - sys_coproc_write_raw!(u32, "SPSEL"); -} - -#[allow(non_upper_case_globals)] -pub static SPSel: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/spsr_el2.rs b/crate/aarch64/src/regs/spsr_el2.rs deleted file mode 100644 index 56078a45..00000000 --- a/crate/aarch64/src/regs/spsr_el2.rs +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Saved Program Status Register - EL2 -//! -//! Holds the saved process state when an exception is taken to EL2. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u32, - SPSR_EL2 [ - /// Process state D mask. The possible values of this bit are: - /// - /// 0 Watchpoint, Breakpoint, and Software Step exceptions targeted at - /// the current Exception level are not masked. - /// - /// 1 Watchpoint, Breakpoint, and Software Step exceptions targeted at - /// the current Exception level are masked. - /// - /// When the target Exception level of the debug exception is higher - /// than the current Exception level, the exception is not masked by - /// this bit. - D OFFSET(9) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// SError interrupt mask bit. The possible values of this bit are: - /// - /// 0 Exception not masked. - /// 1 Exception masked. - A OFFSET(8) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// IRQ mask bit. The possible values of this bit are: - /// - /// 0 Exception not masked. - /// 1 Exception masked. - I OFFSET(7) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// FIQ mask bit. The possible values of this bit are: - /// - /// 0 Exception not masked. - /// 1 Exception masked. - F OFFSET(6) NUMBITS(1) [ - Unmasked = 0, - Masked = 1 - ], - - /// AArch64 state (Exception level and selected SP) that an exception - /// was taken from. The possible values are: - /// - /// M[3:0] | State - /// -------------- - /// 0b0000 | EL0t - /// 0b0100 | EL1t - /// 0b0101 | EL1h - /// 0b1000 | EL2t - /// 0b1001 | EL2h - /// - /// Other values are reserved, and returning to an Exception level that - /// is using AArch64 with a reserved value in this field is treated as - /// an illegal exception return. - /// - /// The bits in this field are interpreted as follows: - /// - M[3:2] holds the Exception Level. - /// - M[1] is unused and is RES 0 for all non-reserved values. - /// - M[0] is used to select the SP: - /// - 0 means the SP is always SP0. - /// - 1 means the exception SP is determined by the EL. - M OFFSET(0) NUMBITS(4) [ - EL0t = 0b0000, - EL1t = 0b0100, - EL1h = 0b0101, - EL2t = 0b1000, - EL2h = 0b1001 - ] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u32, "SPSR_EL2"); - sys_coproc_write_raw!(u32, "SPSR_EL2"); -} - -pub static SPSR_EL2: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/tcr_el1.rs b/crate/aarch64/src/regs/tcr_el1.rs deleted file mode 100644 index 9ebb6d79..00000000 --- a/crate/aarch64/src/regs/tcr_el1.rs +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Translation Control Register - EL1 -//! -//! The control register for stage 1 of the EL1&0 translation regime. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u64, - TCR_EL1 [ - /// Top Byte ignored - indicates whether the top byte of an address is - /// used for address match for the TTBR1_EL1 region, or ignored and used - /// for tagged addresses. Defined values are: - /// - /// 0 Top Byte used in the address calculation. - /// 1 Top Byte ignored in the address calculation. - TBI1 OFFSET(38) NUMBITS(1) [ - Used = 0, - Ignored = 1 - ], - - /// Top Byte ignored - indicates whether the top byte of an address is - /// used for address match for the TTBR0_EL1 region, or ignored and used - /// for tagged addresses. Defined values are: - /// - /// 0 Top Byte used in the address calculation. - /// 1 Top Byte ignored in the address calculation. - TBI0 OFFSET(37) NUMBITS(1) [ - Used = 0, - Ignored = 1 - ], - - /// ASID Size. Defined values are: - /// - /// 0 8 bit - the upper 8 bits of TTBR0_EL1 and TTBR1_EL1 are ignored by - /// hardware for every purpose except reading back the register, and are - /// treated as if they are all zeros for when used for allocation and matching entries in the TLB. - /// 1 16 bit - the upper 16 bits of TTBR0_EL1 and TTBR1_EL1 are used for - /// allocation and matching in the TLB. - /// - /// If the implementation has only 8 bits of ASID, this field is RES0. - AS OFFSET(36) NUMBITS(1) [ - Bits_8 = 0, - Bits_16 = 1 - ], - - /// Intermediate Physical Address Size. - /// - /// 000 32 bits, 4GiB. - /// 001 36 bits, 64GiB. - /// 010 40 bits, 1TiB. - /// 011 42 bits, 4TiB. - /// 100 44 bits, 16TiB. - /// 101 48 bits, 256TiB. - /// 110 52 bits, 4PiB - /// - /// Other values are reserved. - /// - /// The reserved values behave in the same way as the 101 or 110 - /// encoding, but software must not rely on this property as the - /// behavior of the reserved values might change in a future revision of - /// the architecture. - /// - /// The value 110 is permitted only if ARMv8.2-LPA is implemented and - /// the translation granule size is 64KiB. - /// - /// In an implementation that supports 52-bit PAs, if the value of this - /// field is not 110 , then bits[51:48] of every translation table base - /// address for the stage of translation controlled by TCR_EL1 are 0000 - /// . - IPS OFFSET(32) NUMBITS(3) [ - Bits_32 = 0b000, - Bits_36 = 0b001, - Bits_40 = 0b010, - Bits_42 = 0b011, - Bits_44 = 0b100, - Bits_48 = 0b101, - Bits_52 = 0b110 - ], - - /// Granule size for the TTBR1_EL1. - /// - /// 01 16KiB - /// 10 4KiB - /// 11 64KiB - /// - /// Other values are reserved. - /// - /// If the value is programmed to either a reserved value, or a size - /// that has not been implemented, then the hardware will treat the - /// field as if it has been programmed to an IMPLEMENTATION DEFINED - /// choice of the sizes that has been implemented for all purposes other - /// than the value read back from this register. - /// - /// It is IMPLEMENTATION DEFINED whether the value read back is the - /// value programmed or the value that corresponds to the size chosen. - TG1 OFFSET(30) NUMBITS(2) [ - KiB_4 = 0b10, - KiB_16 = 0b01, - KiB_64 = 0b11 - ], - - /// Shareability attribute for memory associated with translation table - /// walks using TTBR1_EL1. - /// - /// 00 Non-shareable - /// 10 Outer Shareable - /// 11 Inner Shareable - /// - /// Other values are reserved. - SH1 OFFSET(28) NUMBITS(2) [ - None = 0b00, - Outer = 0b10, - Inner = 0b11 - ], - - /// Outer cacheability attribute for memory associated with translation - /// table walks using TTBR1_EL1. - /// - /// 00 Normal memory, Outer Non-cacheable - /// - /// 01 Normal memory, Outer Write-Back Read-Allocate Write-Allocate - /// Cacheable - /// - /// 10 Normal memory, Outer Write-Through Read-Allocate No - /// Write-Allocate Cacheable - /// - /// 11 Normal memory, Outer Write-Back Read-Allocate No Write-Allocate - /// Cacheable - ORGN1 OFFSET(26) NUMBITS(2) [ - NonCacheable = 0b00, - WriteBack_ReadAlloc_WriteAlloc_Cacheable = 0b01, - WriteThrough_ReadAlloc_NoWriteAlloc_Cacheable = 0b10, - WriteBack_ReadAlloc_NoWriteAlloc_Cacheable = 0b11 - ], - - /// Inner cacheability attribute for memory associated with translation - /// table walks using TTBR1_EL1. - /// - /// 00 Normal memory, Inner Non-cacheable - /// - /// 01 Normal memory, Inner Write-Back Read-Allocate Write-Allocate - /// Cacheable - /// - /// 10 Normal memory, Inner Write-Through Read-Allocate No - /// Write-Allocate Cacheable - /// - /// 11 Normal memory, Inner Write-Back Read-Allocate No Write-Allocate - /// Cacheable - IRGN1 OFFSET(24) NUMBITS(2) [ - NonCacheable = 0b00, - WriteBack_ReadAlloc_WriteAlloc_Cacheable = 0b01, - WriteThrough_ReadAlloc_NoWriteAlloc_Cacheable = 0b10, - WriteBack_ReadAlloc_NoWriteAlloc_Cacheable = 0b11 - ], - - /// Translation table walk disable for translations using - /// TTBR1_EL1. This bit controls whether a translation table walk is - /// performed on a TLB miss, for an address that is translated using - /// TTBR1_EL1. The encoding of this bit is: - /// - /// 0 Perform translation table walks using TTBR1_EL1. - /// - /// 1 A TLB miss on an address that is translated using TTBR1_EL1 - /// generates a Translation fault. No translation table walk is - /// performed. - EPD1 OFFSET(23) NUMBITS(1) [ - EnableTTBR1Walks = 0, - DisableTTBR1Walks = 1 - ], - - /// Selects whether TTBR0_EL1 or TTBR1_EL1 defines the ASID. The encoding - /// of this bit is: - /// - /// 0 TTBR0_EL1.ASID defines the ASID. - /// - /// 1 TTBR1_EL1.ASID defines the ASID. - A1 OFFSET(22) NUMBITS(1) [ - UseTTBR0ASID = 0b0, - UseTTBR1ASID = 0b1 - ], - - /// The size offset of the memory region addressed by TTBR1_EL1. The - /// region size is 2^(64-T1SZ) bytes. - /// - /// The maximum and minimum possible values for T1SZ depend on the level - /// of translation table and the memory translation granule size, as - /// described in the AArch64 Virtual Memory System Architecture chapter. - T1SZ OFFSET(16) NUMBITS(6) [], - - /// Granule size for the TTBR0_EL1. - /// - /// 00 4KiB - /// 01 64KiB - /// 10 16KiB - /// - /// Other values are reserved. - /// - /// If the value is programmed to either a reserved value, or a size - /// that has not been implemented, then the hardware will treat the - /// field as if it has been programmed to an IMPLEMENTATION DEFINED - /// choice of the sizes that has been implemented for all purposes other - /// than the value read back from this register. - /// - /// It is IMPLEMENTATION DEFINED whether the value read back is the - /// value programmed or the value that corresponds to the size chosen. - TG0 OFFSET(14) NUMBITS(2) [ - KiB_4 = 0b00, - KiB_16 = 0b10, - KiB_64 = 0b01 - ], - - /// Shareability attribute for memory associated with translation table - /// walks using TTBR0_EL1. - /// - /// 00 Non-shareable - /// 10 Outer Shareable - /// 11 Inner Shareable - /// - /// Other values are reserved. - SH0 OFFSET(12) NUMBITS(2) [ - None = 0b00, - Outer = 0b10, - Inner = 0b11 - ], - - /// Outer cacheability attribute for memory associated with translation - /// table walks using TTBR0_EL1. - /// - /// 00 Normal memory, Outer Non-cacheable - /// - /// 01 Normal memory, Outer Write-Back Read-Allocate Write-Allocate - /// Cacheable - /// - /// 10 Normal memory, Outer Write-Through Read-Allocate No - /// Write-Allocate Cacheable - /// - /// 11 Normal memory, Outer Write-Back Read-Allocate No Write-Allocate - /// Cacheable - ORGN0 OFFSET(10) NUMBITS(2) [ - NonCacheable = 0b00, - WriteBack_ReadAlloc_WriteAlloc_Cacheable = 0b01, - WriteThrough_ReadAlloc_NoWriteAlloc_Cacheable = 0b10, - WriteBack_ReadAlloc_NoWriteAlloc_Cacheable = 0b11 - ], - - /// Inner cacheability attribute for memory associated with translation - /// table walks using TTBR0_EL1. - /// - /// 00 Normal memory, Inner Non-cacheable - /// - /// 01 Normal memory, Inner Write-Back Read-Allocate Write-Allocate - /// Cacheable - /// - /// 10 Normal memory, Inner Write-Through Read-Allocate No - /// Write-Allocate Cacheable - /// - /// 11 Normal memory, Inner Write-Back Read-Allocate No Write-Allocate - /// Cacheable - IRGN0 OFFSET(8) NUMBITS(2) [ - NonCacheable = 0b00, - WriteBack_ReadAlloc_WriteAlloc_Cacheable = 0b01, - WriteThrough_ReadAlloc_NoWriteAlloc_Cacheable = 0b10, - WriteBack_ReadAlloc_NoWriteAlloc_Cacheable = 0b11 - ], - - /// Translation table walk disable for translations using - /// TTBR0_EL1. This bit controls whether a translation table walk is - /// performed on a TLB miss, for an address that is translated using - /// TTBR0_EL1. The encoding of this bit is: - /// - /// 0 Perform translation table walks using TTBR0_EL1. - /// - /// 1 A TLB miss on an address that is translated using TTBR0_EL1 - /// generates a Translation fault. No translation table walk is - /// performed. - EPD0 OFFSET(7) NUMBITS(1) [ - EnableTTBR0Walks = 0, - DisableTTBR0Walks = 1 - ], - - /// The size offset of the memory region addressed by TTBR0_EL1. The - /// region size is 2^(64-T0SZ) bytes. - /// - /// The maximum and minimum possible values for T0SZ depend on the level - /// of translation table and the memory translation granule size, as - /// described in the AArch64 Virtual Memory System Architecture chapter. - T0SZ OFFSET(0) NUMBITS(6) [] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "TCR_EL1"); - sys_coproc_write_raw!(u64, "TCR_EL1"); -} - -pub static TCR_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/ttbr0_el1.rs b/crate/aarch64/src/regs/ttbr0_el1.rs deleted file mode 100644 index a29ff792..00000000 --- a/crate/aarch64/src/regs/ttbr0_el1.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Translation Table Base Register 0 - EL1 -//! -//! Holds the base address of the translation table for the initial lookup for -//! stage 1 of the translation of an address from the lower VA range in the -//! EL1&0 translation regime, and other information for this translation regime. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u64, - TTBR0_EL1 [ - /// An ASID for the translation table base address. The TCR_EL1.A1 field - /// selects either TTBR0_EL1.ASID or TTBR1_EL1.ASID. - /// - /// If the implementation has only 8 bits of ASID, then the upper 8 bits - /// of this field are RES 0. - ASID OFFSET(48) NUMBITS(16) [], - - /// Translation table base address - BADDR OFFSET(1) NUMBITS(47) [], - - /// Common not Private - CnP OFFSET(0) NUMBITS(1) [] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "TTBR0_EL1"); - sys_coproc_write_raw!(u64, "TTBR0_EL1"); -} - -impl Reg { - #[inline] - pub fn get_baddr(&self) -> u64 { - self.read(TTBR0_EL1::BADDR) << 1 - } - - #[inline] - pub fn set_baddr(&self, addr: u64) { - self.write(TTBR0_EL1::BADDR.val(addr >> 1)); - } -} - -pub static TTBR0_EL1: Reg = Reg {}; diff --git a/crate/aarch64/src/regs/ttbr1_el1.rs b/crate/aarch64/src/regs/ttbr1_el1.rs deleted file mode 100644 index 7df383c3..00000000 --- a/crate/aarch64/src/regs/ttbr1_el1.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018 by the author(s) - * - * ============================================================================= - * - * Licensed under either of - * - Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) - * - MIT License (http://opensource.org/licenses/MIT) - * at your option. - * - * ============================================================================= - * - * Author(s): - * - Andre Richter - */ - -//! Translation Table Base Register 1 - EL1 -//! -//! Holds the base address of the translation table for the initial lookup for -//! stage 1 of the translation of an address from the upper VA range in the -//! EL1&0 translation regime, and other information for this translation regime. - -use register::cpu::RegisterReadWrite; - -register_bitfields! {u64, - TTBR1_EL1 [ - /// An ASID for the translation table base address. The TCR_EL1.A1 field - /// selects either TTBR0_EL1.ASID or TTBR1_EL1.ASID. - /// - /// If the implementation has only 8 bits of ASID, then the upper 8 bits - /// of this field are RES 0. - ASID OFFSET(48) NUMBITS(16) [], - - /// Translation table base address - BADDR OFFSET(1) NUMBITS(47) [], - - /// Common not Private - CnP OFFSET(0) NUMBITS(1) [] - ] -} - -pub struct Reg; - -impl RegisterReadWrite for Reg { - sys_coproc_read_raw!(u64, "TTBR1_EL1"); - sys_coproc_write_raw!(u64, "TTBR1_EL1"); -} - -impl Reg { - #[inline] - pub fn get_baddr(&self) -> u64 { - self.read(TTBR1_EL1::BADDR) << 1 - } - - #[inline] - pub fn set_baddr(&self, addr: u64) { - self.write(TTBR1_EL1::BADDR.val(addr >> 1)); - } -} - -pub static TTBR1_EL1: Reg = Reg {}; diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 4e2b6dca..d3dd0bea 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -1,6 +1,7 @@ [[package]] name = "aarch64" -version = "0.1.0" +version = "2.2.2" +source = "git+https://github.com/equation314/aarch64#47bf5439f5a1379f0fef6272853cf684207a4e45" dependencies = [ "bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -256,7 +257,7 @@ dependencies = [ name = "ucore" version = "0.1.0" dependencies = [ - "aarch64 0.1.0", + "aarch64 2.2.2 (git+https://github.com/equation314/aarch64)", "atags 0.1.0", "bbl 0.1.0", "bcm2837 0.1.0", @@ -362,6 +363,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum aarch64 2.2.2 (git+https://github.com/equation314/aarch64)" = "" "checksum bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bdcf9294ed648c7cd29b11db06ea244005aeef50ae8f605b1a3af2940bf8f92" "checksum bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)" = "" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 20b696f3..316b21c5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -44,7 +44,7 @@ riscv = { path = "../crate/riscv" } bbl = { path = "../crate/bbl" } [target.'cfg(target_arch = "aarch64")'.dependencies] -aarch64 = { path = "../crate/aarch64" } +aarch64 = { git = "https://github.com/equation314/aarch64" } atags = { path = "../crate/atags" } bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] }