use core::arch::asm;
use aarch64_cpu::{asm::barrier, registers::*};
use ax_memory_addr::{PhysAddr, VirtAddr};
#[inline]
pub fn enable_irqs() {
unsafe { asm!("msr daifclr, #2") };
}
#[inline]
pub fn disable_irqs() {
unsafe { asm!("msr daifset, #2") };
}
#[inline]
pub fn irqs_enabled() -> bool {
!DAIF.matches_all(DAIF::I::Masked)
}
#[inline]
pub fn wait_for_irqs() {
aarch64_cpu::asm::wfi();
}
#[inline]
pub fn halt() {
disable_irqs();
aarch64_cpu::asm::wfi(); }
#[inline]
pub fn read_kernel_page_table() -> PhysAddr {
#[cfg(not(feature = "arm-el2"))]
let root = TTBR1_EL1.get();
#[cfg(feature = "arm-el2")]
let root = TTBR0_EL2.get();
pa!(root as usize)
}
#[inline]
pub fn read_user_page_table() -> PhysAddr {
let root = TTBR0_EL1.get();
pa!(root as usize)
}
#[inline]
pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
#[cfg(not(feature = "arm-el2"))]
{
TTBR1_EL1.set(root_paddr.as_usize() as _);
}
#[cfg(feature = "arm-el2")]
{
TTBR0_EL2.set(root_paddr.as_usize() as _);
}
}
#[inline]
pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
TTBR0_EL1.set(root_paddr.as_usize() as _);
}
#[inline]
pub fn flush_tlb(vaddr: Option<VirtAddr>) {
if let Some(vaddr) = vaddr {
const VA_MASK: usize = (1 << 44) - 1; let operand = (vaddr.as_usize() >> 12) & VA_MASK;
#[cfg(not(feature = "arm-el2"))]
unsafe {
asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) operand)
}
#[cfg(feature = "arm-el2")]
unsafe {
asm!("tlbi vae2is, {}; dsb sy; isb", in(reg) operand)
}
} else {
#[cfg(not(feature = "arm-el2"))]
unsafe {
asm!("dsb sy; isb; tlbi vmalle1; dsb sy; isb")
}
#[cfg(feature = "arm-el2")]
unsafe {
asm!("tlbi alle2; dsb sy; isb")
}
}
}
#[inline]
pub fn flush_icache_all() {
unsafe { asm!("ic iallu; dsb sy; isb") };
}
#[inline]
fn read_ctr_el0() -> u64 {
let value;
unsafe {
asm!("mrs {}, ctr_el0", out(reg) value);
}
value
}
#[inline]
pub fn dcache_line_size_from_ctr() -> usize {
let ctr = read_ctr_el0();
let dminline = ((ctr >> 16) & 0xf) as usize;
4usize << dminline
}
#[inline]
pub fn icache_line_size_from_ctr() -> usize {
let ctr = read_ctr_el0();
let iminline = (ctr & 0xf) as usize;
4usize << iminline
}
#[inline]
pub fn clean_dcache_range_to_pou(vaddr: VirtAddr, size: usize) {
if size == 0 {
return;
}
let line_size = dcache_line_size_from_ctr();
let start = vaddr.as_usize() & !(line_size - 1);
let end = (vaddr.as_usize() + size + line_size - 1) & !(line_size - 1);
for line in (start..end).step_by(line_size) {
unsafe { asm!("dc cvau, {0:x}", in(reg) line) };
}
unsafe { asm!("dsb sy") };
}
#[inline]
pub fn flush_dcache_line(vaddr: VirtAddr) {
unsafe { asm!("dc ivac, {0:x}; dsb sy; isb", in(reg) vaddr.as_usize()) };
}
#[inline]
pub unsafe fn write_exception_vector_base(vbar: usize) {
#[cfg(not(feature = "arm-el2"))]
VBAR_EL1.set(vbar as _);
#[cfg(feature = "arm-el2")]
VBAR_EL2.set(vbar as _);
}
#[inline]
pub fn read_thread_pointer() -> usize {
TPIDR_EL0.get() as usize
}
#[inline]
pub unsafe fn write_thread_pointer(tpidr_el0: usize) {
TPIDR_EL0.set(tpidr_el0 as _)
}
#[inline]
pub fn enable_fp() {
CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
barrier::isb(barrier::SY);
}
#[cfg(feature = "uspace")]
core::arch::global_asm!(include_str!("user_copy.S"));
#[cfg(feature = "uspace")]
unsafe extern "C" {
pub fn user_copy(dst: *mut u8, src: *const u8, size: usize) -> usize;
}