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
37 struct [[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
47 struct [[gnu::packed]] EntryHeader
48 {
49 u8 entry_type;
50 };
51
52 struct [[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
70 enum 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
81 enum 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
92 struct [[gnu::packed]] ExtEntryHeader
93 {
94 u8 entry_type;
95 u8 entry_length;
96 };
97
98 struct [[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
109 struct [[gnu::packed]] BusEntry
110 {
111 EntryHeader h;
112 u8 bus_id;
113 char bus_type[6];
114 };
115
116 struct [[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
125 enum class InterruptType {
126 INT = 0,
127 NMI = 1,
128 SMI = 2,
129 ExtINT = 3,
130 };
131
132 struct [[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
144 struct [[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
156 enum class SystemAddressType {
157 IO = 0,
158 Memory = 1,
159 Prefetch = 2,
160 };
161
162 struct [[gnu::packed]] SystemAddressSpaceMappingEntry
163 {
164 ExtEntryHeader h;
165 u8 bus_id;
166 u8 address_type;
167 u64 address_base;
168 u64 length;
169 };
170
171 struct [[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
180 struct [[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 uintptr_t search_floating_pointer();
229 uintptr_t search_floating_pointer_in_ebda(u16 ebda_segment);
230 uintptr_t search_floating_pointer_in_bios_area();
231
232 uintptr_t m_floating_pointer;
233 uintptr_t m_configuration_table;
234 Vector<uintptr_t> m_io_interrupt_redirection_entries;
235 Vector<uintptr_t> m_bus_entries;
236 bool m_operable;
237
238 size_t m_configuration_table_length;
239 u8 m_specification_revision;
240};
241}