Skip to content

Commit eaa49a4

Browse files
authored
Merge pull request coconut-svsm#1078 from msft-jlange/ipi_fix
cpu/ipi: fix race conditions
2 parents 959ede0 + d482383 commit eaa49a4

1 file changed

Lines changed: 15 additions & 3 deletions

File tree

kernel/src/cpu/ipi.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ fn send_ipi(target_set: IpiTarget<'_>, ipi_helper: &mut dyn IpiHelper) {
365365
let mut interrupt_target = target_set;
366366
let mut interrupt_set: MaybeUninit<CpuSet> = MaybeUninit::uninit();
367367

368+
// There should be no pending activity for the current IPI board. This is
369+
// a debug assert because it does not affect safety, and it should normally
370+
// be guaranteed by the design of the IPI logic without depending on the
371+
// behavior of any routine that invokes the IPI logic.
372+
debug_assert_eq!(ipi_board.pending.load(Ordering::Relaxed), 0);
373+
368374
// Enumerate all CPUs in the target set to advise that an IPI message has
369375
// been posted.
370376
let mut include_self = false;
@@ -374,7 +380,7 @@ fn send_ipi(target_set: IpiTarget<'_>, ipi_helper: &mut dyn IpiHelper) {
374380
if cpu_index == sender_cpu_index {
375381
include_self = true;
376382
} else {
377-
ipi_board.pending.store(1, Ordering::Relaxed);
383+
ipi_board.pending.fetch_add(1, Ordering::Relaxed);
378384
// SAFETY: advertising an IPI message from this CPU is safe
379385
// because the IPI board is fully constructed.
380386
unsafe {
@@ -385,11 +391,12 @@ fn send_ipi(target_set: IpiTarget<'_>, ipi_helper: &mut dyn IpiHelper) {
385391
}
386392
}
387393
IpiTarget::Multiple(cpu_set) => {
394+
let mut target_count: usize = 0;
388395
for cpu_index in cpu_set.iter() {
389396
if cpu_index == sender_cpu_index {
390397
include_self = true;
391398
} else {
392-
ipi_board.pending.fetch_add(1, Ordering::Relaxed);
399+
target_count += 1;
393400
// SAFETY: advertising an IPI message from this CPU is safe
394401
// because the IPI board is fully constructed.
395402
unsafe {
@@ -398,6 +405,11 @@ fn send_ipi(target_set: IpiTarget<'_>, ipi_helper: &mut dyn IpiHelper) {
398405
send_interrupt = true;
399406
}
400407
}
408+
409+
// Record the count of targets that will need to respond before
410+
// this IPI can complete.
411+
ipi_board.pending.fetch_add(target_count, Ordering::Relaxed);
412+
401413
if include_self {
402414
// The CPU set used to send the interrupt must be modified to
403415
// remove the current CPU. This cannot be done in place,
@@ -425,7 +437,7 @@ fn send_ipi(target_set: IpiTarget<'_>, ipi_helper: &mut dyn IpiHelper) {
425437

426438
// Record the count of targets that will need to respond before
427439
// this IPI can complete.
428-
ipi_board.pending.store(target_count, Ordering::Relaxed);
440+
ipi_board.pending.fetch_add(target_count, Ordering::Relaxed);
429441

430442
// Send an interrupt only if there are targets to receive it.
431443
send_interrupt = target_count != 0;

0 commit comments

Comments
 (0)