interrupts: keep the NMI path free of locks and allocation #156

Open
nonos-sync wants to merge 4 commits from nonos-sync/gh-613 into main AGit
Member

@eKisNonos

smp/nmi/mod.rs says nothing reached from an NMI may take a lock, allocate or print. interrupts/handlers/exceptions/nmi.rs did all three whenever on_nmi() didn't claim the NMI (smp/nmi/handle.rs:28-31 documents a coalesced shootdown kick taking that path) or a hardware cause was latched: log_exception (alloc::format! plus the logger) and log_critical/log_warning!. On a CPU already holding one of those locks, that path can't make progress.

Now:

  • nmi_record.rs (new): a per-source AtomicU64 count plus the last RIP, with an nmi_counts() accessor for a later context that is allowed to lock.
  • sys/serial: try_write_line / Line::end_try do a single try_lock. The line is dropped if the serial port is busy; the count still records the NMI.
  • Unchanged: the early return for kernel-sent NMIs and RIP redaction in production mode.

Not changed:

  • NmiSource::Watchdog is never produced by identify_nmi_source.
  • nmi_counts() has no reader yet.

Verification: kernel cargo check (x86_64-nonos.json, microkernel-core and microkernel-core,nonos-smp) passes with only the 2 existing quirk_bits.rs warnings. Not yet boot-tested; a combined make dev-image / dev-boot of all seven fix branches is still to run.


Opened on GitHub by senseix21 as pull request 613. Review and merge happen there while this repository is kept in step from GitHub; this copy follows it, and is marked merged or closed when it is.

@eKisNonos `smp/nmi/mod.rs` says nothing reached from an NMI may take a lock, allocate or print. `interrupts/handlers/exceptions/nmi.rs` did all three whenever `on_nmi()` didn't claim the NMI (`smp/nmi/handle.rs:28-31` documents a coalesced shootdown kick taking that path) or a hardware cause was latched: `log_exception` (`alloc::format!` plus the logger) and `log_critical`/`log_warning!`. On a CPU already holding one of those locks, that path can't make progress. Now: - **`nmi_record.rs` (new):** a per-source `AtomicU64` count plus the last RIP, with an `nmi_counts()` accessor for a later context that is allowed to lock. - **`sys/serial`:** `try_write_line` / `Line::end_try` do a single `try_lock`. The line is dropped if the serial port is busy; the count still records the NMI. - **Unchanged:** the early return for kernel-sent NMIs and RIP redaction in production mode. **Not changed:** - `NmiSource::Watchdog` is never produced by `identify_nmi_source`. - `nmi_counts()` has no reader yet. **Verification:** kernel `cargo check` (`x86_64-nonos.json`, `microkernel-core` and `microkernel-core,nonos-smp`) passes with only the 2 existing `quirk_bits.rs` warnings. Not yet boot-tested; a combined `make dev-image` / `dev-boot` of all seven fix branches is still to run. --- Opened on GitHub by senseix21 as [pull request 613](https://github.com/NON-OS/microkernel/pull/613). Review and merge happen there while this repository is kept in step from GitHub; this copy follows it, and is marked merged or closed when it is.
smp/nmi/mod.rs requires that nothing reached from an NMI takes a lock,
allocates, or prints. The NMI handler broke that whenever on_nmi() did
not claim the NMI, which a coalesced shootdown kick does in normal SMP
operation, or a hardware cause was latched in port B: it formatted the
frame with alloc::format! and went through the logger. An NMI landing
on a CPU that already held the heap or logger lock deadlocked that CPU,
and the next shootdown waiting on it hung the machine.

Each such NMI is now counted per source in lock-free atomics alongside
the last interrupted RIP, readable later from a context that may lock.
The serial line is kept best effort: a single try-lock on the serial
port, and if another holder has it the line is dropped while the count
still records the NMI.
nonos-sync changed title from WIP: interrupts: keep the NMI path free of locks and allocation to interrupts: keep the NMI path free of locks and allocation 2026-10-10 05:09:39 -04:00
The NMI path now only counts the NMIs it could not claim, so the counts need
a reader that may print. The shootdown timeout dump is that reader and the
place they matter: a round that never got its ack has just tried NMI kicks,
and an unknown or hardware NMI landing on the CPU that owed the ack is one
of the things that dump has to tell apart.
interrupts::handlers is x86_64 only, so the shootdown dump's read of the NMI
counts broke the aarch64 build. The read moves into a helper that compiles
on x86_64 alone; the dump is unchanged there.
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin +refs/pull/156/head:nonos-sync/gh-613
git switch nonos-sync/gh-613
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
NON-OS/nonos-micro-kernel!156
No description provided.