pub use crate::arch::current::cache::*;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct ByteRange {
start: usize,
last: Option<usize>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CacheRangeOverflow;
impl core::fmt::Display for CacheRangeOverflow {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("cache range wraps the address space")
}
}
impl core::error::Error for CacheRangeOverflow {}
impl ByteRange {
const fn new(start: usize, bytes: usize) -> Result<Self, CacheRangeOverflow> {
let last = if bytes == 0 {
None
} else {
match start.checked_add(bytes - 1) {
Some(last) => Some(last),
None => return Err(CacheRangeOverflow),
}
};
Ok(Self { start, last })
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "loongarch64",
all(target_arch = "riscv64", feature = "riscv-thead-mae")
))]
pub(crate) fn for_each_line(self, line_size: usize, mut operation: impl FnMut(usize)) {
let Some(last) = self.last else { return };
let mask = line_size - 1;
let last_line = last & !mask;
let mut line = self.start & !mask;
loop {
operation(line);
if line == last_line {
break;
}
line += line_size;
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CacheRange(ByteRange);
impl CacheRange {
pub const fn new(start: crate::VirtAddr, bytes: usize) -> Result<Self, CacheRangeOverflow> {
match ByteRange::new(start.as_usize(), bytes) {
Ok(range) => Ok(Self(range)),
Err(error) => Err(error),
}
}
pub const fn start(self) -> crate::VirtAddr {
crate::VirtAddr::from_usize(self.0.start)
}
pub const fn is_empty(self) -> bool {
self.0.last.is_none()
}
#[cfg(any(target_arch = "aarch64", target_arch = "loongarch64"))]
pub(crate) fn for_each_line(self, size: usize, operation: impl FnMut(usize)) {
self.0.for_each_line(size, operation);
}
}
#[cfg(all(target_arch = "riscv64", feature = "riscv-thead-mae"))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PhysicalCacheRange(ByteRange);
#[cfg(all(target_arch = "riscv64", feature = "riscv-thead-mae"))]
impl PhysicalCacheRange {
pub const fn new(start: crate::PhysAddr, bytes: usize) -> Result<Self, CacheRangeOverflow> {
match ByteRange::new(start.as_usize(), bytes) {
Ok(range) => Ok(Self(range)),
Err(error) => Err(error),
}
}
pub const fn start(self) -> crate::PhysAddr {
crate::PhysAddr::from_usize(self.0.start)
}
pub const fn is_empty(self) -> bool {
self.0.last.is_none()
}
pub(crate) fn for_each_line(self, size: usize, operation: impl FnMut(usize)) {
self.0.for_each_line(size, operation);
}
}
pub fn sync_kernel_text(start: crate::VirtAddr, size: usize) {
crate::mmu::flush_tlb_range(start, size);
flush_icache_all();
}