diff options
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/PCI/Access.cpp | 37 | ||||
-rw-r--r-- | Kernel/PCI/Access.h | 5 | ||||
-rw-r--r-- | Kernel/PCI/MMIOAccess.cpp | 95 | ||||
-rw-r--r-- | Kernel/PCI/MMIOAccess.h | 18 |
4 files changed, 95 insertions, 60 deletions
diff --git a/Kernel/PCI/Access.cpp b/Kernel/PCI/Access.cpp index a480cb8f2e..74efa8fbd4 100644 --- a/Kernel/PCI/Access.cpp +++ b/Kernel/PCI/Access.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <Kernel/IO.h> #include <Kernel/PCI/Access.h> #include <Kernel/PCI/IOAccess.h> @@ -57,18 +58,36 @@ Access::Access() s_access = this; } -static u16 read_type(Address address) +u8 Access::early_read8_field(Address address, u32 field) { - return (read8(address, PCI_CLASS) << 8u) | read8(address, PCI_SUBCLASS); + IO::out32(PCI_ADDRESS_PORT, address.io_address_for_field(field)); + return IO::in8(PCI_VALUE_PORT + (field & 3)); +} + +u16 Access::early_read16_field(Address address, u32 field) +{ + IO::out32(PCI_ADDRESS_PORT, address.io_address_for_field(field)); + return IO::in16(PCI_VALUE_PORT + (field & 2)); +} + +u32 Access::early_read32_field(Address address, u32 field) +{ + IO::out32(PCI_ADDRESS_PORT, address.io_address_for_field(field)); + return IO::in32(PCI_VALUE_PORT); +} + +u16 Access::early_read_type(Address address) +{ + return (early_read8_field(address, PCI_CLASS) << 8u) | early_read8_field(address, PCI_SUBCLASS); } void Access::enumerate_functions(int type, u8 bus, u8 slot, u8 function, Function<void(Address, ID)>& callback) { Address address(0, bus, slot, function); - if (type == -1 || type == read_type(address)) - callback(address, { read16_field(address, PCI_VENDOR_ID), read16_field(address, PCI_DEVICE_ID) }); - if (read_type(address) == PCI_TYPE_BRIDGE) { - u8 secondary_bus = read8_field(address, PCI_SECONDARY_BUS); + if (type == -1 || type == early_read_type(address)) + callback(address, { early_read16_field(address, PCI_VENDOR_ID), early_read16_field(address, PCI_DEVICE_ID) }); + if (early_read_type(address) == PCI_TYPE_BRIDGE) { + u8 secondary_bus = early_read8_field(address, PCI_SECONDARY_BUS); #ifdef PCI_DEBUG klog() << "PCI: Found secondary bus: " << secondary_bus; #endif @@ -80,14 +99,14 @@ void Access::enumerate_functions(int type, u8 bus, u8 slot, u8 function, Functio void Access::enumerate_slot(int type, u8 bus, u8 slot, Function<void(Address, ID)>& callback) { Address address(0, bus, slot, 0); - if (read16_field(address, PCI_VENDOR_ID) == PCI_NONE) + if (early_read16_field(address, PCI_VENDOR_ID) == PCI_NONE) return; enumerate_functions(type, bus, slot, 0, callback); - if (!(read8_field(address, PCI_HEADER_TYPE) & 0x80)) + if (!(early_read8_field(address, PCI_HEADER_TYPE) & 0x80)) return; for (u8 function = 1; function < 8; ++function) { Address address(0, bus, slot, function); - if (read16_field(address, PCI_VENDOR_ID) != PCI_NONE) + if (early_read16_field(address, PCI_VENDOR_ID) != PCI_NONE) enumerate_functions(type, bus, slot, function, callback); } } diff --git a/Kernel/PCI/Access.h b/Kernel/PCI/Access.h index 47375f8f4a..4b6ade98d2 100644 --- a/Kernel/PCI/Access.h +++ b/Kernel/PCI/Access.h @@ -63,6 +63,11 @@ public: protected: virtual void enumerate_hardware(Function<void(Address, ID)>) = 0; + u8 early_read8_field(Address address, u32 field); + u16 early_read16_field(Address address, u32 field); + u32 early_read32_field(Address address, u32 field); + u16 early_read_type(Address address); + Access(); Vector<PhysicalID> m_physical_ids; }; diff --git a/Kernel/PCI/MMIOAccess.cpp b/Kernel/PCI/MMIOAccess.cpp index 9ade94ba4e..8fb27e6ae5 100644 --- a/Kernel/PCI/MMIOAccess.cpp +++ b/Kernel/PCI/MMIOAccess.cpp @@ -35,10 +35,10 @@ namespace PCI { class MMIOSegment { public: MMIOSegment(PhysicalAddress, u8, u8); - u8 get_start_bus(); - u8 get_end_bus(); - size_t get_size(); - PhysicalAddress get_paddr(); + u8 get_start_bus() const; + u8 get_end_bus() const; + size_t get_size() const; + PhysicalAddress get_paddr() const; private: PhysicalAddress m_base_addr; @@ -48,6 +48,17 @@ private: #define PCI_MMIO_CONFIG_SPACE_SIZE 4096 +DeviceConfigurationSpaceMapping::DeviceConfigurationSpaceMapping(Address device_address, const MMIOSegment& mmio_segment) + : m_device_address(device_address) + , m_mapped_region(MM.allocate_kernel_region(PAGE_ROUND_UP(PCI_MMIO_CONFIG_SPACE_SIZE), "PCI MMIO Device Access", Region::Access::Read | Region::Access::Write).release_nonnull()) +{ + PhysicalAddress segment_lower_addr = mmio_segment.get_paddr(); + PhysicalAddress device_physical_mmio_space = segment_lower_addr.offset( + PCI_MMIO_CONFIG_SPACE_SIZE * m_device_address.function() + (PCI_MMIO_CONFIG_SPACE_SIZE * PCI_MAX_FUNCTIONS_PER_DEVICE) * m_device_address.slot() + (PCI_MMIO_CONFIG_SPACE_SIZE * PCI_MAX_FUNCTIONS_PER_DEVICE * PCI_MAX_DEVICES_PER_BUS) * (m_device_address.bus() - mmio_segment.get_start_bus())); + m_mapped_region->physical_page_slot(0) = PhysicalPage::create(device_physical_mmio_space, false, false); + m_mapped_region->remap(); +} + uint32_t MMIOAccess::segment_count() const { return m_segments.size(); @@ -75,10 +86,8 @@ void MMIOAccess::initialize(PhysicalAddress mcfg) MMIOAccess::MMIOAccess(PhysicalAddress p_mcfg) : m_mcfg(p_mcfg) - , m_mapped_address(ChangeableAddress(0xFFFF, 0xFF, 0xFF, 0xFF)) { klog() << "PCI: Using MMIO for PCI configuration space access"; - m_mmio_window_region = MM.allocate_kernel_region(PAGE_ROUND_UP(PCI_MMIO_CONFIG_SPACE_SIZE), "PCI MMIO", Region::Access::Read | Region::Access::Write); auto checkup_region = MM.allocate_kernel_region(p_mcfg.page_base(), (PAGE_SIZE * 2), "PCI MCFG Checkup", Region::Access::Read | Region::Access::Write); #ifdef PCI_DEBUG @@ -112,38 +121,34 @@ MMIOAccess::MMIOAccess(PhysicalAddress p_mcfg) InterruptDisabler disabler; -#ifdef PCI_DEBUG - dbg() << "PCI: mapped address (" << String::format("%w", m_mapped_address.seg()) << ":" << String::format("%b", m_mapped_address.bus()) << ":" << String::format("%b", m_mapped_address.slot()) << "." << String::format("%b", m_mapped_address.function()) << ")"; -#endif - map_device(Address(0, 0, 0, 0)); -#ifdef PCI_DEBUG - dbg() << "PCI: Default mapped address (" << String::format("%w", m_mapped_address.seg()) << ":" << String::format("%b", m_mapped_address.bus()) << ":" << String::format("%b", m_mapped_address.slot()) << "." << String::format("%b", m_mapped_address.function()) << ")"; -#endif - enumerate_hardware([&](const Address& address, ID id) { m_physical_ids.append({ address, id }); + m_mapped_device_regions.append(make<DeviceConfigurationSpaceMapping>(address, m_segments.get(address.seg()).value())); +#ifdef PCI_DEBUG + dbg() << "PCI: Mapping device @ pci (" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ")" + << " " << m_mapped_device_regions.last().vaddr() << " " << m_mapped_device_regions.last().paddr(); +#endif }); } -void MMIOAccess::map_device(Address address) +Optional<VirtualAddress> MMIOAccess::get_device_configuration_space(Address address) { - if (m_mapped_address == address) - return; - // FIXME: Map and put some lock! - ASSERT_INTERRUPTS_DISABLED(); - auto segment = m_segments.get(address.seg()); - ASSERT(segment.has_value()); - PhysicalAddress segment_lower_addr = segment.value().get_paddr(); - PhysicalAddress device_physical_mmio_space = segment_lower_addr.offset( - PCI_MMIO_CONFIG_SPACE_SIZE * address.function() + (PCI_MMIO_CONFIG_SPACE_SIZE * PCI_MAX_FUNCTIONS_PER_DEVICE) * address.slot() + (PCI_MMIO_CONFIG_SPACE_SIZE * PCI_MAX_FUNCTIONS_PER_DEVICE * PCI_MAX_DEVICES_PER_BUS) * (address.bus() - segment.value().get_start_bus())); - + for (auto& mapping : m_mapped_device_regions) { + auto checked_address = mapping.address(); #ifdef PCI_DEBUG - dbg() << "PCI: Mapping device @ pci (" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ")" - << " V 0x" << String::format("%x", m_mmio_window_region->vaddr().get()) << " P 0x" << String::format("%x", device_physical_mmio_space.get()); + dbg() << "PCI Device Configuration Space Mapping: Check if " << checked_address << " was requested"; #endif - m_mmio_window_region->physical_page_slot(0) = PhysicalPage::create(device_physical_mmio_space, false, false); - m_mmio_window_region->remap(); - m_mapped_address = address; + if (address.seg() == checked_address.seg() + && address.bus() == checked_address.bus() + && address.slot() == checked_address.slot() + && address.function() == checked_address.function()) { +#ifdef PCI_DEBUG + dbg() << "PCI Device Configuration Space Mapping: Found " << checked_address; +#endif + return mapping.vaddr(); + } + } + return {}; } u8 MMIOAccess::read8_field(Address address, u32 field) @@ -153,8 +158,7 @@ u8 MMIOAccess::read8_field(Address address, u32 field) #ifdef PCI_DEBUG dbg() << "PCI: Reading field " << field << ", Address(" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ")"; #endif - map_device(address); - return *((u8*)(m_mmio_window_region->vaddr().get() + (field & 0xfff))); + return *((u8*)(get_device_configuration_space(address).value().get() + (field & 0xfff))); } u16 MMIOAccess::read16_field(Address address, u32 field) @@ -164,8 +168,7 @@ u16 MMIOAccess::read16_field(Address address, u32 field) #ifdef PCI_DEBUG dbg() << "PCI: Reading field " << field << ", Address(" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ")"; #endif - map_device(address); - return *((u16*)(m_mmio_window_region->vaddr().get() + (field & 0xfff))); + return *((u16*)(get_device_configuration_space(address).value().get() + (field & 0xfff))); } u32 MMIOAccess::read32_field(Address address, u32 field) @@ -175,8 +178,7 @@ u32 MMIOAccess::read32_field(Address address, u32 field) #ifdef PCI_DEBUG dbg() << "PCI: Reading field " << field << ", Address(" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ")"; #endif - map_device(address); - return *((u32*)(m_mmio_window_region->vaddr().get() + (field & 0xfff))); + return *((u32*)(get_device_configuration_space(address).value().get() + (field & 0xfff))); } void MMIOAccess::write8_field(Address address, u32 field, u8 value) @@ -186,8 +188,7 @@ void MMIOAccess::write8_field(Address address, u32 field, u8 value) #ifdef PCI_DEBUG dbg() << "PCI: Writing to field " << field << ", Address(" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ") value 0x" << String::format("%x", value); #endif - map_device(address); - *((u8*)(m_mmio_window_region->vaddr().get() + (field & 0xfff))) = value; + *((u8*)(get_device_configuration_space(address).value().get() + (field & 0xfff))) = value; } void MMIOAccess::write16_field(Address address, u32 field, u16 value) { @@ -196,8 +197,7 @@ void MMIOAccess::write16_field(Address address, u32 field, u16 value) #ifdef PCI_DEBUG dbg() << "PCI: Writing to field " << field << ", Address(" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ") value 0x" << String::format("%x", value); #endif - map_device(address); - *((u16*)(m_mmio_window_region->vaddr().get() + (field & 0xfff))) = value; + *((u16*)(get_device_configuration_space(address).value().get() + (field & 0xfff))) = value; } void MMIOAccess::write32_field(Address address, u32 field, u32 value) { @@ -206,8 +206,7 @@ void MMIOAccess::write32_field(Address address, u32 field, u32 value) #ifdef PCI_DEBUG dbg() << "PCI: Writing to field " << field << ", Address(" << String::format("%w", address.seg()) << ":" << String::format("%b", address.bus()) << ":" << String::format("%b", address.slot()) << "." << String::format("%b", address.function()) << ") value 0x" << String::format("%x", value); #endif - map_device(address); - *((u32*)(m_mmio_window_region->vaddr().get() + (field & 0xfff))) = value; + *((u32*)(get_device_configuration_space(address).value().get() + (field & 0xfff))) = value; } void MMIOAccess::enumerate_hardware(Function<void(Address, ID)> callback) @@ -217,14 +216,14 @@ void MMIOAccess::enumerate_hardware(Function<void(Address, ID)> callback) dbg() << "PCI: Enumerating Memory mapped IO segment " << seg; #endif // Single PCI host controller. - if ((read8_field(Address(seg), PCI_HEADER_TYPE) & 0x80) == 0) { + if ((early_read8_field(Address(seg), PCI_HEADER_TYPE) & 0x80) == 0) { enumerate_bus(-1, 0, callback); return; } // Multiple PCI host controllers. for (u8 function = 0; function < 8; ++function) { - if (read16_field(Address(seg, 0, 0, function), PCI_VENDOR_ID) == PCI_NONE) + if (early_read16_field(Address(seg, 0, 0, function), PCI_VENDOR_ID) == PCI_NONE) break; enumerate_bus(-1, function, callback); } @@ -238,22 +237,22 @@ MMIOSegment::MMIOSegment(PhysicalAddress segment_base_addr, u8 start_bus, u8 end { } -u8 MMIOSegment::get_start_bus() +u8 MMIOSegment::get_start_bus() const { return m_start_bus; } -u8 MMIOSegment::get_end_bus() +u8 MMIOSegment::get_end_bus() const { return m_end_bus; } -size_t MMIOSegment::get_size() +size_t MMIOSegment::get_size() const { return (PCI_MMIO_CONFIG_SPACE_SIZE * PCI_MAX_FUNCTIONS_PER_DEVICE * PCI_MAX_DEVICES_PER_BUS * (get_end_bus() - get_start_bus())); } -PhysicalAddress MMIOSegment::get_paddr() +PhysicalAddress MMIOSegment::get_paddr() const { return m_base_addr; } diff --git a/Kernel/PCI/MMIOAccess.h b/Kernel/PCI/MMIOAccess.h index d763a9bcfb..97f6fcd8a3 100644 --- a/Kernel/PCI/MMIOAccess.h +++ b/Kernel/PCI/MMIOAccess.h @@ -27,6 +27,7 @@ #pragma once #include <AK/HashMap.h> +#include <AK/NonnullOwnPtrVector.h> #include <AK/OwnPtr.h> #include <AK/Types.h> #include <Kernel/ACPI/Definitions.h> @@ -39,6 +40,18 @@ namespace Kernel { namespace PCI { +class DeviceConfigurationSpaceMapping { +public: + DeviceConfigurationSpaceMapping(Address, const MMIOSegment&); + VirtualAddress vaddr() const { return m_mapped_region->vaddr(); }; + PhysicalAddress paddr() const { return m_mapped_region->physical_page(0)->paddr(); } + const Address& address() const { return m_device_address; }; + +private: + Address m_device_address; + NonnullOwnPtr<Region> m_mapped_region; +}; + class MMIOAccess final : public Access { public: static void initialize(PhysicalAddress mcfg); @@ -57,14 +70,13 @@ private: virtual u16 read16_field(Address address, u32) override; virtual u32 read32_field(Address address, u32) override; - void map_device(Address address); + Optional<VirtualAddress> get_device_configuration_space(Address address); virtual u8 segment_start_bus(u32) const override; virtual u8 segment_end_bus(u32) const override; PhysicalAddress m_mcfg; HashMap<u16, MMIOSegment> m_segments; - OwnPtr<Region> m_mmio_window_region; - ChangeableAddress m_mapped_address; + NonnullOwnPtrVector<DeviceConfigurationSpaceMapping> m_mapped_device_regions; }; } |