/* * Copyright (c) 2020, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Kernel { #define PCI_VENDOR_ID 0x00 // word #define PCI_DEVICE_ID 0x02 // word #define PCI_COMMAND 0x04 // word #define PCI_STATUS 0x06 // word #define PCI_REVISION_ID 0x08 // byte #define PCI_PROG_IF 0x09 // byte #define PCI_SUBCLASS 0x0a // byte #define PCI_CLASS 0x0b // byte #define PCI_CACHE_LINE_SIZE 0x0c // byte #define PCI_LATENCY_TIMER 0x0d // byte #define PCI_HEADER_TYPE 0x0e // byte #define PCI_BIST 0x0f // byte #define PCI_BAR0 0x10 // u32 #define PCI_BAR1 0x14 // u32 #define PCI_BAR2 0x18 // u32 #define PCI_BAR3 0x1C // u32 #define PCI_BAR4 0x20 // u32 #define PCI_BAR5 0x24 // u32 #define PCI_SUBSYSTEM_ID 0x2C // u16 #define PCI_SUBSYSTEM_VENDOR_ID 0x2E // u16 #define PCI_CAPABILITIES_POINTER 0x34 // u8 #define PCI_INTERRUPT_LINE 0x3C // byte #define PCI_SECONDARY_BUS 0x19 // byte #define PCI_HEADER_TYPE_DEVICE 0 #define PCI_HEADER_TYPE_BRIDGE 1 #define PCI_TYPE_BRIDGE 0x0604 #define PCI_ADDRESS_PORT 0xCF8 #define PCI_VALUE_PORT 0xCFC #define PCI_NONE 0xFFFF #define PCI_MAX_DEVICES_PER_BUS 32 #define PCI_MAX_BUSES 256 #define PCI_MAX_FUNCTIONS_PER_DEVICE 8 #define PCI_CAPABILITY_NULL 0x0 #define PCI_CAPABILITY_MSI 0x5 #define PCI_CAPABILITY_VENDOR_SPECIFIC 0x9 #define PCI_CAPABILITY_MSIX 0x11 namespace PCI { struct ID { u16 vendor_id { 0 }; u16 device_id { 0 }; bool is_null() const { return !vendor_id && !device_id; } bool operator==(const ID& other) const { return vendor_id == other.vendor_id && device_id == other.device_id; } bool operator!=(const ID& other) const { return vendor_id != other.vendor_id || device_id != other.device_id; } }; struct Address { public: Address() = default; Address(u16 seg) : m_seg(seg) , m_bus(0) , m_device(0) , m_function(0) { } Address(u16 seg, u8 bus, u8 device, u8 function) : m_seg(seg) , m_bus(bus) , m_device(device) , m_function(function) { } Address(const Address& address) : m_seg(address.seg()) , m_bus(address.bus()) , m_device(address.device()) , m_function(address.function()) { } bool is_null() const { return !m_bus && !m_device && !m_function; } operator bool() const { return !is_null(); } // Disable default implementations that would use surprising integer promotion. bool operator==(const Address&) const = delete; bool operator<=(const Address&) const = delete; bool operator>=(const Address&) const = delete; bool operator<(const Address&) const = delete; bool operator>(const Address&) const = delete; u16 seg() const { return m_seg; } u8 bus() const { return m_bus; } 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); } protected: u32 m_seg { 0 }; u8 m_bus { 0 }; u8 m_device { 0 }; u8 m_function { 0 }; }; struct ChangeableAddress : public Address { ChangeableAddress() : Address(0) { } explicit ChangeableAddress(u16 seg) : Address(seg) { } ChangeableAddress(u16 seg, u8 bus, u8 device, u8 function) : Address(seg, bus, device, function) { } void set_seg(u16 seg) { m_seg = seg; } void set_bus(u8 bus) { m_bus = bus; } void set_device(u8 device) { m_device = device; } void set_function(u8 function) { m_function = function; } bool operator==(const Address& address) { if (m_seg == address.seg() && m_bus == address.bus() && m_device == address.device() && m_function == address.function()) return true; else return false; } const ChangeableAddress& operator=(const Address& address) { set_seg(address.seg()); set_bus(address.bus()); set_device(address.device()); set_function(address.function()); return *this; } }; class Capability { public: Capability(const Address& address, u8 id, u8 ptr) : m_address(address) , m_id(id) , m_ptr(ptr) { } u8 id() const { return m_id; } u8 read8(u32) const; u16 read16(u32) const; u32 read32(u32) const; void write8(u32, u8); void write16(u32, u16); void write32(u32, u32); private: Address m_address; const u8 m_id; const u8 m_ptr; }; class PhysicalID { public: PhysicalID(Address address, ID id, Vector capabilities) : m_address(address) , m_id(id) , m_capabilities(capabilities) { if constexpr (PCI_DEBUG) { for (auto capability : capabilities) dbgln("{} has capability {}", address, capability.id()); } } Vector capabilities() const { return m_capabilities; } const ID& id() const { return m_id; } const Address& address() const { return m_address; } private: Address m_address; ID m_id; Vector m_capabilities; }; ID get_id(PCI::Address); void enumerate(Function callback); void enable_interrupt_line(Address); void disable_interrupt_line(Address); u8 get_interrupt_line(Address); void raw_access(Address, u32, size_t, u32); u32 get_BAR0(Address); u32 get_BAR1(Address); u32 get_BAR2(Address); u32 get_BAR3(Address); u32 get_BAR4(Address); u32 get_BAR5(Address); u32 get_BAR(Address address, u8 bar); u8 get_revision_id(Address); u8 get_programming_interface(Address); u8 get_subclass(Address); u8 get_class(Address); u16 get_subsystem_id(Address); u16 get_subsystem_vendor_id(Address); size_t get_BAR_space_size(Address, u8); Optional get_capabilities_pointer(Address); Vector get_capabilities(Address); void enable_bus_mastering(Address); void disable_bus_mastering(Address); void enable_io_space(Address); void disable_io_space(Address); void enable_memory_space(Address); void disable_memory_space(Address); PhysicalID get_physical_id(Address address); class Access; class MMIOAccess; class WindowedMMIOAccess; class IOAccess; class MMIOSegment; class DeviceController; class Device; } } template<> struct AK::Formatter : Formatter { void format(FormatBuilder& builder, Kernel::PCI::Address value) { return Formatter::format( builder, "PCI [{:04x}:{:02x}:{:02x}:{:02x}]", value.seg(), value.bus(), value.device(), value.function()); } }; template<> struct AK::Formatter : Formatter { void format(FormatBuilder& builder, Kernel::PCI::ID value) { return Formatter::format( builder, "PCI::ID [{:04x}:{:04x}]", value.vendor_id, value.device_id); } };