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.
This commit is contained in:
Jesse Buhagiar 2020-11-10 21:24:19 +11:00 committed by Andreas Kling
parent 33d73c600c
commit 375d269b21
Notes: sideshowbarker 2024-07-19 00:00:59 +09:00
2 changed files with 20 additions and 1 deletions

View file

@ -25,8 +25,10 @@
*/
#include <Kernel/Devices/USB/UHCIController.h>
#include <Kernel/StdLib.h>
#include <Kernel/VM/MemoryManager.h>
#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<u32*>(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!";
}

View file

@ -64,6 +64,7 @@ private:
virtual void handle_irq(const RegisterState&) override;
IOAddress m_io_base;
PhysicalAddress m_framelist;
};
}