Page MenuHomeFreeBSD

atrtc: Prevent duplicate device attachment
Needs ReviewPublic

Authored by guest-seuros on Thu, Jan 29, 10:42 PM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Feb 16, 10:51 AM
Unknown Object (File)
Sun, Feb 15, 10:09 PM
Unknown Object (File)
Tue, Feb 10, 9:04 PM
Unknown Object (File)
Tue, Feb 10, 1:18 AM
Unknown Object (File)
Mon, Feb 2, 6:20 PM
Unknown Object (File)
Fri, Jan 30, 1:19 PM
Unknown Object (File)
Fri, Jan 30, 10:30 AM
Unknown Object (File)
Fri, Jan 30, 6:45 AM
Subscribers

Details

Reviewers
kevans
adrian
ngie
Summary

Both ACPI and ISA probe paths can succeed when BIOS is configured in compatibility mode, causing atrtc1 (ACPI) and atrtc0 (ISA) to attach
to the same RTC hardware. This results in duplicate IRQ handlers, race conditions on register access, and two identical event timers.

Add a static guard flag checked in probe() to ensure only the first instance attaches. Set the flag early in attach(), before any
early-return paths that could bypass it.

Keep RF_SHAREABLE on IRQ allocation to allow coexistence with ACPI system resources.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 70384
Build 67267: arc lint + arc unit

Event Timeline

guest-seuros held this revision as a draft.
guest-seuros edited the summary of this revision. (Show Details)
guest-seuros added reviewers: kevans, adrian, ngie.

@imp, @jhb, @kib: do any of you have any strong opinions with this proposed change?

sys/x86/isa/atrtc.c
472

This is probably better than EBUSY, but someone else might have feelings about what should be used here.

522

Why isn't 8 parametrized out here? Also, why 8? A reference to some specs would be really helpful.

Is there a way to look up whether or not rtc(4) is attached using the bus_(9) APIs instead of using this one-off sentinel?

sys/x86/isa/atrtc.c
472

it the same contract in line 464.

522

Sorry ! RTC IRQ is so old and universal (across chips) that i forget i need to document it, Basically like error 404 in web.

https://wiki.osdev.org/RTC

I will update the diff. Nice catch.

FWIW, we do not disable EFI RT timer services when we attach to rtc, and in reverse. I am not sure, might be we should. Right now we lock accesses according to the UEFI spec recommendation.

BTW, is there a priority in the attach order? I would think that ACPI attachment for rtc should take a priority over ISA/LPC. And then, wouldn't resource allocation conflict prevent double attach?

sys/x86/isa/atrtc.c
207

Better use bool?

505

So why both? Pnpbios? I'd like to understand that before we start adding layer violating hacks. It's just one device and i wonder why we see two views that don't naturally hit a resource conflict... or even why we do both enumerations.

In D54954#1256538, @imp wrote:

So why both? Pnpbios? I'd like to understand that before we start adding layer violating hacks. It's just one device and i wonder why we see two views that don't naturally hit a resource conflict... or even why we do both enumerations.

I can't speak to the exact configuration, but @guest-seuros mentioned something in Discord about the machine being a Hackintosh based PC (which I think might fake the asmc(4) device) and the system having compatibility mode set in the BIOS.

Disabling compatibility mode fixed the issue, but I also recommended disabling the device in /boot/device.hints, if it's an environmental problem that isn't easy to fix.

In D54954#1256538, @imp wrote:

So why both? Pnpbios? I'd like to understand that before we start adding layer violating hacks. It's just one device and i wonder why we see two views that don't naturally hit a resource conflict... or even why we do both enumerations.

I can't speak to the exact configuration, but @guest-seuros mentioned something in Discord about the machine being a Hackintosh based PC (which I think might fake the asmc(4) device) and the system having compatibility mode set in the BIOS.

Disabling compatibility mode fixed the issue, but I also recommended disabling the device in /boot/device.hints, if it's an environmental problem that isn't easy to fix.

That's not a specific enough set of circumstances. What is different about enabling compat mode? It's not a standard thing at all. I think a bootverbose boot will include what is adding the device.

It's not a device.hints issue if changing the bootenv changes behavior. It would populate it always. Something else is actually adding it. What is that thing? That's the real bug here. I'm guessing it's that somehow we have both pnpbios and acpi enumerating it, but I thought we ignored the former if we had the latter... hence my request for more detailed data

Warner's bigger point is that we shouldn't be getting duplicate devices, and we need to understand why. The ACPI bus will "claim" the hints device and use the hint to wire the unit number of any AT RTC device if finds, so the hints can't create a second device if ACPI is involved (unless they have different I/O port resources which would be really, really odd since just the like the IRQ, those have not changed in 40 years and are the same on every x86 box in the world).

sys/x86/isa/atrtc.c
468

You could just check the unit number here and fail it is not 0 without needing the separate global.

522

8 is what the AT (IBM PC AT, from before several committers were born) used for the RTC. It will never be anything but 8. Also, I would not make it shareable. Failing the allocation if there are duplicates is a feature, not a bug. ISA interrupts are edge-triggered and can't be shared.

sys/x86/isa/atrtc.c
522

8 goes back to the IBM PC, released in 1981. It had IRQ 1-8. The AT daisy-chained 2 to be 9-16 and kept the reset the same. While there is some specialized hardware that does share IRQs on the ISA bus, it's super-non-standard and needs careful coordination between the OS and its drivers. IIRC, sio and maybe cy were the only drivers in the tree that ever did that. I wrote one at Timing Solutions that did it too, and it took a lot of effort to not miss interrupts (the ISA bus really wasn't designed for it, though you could get away with it because they were edge triggered: but two cards signaling at the same time would cause interference between the pulses that could result in them being "too slow" to register on some system's PIC, especially if the ISA paths were long like in our custom hardware).

tl;dr: ISA interrupts aren't shared.

Prefer unit 0 using devclass check; remove global sentinel. Drop RF_SHAREABLE and document IRQ 8.

You still haven't answered the question of how you get multiple atrtcX devices in the first place. That should Never Happen(tm) and probably points to some other bug elsewhere that we should handle instead of applying a band-aid to atrtc(4).

sys/x86/isa/atrtc.c
472

You just need if (device_get_unit(dev) != 0)

This is was over complicated.

In D54954#1260711, @jhb wrote:

You still haven't answered the question of how you get multiple atrtcX devices in the first place. That should Never Happen(tm) and probably points to some other bug elsewhere that we should handle instead of applying a band-aid to atrtc(4).

Sorry, i forgot i have to re submit the reply after i submit it.

To answer your question: I didn’t do anything special. The motherboard is a Gigabyte Z790 running a December 2025 BIOS. It was previously set up for Hackintosh, which requires disabling CSM and some other options.

After a system hang, I cleared the CMOS. Once I did that, this error appeared. That means users will hit this error unless they manually change BIOS settings to disable CSM (Compatibility Support Module/Legacy mode)

This is clearly a BIOS firmware bug. Many motherboards from different vendors expose the same duplicate ATRTC device. Darwin detects this, panics, and refuses to boot.

But _how_ are you getting duplicate devices? Do you have two ACPI devices in the namespace? Do you have one from PnPBIOS and one from ACPI?

  • atrtc0 (ISA) attaches first during boot gets IRQ 8
  • atrtc1 (ACPI) attaches second also registers as a TOD clock

Both register as the same RTC hardware.
With CSM enabled the ACPI becomes atrtc0

  • atrtc0 (ISA) attaches first during boot gets IRQ 8
  • atrtc1 (ACPI) attaches second also registers as a TOD clock

Both register as the same RTC hardware.
With CSM enabled the ACPI becomes atrtc0

Can I get somewhere the dmesg from a bootverbose boot under this scenario?