summaryrefslogtreecommitdiff
path: root/Kernel/Bus/PCI/Definitions.h
blob: 24bfa19a7433d10f7e7433dd0a98900b05a0c85a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Function.h>
#include <AK/String.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <Kernel/Debug.h>

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_VENDOR_ID 0x2C  // u16
#define PCI_SUBSYSTEM_ID 0x2E         // u16
#define PCI_CAPABILITIES_POINTER 0x34 // u8
#define PCI_INTERRUPT_LINE 0x3C       // byte
#define PCI_INTERRUPT_PIN 0x3D        // 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

// Taken from https://pcisig.com/sites/default/files/files/PCI_Code-ID_r_1_11__v24_Jan_2019.pdf
#define PCI_MASS_STORAGE_CLASS_ID 0x1
#define PCI_IDE_CTRL_SUBCLASS_ID 0x1
#define PCI_SATA_CTRL_SUBCLASS_ID 0x6
#define PCI_AHCI_IF_PROGIF 0x1

namespace PCI {
struct HardwareID {
    u16 vendor_id { 0 };
    u16 device_id { 0 };

    bool is_null() const { return !vendor_id && !device_id; }

    bool operator==(const HardwareID& other) const
    {
        return vendor_id == other.vendor_id && device_id == other.device_id;
    }
    bool operator!=(const HardwareID& other) const
    {
        return vendor_id != other.vendor_id || device_id != other.device_id;
    }
};

class Domain {
public:
    Domain() = delete;
    Domain(PhysicalAddress base_address, u8 start_bus, u8 end_bus)
        : m_base_addr(base_address)
        , m_start_bus(start_bus)
        , m_end_bus(end_bus)
    {
    }
    u8 start_bus() const { return m_start_bus; }
    u8 end_bus() const { return m_end_bus; }
    PhysicalAddress paddr() const { return m_base_addr; }

private:
    PhysicalAddress m_base_addr;
    u8 m_start_bus;
    u8 m_end_bus;
};

struct Address {
public:
    Address() = default;
    Address(u32 domain)
        : m_domain(domain)
        , m_bus(0)
        , m_device(0)
        , m_function(0)
    {
    }
    Address(u32 domain, u8 bus, u8 device, u8 function)
        : m_domain(domain)
        , m_bus(bus)
        , m_device(device)
        , m_function(function)
    {
    }

    Address(const Address& address)
        : m_domain(address.domain())
        , 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& other) const
    {
        if (this == &other)
            return true;
        return m_domain == other.m_domain && m_bus == other.m_bus && m_device == other.m_device && m_function == other.m_function;
    }
    bool operator!=(const Address& other) const
    {
        return !(*this == other);
    }

    u16 domain() const { return m_domain; }
    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);
    }

private:
    u32 m_domain { 0 };
    u8 m_bus { 0 };
    u8 m_device { 0 };
    u8 m_function { 0 };
};

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;
};

TYPEDEF_DISTINCT_ORDERED_ID(u8, ClassCode);
TYPEDEF_DISTINCT_ORDERED_ID(u8, SubclassCode);
TYPEDEF_DISTINCT_ORDERED_ID(u8, ProgrammingInterface);
TYPEDEF_DISTINCT_ORDERED_ID(u8, RevisionID);
TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemID);
TYPEDEF_DISTINCT_ORDERED_ID(u16, SubsystemVendorID);
TYPEDEF_DISTINCT_ORDERED_ID(u8, InterruptLine);
TYPEDEF_DISTINCT_ORDERED_ID(u8, InterruptPin);

class Access;
class DeviceIdentifier {
public:
    DeviceIdentifier(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> capabilities)
        : m_address(address)
        , m_hardware_id(hardware_id)
        , m_revision_id(revision_id)
        , m_class_code(class_code)
        , m_subclass_code(subclass_code)
        , m_prog_if(prog_if)
        , m_subsystem_id(subsystem_id)
        , m_subsystem_vendor_id(subsystem_vendor_id)
        , m_interrupt_line(interrupt_line)
        , m_interrupt_pin(interrupt_pin)
        , m_capabilities(capabilities)
    {
        if constexpr (PCI_DEBUG) {
            for (const auto& capability : capabilities)
                dbgln("{} has capability {}", address, capability.id());
        }
    }

    Vector<Capability> capabilities() const { return m_capabilities; }
    const HardwareID& hardware_id() const { return m_hardware_id; }
    const Address& address() const { return m_address; }

    RevisionID revision_id() const { return m_revision_id; }
    ClassCode class_code() const { return m_class_code; }
    SubclassCode subclass_code() const { return m_subclass_code; }
    ProgrammingInterface prog_if() const { return m_prog_if; }
    SubsystemID subsystem_id() const { return m_subsystem_id; }
    SubsystemVendorID subsystem_vendor_id() const { return m_subsystem_vendor_id; }

    InterruptLine interrupt_line() const { return m_interrupt_line; }
    InterruptPin interrupt_pin() const { return m_interrupt_pin; }

    void apply_subclass_code_change(Badge<Access>, SubclassCode new_subclass)
    {
        m_subclass_code = new_subclass;
    }
    void apply_prog_if_change(Badge<Access>, ProgrammingInterface new_progif)
    {
        m_prog_if = new_progif;
    }

private:
    Address m_address;
    HardwareID m_hardware_id;

    RevisionID m_revision_id;
    ClassCode m_class_code;
    SubclassCode m_subclass_code;
    ProgrammingInterface m_prog_if;
    SubsystemID m_subsystem_id;
    SubsystemVendorID m_subsystem_vendor_id;

    InterruptLine m_interrupt_line;
    InterruptPin m_interrupt_pin;

    Vector<Capability> m_capabilities;
};

class Domain;
class Device;
}

}

template<>
struct AK::Formatter<Kernel::PCI::Address> : Formatter<FormatString> {
    void format(FormatBuilder& builder, Kernel::PCI::Address value)
    {
        return Formatter<FormatString>::format(
            builder,
            "PCI [{:04x}:{:02x}:{:02x}:{:02x}]", value.domain(), value.bus(), value.device(), value.function());
    }
};

template<>
struct AK::Formatter<Kernel::PCI::HardwareID> : Formatter<FormatString> {
    void format(FormatBuilder& builder, Kernel::PCI::HardwareID value)
    {
        return Formatter<FormatString>::format(
            builder,
            "PCI::HardwareID [{:04x}:{:04x}]", value.vendor_id, value.device_id);
    }
};