Skip to content

Test the driver against a 16550A model, following Linux - #83

Merged
phip1611 merged 5 commits into
rust-osdev:mainfrom
phip1611:linux-flow-tests
Oct 11, 2026
Merged

phip1611 merged 5 commits into
rust-osdev:mainfrom
phip1611:linux-flow-tests

Conversation

@phip1611

@phip1611 phip1611 commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Tests the driver against a 16550A model, following the register-level flows of the Linux 8250 driver: startup, the loopback self-test, polled I/O, and interrupt handling.

The model and the tests were created with Claude Code and Claude Opus 5.5. The model follows the 16550A datasheet and what Linux' 8250_port.c relies on. It is independent of the driver's register definitions, so it also catches wrong constants. It models time, FIFOs, a 16450 mode, read side effects, and interrupt priorities, and it fails a test if the driver spins forever. To validate it, it passes Linux' own autoconfig() probing and THRE tests. It plugs in as custom Backend. No Linux code is copied; the model is an independent implementation.

What it brought: the 33 tests run in milliseconds, without a VMM, and found 12 bugs, fixed in #84, #85, #87, #88, and #89:

  • init() left DLAB set on invalid baud rates, panicked on too low ones, and kept stale data without FIFO.
  • On a 16450, sending overran the transmitter, and test_loopback() hung.
  • Internal LSR and MSR reads lost line errors and modem status changes.
  • flush() returned before the data was on the wire.
  • test_loopback() left loopback mode on errors and caused spurious interrupts.

As Uart16550Tty runs init() and test_loopback(), kernels and boot loaders could hang at boot or lose their console or output.

Where Linux is still more robust: it bounds every wait on the hardware, detects many chips and their quirks, reports line errors per received byte, and supports RX flow control. The model is an ideal 16550A, so it can't replace tests on real hardware.

@phip1611
phip1611 marked this pull request as ready for review October 11, 2026 09:02
@phip1611
phip1611 force-pushed the linux-flow-tests branch 4 times, most recently from 9f55380 to ea49fe6 Compare October 11, 2026 09:23
To test the driver against the flows of the Linux 8250 driver, add a
model of a 16550A that hooks into the driver as custom backend. It
follows the datasheet and what Linux relies on, and passes Linux'
autoconfig and THRE tests.
Check that init() leaves the device in the state Linux' startup leaves
it in, including discarding stale data and interrupt conditions, and
detecting a missing FIFO.
Check that test_loopback() leaves no traces, also without FIFO, and
handles failures. Also check that it keeps modem status changes and is
isolated from interrupts and running transmissions.
Check polled transmit and receive like the Linux console and polling
paths do, including line errors, which sending and receiving must not
lose, and overruns.
Handle interrupts like Linux' serial8250_handle_irq() and check RX, RX
timeout, line status, THRE, and modem status interrupts. Also check
that internal MSR reads, e.g., by the CTS check, don't lose modem
status changes.

The tests now use all of the model, so drop its dead_code allowance.
@phip1611
phip1611 enabled auto-merge October 11, 2026 09:25
@phip1611
phip1611 added this pull request to the merge queue Oct 11, 2026
Merged via the queue into rust-osdev:main with commit a3e7119 Oct 11, 2026
18 checks passed
@phip1611
phip1611 deleted the linux-flow-tests branch October 11, 2026 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant