Serenity Operating System
at master 363 lines 10 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Badge.h> 10#include <AK/DistinctNumeric.h> 11#include <AK/Function.h> 12#include <AK/Types.h> 13#include <AK/Vector.h> 14#include <Kernel/Debug.h> 15#include <Kernel/Locking/Spinlock.h> 16#include <Kernel/PhysicalAddress.h> 17 18namespace Kernel::PCI { 19 20enum class HeaderType { 21 Device = 0, 22 Bridge = 1, 23}; 24 25enum class HeaderType0BaseRegister { 26 BAR0 = 0, 27 BAR1, 28 BAR2, 29 BAR3, 30 BAR4, 31 BAR5, 32}; 33 34enum class BARSpaceType { 35 IOSpace, 36 Memory16BitSpace, 37 Memory32BitSpace, 38 Memory64BitSpace, 39}; 40 41enum class RegisterOffset { 42 VENDOR_ID = 0x00, // word 43 DEVICE_ID = 0x02, // word 44 COMMAND = 0x04, // word 45 STATUS = 0x06, // word 46 REVISION_ID = 0x08, // byte 47 PROG_IF = 0x09, // byte 48 SUBCLASS = 0x0a, // byte 49 CLASS = 0x0b, // byte 50 CACHE_LINE_SIZE = 0x0c, // byte 51 LATENCY_TIMER = 0x0d, // byte 52 HEADER_TYPE = 0x0e, // byte 53 BIST = 0x0f, // byte 54 BAR0 = 0x10, // u32 55 BAR1 = 0x14, // u32 56 BAR2 = 0x18, // u32 57 SECONDARY_BUS = 0x19, // byte 58 BAR3 = 0x1C, // u32 59 BAR4 = 0x20, // u32 60 BAR5 = 0x24, // u32 61 SUBSYSTEM_VENDOR_ID = 0x2C, // u16 62 SUBSYSTEM_ID = 0x2E, // u16 63 EXPANSION_ROM_POINTER = 0x30, // u32 64 CAPABILITIES_POINTER = 0x34, // u8 65 INTERRUPT_LINE = 0x3C, // byte 66 INTERRUPT_PIN = 0x3D, // byte 67}; 68 69enum class Limits { 70 MaxDevicesPerBus = 32, 71 MaxBusesPerDomain = 256, 72 MaxFunctionsPerDevice = 8, 73}; 74 75static constexpr u16 address_port = 0xcf8; 76static constexpr u16 value_port = 0xcfc; 77 78static constexpr size_t mmio_device_space_size = 4096; 79static constexpr u16 none_value = 0xffff; 80static constexpr size_t memory_range_per_bus = mmio_device_space_size * to_underlying(Limits::MaxFunctionsPerDevice) * to_underlying(Limits::MaxDevicesPerBus); 81 82// Taken from https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf 83enum class ClassID { 84 MassStorage = 0x1, 85 Multimedia = 0x4, 86 Bridge = 0x6, 87}; 88 89namespace MassStorage { 90 91enum class SubclassID { 92 IDEController = 0x1, 93 SATAController = 0x6, 94 NVMeController = 0x8, 95}; 96enum class SATAProgIF { 97 AHCI = 0x1, 98}; 99 100} 101 102namespace Multimedia { 103 104enum class SubclassID { 105 AudioController = 0x1, 106}; 107 108} 109 110namespace Bridge { 111 112enum class SubclassID { 113 PCI_TO_PCI = 0x4, 114}; 115 116} 117 118AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, CapabilityID); 119 120namespace Capabilities { 121enum ID { 122 Null = 0x0, 123 MSI = 0x5, 124 VendorSpecific = 0x9, 125 MSIX = 0x11, 126}; 127} 128 129struct HardwareID { 130 u16 vendor_id { 0 }; 131 u16 device_id { 0 }; 132 133 bool is_null() const { return !vendor_id && !device_id; } 134 135 bool operator==(HardwareID const& other) const 136 { 137 return vendor_id == other.vendor_id && device_id == other.device_id; 138 } 139 bool operator!=(HardwareID const& other) const 140 { 141 return vendor_id != other.vendor_id || device_id != other.device_id; 142 } 143}; 144 145class Domain { 146public: 147 Domain() = delete; 148 Domain(u32 domain_number, u8 start_bus, u8 end_bus) 149 : m_domain_number(domain_number) 150 , m_start_bus(start_bus) 151 , m_end_bus(end_bus) 152 { 153 } 154 u8 start_bus() const { return m_start_bus; } 155 u8 end_bus() const { return m_end_bus; } 156 u32 domain_number() const { return m_domain_number; } 157 158private: 159 u32 m_domain_number; 160 u8 m_start_bus; 161 u8 m_end_bus; 162}; 163 164struct Address { 165public: 166 Address() = default; 167 Address(u32 domain) 168 : m_domain(domain) 169 , m_bus(0) 170 , m_device(0) 171 , m_function(0) 172 { 173 } 174 Address(u32 domain, u8 bus, u8 device, u8 function) 175 : m_domain(domain) 176 , m_bus(bus) 177 , m_device(device) 178 , m_function(function) 179 { 180 } 181 182 Address(Address const& address) = default; 183 184 bool is_null() const { return !m_bus && !m_device && !m_function; } 185 operator bool() const { return !is_null(); } 186 187 // Disable default implementations that would use surprising integer promotion. 188 bool operator<=(Address const&) const = delete; 189 bool operator>=(Address const&) const = delete; 190 bool operator<(Address const&) const = delete; 191 bool operator>(Address const&) const = delete; 192 193 bool operator==(Address const& other) const 194 { 195 if (this == &other) 196 return true; 197 return m_domain == other.m_domain && m_bus == other.m_bus && m_device == other.m_device && m_function == other.m_function; 198 } 199 bool operator!=(Address const& other) const 200 { 201 return !(*this == other); 202 } 203 204 u32 domain() const { return m_domain; } 205 u8 bus() const { return m_bus; } 206 u8 device() const { return m_device; } 207 u8 function() const { return m_function; } 208 209private: 210 u32 m_domain { 0 }; 211 u8 m_bus { 0 }; 212 u8 m_device { 0 }; 213 u8 m_function { 0 }; 214}; 215 216class Capability { 217public: 218 Capability(Address address, u8 id, u8 ptr) 219 : m_address(address) 220 , m_id(id) 221 , m_ptr(ptr) 222 { 223 } 224 225 CapabilityID id() const { return m_id; } 226 227 u8 read8(size_t offset) const; 228 u16 read16(size_t offset) const; 229 u32 read32(size_t offset) const; 230 231private: 232 const Address m_address; 233 const CapabilityID m_id; 234 const u8 m_ptr; 235}; 236 237AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, ClassCode); 238AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, SubclassCode); 239AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, ProgrammingInterface); 240AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, RevisionID); 241AK_TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemID); 242AK_TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemVendorID); 243AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, InterruptLine); 244AK_TYPEDEF_DISTINCT_ORDERED_ID(u8, InterruptPin); 245 246class Access; 247class EnumerableDeviceIdentifier { 248public: 249 EnumerableDeviceIdentifier(Address address, HardwareID hardware_id, RevisionID revision_id, ClassCode class_code, SubclassCode subclass_code, ProgrammingInterface prog_if, SubsystemID subsystem_id, SubsystemVendorID subsystem_vendor_id, InterruptLine interrupt_line, InterruptPin interrupt_pin, Vector<Capability> const& capabilities) 250 : m_address(address) 251 , m_hardware_id(hardware_id) 252 , m_revision_id(revision_id) 253 , m_class_code(class_code) 254 , m_subclass_code(subclass_code) 255 , m_prog_if(prog_if) 256 , m_subsystem_id(subsystem_id) 257 , m_subsystem_vendor_id(subsystem_vendor_id) 258 , m_interrupt_line(interrupt_line) 259 , m_interrupt_pin(interrupt_pin) 260 , m_capabilities(capabilities) 261 { 262 if constexpr (PCI_DEBUG) { 263 for (auto const& capability : capabilities) 264 dbgln("{} has capability {}", address, capability.id()); 265 } 266 } 267 268 Vector<Capability> const& capabilities() const { return m_capabilities; } 269 HardwareID const& hardware_id() const { return m_hardware_id; } 270 Address const& address() const { return m_address; } 271 272 RevisionID revision_id() const { return m_revision_id; } 273 ClassCode class_code() const { return m_class_code; } 274 SubclassCode subclass_code() const { return m_subclass_code; } 275 ProgrammingInterface prog_if() const { return m_prog_if; } 276 SubsystemID subsystem_id() const { return m_subsystem_id; } 277 SubsystemVendorID subsystem_vendor_id() const { return m_subsystem_vendor_id; } 278 279 InterruptLine interrupt_line() const { return m_interrupt_line; } 280 InterruptPin interrupt_pin() const { return m_interrupt_pin; } 281 282 void apply_subclass_code_change(Badge<Access>, SubclassCode new_subclass) 283 { 284 m_subclass_code = new_subclass; 285 } 286 void apply_prog_if_change(Badge<Access>, ProgrammingInterface new_progif) 287 { 288 m_prog_if = new_progif; 289 } 290 291protected: 292 Address m_address; 293 HardwareID m_hardware_id; 294 295 RevisionID m_revision_id; 296 ClassCode m_class_code; 297 SubclassCode m_subclass_code; 298 ProgrammingInterface m_prog_if; 299 SubsystemID m_subsystem_id; 300 SubsystemVendorID m_subsystem_vendor_id; 301 302 InterruptLine m_interrupt_line; 303 InterruptPin m_interrupt_pin; 304 305 Vector<Capability> m_capabilities; 306}; 307 308class DeviceIdentifier 309 : public RefCounted<DeviceIdentifier> 310 , public EnumerableDeviceIdentifier { 311 AK_MAKE_NONCOPYABLE(DeviceIdentifier); 312 313public: 314 static ErrorOr<NonnullRefPtr<DeviceIdentifier>> from_enumerable_identifier(EnumerableDeviceIdentifier const& other_identifier); 315 316 Spinlock<LockRank::None>& operation_lock() { return m_operation_lock; } 317 Spinlock<LockRank::None>& operation_lock() const { return m_operation_lock; } 318 319 virtual ~DeviceIdentifier() = default; 320 321private: 322 DeviceIdentifier(EnumerableDeviceIdentifier const& other_identifier) 323 : EnumerableDeviceIdentifier(other_identifier.address(), 324 other_identifier.hardware_id(), 325 other_identifier.revision_id(), 326 other_identifier.class_code(), 327 other_identifier.subclass_code(), 328 other_identifier.prog_if(), 329 other_identifier.subsystem_id(), 330 other_identifier.subsystem_vendor_id(), 331 other_identifier.interrupt_line(), 332 other_identifier.interrupt_pin(), 333 other_identifier.capabilities()) 334 { 335 } 336 337 mutable Spinlock<LockRank::None> m_operation_lock; 338}; 339 340class Domain; 341class Device; 342 343} 344 345template<> 346struct AK::Formatter<Kernel::PCI::Address> : Formatter<FormatString> { 347 ErrorOr<void> format(FormatBuilder& builder, Kernel::PCI::Address value) 348 { 349 return Formatter<FormatString>::format( 350 builder, 351 "PCI [{:04x}:{:02x}:{:02x}:{:02x}]"sv, value.domain(), value.bus(), value.device(), value.function()); 352 } 353}; 354 355template<> 356struct AK::Formatter<Kernel::PCI::HardwareID> : Formatter<FormatString> { 357 ErrorOr<void> format(FormatBuilder& builder, Kernel::PCI::HardwareID value) 358 { 359 return Formatter<FormatString>::format( 360 builder, 361 "PCI::HardwareID [{:04x}:{:04x}]"sv, value.vendor_id, value.device_id); 362 } 363};