Skip to content

Conversation

@phip1611
Copy link
Member

@phip1611 phip1611 commented Jan 17, 2026

TL;DR

As discussed [0], this is my 100% rewrite of the crate. It is 100% spec
complete, highly configurable (usable in kernel drivers) while still
preserving a very simple entry-level abstraction that "just works".

It also runs on real hardware now! The original code wasn't mature
enough for all the caveats. Further, we have one common abstraction for
x86 port I/O and MMIO.

Background

As part of a learning project, I conducted an in-depth exploration of
UART 16550 devices and driver development. During this process, I
identified a key limitation in the current crate: the inability to
configure the baud rate. This functionality is essential for real
hardware usage, and addressing it was my primary motivation.

As I continued, I recognized additional areas for improvement.
Incremental changes quickly proved insufficient to meet the standards
of code quality, completeness, and maintainability I aimed for.
Consequently, I undertook a full rewrite, resulting in a driver that
is fully spec-compliant while maintaining seamless and idiomatic Rust
integration.

While I could release this as a separate crate, I prefer not to fragment
the ecosystem - especially given that rust-osdev already maintains a
crate in this space. I fully acknowledge that this presents a "take it
or leave it" ("friss oder stirb") scenario
😞 . That said, I am eager to
collaborate toward a solution that serves the community effectively,
and I am confident this rewrite provides a strong, forward-looking
foundation.

Notes about Real Hardware Tests

To properly operate with real hardware, I had to specifically
investigate the behavior and especially adapt try_send_bytes()
and test_loopback().

Further, the source and the destination must agree on the baud
rate. Tests in VMs would behave differently (have fewer caveats),
especially as the baud rate is mostly irrelevant there.

About API and Implementation

Please look into lib.rs, I suggest using cargo doc. A small except from README is also here:

Example (Minimalistic)

⚠️ PLEASE NOTE THAT THIS MAY BE SLIGHTLY OUTDATED. THE CURRENT TRUTH IS ONLY IN lib.rs

use uart_16550::{Config, Uart16550Tty};
use core::fmt::Write;

fn main() {
  // SAFETY: The I/O port is valid and we have exclusive access.
  let mut uart = unsafe { Uart16550Tty::new_port(0x3f8, Config::default()).expect("should initialize device") };
  //                                    ^ you could also use `new_mmio(0x1000 as *mut _)` here
  uart.write_str("hello world\nhow's it going?");
}

Example (More low-level control)

⚠️ PLEASE NOTE THAT THIS MAY BE SLIGHTLY OUTDATED. THE CURRENT TRUTH IS ONLY IN lib.rs

use uart_16550::{Config, Uart16550};

fn main() {
  // SAFETY: The I/O port is valid and we have exclusive access.
  let mut uart = unsafe { Uart16550::new_port(0x3f8).expect("should be valid port") };
  //                                 ^ you could also use `new_mmio(0x1000 as *mut _)` here
  uart.init(Config::default()).expect("should init device successfully");
  uart.test_loopback().expect("should have working loopback mode");
  uart.check_remote_ready_to_receive().expect("should have physically connected receiver");
  uart.send_bytes_all(b"hello world!");
}

Hints for Reviewers

I tested this on real hardware, in QEMU, and in Cloud Hypervisor. I
suggest checking this out and using cargo doc --open to get a nice
overview.

I didn't use a LLM to write the code, only for this cover letter
(commit message) to improve it.

Steps to Undraft

  • more testing from my side
  • add a test
  • add CI
  • finish discussions
  • [optional] make me maintainer of this repository

[0] https://rust-osdev.zulipchat.com/#narrow/channel/426430-general/topic/uart.2016550.20.2F.20serial/near/566528969

Closes #37 #38 #30

Copy link

@Wasabi375 Wasabi375 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First off I want to say that this looks great and I'm all for merging this. Thanks for the great work.

That said, I'm not a maintainer here so please feel free to ignore my comments (especially the style based ones if you don't agree).

@phip1611
Copy link
Member Author

First off I want to say that this looks great and I'm all for merging this. Thanks for the great work.

That said, I'm not a maintainer here so please feel free to ignore my comments (especially the style based ones if you don't agree).

thanks, your review was already very helpful!

@phip1611 phip1611 force-pushed the rewrite branch 8 times, most recently from 76bde4a to 132b3a4 Compare January 18, 2026 18:03
## TL;DR

As discussed [0], this is my 100% rewrite of the crate. It is 100% spec
compliant, highly configurable (usable in kernel drivers) while still
preserving a very simple entry-level abstraction that "just works".

**It also runs on real hardware now!** The original code wasn't mature
enough for all the caveats. Further, we have one common abstraction for
x86 port I/O and MMIO.

## Background

As part of a learning project, I conducted an in-depth exploration of
UART 16550 devices and driver development. During this process, I
identified a key limitation in the current crate: the inability to
configure the baud rate. This functionality is essential for real
hardware usage, and addressing it was my primary motivation.

As I continued, I recognized additional areas for improvement.
Incremental changes quickly proved insufficient to meet the standards
of code quality, completeness, and maintainability I aimed for.
Consequently, I undertook a full rewrite, resulting in a driver that
is fully spec-compliant while maintaining seamless and idiomatic Rust
integration.

While I could release this as a separate crate, I prefer not to fragment
the ecosystem - especially given that rust-osdev already maintains a
crate in this space. **I fully acknowledge that this presents a "take it
or leave it" ("friss oder stirb") scenario** 😞 . That said, I am eager to
collaborate toward a solution that serves the community effectively,
and I am confident this rewrite provides a strong, forward-looking
foundation.

## Notes about Real Hardware Tests

To properly operate with real hardware, I had to specifically
investigate the behavior and especially adapt try_send_bytes()
and test_loopback().

Further, the source and the destination must agree on the baud
rate. Tests in VMs would behave differently (have fewer caveats),
especially as the baud rate is mostly irrelevant there.

## About API and Implementation

Please look into `lib.rs`, I suggest using `cargo doc`. A small except from README is also here:

[0] https://rust-osdev.zulipchat.com/#narrow/channel/426430-general/topic/uart.2016550.20.2F.20serial/near/566528969
This is a basic integration test that runs the code in a VM machine
that uses a x86 port I/O backed UART16550.
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.

Option to set a custom baud rate

2 participants