moa_cache 0.1.3

CPU 缓存维护操作(D-cache / I-cache)
Documentation
use core::sync::atomic::{AtomicUsize, Ordering};

static DCACHE_LINE_SIZE: AtomicUsize = AtomicUsize::new(64);
static ICACHE_LINE_SIZE: AtomicUsize = AtomicUsize::new(64);

#[inline(always)]
pub(super) fn arch_cache_init() {
    let ctr: usize;
    unsafe { core::arch::asm!("mrs {}, ctr_el0", out(reg) ctr) };
    DCACHE_LINE_SIZE.store(4 << ((ctr >> 16) & 0xf), Ordering::Relaxed);
    ICACHE_LINE_SIZE.store(4 << (ctr & 0xf), Ordering::Relaxed);
}

#[inline(always)]
pub(super) fn arch_dcache_line_size() -> usize {
    DCACHE_LINE_SIZE.load(Ordering::Relaxed)
}

#[inline(always)]
fn icache_line_size() -> usize {
    ICACHE_LINE_SIZE.load(Ordering::Relaxed)
}

pub(super) fn arch_clean_dcache_area(addr: usize, size: usize) {
    let line = arch_dcache_line_size();
    let end = addr + size;
    let mut cur = addr & !(line - 1);
    while cur < end {
        unsafe { core::arch::asm!("dc cvac, {}", in(reg) cur) };
        cur += line;
    }
    unsafe { core::arch::aarch64::__dsb(core::arch::aarch64::SY) };
}

pub(super) fn arch_inval_dcache_area(addr: usize, size: usize) {
    let line = arch_dcache_line_size();
    let mask = line - 1;
    let end = addr + size;
    let end_aligned = end & !mask;

    if end & mask != 0 {
        unsafe { core::arch::asm!("dc civac, {}", in(reg) end_aligned) };
    }
    let mut cur = addr & !mask;
    if addr & mask != 0 {
        unsafe { core::arch::asm!("dc civac, {}", in(reg) cur) };
        cur += line;
    }
    while cur < end_aligned {
        unsafe { core::arch::asm!("dc ivac, {}", in(reg) cur) };
        cur += line;
    }
    unsafe { core::arch::aarch64::__dsb(core::arch::aarch64::SY) };
}

pub(super) fn arch_flush_dcache_area(addr: usize, size: usize) {
    let line = arch_dcache_line_size();
    let end = addr + size;
    let mut cur = addr & !(line - 1);
    while cur < end {
        unsafe { core::arch::asm!("dc civac, {}", in(reg) cur) };
        cur += line;
    }
    unsafe { core::arch::aarch64::__dsb(core::arch::aarch64::SY) };
}

#[inline(always)]
pub(super) fn arch_flush_icache_all() {
    unsafe {
        core::arch::asm!("ic iallu");
        core::arch::aarch64::__dsb(core::arch::aarch64::NSH);
        core::arch::aarch64::__isb(core::arch::aarch64::SY);
    }
}

pub(super) fn arch_flush_icache_range(start: usize, end: usize) {
    let dline = arch_dcache_line_size();
    let mut cur = start & !(dline - 1);
    while cur < end {
        unsafe { core::arch::asm!("dc cvau, {}", in(reg) cur) };
        cur += dline;
    }
    unsafe { core::arch::aarch64::__dsb(core::arch::aarch64::ISH) };

    let iline = icache_line_size();
    cur = start & !(iline - 1);
    while cur < end {
        unsafe { core::arch::asm!("ic ivau, {}", in(reg) cur) };
        cur += iline;
    }
    unsafe {
        core::arch::aarch64::__dsb(core::arch::aarch64::ISH);
        core::arch::aarch64::__isb(core::arch::aarch64::SY);
    }
}