Skip to main content

ax_cpu/
cache.rs

1//! CPU cache maintenance.
2
3pub use crate::arch::current::cache::*;
4
5/// A checked byte range for CPU cache maintenance.
6/// Construction validates arithmetic, not mapping or memory ownership.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8struct ByteRange {
9    start: usize,
10    last: Option<usize>,
11}
12
13/// The requested cache byte range wraps the CPU address space.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct CacheRangeOverflow;
16
17impl core::fmt::Display for CacheRangeOverflow {
18    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19        f.write_str("cache range wraps the address space")
20    }
21}
22impl core::error::Error for CacheRangeOverflow {}
23
24impl ByteRange {
25    /// Checks the inclusive endpoint. A zero-byte request touches no cache line.
26    const fn new(start: usize, bytes: usize) -> Result<Self, CacheRangeOverflow> {
27        let last = if bytes == 0 {
28            None
29        } else {
30            match start.checked_add(bytes - 1) {
31                Some(last) => Some(last),
32                None => return Err(CacheRangeOverflow),
33            }
34        };
35        Ok(Self { start, last })
36    }
37
38    #[cfg(any(
39        target_arch = "aarch64",
40        target_arch = "loongarch64",
41        all(target_arch = "riscv64", feature = "riscv-thead-mae")
42    ))]
43    pub(crate) fn for_each_line(self, line_size: usize, mut operation: impl FnMut(usize)) {
44        let Some(last) = self.last else { return };
45        let mask = line_size - 1;
46        let last_line = last & !mask;
47        let mut line = self.start & !mask;
48        loop {
49            operation(line);
50            if line == last_line {
51                break;
52            }
53            line += line_size;
54        }
55    }
56}
57
58/// A checked virtual byte range. Construction validates arithmetic, not mapping.
59#[derive(Clone, Copy, Debug, Eq, PartialEq)]
60pub struct CacheRange(ByteRange);
61impl CacheRange {
62    /// Checks the inclusive endpoint; empty ranges perform no maintenance.
63    pub const fn new(start: crate::VirtAddr, bytes: usize) -> Result<Self, CacheRangeOverflow> {
64        match ByteRange::new(start.as_usize(), bytes) {
65            Ok(range) => Ok(Self(range)),
66            Err(error) => Err(error),
67        }
68    }
69    /// Returns the first requested virtual byte.
70    pub const fn start(self) -> crate::VirtAddr {
71        crate::VirtAddr::from_usize(self.0.start)
72    }
73    /// Reports a zero-length request.
74    pub const fn is_empty(self) -> bool {
75        self.0.last.is_none()
76    }
77    #[cfg(any(target_arch = "aarch64", target_arch = "loongarch64"))]
78    pub(crate) fn for_each_line(self, size: usize, operation: impl FnMut(usize)) {
79        self.0.for_each_line(size, operation);
80    }
81}
82
83/// A checked physical byte range for physical-address cache instructions.
84#[cfg(all(target_arch = "riscv64", feature = "riscv-thead-mae"))]
85#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86pub struct PhysicalCacheRange(ByteRange);
87#[cfg(all(target_arch = "riscv64", feature = "riscv-thead-mae"))]
88impl PhysicalCacheRange {
89    /// Checks physical endpoint arithmetic without converting a virtual alias.
90    pub const fn new(start: crate::PhysAddr, bytes: usize) -> Result<Self, CacheRangeOverflow> {
91        match ByteRange::new(start.as_usize(), bytes) {
92            Ok(range) => Ok(Self(range)),
93            Err(error) => Err(error),
94        }
95    }
96    /// Returns the first requested physical byte.
97    pub const fn start(self) -> crate::PhysAddr {
98        crate::PhysAddr::from_usize(self.0.start)
99    }
100    /// Reports a zero-length request.
101    pub const fn is_empty(self) -> bool {
102        self.0.last.is_none()
103    }
104    pub(crate) fn for_each_line(self, size: usize, operation: impl FnMut(usize)) {
105        self.0.for_each_line(size, operation);
106    }
107}
108
109/// Completes local translation and instruction synchronization for modified text.
110/// The owner must first publish the modified bytes using
111/// `clean_dcache_range_to_pou`, and coordinate any other CPUs executing this text.
112pub fn sync_kernel_text(start: crate::VirtAddr, size: usize) {
113    crate::mmu::flush_tlb_range(start, size);
114    flush_icache_all();
115}