Browse Source

[xhci] Do not release ownership back to BIOS when booting an OS

xHCI (and EHCI) nominally provide a mechanism for releasing ownership
of the host controller back to the BIOS, which can then potentially
restore legacy USB keyboard functionality.

This is a rarely used code path, since most operating systems claim
ownership and never attempt to later return to the BIOS.  On some
systems (observed with a Lenovo X1 Carbon), this code path leads to
obscure and interesting bugs: if the xHCI and EHCI controllers are
both claimed and later released back to the BIOS, then a subsequent
call to INT 16,0305 to set the keyboard repeat rate to a non-default
value will lock the system.

Obscure though this sequence of operations may sound, it is exactly
what happens when using iPXE to boot a Linux kernel via a USB network
card.  There is old and probably unwanted code in Linux's
arch/x86/boot/main.c which sets the keyboard repeat rate (with the
accompanying comment "Set keyboard repeat rate (why?)").  When booting
Linux via a USB network card on a Lenovo X1 Carbon, the system
therefore locks up immediately after jumping to the kernel's entry
point.

Work around this problem by preventing the release of ownership back
to the BIOS if it is known that we are shutting down to boot an OS.
This should allow legacy USB keyboard functionality to be restored if
the user chooses to exit iPXE, while avoiding the rarely used code
paths (and corresponding BIOS bugs) if the user chooses instead to
boot an OS.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
ec0e2a7bd7
1 changed files with 27 additions and 0 deletions
  1. 27
    0
      src/drivers/usb/xhci.c

+ 27
- 0
src/drivers/usb/xhci.c View File

34
 #include <ipxe/umalloc.h>
34
 #include <ipxe/umalloc.h>
35
 #include <ipxe/pci.h>
35
 #include <ipxe/pci.h>
36
 #include <ipxe/usb.h>
36
 #include <ipxe/usb.h>
37
+#include <ipxe/init.h>
37
 #include <ipxe/profile.h>
38
 #include <ipxe/profile.h>
38
 #include "xhci.h"
39
 #include "xhci.h"
39
 
40
 
521
  ******************************************************************************
522
  ******************************************************************************
522
  */
523
  */
523
 
524
 
525
+/** Prevent the release of ownership back to BIOS */
526
+static int xhci_legacy_prevent_release;
527
+
524
 /**
528
 /**
525
  * Initialise USB legacy support
529
  * Initialise USB legacy support
526
  *
530
  *
610
 	if ( ! xhci->legacy )
614
 	if ( ! xhci->legacy )
611
 		return;
615
 		return;
612
 
616
 
617
+	/* Do nothing if releasing ownership is prevented */
618
+	if ( xhci_legacy_prevent_release ) {
619
+		DBGC ( xhci, "XHCI %p not releasing ownership to BIOS\n", xhci);
620
+		return;
621
+	}
622
+
613
 	/* Release ownership */
623
 	/* Release ownership */
614
 	writeb ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
624
 	writeb ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
615
 	DBGC ( xhci, "XHCI %p released ownership to BIOS\n", xhci );
625
 	DBGC ( xhci, "XHCI %p released ownership to BIOS\n", xhci );
3190
 	.probe = xhci_probe,
3200
 	.probe = xhci_probe,
3191
 	.remove = xhci_remove,
3201
 	.remove = xhci_remove,
3192
 };
3202
 };
3203
+
3204
+/**
3205
+ * Prepare for exit
3206
+ *
3207
+ * @v booting		System is shutting down for OS boot
3208
+ */
3209
+static void xhci_shutdown ( int booting ) {
3210
+	/* If we are shutting down to boot an OS, then prevent the
3211
+	 * release of ownership back to BIOS.
3212
+	 */
3213
+	xhci_legacy_prevent_release = booting;
3214
+}
3215
+
3216
+/** Startup/shutdown function */
3217
+struct startup_fn xhci_startup __startup_fn ( STARTUP_LATE ) = {
3218
+	.shutdown = xhci_shutdown,
3219
+};

Loading…
Cancel
Save