1use crate::sync::{
3 RwLock,
4 atomic::{AtomicBool, AtomicUsize},
5};
6use abyss::{
7 MAX_CPU,
8 addressing::Va,
9 boot::ONLINE_CPU,
10 dev::x86_64::apic::{IPIDest, Mode},
11 interrupt::Registers,
12 spinlock::SpinLock,
13 x86_64::Cr3,
14};
15use core::sync::atomic::Ordering;
16
17#[doc(hidden)]
18static IN_PROGRESS: SpinLock<()> = SpinLock::new(());
19
20#[doc(hidden)]
21static REQUEST: RwLock<Option<TlbIpi>> = RwLock::new(None);
22
23#[doc(hidden)]
24#[allow(clippy::declare_interior_mutable_const)]
25const PER_CORE_STATUS: AtomicBool = AtomicBool::new(false);
26
27#[doc(hidden)]
28static HAVE_REQUEST: [AtomicBool; MAX_CPU] = [PER_CORE_STATUS; MAX_CPU];
29
30pub struct TlbIpi {
32 cr3: Cr3,
34
35 va: Option<Va>,
38
39 processed: AtomicUsize,
41}
42
43impl TlbIpi {
44 pub fn send(cr3: Cr3, va: Option<Va>) {
46 let guard = loop {
47 if let Ok(guard) = IN_PROGRESS.try_lock() {
48 break guard;
49 }
50
51 TlbIpi::handle();
52 };
53
54 {
56 let mut request = REQUEST.write();
57
58 assert!(
59 request.is_none(),
60 "Before sending TLB Shootdown request, the request queue must be empty."
61 );
62
63 *request = Some(Self {
64 cr3,
65 va,
66 processed: AtomicUsize::new(0),
67 });
68 }
69
70 {
72 let request = REQUEST.read();
73 let self_id = abyss::x86_64::intrinsics::cpuid();
74
75 let online_cpu_cnt = ONLINE_CPU
76 .iter()
77 .enumerate()
78 .filter(|(i, cpu)| {
79 if *i == self_id {
80 true
81 } else if cpu.load(Ordering::SeqCst) {
82 HAVE_REQUEST[*i].store(true);
83 true
84 } else {
85 false
86 }
87 })
88 .count();
89
90 unsafe {
91 abyss::dev::x86_64::apic::send_ipi(IPIDest::AllExcludingSelf, Mode::Fixed(0x7e));
92 }
93
94 let request_ref = request.as_ref().unwrap();
95
96 while request_ref.processed.load() < online_cpu_cnt - 1 {
97 core::hint::spin_loop();
98 }
99 }
100
101 {
103 let mut request = REQUEST.write();
104 *request = None;
105 }
106
107 guard.unlock();
108 }
109
110 fn handle() {
111 let core_id = abyss::x86_64::intrinsics::cpuid();
112 if HAVE_REQUEST[core_id].load() {
113 let request = REQUEST.read();
114
115 if let Some(request) = &*request {
116 if request.cr3 == Cr3::current() {
117 match request.va {
118 Some(va) => unsafe {
119 core::arch::asm!(
120 "invlpg [{0}]",
121 in(reg) va.into_usize(),
122 options(nostack)
123 )
124 },
125 _ => unsafe {
126 core::arch::asm! {
127 "mov rax, cr3",
128 "mov cr3, rax",
129 out("rax") _,
130 options(nostack)
131 }
132 },
133 }
134 }
135
136 request.processed.fetch_add(1);
137 HAVE_REQUEST[core_id].store(false);
138 }
139 }
140 }
141}
142
143pub fn handler(_regs: &mut Registers) {
145 TlbIpi::handle();
146}