From efa6536465151fe6b37339337032d1912efed761 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 6 Jan 2022 19:59:18 -0300 Subject: [PATCH] usblgoff: Add tool for disabling USB legacy emulation --- .github/workflows/build.yml | 5 ++ .gitignore | 2 +- clib/clib.c | 28 +++++++ clib/clib.h | 6 ++ clib/watcom.mk | 5 ++ usblgoff/Makefile | 22 ++++++ usblgoff/README.md | 12 +++ usblgoff/usblgoff.c | 152 ++++++++++++++++++++++++++++++++++++ 8 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 usblgoff/Makefile create mode 100644 usblgoff/README.md create mode 100644 usblgoff/usblgoff.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a44f4bb..171ef7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,6 +42,10 @@ jobs: wmake make -f Makefile.uefi ARCH=x86_64 python3 pciids.py + - name: Build `usblgoff` + run: | + cd ${{ github.workspace }}/usblgoff + wmake - uses: actions/upload-artifact@v2 with: name: probing-tools-${{ github.sha }} @@ -52,6 +56,7 @@ jobs: ac97/*.md acpi/*.md pcireg/*.md + usblgoff/*.md newbasic: name: NewBasic diff --git a/.gitignore b/.gitignore index 9afff6f..51b8bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,4 @@ pci?????.bin # Binaries *.exe *.com -*.efi \ No newline at end of file +*.efi diff --git a/clib/clib.c b/clib/clib.c index cba8924..fea8650 100644 --- a/clib/clib.c +++ b/clib/clib.c @@ -386,6 +386,34 @@ pci_get_io_bar(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t siz } +#ifdef IS_32BIT +uint32_t +pci_get_mem_bar(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t size, const char *name) +{ + uint32_t ret; + + printf("%s memory BAR is ", name); + + /* Read BAR register. */ + ret = pci_readl(bus, dev, func, reg); + if ((ret & 0x00000001) || (ret == 0xffffffff)) { + printf("invalid! (%08X)", ret); + ret = 0; + } else { + /* Don't even try to find a valid memory range if the BAR is unassigned. */ + ret &= ~(size - 1); + if (ret) + printf("assigned to %08X", ret); + else + printf("unassigned!"); + } + + printf("\n"); + return ret; +} +#endif + + int pci_init() { diff --git a/clib/clib.h b/clib/clib.h index 55afe0e..fab0d86 100644 --- a/clib/clib.h +++ b/clib/clib.h @@ -34,6 +34,9 @@ #ifndef __POSIX_UEFI__ # define FMT_FLOAT_SUPPORTED 1 #endif +#if !defined(__WATCOMC__) || defined(M_I386) +# define IS_32BIT 1 +#endif #pragma pack(push, 0) @@ -124,6 +127,9 @@ extern uint16_t io_find_range(uint16_t size); /* PCI functions. */ extern uint32_t pci_cf8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); extern uint16_t pci_get_io_bar(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t size, const char *name); +#ifdef IS_32BIT +extern uint32_t pci_get_mem_bar(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t size, const char *name); +#endif extern int pci_init(); extern uint8_t pci_readb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); extern uint16_t pci_readw(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); diff --git a/clib/watcom.mk b/clib/watcom.mk index 258854c..36b4bbc 100644 --- a/clib/watcom.mk +++ b/clib/watcom.mk @@ -18,10 +18,12 @@ # Establish host-specific stuff. !ifdef __UNIX__ DEL = rm -f +COPY = cp CP437 = cp437 SLASH = / !else DEL = del +COPY = copy /y CP437 = cp437.exe SLASH = \ !if "$(SYSTEM)" == "HOST" @@ -74,6 +76,9 @@ all: ..$(SLASH)cp437$(SLASH)$(CP437) $(DEST) # Main target. $(DEST): $(OBJS) +!if "$(SYSTEM)" == "PMODEW" + $(COPY) %WATCOM%$(SLASH)binw$(SLASH)pmodew.exe .$(SLASH) +!endif %write $@.lnk NAME $@ !if "$(SYSTEM)" != "HOST" %write $@.lnk SYSTEM $(SYSTEM) diff --git a/usblgoff/Makefile b/usblgoff/Makefile new file mode 100644 index 0000000..88879f0 --- /dev/null +++ b/usblgoff/Makefile @@ -0,0 +1,22 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Makefile for compiling C-based tools with Watcom. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +SYSTEM = PMODEW +OBJS = usblgoff.obj clib.obj +DEST = USBLGOFF.EXE + +!include ../clib/watcom.mk diff --git a/usblgoff/README.md b/usblgoff/README.md new file mode 100644 index 0000000..7ef6a81 --- /dev/null +++ b/usblgoff/README.md @@ -0,0 +1,12 @@ +usblgoff +======== +DOS tool for disabling USB legacy emulation to allow for running keyboard controller probing tools. + +Usage +----- +Run `USBLGOFF.EXE` on a system with USB. The I/O traps set by onboard USB controllers and a handful of chipsets will be disabled, and the virtual keyboard controller created by the BIOS for USB input emulation should no longer interfere with KBC probing tools such as [amikey](../amikey) until the system is rebooted. + +Building +-------- +* **Windows:** Run `wmake` from an OpenWatcom "Build Environment" command prompt. +* **Linux:** Run `wmake` with OpenWatcom tools present in `$PATH`. diff --git a/usblgoff/usblgoff.c b/usblgoff/usblgoff.c new file mode 100644 index 0000000..ab5df37 --- /dev/null +++ b/usblgoff/usblgoff.c @@ -0,0 +1,152 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box Probing Tools distribution. + * + * USB legacy emulation disable tool. + * + * + * + * Authors: RichardG, + * + * Copyright 2022 RichardG. + * + * ┌──────────────────────────────────────────────────────────────┐ + * │ This file is UTF-8 encoded. If this text is surrounded by │ + * │ garbage, please tell your editor to open this file as UTF-8. │ + * └──────────────────────────────────────────────────────────────┘ + */ +#include +#include +#include +#include "clib.h" + + +static void +pci_scan_callback(uint8_t bus, uint8_t dev, uint8_t func, + uint16_t ven_id, uint16_t dev_id) +{ + uint8_t i; + uint16_t j, start, end; +#ifdef IS_32BIT + uint32_t mmio_base, *mmio; +#endif + +#ifdef IS_32BIT + /* Disable southbridge I/O traps. */ + if ((ven_id == 0x8086) && (((dev_id >= 0x2640) && (dev_id <= 0x2642)) /* ICH6 */ || + ((dev_id >= 0x27b0) && (dev_id <= 0x27bd)) /* ICH7 */ || + ((dev_id >= 0x2810) && (dev_id <= 0x2815)) /* ICH8 */ || + ((dev_id >= 0x2912) && (dev_id <= 0x2919)) /* ICH9 */ || + ((dev_id >= 0x3a14) && (dev_id <= 0x3a1a)) /* ICH10 */)) { + printf("Found ICH6-10 LPC bridge %04X at bus %02X device %02X function %d\n", dev_id, bus, dev, func); + + /* Get RCBA. */ + printf("> RCBA is "); + mmio_base = pci_readl(bus, dev, func, 0xf0) & ~0x00003fff; + if ((mmio_base & 0x00000001) && (mmio_base != 0xffffffff)) { + printf("assigned to %08X\n", mmio_base); + mmio = (uint32_t *) mmio_base; + + /* Disable all relevant I/O traps. */ + for (i = 0; i < 4; i++) { + /* Check if the trap is enabled. */ + j = (0x1e80 | (i << 3)) >> 2; + if (mmio[j] & 0x00000001) { + start = mmio[j] & 0xfffc; + end = (mmio[j] >> 16) & 0xfc; /* temporarily just the mask */ + printf("> Trap %d (%04X+%02X)", i, start, end); + end += start; /* now the actual end */ + + /* Check if the trap covers the KBC ports. */ + if (((start <= 0x60) && (end >= 0x60)) || + ((start <= 0x64) && (end >= 0x64))) { + /* Clear TRSE bit. */ + mmio[j] &= ~0x00000001; + + /* Check if the bit was actually cleared. */ + if (mmio[j] & 0x00000001) + printf("enable bit stuck! (%08X%08X)\n", mmio[j | 1], mmio[j]); + else + printf("disabled\n"); + } else { + printf("not relevant\n"); + } + } + } + } else { + printf("unassigned! (%08X)\n", mmio_base); + } + + return; + } +#endif + + /* Skip non-USB devices. */ + if (pci_readw(bus, dev, func, 0x0a) != 0x0c03) + return; + + /* Read progif code. */ + i = pci_readb(bus, dev, func, 0x09); + + /* Act according to the device class. */ + if (i == 0x00) { /* UHCI */ + printf("Found UHCI USB controller at bus %02X device %02X function %d\n", bus, dev, func); + + /* Clear 60/64h trap/SMI R/W bits. */ + j = pci_readw(bus, dev, func, 0xc0); + pci_writew(bus, dev, func, 0xc0, j & ~0x000f); + + /* Check if the bits were actually cleared. */ + j = pci_readw(bus, dev, func, 0xc0); + if (j & 0x000f) + printf("> I/O trap bits stuck! (%04X)\n", j); + else + printf("> I/O traps disabled\n"); + } else if (i == 0x10) { /* OHCI */ + printf("Found OHCI USB controller at bus %02X device %02X function %d\n", bus, dev, func); + +#ifdef IS_32BIT + /* Get MMIO base address. */ + mmio_base = pci_get_mem_bar(bus, dev, func, 0x10, 4096, "> MMIO"); + if (mmio_base) { + mmio = (uint32_t *) mmio_base; + + /* Clear EmulationEnable bit. */ + mmio[0x100 >> 2] &= ~0x00000001; + + /* Check if the bit was actually cleared. */ + if (mmio[0x100 >> 2] & 0x00000001) + printf("> Emulation bit stuck! (%08X)\n", mmio[0x100 >> 2]); + else + printf("> Emulation disabled\n"); + } +#else + printf("> OHCI not supported on 16-bit build!\n"); +#endif + } else if ((i != 0x20) && (i != 0x30)) { /* not EHCI or XHCI */ + printf("Found unknown USB controller type %02X at bus %02X device %02X function %d\n", i, bus, dev, func); + } +} + + +int +main(int argc, char **argv) +{ + uint8_t dev, func; + + /* Disable stdout buffering. */ + term_unbuffer_stdout(); + + /* Initialize PCI, and exit in case of failure. */ + if (!pci_init()) + return 1; + + /* Scan PCI bus 0. */ + pci_scan_bus(0, pci_scan_callback); + + return 0; +}