summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/PCI/Access.cpp37
-rw-r--r--Kernel/PCI/Access.h5
-rw-r--r--Kernel/PCI/MMIOAccess.cpp95
-rw-r--r--Kernel/PCI/MMIOAccess.h18
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;
};
}