Serenity Operating System
1/*
2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/Types.h>
30#include <Kernel/VM/Region.h>
31#include <LibBareMetal/Memory/PhysicalAddress.h>
32#include <LibBareMetal/Memory/VirtualAddress.h>
33
34namespace Kernel {
35namespace MultiProcessor {
36
37struct [[gnu::packed]] FloatingPointer
38{
39 char sig[4];
40 u32 physical_address_ptr;
41 u8 length;
42 u8 specification_revision;
43 u8 checksum;
44 u8 feature_info[5];
45};
46
47struct [[gnu::packed]] EntryHeader
48{
49 u8 entry_type;
50};
51
52struct [[gnu::packed]] ConfigurationTableHeader
53{
54 char sig[4];
55 u16 length;
56 u8 specification_revision;
57 u8 checksum;
58 char oem_id[8];
59 char product_id[12];
60 u32 oem_table_ptr;
61 u16 oem_table_size;
62 u16 entry_count;
63 u32 local_apic_address;
64 u16 ext_table_length;
65 u8 ext_table_checksum;
66 u8 reserved;
67 EntryHeader entries[];
68};
69
70enum class ConfigurationTableEntryType {
71 Processor = 0,
72 Bus = 1,
73 IOAPIC = 2,
74 IO_Interrupt_Assignment = 3,
75 Local_Interrupt_Assignment = 4,
76 SystemAddressSpaceMapping = 128,
77 BusHierarchyDescriptor = 129,
78 CompatibilityBusAddressSpaceModifier = 130
79};
80
81enum class ConfigurationTableEntryLength {
82 Processor = 20,
83 Bus = 8,
84 IOAPIC = 8,
85 IO_Interrupt_Assignment = 8,
86 Local_Interrupt_Assignment = 8,
87 SystemAddressSpaceMapping = 20,
88 BusHierarchyDescriptor = 8,
89 CompatibilityBusAddressSpaceModifier = 8
90};
91
92struct [[gnu::packed]] ExtEntryHeader
93{
94 u8 entry_type;
95 u8 entry_length;
96};
97
98struct [[gnu::packed]] ProcessorEntry
99{
100 EntryHeader h;
101 u8 local_apic_id;
102 u8 local_apic_version;
103 u8 cpu_flags;
104 u32 cpu_signature;
105 u32 feature_flags;
106 u8 reserved[8];
107};
108
109struct [[gnu::packed]] BusEntry
110{
111 EntryHeader h;
112 u8 bus_id;
113 char bus_type[6];
114};
115
116struct [[gnu::packed]] IOAPICEntry
117{
118 EntryHeader h;
119 u8 ioapic_id;
120 u8 ioapic_version;
121 u8 ioapic_flags;
122 u32 ioapic_address;
123};
124
125enum class InterruptType {
126 INT = 0,
127 NMI = 1,
128 SMI = 2,
129 ExtINT = 3,
130};
131
132struct [[gnu::packed]] IOInterruptAssignmentEntry
133{
134 EntryHeader h;
135 u8 interrupt_type;
136 u8 polarity;
137 u8 trigger_mode;
138 u8 source_bus_id;
139 u8 source_bus_irq;
140 u8 destination_ioapic_id;
141 u8 destination_ioapic_intin_pin;
142};
143
144struct [[gnu::packed]] LocalInterruptAssignmentEntry
145{
146 EntryHeader h;
147 u8 interrupt_type;
148 u8 polarity;
149 u8 trigger_mode;
150 u8 source_bus_id;
151 u8 source_bus_irq;
152 u8 destination_lapic_id;
153 u8 destination_lapic_lintin_pin;
154};
155
156enum class SystemAddressType {
157 IO = 0,
158 Memory = 1,
159 Prefetch = 2,
160};
161
162struct [[gnu::packed]] SystemAddressSpaceMappingEntry
163{
164 ExtEntryHeader h;
165 u8 bus_id;
166 u8 address_type;
167 u64 address_base;
168 u64 length;
169};
170
171struct [[gnu::packed]] BusHierarchyDescriptorEntry
172{
173 ExtEntryHeader h;
174 u8 bus_id;
175 u8 bus_info;
176 u8 parent_bus;
177 u8 reserved[3];
178};
179
180struct [[gnu::packed]] CompatibilityBusAddressSpaceModifierEntry
181{
182 ExtEntryHeader h;
183 u8 bus_id;
184 u8 address_modifier;
185 u32 predefined_range_list;
186};
187
188}
189
190class PCIInterruptOverrideMetadata : public RefCounted<PCIInterruptOverrideMetadata> {
191public:
192 PCIInterruptOverrideMetadata(u8 bus_id, u8 polarity, u8 trigger_mode, u8 source_irq, u32 ioapic_id, u16 ioapic_int_pin);
193 u8 bus() const;
194 u8 polarity() const;
195 u8 trigger_mode() const;
196 u8 pci_interrupt_pin() const;
197 u8 pci_device_number() const;
198 u32 ioapic_id() const;
199 u16 ioapic_interrupt_pin() const;
200
201private:
202 u8 m_bus_id;
203 u8 m_polarity;
204 u8 m_trigger_mode;
205 u8 m_pci_interrupt_pin;
206 u8 m_pci_device_number;
207 u32 m_ioapic_id;
208 u16 m_ioapic_interrupt_pin;
209};
210
211class MultiProcessorParser {
212public:
213 static MultiProcessorParser& the();
214
215 static bool is_initialized();
216 static void initialize();
217 Vector<RefPtr<PCIInterruptOverrideMetadata>> get_pci_interrupt_redirections();
218
219protected:
220 MultiProcessorParser();
221
222 void parse_configuration_table();
223 size_t get_configuration_table_length();
224 void parse_floating_pointer_data();
225
226 Vector<unsigned> get_pci_bus_ids();
227
228 FlatPtr search_floating_pointer();
229 FlatPtr search_floating_pointer_in_ebda(u16 ebda_segment);
230 FlatPtr search_floating_pointer_in_bios_area();
231
232 FlatPtr m_floating_pointer;
233 FlatPtr m_configuration_table;
234 Vector<FlatPtr> m_io_interrupt_redirection_entries;
235 Vector<FlatPtr> m_bus_entries;
236 bool m_operable;
237
238 size_t m_configuration_table_length;
239 u8 m_specification_revision;
240};
241}