Serenity Operating System
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};