1#[cfg(target_arch = "x86_64")]
46use core::arch::x86_64::_mm_clflush;
47
48#[link(name = "clf")]
49extern "C" {
50 #[allow(dead_code)]
51 fn clf_fallback_clear_cache(begin_ptr: *const u8, end_ptr: *const u8);
52}
53
54fn get_cache_line_size() -> usize {
58 use core::sync::atomic::{AtomicUsize, Ordering};
59 static CACHE_LINE_SIZE: AtomicUsize = AtomicUsize::new(0);
60
61 let size = CACHE_LINE_SIZE.load(Ordering::Relaxed);
62 if size != 0 {
63 return size;
64 }
65
66 let detected_size = detect_cache_line_size();
67 CACHE_LINE_SIZE.store(detected_size, Ordering::Relaxed);
68 detected_size
69}
70
71fn detect_cache_line_size() -> usize {
72 #[cfg(target_arch = "x86_64")]
73 {
74 #[allow(unused_unsafe)]
76 let cpuid = unsafe { core::arch::x86_64::__cpuid(1) };
77 let size = ((cpuid.ebx >> 8) & 0xff) as usize * 8;
78 if size != 0 {
79 return size;
80 }
81 }
82
83 64
88}
89
90pub unsafe fn cache_line_flush_with_ptr(begin_ptr: *const u8, end_ptr: *const u8) {
97 #[cfg(target_arch = "x86_64")]
98 {
99 let size = get_cache_line_size();
100 let mut ptr = begin_ptr;
101 while ptr < end_ptr {
102 _mm_clflush(ptr);
103 ptr = ptr.add(size);
104 }
105 }
106
107 #[cfg(target_arch = "aarch64")]
108 {
109 let size = get_cache_line_size();
110 let mut ptr = begin_ptr as usize;
111 let end = end_ptr as usize;
112 while ptr < end {
113 core::arch::asm!("dc civac, {0}", in(reg) ptr, options(nostack, preserves_flags));
114 ptr += size;
115 }
116 core::arch::asm!("dsb ish", options(nostack, preserves_flags));
117 }
118
119 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
120 {
121 clf_fallback_clear_cache(begin_ptr, end_ptr);
122 }
123}
124
125pub fn cache_line_flush_with_slice<T>(slice: &[T]) {
129 let begin_ptr = slice.as_ptr() as *const u8;
130 let end_ptr = unsafe { begin_ptr.add(core::mem::size_of_val(slice)) };
131 unsafe { cache_line_flush_with_ptr(begin_ptr, end_ptr) };
132}
133
134#[cfg(test)]
135mod tests {
136 #[test]
137 fn it_works_1() {
138 let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
139 unsafe {
140 super::cache_line_flush_with_ptr(a.as_ptr(), a.as_ptr().add(a.len()));
141 }
142 }
143 #[test]
144 fn it_works_2() {
145 let a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
146 super::cache_line_flush_with_slice(&a);
147 }
148 #[test]
149 fn large_slice() {
150 let a = vec![0u8; 1024 * 1024]; super::cache_line_flush_with_slice(&a);
152 }
153}