From 06a32b6e16062ccebbe7a6f02a045b44aa647998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Sun, 18 Feb 2024 18:26:42 +0100 Subject: [PATCH] Kernel/USB: Handle non-page aligned EHCI controller BARs correctly BARs don't have to be page-aligned. This patch correctly calculates the needed memory range and register base address in that region. --- Kernel/Bus/USB/EHCI/EHCIController.cpp | 14 +++++++++----- Kernel/Bus/USB/EHCI/EHCIController.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Kernel/Bus/USB/EHCI/EHCIController.cpp b/Kernel/Bus/USB/EHCI/EHCIController.cpp index 43b9c41445..be1c255a35 100644 --- a/Kernel/Bus/USB/EHCI/EHCIController.cpp +++ b/Kernel/Bus/USB/EHCI/EHCIController.cpp @@ -16,24 +16,28 @@ ErrorOr> EHCIController::try_to_initialize(con // FIXME: This assumes the BIOS left us a physical region for the controller auto pci_bar_address = TRY(PCI::get_bar_address(pci_device_identifier, SpaceBaseAddressRegister)); auto pci_bar_space_size = PCI::get_BAR_space_size(pci_device_identifier, SpaceBaseAddressRegister); - auto register_region = TRY(MM.allocate_kernel_region(pci_bar_address, pci_bar_space_size, {}, Memory::Region::Access::ReadWrite)); + + auto register_region_size = TRY(Memory::page_round_up(pci_bar_address.offset_in_page() + pci_bar_space_size)); + auto register_region = TRY(MM.allocate_kernel_region(pci_bar_address.page_base(), register_region_size, {}, Memory::Region::Access::ReadWrite)); + + VirtualAddress register_base_address = register_region->vaddr().offset(pci_bar_address.offset_in_page()); PCI::enable_bus_mastering(pci_device_identifier); PCI::enable_memory_space(pci_device_identifier); - auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) EHCIController(pci_device_identifier, move(register_region)))); + auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) EHCIController(pci_device_identifier, move(register_region), register_base_address))); TRY(controller->initialize()); return controller; } -EHCIController::EHCIController(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr register_region) +EHCIController::EHCIController(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr register_region, VirtualAddress register_base_address) : PCI::Device(pci_device_identifier) , m_register_region(move(register_region)) { - m_cap_regs = bit_cast(m_register_region->vaddr().get()); - m_op_regs = bit_cast(m_register_region->vaddr().get() + m_cap_regs->capability_length); + m_cap_regs = bit_cast(register_base_address.get()); + m_op_regs = bit_cast(register_base_address.get() + m_cap_regs->capability_length); } ErrorOr EHCIController::initialize() diff --git a/Kernel/Bus/USB/EHCI/EHCIController.h b/Kernel/Bus/USB/EHCI/EHCIController.h index e9bdf70d3d..1517bd782b 100644 --- a/Kernel/Bus/USB/EHCI/EHCIController.h +++ b/Kernel/Bus/USB/EHCI/EHCIController.h @@ -36,7 +36,7 @@ public: virtual ErrorOr submit_async_interrupt_transfer(NonnullLockRefPtr, u16) override { return ENOTSUP; } private: - EHCIController(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr register_region); + EHCIController(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr register_region, VirtualAddress register_base_address); NonnullOwnPtr m_register_region; CapabilityRegisters const* m_cap_regs;