Skip to content

Update and integrate uart_16550 to 0.8 [Rebase & FF] - #1694

Merged
makubacki merged 2 commits into
OpenDevicePartnership:mainfrom
makubacki:update_uart_16550_to_0_6
Aug 19, 2026
Merged

Update and integrate uart_16550 to 0.8 [Rebase & FF]#1694
makubacki merged 2 commits into
OpenDevicePartnership:mainfrom
makubacki:update_uart_16550_to_0_6

Conversation

@makubacki

@makubacki makubacki commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Description

⚠️ Waiting on rust-osdev/uart_16550#65 before mering

This PR originally targeted updating to uart_16550 0.6 but was later updated to target 0.8 as discussed in the PR comments. The commit messages copied/pasted into this PR description below reflect the final changes to 0.8.


Update and integrate uart_16550 to 0.8

The 0.3.2 version of uart_16550 depends on the unmaintained x86 crate
(not updated in ~4 years), which pulls in an old 1.x bitflags release
that duplicates the version used everywhere else in Patina. This
uart_16550 update was raised before in PR 1560, but the duplicate
dependency has become enough of a problem to make the update now.

Bumping to 0.8 lets us drop the bitflags skip entry in deny.toml and
reduce the copies of bitflags in the dependency tree.

In this crate update, the old SerialPort and MmioSerialPort types
are replaced with a generic Uart16550<Backend> driver. Construction
is now fallible because it validates the address range and performs
real hardware presence checks before applying the baud rate and format.

Because the constructors are fallible, there is a tendency to expect()
on the return value which panics if the address is bad or the probe
fails. We generally don't want to panic because a UART probe check
failed as that could boot a device. In reality, it will be obvious
in most platforms if UART fails because there will be no output.

new_io() and new_mmio() are const fn and do not fail. They
just record basic information and defer everything else. The underlying
driver is built lazily the first time it is actually needed.

Presence probing and configuration happen through the explicit
SerialIO::init call, and a failed probe there does not block
reads or writes afterward.

The goal is to make UART safe while reducing potential panics and
allowing graceful degradation in cases where a UART might not behave
as expected.


Cargo.toml: No longer allow multiple_crate_versions

This was enabled until the uart_16550 crate could be updated so the
crate dependency on bitflags v1 could be removed. Since that is now
done, the lint no longer needs to be allowed.


  • Impacts functionality?
  • Impacts security?
  • Breaking change?
  • Includes tests?
  • Includes documentation?

How This Was Tested

  • cargo make all
  • Boot ArmVirt and Q35 to EFI shell and check UART output
  • Verify UART output on a physical Intel platform

Today

bitflags v1.3.2
├── raw-cpuid v10.7.0
│   └── x86 v0.52.0
│       └── uart_16550 v0.3.2
│           ├── patina v23.0.1 (patina/sdk/patina)

...

bitflags v2.13.1
├── gdbstub v0.7.10
│   └── patina_debugger v23.0.1 (patina/core/patina_debugger) (*)
├── patina_paging v11.0.6

...

After: bitflags 2.x used everywhere

Integration Instructions

  • N/A

This is a little opinionated in how fatal I think UART operations should be to boot. I'm happy to make changes if others have reasons to handle errors differently.

@makubacki makubacki self-assigned this Aug 6, 2026
@makubacki
makubacki force-pushed the update_uart_16550_to_0_6 branch from 18a3a64 to 382ce7b Compare August 6, 2026 23:18
@makubacki
makubacki marked this pull request as ready for review August 6, 2026 23:23
@patina-automation

patina-automation Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

✅ QEMU Validation Passed

All QEMU validation jobs completed successfully.

Note: Q35 is only built on Windows hosts (QEMU boot is disabled due to a QEMU vfat issue).

Workflow run: https://github.com/OpenDevicePartnership/patina/actions/runs/32201683175

Boot Time to EFI Shell

Platform Elapsed
ArmVirt (Linux Host) 25.2s
Q35 (Linux Host) 23.2s

Dependencies

Repository Ref
patina 599c67a
patina-dxe-core-qemu 5c12f1a
patina-fw-patcher d06ba7e
patina-qemu firmware v4.0.5
patina-qemu build script c1946d7

This comment was automatically generated by the Patina QEMU PR Validation Post workflow.

@github-actions github-actions Bot added impact:testing Affects testing type:documentation Improvements or additions to documentation labels Aug 6, 2026
@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...dk/patina/src/peripheral/serial/uart/uart_16550.rs 90.91% 5 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread docs/src/dev/principles/abstractions.md Outdated
@makubacki
makubacki force-pushed the update_uart_16550_to_0_6 branch from 382ce7b to b81f7af Compare August 10, 2026 15:48

@phip1611 phip1611 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

thanks for bumping the dependency! Just a heads up. uart_16550 @ 0.6.0 might be a little stricted than needed which can influence your testing on real hardware. I'll fix that in the next couple of weeks and cut a new release!

Context: rust-osdev/uart_16550#65

@makubacki

Copy link
Copy Markdown
Collaborator Author

thanks for bumping the dependency! Just a heads up. uart_16550 @ 0.6.0 might be a little stricted than needed which can influence your testing on real hardware. I'll fix that in the next couple of weeks and cut a new release!

Context: rust-osdev/uart_16550#65

Hey @phip1611! Thanks for the info and review.

@makubacki

makubacki commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator Author

thanks for bumping the dependency! Just a heads up. uart_16550 @ 0.6.0 might be a little stricted than needed which can influence your testing on real hardware. I'll fix that in the next couple of weeks and cut a new release!
Context: rust-osdev/uart_16550#65

I've confirmed that this does impact at least one relevant physical platform. I was able to work around it by updating ready_to_send() locally with:

--- a/src/lib.rs
+++ b/src/lib.rs
@@ -668,8 +668,6 @@ impl<B: Backend> Uart16550<B> {
     /// an established connection.
     pub fn ready_to_send(&mut self) -> Result<(), ByteSendError> {
         let lsr = self.lsr();
-        let msr = self.msr();
-        let mcr = self.mcr();
 
         // In FIFO mode, this bit is set when the transmitter’s FIFO is
         // completely empty, being 0 if there is at least one byte in the
@@ -679,12 +677,6 @@ impl<B: Backend> Uart16550<B> {
             return Err(ByteSendError::NoCapacity);
         }
 
-        // Software flow control. TODO, what to do with hardware flow control?
-        // Is this something we can and should support?
-        if !mcr.contains(MCR::LOOP_BACK) && !msr.contains(MSR::CTS) {
-            return Err(ByteSendError::RemoteNotClearToSend);
-        }
-
         Ok(())
     }

I'll leave this PR open until that release is made.

Comment thread sdk/patina/src/peripheral/serial/uart/uart_16550.rs Outdated
@phip1611

phip1611 commented Aug 14, 2026

Copy link
Copy Markdown

thanks for bumping the dependency! Just a heads up. uart_16550 @ 0.6.0 might be a little stricted than needed which can influence your testing on real hardware. I'll fix that in the next couple of weeks and cut a new release!
Context: rust-osdev/uart_16550#65

I've confirmed that this does impact at least one relevant physical platform. I was able to work around it by updating ready_to_send() locally with:

Could you please check if the comments in the latest PR version (including the commit message) align with your knowledge about Uart hardware? rust-osdev/uart_16550#66

I'd appreciate if you could approve the PR then, so we can move forward!

@makubacki

Copy link
Copy Markdown
Collaborator Author

thanks for bumping the dependency! Just a heads up. uart_16550 @ 0.6.0 might be a little stricted than needed which can influence your testing on real hardware. I'll fix that in the next couple of weeks and cut a new release!
Context: rust-osdev/uart_16550#65

I've confirmed that this does impact at least one relevant physical platform. I was able to work around it by updating ready_to_send() locally with:

Could you please check if the comments in the latest PR version (including the commit message) align with your knowledge about Uart hardware? rust-osdev/uart_16550#66

I'd appreciate if you could approve the PR then, so we can move forward!

@phip1611, the PR content and commit message look good to me. I also tried the PR (at commit fe65e0b) and it worked. I left a minor comment, but I'll approve the PR to show support for it moving ahead.

Comment thread Cargo.toml Outdated
Comment thread sdk/patina/src/peripheral/serial/uart/uart_16550.rs
@makubacki
makubacki force-pushed the update_uart_16550_to_0_6 branch from b81f7af to 367d1b0 Compare August 17, 2026 21:19
@makubacki makubacki changed the title Update and integrate uart_16550 to 0.6 Update and integrate uart_16550 to 0.8 [Rebase & FF] Aug 17, 2026
The 0.3.2 version of uart_16550 depends on the unmaintained x86 crate
(not updated in ~4 years), which pulls in an old 1.x bitflags release
that duplicates the version used everywhere else in Patina. This
uart_16550 update was raised before in PR 1560, but the duplicate
dependency has become enough of a problem to make the update now.

Bumping to 0.8 lets us drop the bitflags skip entry in deny.toml and
reduce the copies of bitflags in the dependency tree.

In this crate update, the old `SerialPort` and `MmioSerialPort` types
are replaced with a generic `Uart16550<Backend>` driver. Construction
is now fallible because it validates the address range and performs
real hardware presence checks before applying the baud rate and format.

Because the constructors are fallible, there is a tendency to `expect()`
on the return value which panics if the address is bad or the probe
fails. We generally don't want to panic because a UART probe check
failed as that could boot a device. In reality, it will be obvious
in most platforms if UART fails because there will be no output.

`new_io()` and `new_mmio()` are `const fn` and do not fail. They
just record basic information and defer everything else. The underlying
driver is built lazily the first time it is actually needed.

Presence probing and configuration happen through the explicit
`SerialIO::init` call, and a failed probe there does not block
reads or writes afterward.

The goal is to make UART safe while reducing potential panics and
allowing graceful degradation in cases where a UART might not behave
as expected.

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
This was enabled until the uart_16550 crate could be updated so the
crate dependency on bitflags v1 could be removed. Since that is now
done, the lint no longer needs to be allowed.

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
@makubacki
makubacki force-pushed the update_uart_16550_to_0_6 branch from 367d1b0 to 599c67a Compare August 19, 2026 00:21
@makubacki
makubacki merged commit ad3c5e5 into OpenDevicePartnership:main Aug 19, 2026
11 checks passed
@phip1611

Copy link
Copy Markdown

Cool! Out of curiosity: is Patina already deployed somewhere (on scale) or is it still in an experimental stage?

@makubacki

Copy link
Copy Markdown
Collaborator Author

Cool! Out of curiosity: is Patina already deployed somewhere (on scale) or is it still in an experimental stage?

It's used in newer Surface devices (search for "Patina" on this page) with other vendors at varying levels of evaluation and adoption.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

impact:testing Affects testing type:documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants