diff options
Diffstat (limited to 'Kernel/Bus/PCI')
-rw-r--r-- | Kernel/Bus/PCI/Access.cpp | 461 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Access.h | 54 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Controller/HostBridge.cpp | 175 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Controller/HostBridge.h | 49 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Controller/HostController.h | 45 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.cpp | 94 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h | 42 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Definitions.h | 13 | ||||
-rw-r--r-- | Kernel/Bus/PCI/Initializer.cpp | 4 |
9 files changed, 513 insertions, 424 deletions
diff --git a/Kernel/Bus/PCI/Access.cpp b/Kernel/Bus/PCI/Access.cpp index 183c52fd5e..0959bed47d 100644 --- a/Kernel/Bus/PCI/Access.cpp +++ b/Kernel/Bus/PCI/Access.cpp @@ -9,10 +9,13 @@ #include <AK/HashTable.h> #include <Kernel/Arch/x86/IO.h> #include <Kernel/Bus/PCI/Access.h> +#include <Kernel/Bus/PCI/Controller/HostBridge.h> +#include <Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h> #include <Kernel/Debug.h> #include <Kernel/Firmware/ACPI/Definitions.h> #include <Kernel/Memory/MemoryManager.h> #include <Kernel/Memory/Region.h> +#include <Kernel/Memory/TypedMapping.h> #include <Kernel/Sections.h> namespace Kernel::PCI { @@ -34,28 +37,18 @@ bool Access::is_initialized() return (s_access != nullptr); } -UNMAP_AFTER_INIT bool Access::initialize_for_memory_access(PhysicalAddress mcfg_table) +UNMAP_AFTER_INIT bool Access::find_and_register_pci_host_bridges_from_acpi_mcfg_table(PhysicalAddress mcfg_table) { - if (Access::is_initialized()) - return false; - - auto* access = new Access(Access::AccessType::Memory); - if (!access->search_pci_domains_from_acpi_mcfg_table(mcfg_table)) - return false; - access->rescan_hardware_with_memory_addressing(); - dbgln_if(PCI_DEBUG, "PCI: MMIO access initialised."); - return true; -} + u32 length = 0; + u8 revision = 0; + { + auto mapped_mcfg_table = Memory::map_typed<ACPI::Structures::SDTHeader>(mcfg_table); + length = mapped_mcfg_table->length; + revision = mapped_mcfg_table->revision; + } -UNMAP_AFTER_INIT bool Access::search_pci_domains_from_acpi_mcfg_table(PhysicalAddress mcfg_table) -{ - auto checkup_region_or_error = MM.allocate_kernel_region(mcfg_table.page_base(), (PAGE_SIZE * 2), "PCI MCFG Checkup", Memory::Region::Access::ReadWrite); - if (checkup_region_or_error.is_error()) + if (length == sizeof(ACPI::Structures::SDTHeader)) return false; - dbgln_if(PCI_DEBUG, "PCI: Checking MCFG Table length to choose the correct mapping size"); - auto* sdt = (ACPI::Structures::SDTHeader*)checkup_region_or_error.value()->vaddr().offset(mcfg_table.offset_in_page()).as_ptr(); - u32 length = sdt->length; - u8 revision = sdt->revision; dbgln("PCI: MCFG, length: {}, revision: {}", length, revision); @@ -77,200 +70,108 @@ UNMAP_AFTER_INIT bool Access::search_pci_domains_from_acpi_mcfg_table(PhysicalAd for (u32 index = 0; index < ((mcfg.header.length - sizeof(ACPI::Structures::MCFG)) / sizeof(ACPI::Structures::PCI_MMIO_Descriptor)); index++) { u8 start_bus = mcfg.descriptors[index].start_pci_bus; u8 end_bus = mcfg.descriptors[index].end_pci_bus; - u32 lower_addr = mcfg.descriptors[index].base_addr; + u64 start_addr = mcfg.descriptors[index].base_addr; - auto result = m_domains.set(index, { PhysicalAddress(lower_addr), start_bus, end_bus }); - VERIFY(result == AK::HashSetResult::InsertedNewEntry); - dmesgln("PCI: New PCI domain @ {}, PCI buses ({}-{})", PhysicalAddress { lower_addr }, start_bus, end_bus); + Domain pci_domain { index, start_bus, end_bus }; + dmesgln("PCI: New PCI domain @ {}, PCI buses ({}-{})", PhysicalAddress { start_addr }, start_bus, end_bus); + auto host_bridge = MemoryBackedHostBridge::must_create(pci_domain, PhysicalAddress { start_addr }); + add_host_controller(move(host_bridge)); } - VERIFY(m_domains.contains(0)); - dmesgln("PCI: MMIO domain: {}", m_domains.size()); + return true; } -UNMAP_AFTER_INIT bool Access::initialize_for_io_access() +UNMAP_AFTER_INIT bool Access::initialize_for_multiple_pci_domains(PhysicalAddress mcfg_table) { - if (Access::is_initialized()) { + if (Access::is_initialized()) return false; - } - auto* access = new Access(Access::AccessType::IO); - access->rescan_hardware_with_io_addressing(); - dbgln_if(PCI_DEBUG, "PCI: IO access initialised."); + + auto* access = new Access(); + if (!access->find_and_register_pci_host_bridges_from_acpi_mcfg_table(mcfg_table)) + return false; + access->rescan_hardware(); + dbgln_if(PCI_DEBUG, "PCI: access for multiple PCI domain initialised."); return true; } -UNMAP_AFTER_INIT Access::Access(AccessType access_type) - : m_enumerated_buses(256, false) - , m_access_type(access_type) +UNMAP_AFTER_INIT bool Access::initialize_for_one_pci_domain() { - if (access_type == AccessType::IO) - dmesgln("PCI: Using I/O instructions for PCI configuration space access"); - else - dmesgln("PCI: Using memory access for PCI configuration space accesses"); - s_access = this; + if (Access::is_initialized()) { + return false; + } + auto* access = new Access(); + auto host_bridge = HostBridge::must_create_with_io_access(); + access->add_host_controller(move(host_bridge)); + access->rescan_hardware(); + dbgln_if(PCI_DEBUG, "PCI: access for one PCI domain initialised."); + return true; } -Optional<PhysicalAddress> Access::determine_memory_mapped_bus_base_address(u32 domain, u8 bus) const +UNMAP_AFTER_INIT void Access::add_host_controller(NonnullOwnPtr<HostController> controller) { - auto chosen_domain = m_domains.get(domain); - if (!chosen_domain.has_value()) - return {}; - if (!(chosen_domain.value().start_bus() <= bus && bus <= chosen_domain.value().end_bus())) - return {}; - return chosen_domain.value().paddr().offset(memory_range_per_bus * (bus - chosen_domain.value().start_bus())); + auto domain_number = controller->domain_number(); + m_host_controllers.set(domain_number, move(controller)); } -void Access::map_bus_region(u32 domain, u8 bus) +UNMAP_AFTER_INIT Access::Access() { - VERIFY(m_access_lock.is_locked()); - if (m_mapped_bus == bus && m_mapped_bus_region) - return; - auto bus_base_address = determine_memory_mapped_bus_base_address(domain, bus); - // FIXME: Find a way to propagate error from here. - if (!bus_base_address.has_value()) - VERIFY_NOT_REACHED(); - auto region_or_error = MM.allocate_kernel_region(bus_base_address.value(), memory_range_per_bus, "PCI ECAM", Memory::Region::Access::ReadWrite); - // FIXME: Find a way to propagate error from here. - if (region_or_error.is_error()) - VERIFY_NOT_REACHED(); - m_mapped_bus_region = region_or_error.release_value(); - m_mapped_bus = bus; - dbgln_if(PCI_DEBUG, "PCI: New PCI ECAM Mapped region for bus {} @ {} {}", bus, m_mapped_bus_region->vaddr(), m_mapped_bus_region->physical_page(0)->paddr()); + s_access = this; } -VirtualAddress Access::get_device_configuration_memory_mapped_space(Address address) +UNMAP_AFTER_INIT void Access::rescan_hardware() { - VERIFY(m_access_lock.is_locked()); - dbgln_if(PCI_DEBUG, "PCI: Getting device configuration space for {}", address); - map_bus_region(address.domain(), address.bus()); - return m_mapped_bus_region->vaddr().offset(mmio_device_space_size * address.function() + (mmio_device_space_size * to_underlying(Limits::MaxFunctionsPerDevice)) * address.device()); + MutexLocker locker(m_access_lock); + SpinlockLocker scan_locker(m_scan_lock); + VERIFY(m_device_identifiers.is_empty()); + for (auto it = m_host_controllers.begin(); it != m_host_controllers.end(); ++it) { + (*it).value->enumerate_attached_devices([this](DeviceIdentifier device_identifier) -> void { + m_device_identifiers.append(device_identifier); + }); + } } -u8 Access::io_read8_field(Address address, u32 field) -{ - MutexLocker lock(m_access_lock); - dbgln_if(PCI_DEBUG, "PCI: IO Reading 8-bit field {:#08x} for {}", field, address); - IO::out32(PCI::address_port, address.io_address_for_field(field)); - return IO::in8(PCI::value_port + (field & 3)); -} -u16 Access::io_read16_field(Address address, u32 field) -{ - MutexLocker lock(m_access_lock); - dbgln_if(PCI_DEBUG, "PCI: IO Reading 16-bit field {:#08x} for {}", field, address); - IO::out32(PCI::address_port, address.io_address_for_field(field)); - return IO::in16(PCI::value_port + (field & 2)); -} -u32 Access::io_read32_field(Address address, u32 field) -{ - MutexLocker lock(m_access_lock); - dbgln_if(PCI_DEBUG, "PCI: IO Reading 32-bit field {:#08x} for {}", field, address); - IO::out32(PCI::address_port, address.io_address_for_field(field)); - return IO::in32(PCI::value_port); -} -void Access::io_write8_field(Address address, u32 field, u8 value) -{ - MutexLocker lock(m_access_lock); - dbgln_if(PCI_DEBUG, "PCI: IO Writing to 8-bit field {:#08x}, value={:#02x} for {}", field, value, address); - IO::out32(PCI::address_port, address.io_address_for_field(field)); - IO::out8(PCI::value_port + (field & 3), value); -} -void Access::io_write16_field(Address address, u32 field, u16 value) -{ - MutexLocker lock(m_access_lock); - dbgln_if(PCI_DEBUG, "PCI: IO Writing to 16-bit field {:#08x}, value={:#02x} for {}", field, value, address); - IO::out32(PCI::address_port, address.io_address_for_field(field)); - IO::out16(PCI::value_port + (field & 2), value); -} -void Access::io_write32_field(Address address, u32 field, u32 value) +void Access::fast_enumerate(Function<void(DeviceIdentifier const&)>& callback) const { - MutexLocker lock(m_access_lock); - dbgln_if(PCI_DEBUG, "PCI: IO Writing to 32-bit field {:#08x}, value={:#02x} for {}", field, value, address); - IO::out32(PCI::address_port, address.io_address_for_field(field)); - IO::out32(PCI::value_port, value); + MutexLocker locker(m_access_lock); + VERIFY(!m_device_identifiers.is_empty()); + for (auto const& device_identifier : m_device_identifiers) { + callback(device_identifier); + } } -u8 Access::memory_read8_field(Address address, u32 field) -{ - MutexLocker lock(m_access_lock); - VERIFY(field <= 0xfff); - dbgln_if(PCI_DEBUG, "PCI: MMIO Reading 8-bit field {:#08x} for {}", field, address); - return *((volatile u8*)(get_device_configuration_memory_mapped_space(address).get() + (field & 0xfff))); -} -u16 Access::memory_read16_field(Address address, u32 field) -{ - MutexLocker lock(m_access_lock); - VERIFY(field < 0xfff); - dbgln_if(PCI_DEBUG, "PCI: MMIO Reading 16-bit field {:#08x} for {}", field, address); - u16 data = 0; - ByteReader::load<u16>(get_device_configuration_memory_mapped_space(address).offset(field & 0xfff).as_ptr(), data); - return data; -} -u32 Access::memory_read32_field(Address address, u32 field) -{ - MutexLocker lock(m_access_lock); - VERIFY(field <= 0xffc); - dbgln_if(PCI_DEBUG, "PCI: MMIO Reading 32-bit field {:#08x} for {}", field, address); - u32 data = 0; - ByteReader::load<u32>(get_device_configuration_memory_mapped_space(address).offset(field & 0xfff).as_ptr(), data); - return data; -} -void Access::memory_write8_field(Address address, u32 field, u8 value) -{ - MutexLocker lock(m_access_lock); - VERIFY(field <= 0xfff); - dbgln_if(PCI_DEBUG, "PCI: MMIO Writing 8-bit field {:#08x}, value={:#02x} for {}", field, value, address); - *((volatile u8*)(get_device_configuration_memory_mapped_space(address).get() + (field & 0xfff))) = value; -} -void Access::memory_write16_field(Address address, u32 field, u16 value) -{ - MutexLocker lock(m_access_lock); - VERIFY(field < 0xfff); - dbgln_if(PCI_DEBUG, "PCI: MMIO Writing 16-bit field {:#08x}, value={:#02x} for {}", field, value, address); - ByteReader::store<u16>(get_device_configuration_memory_mapped_space(address).offset(field & 0xfff).as_ptr(), value); -} -void Access::memory_write32_field(Address address, u32 field, u32 value) +DeviceIdentifier Access::get_device_identifier(Address address) const { - MutexLocker lock(m_access_lock); - VERIFY(field <= 0xffc); - dbgln_if(PCI_DEBUG, "PCI: MMIO Writing 32-bit field {:#08x}, value={:#02x} for {}", field, value, address); - ByteReader::store<u32>(get_device_configuration_memory_mapped_space(address).offset(field & 0xfff).as_ptr(), value); + for (auto device_identifier : m_device_identifiers) { + if (device_identifier.address().domain() == address.domain() + && device_identifier.address().bus() == address.bus() + && device_identifier.address().device() == address.device() + && device_identifier.address().function() == address.function()) { + return device_identifier; + } + } + VERIFY_NOT_REACHED(); } void Access::write8_field(Address address, u32 field, u8 value) { - switch (m_access_type) { - case AccessType::IO: - io_write8_field(address, field, value); - return; - case AccessType::Memory: - memory_write8_field(address, field, value); - return; - } - VERIFY_NOT_REACHED(); + MutexLocker lock(m_access_lock); + VERIFY(m_host_controllers.contains(address.domain())); + auto& controller = *m_host_controllers.get(address.domain()).value(); + controller.write8_field(address.bus(), address.device(), address.function(), field, value); } void Access::write16_field(Address address, u32 field, u16 value) { - switch (m_access_type) { - case AccessType::IO: - io_write16_field(address, field, value); - return; - case AccessType::Memory: - memory_write16_field(address, field, value); - return; - } - VERIFY_NOT_REACHED(); + MutexLocker lock(m_access_lock); + VERIFY(m_host_controllers.contains(address.domain())); + auto& controller = *m_host_controllers.get(address.domain()).value(); + controller.write16_field(address.bus(), address.device(), address.function(), field, value); } void Access::write32_field(Address address, u32 field, u32 value) { - switch (m_access_type) { - case AccessType::IO: - io_write32_field(address, field, value); - return; - case AccessType::Memory: - memory_write32_field(address, field, value); - return; - } - VERIFY_NOT_REACHED(); + MutexLocker lock(m_access_lock); + VERIFY(m_host_controllers.contains(address.domain())); + auto& controller = *m_host_controllers.get(address.domain()).value(); + controller.write32_field(address.bus(), address.device(), address.function(), field, value); } u8 Access::read8_field(Address address, RegisterOffset field) @@ -284,206 +185,24 @@ u16 Access::read16_field(Address address, RegisterOffset field) u8 Access::read8_field(Address address, u32 field) { - switch (m_access_type) { - case AccessType::IO: - return io_read8_field(address, field); - case AccessType::Memory: - return memory_read8_field(address, field); - } - VERIFY_NOT_REACHED(); + MutexLocker lock(m_access_lock); + VERIFY(m_host_controllers.contains(address.domain())); + auto& controller = *m_host_controllers.get(address.domain()).value(); + return controller.read8_field(address.bus(), address.device(), address.function(), field); } u16 Access::read16_field(Address address, u32 field) { - switch (m_access_type) { - case AccessType::IO: - return io_read16_field(address, field); - case AccessType::Memory: - return memory_read16_field(address, field); - } - VERIFY_NOT_REACHED(); + MutexLocker lock(m_access_lock); + VERIFY(m_host_controllers.contains(address.domain())); + auto& controller = *m_host_controllers.get(address.domain()).value(); + return controller.read16_field(address.bus(), address.device(), address.function(), field); } u32 Access::read32_field(Address address, u32 field) { - switch (m_access_type) { - case AccessType::IO: - return io_read32_field(address, field); - case AccessType::Memory: - return memory_read32_field(address, field); - } - VERIFY_NOT_REACHED(); -} - -UNMAP_AFTER_INIT void Access::rescan_hardware_with_memory_addressing() -{ - MutexLocker locker(m_access_lock); - SpinlockLocker scan_locker(m_scan_lock); - VERIFY(m_device_identifiers.is_empty()); - VERIFY(!m_domains.is_empty()); - VERIFY(m_access_type == AccessType::Memory); - for (u32 domain = 0; domain < m_domains.size(); domain++) { - dbgln_if(PCI_DEBUG, "PCI: Scan memory mapped domain {}", domain); - // Single PCI host controller. - if ((read8_field(Address(domain), PCI::RegisterOffset::HEADER_TYPE) & 0x80) == 0) { - enumerate_bus(-1, 0, true); - return; - } - - // Multiple PCI host controllers. - for (u8 function = 0; function < 8; ++function) { - if (read16_field(Address(domain, 0, 0, function), PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) - break; - enumerate_bus(-1, function, false); - } - } -} - -UNMAP_AFTER_INIT void Access::rescan_hardware_with_io_addressing() -{ - MutexLocker locker(m_access_lock); - SpinlockLocker scan_locker(m_scan_lock); - VERIFY(m_device_identifiers.is_empty()); - VERIFY(m_access_type == AccessType::IO); - dbgln_if(PCI_DEBUG, "PCI: IO enumerating hardware"); - - // First scan bus 0. Find any device on that bus, and if it's a PCI-to-PCI - // bridge, recursively scan it too. - m_enumerated_buses.set(0, true); - enumerate_bus(-1, 0, true); - - // Handle Multiple PCI host bridges on slot 0, device 0. - // If we happen to miss some PCI buses because they are not reachable through - // recursive PCI-to-PCI bridges starting from bus 0, we might find them here. - if ((read8_field(Address(), PCI::RegisterOffset::HEADER_TYPE) & 0x80) != 0) { - for (int bus = 1; bus < 256; ++bus) { - if (read16_field(Address(0, 0, 0, bus), PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) - continue; - if (read16_field(Address(0, 0, 0, bus), PCI::RegisterOffset::CLASS) != 0x6) - continue; - if (m_enumerated_buses.get(bus)) - continue; - enumerate_bus(-1, bus, false); - m_enumerated_buses.set(bus, true); - } - } -} - -UNMAP_AFTER_INIT void Access::rescan_hardware() -{ - switch (m_access_type) { - case AccessType::IO: - rescan_hardware_with_io_addressing(); - break; - case AccessType::Memory: - rescan_hardware_with_memory_addressing(); - break; - default: - VERIFY_NOT_REACHED(); - } -} - -UNMAP_AFTER_INIT Optional<u8> Access::get_capabilities_pointer(Address address) -{ - dbgln_if(PCI_DEBUG, "PCI: Getting capabilities pointer for {}", address); - if (read16_field(address, PCI::RegisterOffset::STATUS) & (1 << 4)) { - dbgln_if(PCI_DEBUG, "PCI: Found capabilities pointer for {}", address); - return read8_field(address, PCI::RegisterOffset::CAPABILITIES_POINTER); - } - dbgln_if(PCI_DEBUG, "PCI: No capabilities pointer for {}", address); - return {}; -} - -UNMAP_AFTER_INIT Vector<Capability> Access::get_capabilities(Address address) -{ - dbgln_if(PCI_DEBUG, "PCI: Getting capabilities for {}", address); - auto capabilities_pointer = get_capabilities_pointer(address); - if (!capabilities_pointer.has_value()) { - dbgln_if(PCI_DEBUG, "PCI: No capabilities for {}", address); - return {}; - } - Vector<Capability> capabilities; - auto capability_pointer = capabilities_pointer.value(); - while (capability_pointer != 0) { - dbgln_if(PCI_DEBUG, "PCI: Reading in capability at {:#02x} for {}", capability_pointer, address); - u16 capability_header = read16_field(address, capability_pointer); - u8 capability_id = capability_header & 0xff; - capabilities.append({ address, capability_id, capability_pointer }); - capability_pointer = capability_header >> 8; - } - return capabilities; -} - -UNMAP_AFTER_INIT void Access::enumerate_functions(int type, u8 bus, u8 device, u8 function, bool recursive) -{ - dbgln_if(PCI_DEBUG, "PCI: Enumerating function type={}, bus={}, device={}, function={}", type, bus, device, function); - Address address(0, bus, device, function); - auto read_type = (read8_field(address, PCI::RegisterOffset::CLASS) << 8u) | read8_field(address, PCI::RegisterOffset::SUBCLASS); - if (type == -1 || type == read_type) { - HardwareID id = { read16_field(address, PCI::RegisterOffset::VENDOR_ID), read16_field(address, PCI::RegisterOffset::DEVICE_ID) }; - ClassCode class_code = read8_field(address, PCI::RegisterOffset::CLASS); - SubclassCode subclass_code = read8_field(address, PCI::RegisterOffset::SUBCLASS); - ProgrammingInterface prog_if = read8_field(address, PCI::RegisterOffset::PROG_IF); - RevisionID revision_id = read8_field(address, PCI::RegisterOffset::REVISION_ID); - SubsystemID subsystem_id = read16_field(address, PCI::RegisterOffset::SUBSYSTEM_ID); - SubsystemVendorID subsystem_vendor_id = read16_field(address, PCI::RegisterOffset::SUBSYSTEM_VENDOR_ID); - InterruptLine interrupt_line = read8_field(address, PCI::RegisterOffset::INTERRUPT_LINE); - InterruptPin interrupt_pin = read8_field(address, PCI::RegisterOffset::INTERRUPT_PIN); - m_device_identifiers.append(DeviceIdentifier { address, id, revision_id, class_code, subclass_code, prog_if, subsystem_id, subsystem_vendor_id, interrupt_line, interrupt_pin, get_capabilities(address) }); - } - - if (read_type == (to_underlying(PCI::ClassID::Bridge) << 8 | to_underlying(PCI::Bridge::SubclassID::PCI_TO_PCI)) - && recursive - && (!m_enumerated_buses.get(read8_field(address, PCI::RegisterOffset::SECONDARY_BUS)))) { - u8 secondary_bus = read8_field(address, PCI::RegisterOffset::SECONDARY_BUS); - dbgln_if(PCI_DEBUG, "PCI: Found secondary bus: {}", secondary_bus); - VERIFY(secondary_bus != bus); - m_enumerated_buses.set(secondary_bus, true); - enumerate_bus(type, secondary_bus, recursive); - } -} - -UNMAP_AFTER_INIT void Access::enumerate_device(int type, u8 bus, u8 device, bool recursive) -{ - dbgln_if(PCI_DEBUG, "PCI: Enumerating device type={}, bus={}, device={}", type, bus, device); - Address address(0, bus, device, 0); - if (read16_field(address, PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) - return; - enumerate_functions(type, bus, device, 0, recursive); - if (!(read8_field(address, PCI::RegisterOffset::HEADER_TYPE) & 0x80)) - return; - for (u8 function = 1; function < 8; ++function) { - Address address(0, bus, device, function); - if (read16_field(address, PCI::RegisterOffset::VENDOR_ID) != PCI::none_value) - enumerate_functions(type, bus, device, function, recursive); - } -} - -UNMAP_AFTER_INIT void Access::enumerate_bus(int type, u8 bus, bool recursive) -{ - dbgln_if(PCI_DEBUG, "PCI: Enumerating bus type={}, bus={}", type, bus); - for (u8 device = 0; device < 32; ++device) - enumerate_device(type, bus, device, recursive); -} - -void Access::fast_enumerate(Function<void(DeviceIdentifier const&)>& callback) const -{ - MutexLocker locker(m_access_lock); - VERIFY(!m_device_identifiers.is_empty()); - for (auto const& device_identifier : m_device_identifiers) { - callback(device_identifier); - } -} - -DeviceIdentifier Access::get_device_identifier(Address address) const -{ - for (auto device_identifier : m_device_identifiers) { - if (device_identifier.address().domain() == address.domain() - && device_identifier.address().bus() == address.bus() - && device_identifier.address().device() == address.device() - && device_identifier.address().function() == address.function()) { - return device_identifier; - } - } - VERIFY_NOT_REACHED(); + MutexLocker lock(m_access_lock); + VERIFY(m_host_controllers.contains(address.domain())); + auto& controller = *m_host_controllers.get(address.domain()).value(); + return controller.read32_field(address.bus(), address.device(), address.function(), field); } } diff --git a/Kernel/Bus/PCI/Access.h b/Kernel/Bus/PCI/Access.h index a546d1ad82..a247572a05 100644 --- a/Kernel/Bus/PCI/Access.h +++ b/Kernel/Bus/PCI/Access.h @@ -8,26 +8,21 @@ #include <AK/Bitmap.h> #include <AK/Vector.h> +#include <Kernel/Bus/PCI/Controller/HostController.h> #include <Kernel/Bus/PCI/Definitions.h> #include <Kernel/FileSystem/SysFS.h> #include <Kernel/Locking/Spinlock.h> namespace Kernel::PCI { +class HostBridge; class Access { public: - enum class AccessType { - IO, - Memory, - }; - - static bool initialize_for_memory_access(PhysicalAddress mcfg_table); - static bool initialize_for_io_access(); + static bool initialize_for_multiple_pci_domains(PhysicalAddress mcfg_table); + static bool initialize_for_one_pci_domain(); void fast_enumerate(Function<void(DeviceIdentifier const&)>&) const; void rescan_hardware(); - void rescan_hardware_with_memory_addressing(); - void rescan_hardware_with_io_addressing(); static Access& the(); static bool is_initialized(); @@ -40,50 +35,25 @@ public: u32 read32_field(Address address, u32 field); DeviceIdentifier get_device_identifier(Address address) const; + Spinlock const& scan_lock() const { return m_scan_lock; } + Mutex const& access_lock() const { return m_access_lock; } + private: u8 read8_field(Address address, RegisterOffset field); u16 read16_field(Address address, RegisterOffset field); - void enumerate_bus(int type, u8 bus, bool recursive); - void enumerate_functions(int type, u8 bus, u8 device, u8 function, bool recursive); - void enumerate_device(int type, u8 bus, u8 device, bool recursive); + void add_host_controller(NonnullOwnPtr<HostController>); + bool find_and_register_pci_host_bridges_from_acpi_mcfg_table(PhysicalAddress mcfg); + Access(); - explicit Access(AccessType); - bool search_pci_domains_from_acpi_mcfg_table(PhysicalAddress mcfg); Vector<Capability> get_capabilities(Address); Optional<u8> get_capabilities_pointer(Address address); - // IO access (legacy) operations - u8 io_read8_field(Address address, u32 field); - u16 io_read16_field(Address address, u32 field); - u32 io_read32_field(Address address, u32 field); - void io_write8_field(Address address, u32, u8); - void io_write16_field(Address address, u32, u16); - void io_write32_field(Address address, u32, u32); - u16 io_read_type(Address address); - - // Memory-mapped access operations - void map_bus_region(u32 domain, u8 bus); - u8 memory_read8_field(Address address, u32 field); - u16 memory_read16_field(Address address, u32 field); - u32 memory_read32_field(Address address, u32 field); - void memory_write8_field(Address address, u32, u8); - void memory_write16_field(Address address, u32, u16); - void memory_write32_field(Address address, u32, u32); - u16 memory_read_type(Address address); - VirtualAddress get_device_configuration_memory_mapped_space(Address address); - Optional<PhysicalAddress> determine_memory_mapped_bus_base_address(u32 domain, u8 bus) const; - - // Data-members for accessing Memory mapped PCI devices' configuration spaces - u8 m_mapped_bus { 0 }; - OwnPtr<Memory::Region> m_mapped_bus_region; - HashMap<u32, PCI::Domain> m_domains; - // General Data-members mutable Mutex m_access_lock; mutable Spinlock m_scan_lock; - Bitmap m_enumerated_buses; - AccessType m_access_type; + + HashMap<u32, NonnullOwnPtr<HostController>> m_host_controllers; Vector<DeviceIdentifier> m_device_identifiers; }; } diff --git a/Kernel/Bus/PCI/Controller/HostBridge.cpp b/Kernel/Bus/PCI/Controller/HostBridge.cpp new file mode 100644 index 0000000000..319d24be05 --- /dev/null +++ b/Kernel/Bus/PCI/Controller/HostBridge.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/Arch/x86/IO.h> +#include <Kernel/Bus/PCI/Access.h> +#include <Kernel/Bus/PCI/Controller/HostBridge.h> +#include <Kernel/Sections.h> + +namespace Kernel::PCI { + +NonnullOwnPtr<HostBridge> HostBridge::must_create_with_io_access() +{ + PCI::Domain domain { 0, 0, 0xff }; + return adopt_own_if_nonnull(new (nothrow) HostBridge(domain)).release_nonnull(); +} + +HostBridge::HostBridge(PCI::Domain const& domain) + : HostController(domain) + , m_enumerated_buses(256, false) +{ +} + +UNMAP_AFTER_INIT Optional<u8> HostBridge::get_capabilities_pointer_for_function(BusNumber bus, DeviceNumber device, FunctionNumber function) +{ + if (read16_field(bus, device, function, PCI::RegisterOffset::STATUS) & (1 << 4)) { + return read8_field(bus, device, function, PCI::RegisterOffset::CAPABILITIES_POINTER); + } + return {}; +} + +UNMAP_AFTER_INIT Vector<Capability> HostBridge::get_capabilities_for_function(BusNumber bus, DeviceNumber device, FunctionNumber function) +{ + auto capabilities_pointer = get_capabilities_pointer_for_function(bus, device, function); + if (!capabilities_pointer.has_value()) { + return {}; + } + Vector<Capability> capabilities; + auto capability_pointer = capabilities_pointer.value(); + while (capability_pointer != 0) { + u16 capability_header = read16_field(bus, device, function, capability_pointer); + u8 capability_id = capability_header & 0xff; + + // FIXME: Don't attach a PCI address to a capability object + capabilities.append({ Address(domain_number(), bus.value(), device.value(), function.value()), capability_id, capability_pointer }); + capability_pointer = capability_header >> 8; + } + return capabilities; +} + +UNMAP_AFTER_INIT void HostBridge::enumerate_functions(Function<void(DeviceIdentifier)> const& callback, BusNumber bus, DeviceNumber device, FunctionNumber function, bool recursive_search_into_bridges) +{ + dbgln_if(PCI_DEBUG, "PCI: Enumerating function, bus={}, device={}, function={}", bus, device, function); + Address address(0, bus.value(), device.value(), function.value()); + auto pci_class = (read8_field(bus, device, function, PCI::RegisterOffset::CLASS) << 8u) | read8_field(bus, device, function, PCI::RegisterOffset::SUBCLASS); + + HardwareID id = { read16_field(bus, device, function, PCI::RegisterOffset::VENDOR_ID), read16_field(bus, device, function, PCI::RegisterOffset::DEVICE_ID) }; + ClassCode class_code = read8_field(bus, device, function, PCI::RegisterOffset::CLASS); + SubclassCode subclass_code = read8_field(bus, device, function, PCI::RegisterOffset::SUBCLASS); + ProgrammingInterface prog_if = read8_field(bus, device, function, PCI::RegisterOffset::PROG_IF); + RevisionID revision_id = read8_field(bus, device, function, PCI::RegisterOffset::REVISION_ID); + SubsystemID subsystem_id = read16_field(bus, device, function, PCI::RegisterOffset::SUBSYSTEM_ID); + SubsystemVendorID subsystem_vendor_id = read16_field(bus, device, function, PCI::RegisterOffset::SUBSYSTEM_VENDOR_ID); + InterruptLine interrupt_line = read8_field(bus, device, function, PCI::RegisterOffset::INTERRUPT_LINE); + InterruptPin interrupt_pin = read8_field(bus, device, function, PCI::RegisterOffset::INTERRUPT_PIN); + auto capabilities = get_capabilities_for_function(bus, device, function); + callback(DeviceIdentifier { address, id, revision_id, class_code, subclass_code, prog_if, subsystem_id, subsystem_vendor_id, interrupt_line, interrupt_pin, capabilities }); + + if (pci_class == (to_underlying(PCI::ClassID::Bridge) << 8 | to_underlying(PCI::Bridge::SubclassID::PCI_TO_PCI)) + && recursive_search_into_bridges + && (!m_enumerated_buses.get(read8_field(bus, device, function, PCI::RegisterOffset::SECONDARY_BUS)))) { + u8 secondary_bus = read8_field(bus, device, function, PCI::RegisterOffset::SECONDARY_BUS); + dbgln_if(PCI_DEBUG, "PCI: Found secondary bus: {}", secondary_bus); + VERIFY(secondary_bus != bus); + m_enumerated_buses.set(secondary_bus, true); + enumerate_bus(callback, secondary_bus, recursive_search_into_bridges); + } +} + +UNMAP_AFTER_INIT void HostBridge::enumerate_device(Function<void(DeviceIdentifier)> const& callback, BusNumber bus, DeviceNumber device, bool recursive_search_into_bridges) +{ + dbgln_if(PCI_DEBUG, "PCI: Enumerating device in bus={}, device={}", bus, device); + if (read16_field(bus, device, 0, PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) + return; + enumerate_functions(callback, bus, device, 0, recursive_search_into_bridges); + if (!(read8_field(bus, device, 0, PCI::RegisterOffset::HEADER_TYPE) & 0x80)) + return; + for (u8 function = 1; function < 8; ++function) { + if (read16_field(bus, device, function, PCI::RegisterOffset::VENDOR_ID) != PCI::none_value) + enumerate_functions(callback, bus, device, function, recursive_search_into_bridges); + } +} + +UNMAP_AFTER_INIT void HostBridge::enumerate_bus(Function<void(DeviceIdentifier)> const& callback, BusNumber bus, bool recursive_search_into_bridges) +{ + dbgln_if(PCI_DEBUG, "PCI: Enumerating bus {}", bus); + for (u8 device = 0; device < 32; ++device) + enumerate_device(callback, bus, device, recursive_search_into_bridges); +} + +UNMAP_AFTER_INIT void HostBridge::enumerate_attached_devices(Function<void(DeviceIdentifier)> callback) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(Access::the().scan_lock().is_locked()); + // First scan bus 0. Find any device on that bus, and if it's a PCI-to-PCI + // bridge, recursively scan it too. + m_enumerated_buses.set(0, true); + enumerate_bus(callback, 0, true); + + // Handle Multiple PCI host bridges on slot 0, device 0. + // If we happen to miss some PCI buses because they are not reachable through + // recursive PCI-to-PCI bridges starting from bus 0, we might find them here. + if ((read8_field(0, 0, 0, PCI::RegisterOffset::HEADER_TYPE) & 0x80) != 0) { + for (int bus_as_function_number = 1; bus_as_function_number < 256; ++bus_as_function_number) { + if (read16_field(0, 0, bus_as_function_number, PCI::RegisterOffset::VENDOR_ID) == PCI::none_value) + continue; + if (read16_field(0, 0, bus_as_function_number, PCI::RegisterOffset::CLASS) != 0x6) + continue; + if (m_enumerated_buses.get(bus_as_function_number)) + continue; + enumerate_bus(callback, bus_as_function_number, false); + m_enumerated_buses.set(bus_as_function_number, true); + } + } +} + +static u32 io_address_for_pci_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u8 field) +{ + return 0x80000000u | (bus.value() << 16u) | (device.value() << 11u) | (function.value() << 8u) | (field & 0xfc); +} + +void HostBridge::write8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u8 value) +{ + IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field)); + IO::out8(PCI::value_port + (field & 3), value); +} +void HostBridge::write16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u16 value) +{ + IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field)); + IO::out16(PCI::value_port + (field & 2), value); +} +void HostBridge::write32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u32 value) +{ + IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field)); + IO::out32(PCI::value_port, value); +} + +u8 HostBridge::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) +{ + IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field)); + return IO::in8(PCI::value_port + (field & 3)); +} +u16 HostBridge::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) +{ + IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field)); + return IO::in16(PCI::value_port + (field & 2)); +} +u32 HostBridge::read32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) +{ + IO::out32(PCI::address_port, io_address_for_pci_field(bus, device, function, field)); + return IO::in32(PCI::value_port); +} + +u8 HostBridge::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, PCI::RegisterOffset field) +{ + return read8_field(bus, device, function, to_underlying(field)); +} +u16 HostBridge::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, PCI::RegisterOffset field) +{ + return read16_field(bus, device, function, to_underlying(field)); +} + +} diff --git a/Kernel/Bus/PCI/Controller/HostBridge.h b/Kernel/Bus/PCI/Controller/HostBridge.h new file mode 100644 index 0000000000..ce36a3f3d8 --- /dev/null +++ b/Kernel/Bus/PCI/Controller/HostBridge.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Bitmap.h> +#include <AK/NonnullOwnPtr.h> +#include <AK/OwnPtr.h> +#include <AK/Vector.h> +#include <Kernel/Bus/PCI/Controller/HostController.h> +#include <Kernel/Locking/Spinlock.h> + +namespace Kernel::PCI { + +class HostBridge : public HostController { +public: + static NonnullOwnPtr<HostBridge> must_create_with_io_access(); + + virtual void write8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value) override; + virtual void write16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value) override; + virtual void write32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value) override; + + virtual u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override; + virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override; + virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override; + +protected: + explicit HostBridge(PCI::Domain const&); + +private: + virtual void enumerate_attached_devices(Function<void(DeviceIdentifier)> callback) override; + + Bitmap m_enumerated_buses; + + u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field); + u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, RegisterOffset field); + + Optional<u8> get_capabilities_pointer_for_function(BusNumber, DeviceNumber, FunctionNumber); + Vector<Capability> get_capabilities_for_function(BusNumber, DeviceNumber, FunctionNumber); + + void enumerate_bus(Function<void(DeviceIdentifier)> const& callback, BusNumber, bool recursive); + void enumerate_functions(Function<void(DeviceIdentifier)> const& callback, BusNumber, DeviceNumber, FunctionNumber, bool recursive); + void enumerate_device(Function<void(DeviceIdentifier)> const& callback, BusNumber bus, DeviceNumber device, bool recursive); +}; + +} diff --git a/Kernel/Bus/PCI/Controller/HostController.h b/Kernel/Bus/PCI/Controller/HostController.h new file mode 100644 index 0000000000..80a10280cf --- /dev/null +++ b/Kernel/Bus/PCI/Controller/HostController.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Bitmap.h> +#include <AK/Vector.h> +#include <Kernel/Bus/PCI/Definitions.h> +#include <Kernel/Locking/Spinlock.h> + +namespace Kernel::PCI { + +TYPEDEF_DISTINCT_ORDERED_ID(u8, BusNumber); +TYPEDEF_DISTINCT_ORDERED_ID(u8, DeviceNumber); +TYPEDEF_DISTINCT_ORDERED_ID(u8, FunctionNumber); + +class HostController { +public: + virtual ~HostController() = default; + + virtual void write8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value) = 0; + virtual void write16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value) = 0; + virtual void write32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value) = 0; + + virtual u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) = 0; + virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) = 0; + virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) = 0; + + u32 domain_number() const { return m_domain.domain_number(); } + + virtual void enumerate_attached_devices(Function<void(DeviceIdentifier)> callback) = 0; + +protected: + explicit HostController(PCI::Domain const& domain) + : m_domain(domain) + { + } + + const PCI::Domain m_domain; +}; + +} diff --git a/Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.cpp b/Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.cpp new file mode 100644 index 0000000000..febee0a068 --- /dev/null +++ b/Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/ByteReader.h> +#include <Kernel/Arch/x86/IO.h> +#include <Kernel/Bus/PCI/Access.h> +#include <Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h> + +namespace Kernel::PCI { + +NonnullOwnPtr<MemoryBackedHostBridge> MemoryBackedHostBridge::must_create(Domain const& domain, PhysicalAddress start_address) +{ + return adopt_own_if_nonnull(new (nothrow) MemoryBackedHostBridge(domain, start_address)).release_nonnull(); +} + +MemoryBackedHostBridge::MemoryBackedHostBridge(PCI::Domain const& domain, PhysicalAddress start_address) + : HostBridge(domain) + , m_start_address(start_address) +{ +} + +u8 MemoryBackedHostBridge::read8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(field <= 0xfff); + return *((volatile u8*)(get_device_configuration_memory_mapped_space(bus, device, function).get() + (field & 0xfff))); +} +u16 MemoryBackedHostBridge::read16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(field < 0xfff); + u16 data = 0; + ByteReader::load<u16>(get_device_configuration_memory_mapped_space(bus, device, function).offset(field & 0xfff).as_ptr(), data); + return data; +} +u32 MemoryBackedHostBridge::read32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(field <= 0xffc); + u32 data = 0; + ByteReader::load<u32>(get_device_configuration_memory_mapped_space(bus, device, function).offset(field & 0xfff).as_ptr(), data); + return data; +} +void MemoryBackedHostBridge::write8_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u8 value) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(field <= 0xfff); + *((volatile u8*)(get_device_configuration_memory_mapped_space(bus, device, function).get() + (field & 0xfff))) = value; +} +void MemoryBackedHostBridge::write16_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u16 value) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(field < 0xfff); + ByteReader::store<u16>(get_device_configuration_memory_mapped_space(bus, device, function).offset(field & 0xfff).as_ptr(), value); +} +void MemoryBackedHostBridge::write32_field(BusNumber bus, DeviceNumber device, FunctionNumber function, u32 field, u32 value) +{ + VERIFY(Access::the().access_lock().is_locked()); + VERIFY(field <= 0xffc); + ByteReader::store<u32>(get_device_configuration_memory_mapped_space(bus, device, function).offset(field & 0xfff).as_ptr(), value); +} + +void MemoryBackedHostBridge::map_bus_region(BusNumber bus) +{ + VERIFY(Access::the().access_lock().is_locked()); + if (m_mapped_bus == bus && m_mapped_bus_region) + return; + auto bus_base_address = determine_memory_mapped_bus_base_address(bus); + auto region_or_error = MM.allocate_kernel_region(bus_base_address, memory_range_per_bus, "PCI ECAM", Memory::Region::Access::ReadWrite); + // FIXME: Find a way to propagate error from here. + if (region_or_error.is_error()) + VERIFY_NOT_REACHED(); + m_mapped_bus_region = region_or_error.release_value(); + m_mapped_bus = bus; + dbgln_if(PCI_DEBUG, "PCI: New PCI ECAM Mapped region for bus {} @ {} {}", bus, m_mapped_bus_region->vaddr(), m_mapped_bus_region->physical_page(0)->paddr()); +} + +VirtualAddress MemoryBackedHostBridge::get_device_configuration_memory_mapped_space(BusNumber bus, DeviceNumber device, FunctionNumber function) +{ + VERIFY(Access::the().access_lock().is_locked()); + map_bus_region(bus); + return m_mapped_bus_region->vaddr().offset(mmio_device_space_size * function.value() + (mmio_device_space_size * to_underlying(Limits::MaxFunctionsPerDevice)) * device.value()); +} + +PhysicalAddress MemoryBackedHostBridge::determine_memory_mapped_bus_base_address(BusNumber bus) const +{ + auto start_bus = min(bus.value(), m_domain.start_bus()); + return m_start_address.offset(memory_range_per_bus * (bus.value() - start_bus)); +} + +} diff --git a/Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h b/Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h new file mode 100644 index 0000000000..68968554ea --- /dev/null +++ b/Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Bitmap.h> +#include <AK/Vector.h> +#include <Kernel/Bus/PCI/Controller/HostBridge.h> +#include <Kernel/Locking/Spinlock.h> + +namespace Kernel::PCI { + +class MemoryBackedHostBridge final : public HostBridge { +public: + static NonnullOwnPtr<MemoryBackedHostBridge> must_create(Domain const&, PhysicalAddress); + + virtual void write8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u8 value) override; + virtual void write16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u16 value) override; + virtual void write32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field, u32 value) override; + + virtual u8 read8_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override; + virtual u16 read16_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override; + virtual u32 read32_field(BusNumber, DeviceNumber, FunctionNumber, u32 field) override; + +private: + MemoryBackedHostBridge(PCI::Domain const&, PhysicalAddress); + + // Memory-mapped access operations + void map_bus_region(BusNumber); + VirtualAddress get_device_configuration_memory_mapped_space(BusNumber, DeviceNumber, FunctionNumber); + PhysicalAddress determine_memory_mapped_bus_base_address(BusNumber) const; + + // Data-members for accessing Memory mapped PCI devices' configuration spaces + BusNumber m_mapped_bus { 0 }; + OwnPtr<Memory::Region> m_mapped_bus_region; + PhysicalAddress m_start_address; +}; + +} diff --git a/Kernel/Bus/PCI/Definitions.h b/Kernel/Bus/PCI/Definitions.h index 1b0faf4411..4d9447020d 100644 --- a/Kernel/Bus/PCI/Definitions.h +++ b/Kernel/Bus/PCI/Definitions.h @@ -128,18 +128,18 @@ struct HardwareID { class Domain { public: Domain() = delete; - Domain(PhysicalAddress base_address, u8 start_bus, u8 end_bus) - : m_base_addr(base_address) + Domain(u32 domain_number, u8 start_bus, u8 end_bus) + : m_domain_number(domain_number) , m_start_bus(start_bus) , m_end_bus(end_bus) { } u8 start_bus() const { return m_start_bus; } u8 end_bus() const { return m_end_bus; } - PhysicalAddress paddr() const { return m_base_addr; } + u32 domain_number() const { return m_domain_number; } private: - PhysicalAddress m_base_addr; + u32 m_domain_number; u8 m_start_bus; u8 m_end_bus; }; @@ -189,11 +189,6 @@ public: u8 device() const { return m_device; } u8 function() const { return m_function; } - u32 io_address_for_field(u8 field) const - { - return 0x80000000u | (m_bus << 16u) | (m_device << 11u) | (m_function << 8u) | (field & 0xfc); - } - private: u32 m_domain { 0 }; u8 m_bus { 0 }; diff --git a/Kernel/Bus/PCI/Initializer.cpp b/Kernel/Bus/PCI/Initializer.cpp index 24bc607a0a..3a17957678 100644 --- a/Kernel/Bus/PCI/Initializer.cpp +++ b/Kernel/Bus/PCI/Initializer.cpp @@ -40,12 +40,12 @@ UNMAP_AFTER_INIT void initialize() case PCIAccessLevel::MemoryAddressing: { auto mcfg = ACPI::Parser::the()->find_table("MCFG"); VERIFY(mcfg.has_value()); - auto success = Access::initialize_for_memory_access(mcfg.value()); + auto success = Access::initialize_for_multiple_pci_domains(mcfg.value()); VERIFY(success); break; } case PCIAccessLevel::IOAddressing: { - auto success = Access::initialize_for_io_access(); + auto success = Access::initialize_for_one_pci_domain(); VERIFY(success); break; } |