Skip to content

Commit b1f653f

Browse files
authored
Merge pull request #186 from Freax13/fix/tlb-flush
fix race condition in TLB flushing code
2 parents 9117e0b + 4d706a8 commit b1f653f

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

common/constants/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use core::{
66
fmt::{self, Debug, Display},
77
marker::PhantomData,
8-
ops::{BitAnd, BitAndAssign, BitOrAssign, Index, Not, RangeInclusive},
8+
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Index, Not, RangeInclusive},
99
sync::atomic::{AtomicU32, Ordering},
1010
};
1111

@@ -165,10 +165,18 @@ impl ApBitmap {
165165
}
166166
}
167167

168+
impl BitOr for ApBitmap {
169+
type Output = Self;
170+
171+
fn bitor(self, rhs: Self) -> Self::Output {
172+
Self(self.0 | rhs.0)
173+
}
174+
}
175+
168176
impl BitOrAssign for ApBitmap {
169177
#[inline]
170178
fn bitor_assign(&mut self, rhs: Self) {
171-
self.0 |= rhs.0;
179+
*self = *self | rhs;
172180
}
173181
}
174182

tee/kernel/src/memory/pagetable/flush.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ impl ActivePageTableGuard {
205205
}
206206
if num_pages < usize::from(invlpgb.invlpgb_count_max()) {
207207
builder = builder.pages(Page::range(*pages.start(), *pages.end() + 1));
208+
} else {
209+
state.needs_flush = ApBitmap::empty();
208210
}
209211
builder.flush();
210212
invlpgb.tlbsync();
@@ -298,18 +300,30 @@ impl FlushGuard for GlobalFlushGuard {
298300
// IPI, so the other thread thinks that the bit was never cleared and
299301
// it won't get cleared again because we didn't set another IPI.
300302
let active_aps = ACTIVE_APS.get_all();
301-
let other_active_aps = active_aps & all_other_aps;
302303
let inactive_aps = !active_aps & all_other_aps;
303-
PENDING_GLOBAL_TLB_SHOOTDOWN.set_all(other_active_aps);
304304
LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN.set_all(inactive_aps);
305+
// Re-fetch `ACTIVE_APS` after setting `LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN`.
306+
// If we don't do this, there's a race condition:
307+
// +----------------------------------------------------------------------------------+
308+
// | this AP | other AP |
309+
// | ... | inactive |
310+
// | read ACTIVE_APS | |
311+
// | | wake up |
312+
// | | set ACTIVE_APS |
313+
// | | read LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN |
314+
// | write LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN | |
315+
// +----------------------------------------------------------------------------------+
316+
let active_aps = active_aps | ACTIVE_APS.get_all();
317+
let other_active_aps = active_aps & all_other_aps;
318+
PENDING_GLOBAL_TLB_SHOOTDOWN.set_all(other_active_aps);
305319

306320
// Send IPIs to all other currently active APs.
307321
send_tlb_ipis(other_active_aps);
308322

309323
// Flush the local TLB entry.
310324
tlb::flush(page.start_address());
311325

312-
// Wait for the APS to acknowledge the IPI.
326+
// Wait for the APs to acknowledge the IPI.
313327
let mut remaining_aps = other_active_aps;
314328
while !remaining_aps.is_empty() {
315329
remaining_aps &= PENDING_GLOBAL_TLB_SHOOTDOWN.get_all();

0 commit comments

Comments
 (0)