Kernel: Take ownership of xHCI controller from bios

This commit is contained in:
Bananymous 2024-07-14 03:31:35 +03:00
parent baa4e6475a
commit 86e9d92ecb
6 changed files with 94 additions and 8 deletions

View File

@ -38,7 +38,8 @@ namespace Kernel
};
public:
static BAN::ErrorOr<BAN::UniqPtr<XHCIController>> initialize(PCI::Device&);
static BAN::ErrorOr<void> take_ownership(PCI::Device&);
static BAN::ErrorOr<BAN::UniqPtr<XHCIController>> create(PCI::Device&);
void handle_irq() final override;

View File

@ -409,6 +409,17 @@ namespace Kernel::XHCI
};
static_assert(sizeof(ExtendedCap) == 4);
struct USBLegacySupportCap
{
uint32_t capability_id : 8;
uint32_t next_capability : 8;
uint32_t hc_bios_owned_semaphore : 1;
uint32_t : 7;
uint32_t hc_os_owned_semaphore : 1;
uint32_t : 7;
};
static_assert(sizeof(USBLegacySupportCap) == 4);
struct SupportedPrococolCap
{
uint32_t capability_id : 8;

View File

@ -241,8 +241,6 @@ namespace Kernel::Input
BAN::ErrorOr<void> PS2Controller::initialize_impl()
{
// FIXME: Initialise USB Controllers
// Determine if the PS/2 Controller Exists
auto* fadt = static_cast<const ACPI::FADT*>(ACPI::ACPI::get().get_header("FACP"_sv, 0));
if (fadt && fadt->revision > 1 && !(fadt->iapc_boot_arch & (1 << 1)))

View File

@ -13,6 +13,36 @@ namespace Kernel
ASSERT(!s_instance);
auto manager = TRY(BAN::UniqPtr<USBManager>::create());
s_instance = BAN::move(manager);
PCI::PCIManager::get().for_each_device(
[](PCI::Device& pci_device)
{
if (pci_device.class_code() != 0x0C || pci_device.subclass() != 0x03)
return;
switch (pci_device.prog_if())
{
case 0x00:
dprintln("Unsupported UHCI controller");
break;
case 0x10:
dprintln("Unsupported OHCI controller");
break;
case 0x20:
dprintln("Unsupported EHCI controller");
break;
case 0x30:
if (auto ret = XHCIController::take_ownership(pci_device); ret.is_error())
dprintln("Could not take ownership of xHCI controller: {}", ret.error());
else
dprintln("Took ownership of xHCI controller");
break;
default:
dprintln("Unsupported USB controller, prog if {2H}", pci_device.prog_if());
break;
}
}
);
return {};
}
@ -40,12 +70,13 @@ namespace Kernel
dprintln("Unsupported EHCI controller");
return BAN::Error::from_errno(ENOTSUP);
case 0x30:
if (auto ret = XHCIController::initialize(pci_device); ret.is_error())
if (auto ret = XHCIController::create(pci_device); ret.is_error())
dprintln("Could not initialize XHCI controller: {}", ret.error());
else
controller = ret.release_value();
break;
default:
dprintln("Unsupported USB controller, prog if {2H}", pci_device.prog_if());
return BAN::Error::from_errno(EINVAL);
}

View File

@ -22,7 +22,51 @@ namespace Kernel
m_port_updater->exit(0, SIGKILL);
}
BAN::ErrorOr<BAN::UniqPtr<XHCIController>> XHCIController::initialize(PCI::Device& pci_device)
BAN::ErrorOr<void> XHCIController::take_ownership(PCI::Device& pci_device)
{
auto bar = TRY(pci_device.allocate_bar_region(0));
if (bar->type() != PCI::BarType::MEM)
{
dwarnln("XHCI controller with non-memory configuration space");
return BAN::Error::from_errno(EINVAL);
}
auto& capabilities = *reinterpret_cast<volatile XHCI::CapabilityRegs*>(bar->vaddr());
const uint16_t ext_offset = capabilities.hccparams1.xhci_extended_capabilities_pointer;
if (ext_offset == 0)
{
dwarnln("XHCI controller does not have extended capabilities");
return BAN::Error::from_errno(EFAULT);
}
vaddr_t ext_addr = bar->vaddr() + ext_offset * 4;
while (true)
{
auto& ext_cap = *reinterpret_cast<volatile XHCI::ExtendedCap*>(ext_addr);
if (ext_cap.capability_id == XHCI::ExtendedCapabilityID::USBLegacySupport)
{
auto& legacy = *reinterpret_cast<volatile XHCI::USBLegacySupportCap*>(ext_addr);
if (!legacy.hc_bios_owned_semaphore)
return {};
legacy.hc_os_owned_semaphore = 1;
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000;
while (legacy.hc_bios_owned_semaphore)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
return {};
}
if (ext_cap.next_capability == 0)
break;
ext_addr += ext_cap.next_capability * 4;
}
return {};
}
BAN::ErrorOr<BAN::UniqPtr<XHCIController>> XHCIController::create(PCI::Device& pci_device)
{
auto controller = TRY(BAN::UniqPtr<XHCIController>::create(pci_device));
TRY(controller->initialize_impl());

View File

@ -189,6 +189,9 @@ static void init2(void*)
PCI::PCIManager::initialize();
dprintln("PCI initialized");
MUST(USBManager::initialize());
dprintln("USBManager initialized");
if (ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()).is_error())
dprintln("Failed to enter ACPI mode");
@ -202,14 +205,12 @@ static void init2(void*)
// Initialize empty keymap
MUST(LibInput::KeyboardLayout::initialize());
// FIXME: initialize PS/2 after USB
// FIXME: implement device hot plugging, so multiple devices is possible
//if (auto res = PS2Controller::initialize(); res.is_error())
// dprintln("{}", res.error());
MUST(NetworkManager::initialize());
MUST(USBManager::initialize());
// NOTE: PCI devices are the last ones to be initialized
// so other devices can reserve predefined interrupts
PCI::PCIManager::get().initialize_devices();