use core::arch::asm;
use memory_addr::{PhysAddr, VirtAddr};
use aarch32_cpu::register::*;
pub use aarch32_cpu::asm::{dmb, dsb, isb, sev, wfe, wfi};
#[inline]
pub fn enable_irqs() {
unsafe { aarch32_cpu::interrupt::enable() };
}
#[inline]
pub fn disable_irqs() {
aarch32_cpu::interrupt::disable();
}
#[inline]
pub fn irqs_enabled() -> bool {
let cpsr = Cpsr::read();
!cpsr.i() }
#[inline]
pub fn wait_for_irqs() {
wfi();
}
#[inline]
pub fn halt() {
disable_irqs();
wfi(); }
#[inline]
pub fn read_kernel_page_table() -> PhysAddr {
let root: u32;
unsafe { asm!("mrc p15, 0, {}, c2, c0, 1", out(reg) root) };
pa!(root as usize)
}
#[inline]
pub fn read_user_page_table() -> PhysAddr {
let root: u32;
unsafe { asm!("mrc p15, 0, {}, c2, c0, 0", out(reg) root) };
pa!(root as usize)
}
#[inline]
pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
let root = root_paddr.as_usize() as u32;
unsafe {
asm!("mcr p15, 0, {}, c2, c0, 1", in(reg) root);
dsb();
isb();
}
}
#[inline]
pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
let root = root_paddr.as_usize() as u32;
unsafe {
asm!("mcr p15, 0, {}, c2, c0, 0", in(reg) root);
dsb();
isb();
}
}
#[inline]
pub unsafe fn write_ttbcr(ttbcr: u32) {
unsafe {
asm!("mcr p15, 0, {}, c2, c0, 2", in(reg) ttbcr);
dsb();
isb();
}
}
#[inline]
pub unsafe fn write_dacr(dacr: u32) {
unsafe {
asm!("mcr p15, 0, {}, c3, c0, 0", in(reg) dacr);
dsb();
isb();
}
}
#[inline]
pub fn flush_tlb(vaddr: Option<VirtAddr>) {
unsafe {
if let Some(vaddr) = vaddr {
let addr = vaddr.as_usize() as u32;
asm!("mcr p15, 0, {}, c8, c7, 1", in(reg) addr);
} else {
TlbIAll::write();
}
dsb();
isb();
}
}
#[inline]
pub fn flush_icache_all() {
unsafe {
asm!("mcr p15, 0, {}, c7, c5, 0", in(reg) 0);
dsb();
isb();
}
}
#[inline]
pub fn flush_dcache_line(vaddr: VirtAddr) {
let addr = vaddr.as_usize() as u32;
aarch32_cpu::cache::clean_and_invalidate_data_cache_line_to_poc(addr);
dsb();
isb();
}
#[inline]
pub fn read_exception_vector_base() -> usize {
let vbar: u32;
unsafe { asm!("mrc p15, 0, {}, c12, c0, 0", out(reg) vbar) };
vbar as usize
}
#[inline]
pub unsafe fn write_exception_vector_base(vbar: usize) {
let vbar = vbar as u32;
asm!("mcr p15, 0, {}, c12, c0, 0", in(reg) vbar);
dsb();
isb();
}
#[inline]
pub fn read_thread_pointer() -> usize {
Tpidruro::read().0 as usize
}
#[inline]
pub unsafe fn write_thread_pointer(tp: usize) {
unsafe { Tpidruro::write(Tpidruro(tp as u32)) };
isb();
}
#[cfg(feature = "fp-simd")]
#[inline]
pub fn enable_fp() {
let mut cpacr = Cpacr::read();
cpacr.0 |= (0b11 << 20) | (0b11 << 22);
unsafe {
Cpacr::write(cpacr);
isb();
asm!("vmsr fpexc, {}", in(reg) 0x40000000u32);
}
}
#[inline]
pub fn read_dfsr() -> Dfsr {
Dfsr::read()
}
#[inline]
pub fn read_dfar() -> Dfar {
Dfar::read()
}
#[inline]
pub fn read_ifsr() -> Ifsr {
Ifsr::read()
}
#[inline]
pub fn read_ifar() -> Ifar {
Ifar::read()
}
#[inline]
pub fn read_sctlr() -> Sctlr {
Sctlr::read()
}
#[inline]
pub unsafe fn write_sctlr(sctlr: Sctlr) {
Sctlr::write(sctlr);
dsb();
isb();
}
#[inline]
pub fn read_cpsr() -> Cpsr {
Cpsr::read()
}
#[inline]
pub fn timer_frequency() -> u32 {
let freq: u32;
unsafe {
asm!("mrc p15, 0, {}, c14, c0, 0", out(reg) freq);
}
freq
}
#[inline]
pub fn phys_timer_counter() -> u64 {
let mut low: u32;
let mut high: u32;
unsafe {
asm!("mrrc p15, 0, {}, {}, c14", out(reg) low, out(reg) high);
}
((high as u64) << 32) | (low as u64)
}
#[inline]
pub fn phys_timer_enable(enabled: bool) {
let mut ctl: u32;
unsafe {
asm!("mrc p15, 0, {}, c14, c2, 1", out(reg) ctl);
if enabled {
ctl |= 1;
} else {
ctl &= !1;
}
asm!("mcr p15, 0, {}, c14, c2, 1", in(reg) ctl);
isb();
}
}
#[inline]
pub fn phys_timer_set_countdown(ticks: u32) {
unsafe {
asm!("mcr p15, 0, {}, c14, c2, 0", in(reg) ticks);
isb();
}
}
#[inline]
pub fn virt_timer_counter() -> u64 {
let low: u32;
let high: u32;
unsafe {
asm!("mrrc p15, 1, {}, {}, c14", out(reg) low, out(reg) high);
}
((high as u64) << 32) | (low as u64)
}
#[inline]
pub fn virt_timer_enable(enabled: bool) {
let mut ctl: u32;
unsafe {
asm!("mrc p15, 0, {}, c14, c3, 1", out(reg) ctl);
if enabled {
ctl |= 1;
} else {
ctl &= !1;
}
asm!("mcr p15, 0, {}, c14, c3, 1", in(reg) ctl);
isb();
}
}
#[inline]
pub fn virt_timer_set_countdown(ticks: u32) {
unsafe {
asm!("mcr p15, 0, {}, c14, c3, 0", in(reg) ticks);
isb();
}
}