2019-06-17 09:32:10 +08:00
|
|
|
use crate::{register_bit, register_bits};
|
2019-08-11 06:55:27 +08:00
|
|
|
use crate::regs::{RegisterR, RegisterW};
|
2019-05-05 20:56:23 +08:00
|
|
|
|
2019-06-17 07:36:11 +08:00
|
|
|
macro_rules! def_reg_r {
|
2019-06-12 06:20:23 +08:00
|
|
|
($name:tt, $type: ty, $asm_instr:tt) => {
|
|
|
|
impl RegisterR for $name {
|
|
|
|
type R = $type;
|
|
|
|
|
2019-05-05 20:56:23 +08:00
|
|
|
#[inline(always)]
|
2019-06-12 06:20:23 +08:00
|
|
|
fn read(&self) -> Self::R {
|
2019-06-17 07:36:11 +08:00
|
|
|
let mut value: u32;
|
2019-05-05 20:56:23 +08:00
|
|
|
unsafe { asm!($asm_instr : "=r" (value) ::: "volatile") }
|
2019-06-17 07:36:11 +08:00
|
|
|
value.into()
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-17 07:36:11 +08:00
|
|
|
macro_rules! def_reg_w {
|
2019-05-05 20:56:23 +08:00
|
|
|
($name:ty, $type:ty, $asm_instr:tt) => {
|
2019-06-12 06:20:23 +08:00
|
|
|
impl RegisterW for $name {
|
|
|
|
type W = $type;
|
|
|
|
|
2019-05-05 20:56:23 +08:00
|
|
|
#[inline(always)]
|
2019-06-12 06:20:23 +08:00
|
|
|
fn write(&mut self, value: Self::W) {
|
2019-06-17 07:36:11 +08:00
|
|
|
let value: u32 = value.into();
|
2019-05-05 20:56:23 +08:00
|
|
|
unsafe { asm!($asm_instr :: "r" (value) :: "volatile") }
|
|
|
|
}
|
2019-06-12 06:20:23 +08:00
|
|
|
|
|
|
|
fn zeroed() -> Self::W {
|
2019-06-17 07:36:11 +08:00
|
|
|
0u32.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! wrap_reg {
|
|
|
|
($mod_name: ident) => {
|
|
|
|
pub mod $mod_name {
|
|
|
|
pub struct Read {
|
|
|
|
pub inner: u32,
|
|
|
|
}
|
|
|
|
impl From<u32> for Read {
|
|
|
|
fn from(value: u32) -> Self {
|
|
|
|
Read { inner: value }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Write {
|
|
|
|
pub inner: u32,
|
|
|
|
}
|
|
|
|
impl From<u32> for Write {
|
|
|
|
fn from(value: u32) -> Self {
|
|
|
|
Write { inner: value }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Into<u32> for Write {
|
|
|
|
fn into(self) -> u32 {
|
|
|
|
self.inner
|
|
|
|
}
|
2019-06-12 06:20:23 +08:00
|
|
|
}
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-27 07:44:24 +08:00
|
|
|
/// Stack Pointer
|
2019-05-05 20:56:23 +08:00
|
|
|
pub struct SP;
|
2019-06-17 07:36:11 +08:00
|
|
|
def_reg_r!(SP, u32, "mov $0, sp");
|
|
|
|
def_reg_w!(SP, u32, "mov sp, $0");
|
2019-05-05 20:56:23 +08:00
|
|
|
|
2019-05-27 07:44:24 +08:00
|
|
|
/// Link register (function call return address)
|
|
|
|
pub struct LR;
|
2019-06-17 07:36:11 +08:00
|
|
|
def_reg_r!(LR, u32, "mov $0, lr");
|
|
|
|
def_reg_w!(LR, u32, "mov lr, $0");
|
2019-05-27 07:44:24 +08:00
|
|
|
|
2019-05-05 20:56:23 +08:00
|
|
|
pub struct MPIDR;
|
2019-06-17 07:36:11 +08:00
|
|
|
def_reg_r!(MPIDR, u32, "mrc p15, 0, $0, c0, c0, 5");
|
2019-05-24 01:05:06 +08:00
|
|
|
|
2019-06-12 06:20:23 +08:00
|
|
|
pub struct DFAR;
|
2019-06-17 07:36:11 +08:00
|
|
|
def_reg_r!(DFAR, u32, "mrc p15, 0, $0, c6, c0, 0");
|
2019-06-12 06:20:23 +08:00
|
|
|
|
|
|
|
pub struct DFSR;
|
2019-06-17 07:36:11 +08:00
|
|
|
def_reg_r!(DFSR, u32, "mrc p15, 0, $0, c5, c0, 0");
|
2019-06-12 06:20:23 +08:00
|
|
|
|
|
|
|
pub struct SCTLR;
|
2019-06-17 07:36:11 +08:00
|
|
|
wrap_reg!(sctlr);
|
|
|
|
def_reg_r!(SCTLR, sctlr::Read, "mrc p15, 0, $0, c1, c0, 0");
|
|
|
|
def_reg_w!(SCTLR, sctlr::Write, "mcr p15, 0, $0, c1, c0, 0");
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// Enables MMU
|
|
|
|
m, 0);
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// Strict Alignment Checking
|
|
|
|
a, 1);
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// Data Caching
|
|
|
|
c, 2);
|
|
|
|
register_bit!(sctlr, sw, 10);
|
|
|
|
register_bit!(sctlr, z, 11);
|
|
|
|
register_bit!(sctlr, i, 12);
|
|
|
|
register_bit!(sctlr, v, 13);
|
|
|
|
register_bit!(sctlr, ha, 17);
|
|
|
|
register_bit!(sctlr, ee, 25);
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// (read-only)
|
|
|
|
nmfi, 27);
|
|
|
|
register_bit!(sctlr, unaligned, 22);
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// TEX Remap Enable
|
|
|
|
tre, 28);
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// Access Flag Enable
|
|
|
|
afe, 29);
|
|
|
|
register_bit!(sctlr,
|
|
|
|
/// Thumb Exception Enable
|
|
|
|
te, 30);
|
2019-06-12 06:20:23 +08:00
|
|
|
|
2019-08-30 15:55:59 +08:00
|
|
|
impl crate::regs::RegisterRW for SCTLR {
|
|
|
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
|
|
|
// todo: this may fail for .nmfi and, in non-secure state,
|
|
|
|
// also RR (bit 14)
|
|
|
|
let inner = self.read().inner;
|
|
|
|
let inner_w = f(
|
|
|
|
sctlr::Read { inner },
|
|
|
|
sctlr::Write { inner }
|
|
|
|
);
|
|
|
|
self.write(inner_w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Auxiliary Control Register
|
|
|
|
pub struct ACTLR;
|
|
|
|
wrap_reg!(actlr);
|
|
|
|
def_reg_r!(ACTLR, actlr::Read, "mrc p15, 0, $0, c1, c0, 1");
|
|
|
|
def_reg_w!(ACTLR, actlr::Write, "mcr p15, 0, $0, c1, c0, 1");
|
|
|
|
// SMP bit
|
|
|
|
register_bit!(actlr, parity_on, 9);
|
|
|
|
register_bit!(actlr, alloc_one_way, 8);
|
|
|
|
register_bit!(actlr, excl, 7);
|
|
|
|
register_bit!(actlr, smp, 6);
|
|
|
|
register_bit!(actlr, write_full_line_of_zeros, 3);
|
|
|
|
register_bit!(actlr, l1_prefetch_enable, 2);
|
|
|
|
// Cache/TLB maintenance broadcast
|
|
|
|
register_bit!(actlr, fw, 0);
|
|
|
|
|
|
|
|
impl crate::regs::RegisterRW for ACTLR {
|
|
|
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
|
|
|
let inner = self.read().inner;
|
|
|
|
let inner_w = f(
|
|
|
|
actlr::Read { inner },
|
|
|
|
actlr::Write { inner }
|
|
|
|
);
|
|
|
|
self.write(inner_w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-17 09:32:10 +08:00
|
|
|
/// Domain Access Control Register
|
|
|
|
pub struct DACR;
|
|
|
|
def_reg_r!(DACR, u32, "mrc p15, 0, $0, c3, c0, 0");
|
|
|
|
def_reg_w!(DACR, u32, "mcr p15, 0, $0, c3, c0, 0");
|
|
|
|
|
|
|
|
/// Translation Table Base Register 0
|
|
|
|
pub struct TTBR0;
|
|
|
|
/// Translation Table Base Register 1
|
|
|
|
pub struct TTBR1;
|
|
|
|
def_reg_r!(TTBR0, ttbr::Read, "mrc p15, 0, $0, c2, c0, 0");
|
|
|
|
def_reg_w!(TTBR0, ttbr::Write, "mcr p15, 0, $0, c2, c0, 0");
|
|
|
|
def_reg_r!(TTBR1, ttbr::Read, "mrc p15, 0, $0, c2, c0, 1");
|
|
|
|
def_reg_w!(TTBR1, ttbr::Write, "mcr p15, 0, $0, c2, c0, 1");
|
|
|
|
wrap_reg!(ttbr);
|
|
|
|
register_bits!(ttbr, table_base, u32, 14, 31);
|
|
|
|
register_bit!(ttbr, irgn0, 6);
|
|
|
|
register_bits!(ttbr, rgn, u8, 3, 4);
|
|
|
|
register_bit!(ttbr,
|
|
|
|
/// Translation table walk to shared memory?
|
|
|
|
s, 1);
|
|
|
|
register_bit!(ttbr, irgn1, 0);
|
|
|
|
|
2019-05-24 01:05:06 +08:00
|
|
|
/// Invalidate TLBs
|
2019-06-12 06:20:23 +08:00
|
|
|
#[inline(always)]
|
2019-05-24 01:05:06 +08:00
|
|
|
pub fn tlbiall() {
|
|
|
|
unsafe {
|
|
|
|
asm!("mcr p15, 0, $0, c8, c7, 0" :: "r" (0) :: "volatile");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Invalidate I-Cache
|
2019-06-12 06:20:23 +08:00
|
|
|
#[inline(always)]
|
2019-05-24 01:05:06 +08:00
|
|
|
pub fn iciallu() {
|
|
|
|
unsafe {
|
|
|
|
asm!("mcr p15, 0, $0, c7, c5, 0" :: "r" (0) :: "volatile");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Invalidate Branch Predictor Array
|
2019-06-12 06:20:23 +08:00
|
|
|
#[inline(always)]
|
2019-05-24 01:05:06 +08:00
|
|
|
pub fn bpiall() {
|
|
|
|
unsafe {
|
|
|
|
asm!("mcr p15, 0, $0, c7, c5, 6" :: "r" (0) :: "volatile");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Invalidate D-Cache
|
2019-06-12 06:20:23 +08:00
|
|
|
#[inline(always)]
|
2019-08-30 15:55:59 +08:00
|
|
|
pub fn dcisw(setway: u32) {
|
2019-05-24 01:05:06 +08:00
|
|
|
// TODO: $0 is r11 at what value?
|
|
|
|
unsafe {
|
2019-08-30 15:55:59 +08:00
|
|
|
// steinb: the following is incorrect
|
|
|
|
//asm!("mcr p15, 0, $0, c7, c5, 6" :: "r" (0) :: "volatile");
|
|
|
|
|
|
|
|
// acc. to ARM Architecture Reference Manual, Figure B3-32;
|
|
|
|
// also see example code (for DCCISW, but DCISW will be
|
|
|
|
// analogous) "Example code for cache maintenance operations"
|
|
|
|
// on pages B2-1286 and B2-1287.
|
|
|
|
asm!("mcr p15, 0, $0, c7, c6, 2" :: "r" (setway) :: "volatile");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn dciall() {
|
|
|
|
// the cache associativity could be read from a register, but will
|
|
|
|
// always be 4 in L1 data cache of a cortex a9
|
|
|
|
let ways = 4;
|
|
|
|
let bit_pos_of_way = 30; // 32 - log2(ways)
|
|
|
|
|
|
|
|
// the cache sets could be read from a register, but are always
|
|
|
|
// 256 for the cores in the zync-7000; in general, 128 or 512 are
|
|
|
|
// also possible.
|
|
|
|
let sets = 256;
|
|
|
|
let bit_pos_of_set = 5; // for a line size of 8 words = 2^5 bytes
|
|
|
|
|
|
|
|
// select L1 data cache
|
|
|
|
unsafe {
|
|
|
|
asm!("mcr p15, 2, $0, c0, c0, 0" :: "r" (0) :: "volatile");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invalidate entire D-Cache by iterating every set and every way
|
|
|
|
for set in 0..sets {
|
|
|
|
for way in 0..ways {
|
|
|
|
dcisw((set << bit_pos_of_set) | (way << bit_pos_of_way));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// clear cache line by virtual address to point of coherency (DCCMVAC)
|
|
|
|
#[inline]
|
|
|
|
pub fn dccmvac(addr: u32) {
|
|
|
|
unsafe {
|
|
|
|
asm!("mcr p15, 0, $0, c7, c10, 1" :: "r" (addr) :: "volatile");
|
2019-05-24 01:05:06 +08:00
|
|
|
}
|
|
|
|
}
|