From 375d269b213c8dca6a89ca940ad6be363fff56d3 Mon Sep 17 00:00:00 2001 From: Jesse Buhagiar Date: Tue, 10 Nov 2020 21:24:19 +1100 Subject: [PATCH] Kernel/USB: Prevent system crash via correct UHCI inititilisation It seems that not setting the framelist address register was causing the entire system to lock up as it generated an insane interrupt storm in the IRQ handler for the UHCI controller. We now allocate a 4KiB aligned page via `MemoryManager::allocate_supervisor_physical_page()` and set every value to 1. In effect, this creates a framelist with each entry being a "TERMINATE" entry in which the controller stalls until its' 1mS time slice is up. Some more registers have also been set for consistency, though it seems like this don't need to be set explicitly in software. --- Kernel/Devices/USB/UHCIController.cpp | 20 +++++++++++++++++++- Kernel/Devices/USB/UHCIController.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Kernel/Devices/USB/UHCIController.cpp b/Kernel/Devices/USB/UHCIController.cpp index a6a997050b..2f26bdb092 100644 --- a/Kernel/Devices/USB/UHCIController.cpp +++ b/Kernel/Devices/USB/UHCIController.cpp @@ -25,8 +25,10 @@ */ #include +#include +#include -#define UHCI_ENABLED 0 +#define UHCI_ENABLED 1 namespace Kernel::USB { @@ -46,6 +48,11 @@ static constexpr u16 UHCI_USBSTS_RESUME_RECEIVED = 0x0004; static constexpr u16 UHCI_USBSTS_USB_ERROR_INTERRUPT = 0x0002; static constexpr u16 UHCI_USBSTS_USB_INTERRUPT = 0x0001; +static constexpr u8 UHCI_USBINTR_TIMEOUT_CRC_ENABLE = 0x01; +static constexpr u8 UHCI_USBINTR_RESUME_INTR_ENABLE = 0x02; +static constexpr u8 UHCI_USBINTR_IOC_ENABLE = 0x04; +static constexpr u8 UHCI_USBINTR_SHORT_PACKET_INTR_ENABLE = 0x08; + void UHCIController::detect() { #if !UHCI_ENABLED @@ -90,6 +97,17 @@ void UHCIController::reset() break; } + // Let's allocate the physical page for the Frame List (which is 4KiB aligned) + m_framelist = MemoryManager::the().allocate_supervisor_physical_page()->paddr(); + klog() << "UHCI: Allocated framelist at physical address " << m_framelist; + memset(reinterpret_cast(low_physical_to_virtual(m_framelist.as_ptr())), 1, 1024); // All frames are TERMINATE frames + + write_sofmod(64); // 1mS frame time + write_flbaseadd(m_framelist.get()); // Frame list (physical) address + write_frnum(0); // Set the initial frame number + + // Enable all interrupt types + write_frnum(UHCI_USBINTR_TIMEOUT_CRC_ENABLE | UHCI_USBINTR_RESUME_INTR_ENABLE | UHCI_USBINTR_IOC_ENABLE | UHCI_USBINTR_SHORT_PACKET_INTR_ENABLE); klog() << "UHCI: Reset completed!"; } diff --git a/Kernel/Devices/USB/UHCIController.h b/Kernel/Devices/USB/UHCIController.h index 2bea92b24a..aa6715803c 100644 --- a/Kernel/Devices/USB/UHCIController.h +++ b/Kernel/Devices/USB/UHCIController.h @@ -64,6 +64,7 @@ private: virtual void handle_irq(const RegisterState&) override; IOAddress m_io_base; + PhysicalAddress m_framelist; }; }