csmwrap icon indicating copy to clipboard operation
csmwrap copied to clipboard

USB keyboard (attached to xHCI controller) goes dead when SeaBIOS takes over (not 4G-related)

Open PluMGMK opened this issue 6 months ago • 24 comments

Hello! I heard about CSMWrap recently, and it seems like a very interesting and laudable project!

I decided to test it out on my PC, with an MSI Z97-GAMING-3 motherboard. This motherboard has its own CSM which works really well (I can boot Windows 3.1 in Enhanced Mode), but I wanted to check if CSMWrap would work equally well.

Unfortunately, as soon as the SeaBIOS text comes up on the screen, my keyboard loses power (it's a gaming keyboard with lots of LEDs so it's obvious when this happens). SeaBIOS gets stuck at "Booting from Hard Disk", but I don't (yet) see that as a problem since I have no idea which disk it's trying to boot from, and can't steer it in the right direction without a keyboard.

After some investigation, it turns out that every USB port on the outside of my PC is connected to the xHCI controller. There are two EHCI controllers, but it seems their ports are only exposed via pins on the motherboard, and I don't have any breakouts handy…

I've mentions of xHCI under some of the other issues, but they all seem to lead back to the "Above 4G decoding" problem, which is definitely not the issue here. I checked /proc/iomem, and even with the CSM turned off, all PCI devices are mapped below the 4G boundary.

PluMGMK avatar Jun 04 '25 00:06 PluMGMK

Oops yes, there are some known issues on Haswell XHCI, which leads to #25, I haven't investigated yet. Do you have access to COM port to get some debug message?

Thanks!

FlyGoat avatar Jun 04 '25 09:06 FlyGoat

Yep, I have the COM port working! Do I need to do anything to turn on debug output to it?

PluMGMK avatar Jun 04 '25 10:06 PluMGMK

@PluMGMK Disable all xHCI controlers in hidden CMOS Setup - using AmiSetupWriter.efi or RU.efi

XHCI Mode offset 0x2BE

AmiSetupWriter.efi 0x2BE 0x0

With an EHCI controller, CSMWrap will work.

Gelip avatar Jun 06 '25 16:06 Gelip

You say that this issue isn't related to above 4G BARs, but could you please still give https://github.com/FlyGoat/CSMWrap/issues/56#issuecomment-2963295908 a try? @PluMGMK

mintsuki avatar Jun 11 '25 15:06 mintsuki

I can try, but it doesn't sound too promising based on other responses to the message you linked…

I still haven't figured out how to turn on serial debug output, any pointers? I have a machine connected via null-modem running picocom, which is the same way I debug all my Windows 3.1 drivers.

PluMGMK avatar Jun 11 '25 16:06 PluMGMK

Actually, is USB keyboard support even a thing in CSMwrap? Or is it something that the booted "legacy" OS (e.g. Windows XP/Vista/7) is responsible for?

It's not clear to me if CSMwrap can install the necessary SMM code to talk to the USB keyboard and translate the data into legacy IRQs…

PluMGMK avatar Oct 19 '25 18:10 PluMGMK

@PluMGMK SeaBIOS (used by CSMWrap) implements the BIOS interrupts like 16h keyboard services.

Stuff like IRQ and port I/O can't be emulated by SeaBIOS because it requires SMM (or it's done by the chipset I'm not sure)

xCuri0 avatar Oct 19 '25 18:10 xCuri0

OK fair enough, so with a USB keyboard I should (if the keyboard worked) be able to interact with the BIOS itself, and possibly use DOS, but I can probably forget about games and probably even Windows 3.1 / 9x, which try to hook IRQ1 directly. Makes sense!

PluMGMK avatar Oct 19 '25 18:10 PluMGMK

An external MCU (RP2040) on the LPC port could be used for PS/2 emulation, would consist of a small modification for SeaBIOS to write HID events (handle_mouse / handle_key) to a port the MCU is listening on and have it forward that to port 60/64. I think the chipset provides registers to generate IRQ1/12 ?

Alternatively this could be done with a minimal UEFI SMM module though that requires firmware modification and OEMs are increasingly locking down firmware with stuff like BootGuard.

xCuri0 avatar Oct 20 '25 01:10 xCuri0

I think the chipset provides registers to generate IRQ1/12 ?

I guess my chipset does, but I wouldn't be so sure about the newer ones on mobos that don't have CSMs (which are, after all, the real target of this project). But couldn't those be raised over the LPC port the MCU is on too?

I guess SMM isn't required as long as you have timer interrupts running, but then a problem would be if the legacy OS masks IRQ0 but still expects to get IRQ1 and 12. I wonder (naïvely) if some trickery could be done there involving asking the LAPIC to signal timer interrupts in a way that's transparent to legacy OSes, but handling everything else through the legacy PIC? I don't know enough about the LAPIC to see why that's a Bad Idea™, but I'm sure it is…

PluMGMK avatar Oct 20 '25 19:10 PluMGMK

@PluMGMK SeaBIOS already uses timer interrupts (through use of PIT and PIC) for USB polling so I imagine that won't be a problem. https://github.com/coreboot/seabios/blob/master/src/clock.c#L302

external MCU on LPC bus or SMM module is required because afaik there's no other way to trap port 60/64 I/O.

xCuri0 avatar Oct 21 '25 00:10 xCuri0

@PluMGMK SeaBIOS already uses timer interrupts (through use of PIT and PIC) for USB polling so I imagine that won't be a problem. https://github.com/coreboot/seabios/blob/master/src/clock.c#L302

Indeed, but I'm wondering about corner cases where that likewise wouldn't work. Let's say I'm debugging a program in DOS with the debug command, and the program masks every IRQ except one that it's interested in. Then I have a breakpoint in the middle of the section where they're masked, and debug unmasks IRQ1 so I can use the keyboard to interact with it. But it leaves IRQ0 masked so the keyboard won't actually work…

(Although I'll have to double-check if this is what debug actually does – maybe it unmasks IRQ0 as well to make sure the system clock won't be out of whack…)

external MCU on LPC bus or SMM module is required because afaik there's no other way to trap port 60/64 I/O.

Sure, but not both, right? 🙂

PluMGMK avatar Oct 21 '25 18:10 PluMGMK

@PluMGMK

Seems like SMM modules access I/O ports just by using in https://github.com/tandasat/HelloSmm/blob/main/HelloSmm/HelloSmm.c, out probably also works the same.

If it works like that outside of SMM too then fully implementing PS/2 emulation within the SeaBIOS polling loop should be possible if generating IRQ1/12 can be sorted out.

xCuri0 avatar Oct 21 '25 19:10 xCuri0

Indeed, but don't some of the keyboard ports have different input and output functions? SMM won't help with that without having some hardware to back it up...

PluMGMK avatar Oct 21 '25 20:10 PluMGMK

IRQ1/12 can be generated through the chipset register called LEGACY_ELIM on 800 series and SW_IRQ_GEN on 7 series both being the same. It's likely that OEM UEFI uses this to generate them.

Image Image Image

There are also the ULKMC "USB Legacy Keyboard/Mouse Control" registers for generating SMIs on port 60/64 I/O access along with some other registers relating to routing it through eSPI/LPC bus too.

I wouldn't be surprised if Intel removes these in the next generation though and I didn't look into how to do it on AMD.

xCuri0 avatar Oct 22 '25 03:10 xCuri0

XHCI specification also contains various "USB Legacy Support" registers for generating SMIs on USB events but SeaBIOS uses polling instead so I don't think it will be relevant.

Also found this patent on how USB legacy support is implemented https://patents.google.com/patent/US6067589A/en, seems to use SMI events generated by the USB controller and I would assume OEM UEFI is the same.

Seems that OEM UEFI works like the following.

  1. Enable USB controller SMI event generation
  2. Handle the HID event in SMI handler and put it into a variable that will be read later before generating IRQ1/12.
  3. Trap port 60/64h I/O access with SMI handler and use the variable stored earlier to return a value (heavily simplified but it's basically that).

SeaBIOS USB support is based on polling though so I'm not sure how it would work and if SMM is even necessary.

xCuri0 avatar Oct 22 '25 03:10 xCuri0

IRQ1/12 can be generated through the chipset register called LEGACY_ELIM on 800 series and SW_IRQ_GEN on 7 series both being the same. It's likely that OEM UEFI uses this to generate them.

There are also the ULKMC "USB Legacy Keyboard/Mouse Control" registers for generating SMIs on port 60/64 I/O access along with some other registers relating to routing it through eSPI/LPC bus too.

Thanks for posting these, I hadn't realized that there was such a clear and well-documented mechanism to do this!

I wouldn't be surprised if Intel removes these in the next generation though and I didn't look into how to do it on AMD.

Aye, that's what I'm afraid of. Your other approach with an external MCU sounds much more future-proof, but obviously is outside the scope of this software project.

This conversation has answered a few questions I've had in the back of my mind for the last few years about what hardware even exists in modern motherboards to support legacy OSes though, so thanks for that!

Also found this patent on how USB legacy support is implemented https://patents.google.com/patent/US6067589A/en, seems to use SMI events generated by the USB controller and I would assume OEM UEFI is the same.

Ah, so it's patent-encumbered? I guess that's another roadblock, besides firmware being locked down preventing the addition of SMM modules…

SeaBIOS USB support is based on polling though so I'm not sure how it would work and if SMM is even necessary.

I guess SMM would be necessary to trap the I/O ports – that or creating some kind of minimalist VT-x shim (which would probably solve a lot of other problems too, but no doubt create new ones!)

PluMGMK avatar Oct 22 '25 19:10 PluMGMK

Ah, so it's patent-encumbered? I guess that's another roadblock, besides firmware being locked down preventing the addition of SMM modules…

@PluMGMK Seems the patent expired. I doubt it's under copyright/trademark/other stuff that would prevent people from reading it, but that would be something people would have to research (I am also not a lawyer)

DistroHopper39B avatar Oct 22 '25 19:10 DistroHopper39B

Are there any open source implementations of the USB -> PS/2 SMM module ? SeaBIOS/coreboot by design avoid SMM as much as possible for security reasons and TianoCore CSM was just using SeaBIOS before they removed it.

Closest thing I could find is the QEMU implementation of i8042 PS/2 controller: https://github.com/qemu/qemu/blob/master/hw/input/pckbd.c

xCuri0 avatar Oct 23 '25 14:10 xCuri0

Are there any open source implementations of the USB -> PS/2 SMM module ? SeaBIOS/coreboot by design avoid SMM as much as possible for security reasons and TianoCore CSM was just using SeaBIOS before they removed it.

Closest thing I could find is the QEMU implementation of i8042 PS/2 controller: https://github.com/qemu/qemu/blob/master/hw/input/pckbd.c

Can't this be re-implemented back by you guys?

UsefulVideos avatar Oct 24 '25 21:10 UsefulVideos

As an SMM driver maybe, could keep a buffer of HID events received by SeaBIOS at a specific location and have the SMM driver use those to emulate I/O ports 60/64.

ig OEM UEFI has the entire USB stack in SMM but that's more effort to implement and opens up possible security holes the only advantage of it is lower input latency compared to the 50ms timer SeaBIOS uses for inputs.

xCuri0 avatar Oct 25 '25 16:10 xCuri0

But doing something in SMM would require the user to re-flash their firmware, right? csmwrap as a bootable OS doesn't have permission to install its own SMM modules, does it?

PluMGMK avatar Oct 25 '25 18:10 PluMGMK

@PluMGMK yes and there's no other way to intercept port 60/64 besides virtualization afaik.

xCuri0 avatar Oct 25 '25 18:10 xCuri0

Also I'm not surprised SeaBIOS didn't use SMM for its USB implementation because there's a ton of CVEs relating to the SMM USB stack on OEM UEFI. https://www.binarly.io/blog/ami-usbrt-repeatable-failures-a-6-year-old-attack-vector-still-affecting-millions-of-enterprise-devices

xCuri0 avatar Oct 25 '25 18:10 xCuri0