summaryrefslogtreecommitdiff
path: root/Kernel/Bus/PCI
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Bus/PCI')
-rw-r--r--Kernel/Bus/PCI/Access.cpp461
-rw-r--r--Kernel/Bus/PCI/Access.h54
-rw-r--r--Kernel/Bus/PCI/Controller/HostBridge.cpp175
-rw-r--r--Kernel/Bus/PCI/Controller/HostBridge.h49
-rw-r--r--Kernel/Bus/PCI/Controller/HostController.h45
-rw-r--r--Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.cpp94
-rw-r--r--Kernel/Bus/PCI/Controller/MemoryBackedHostBridge.h42
-rw-r--r--Kernel/Bus/PCI/Definitions.h13
-rw-r--r--Kernel/Bus/PCI/Initializer.cpp4
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;
}