summaryrefslogtreecommitdiff
path: root/Kernel/Firmware/ACPI/MultiProcessorParser.cpp
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-09-11 10:39:47 +0300
committerAndreas Kling <kling@serenityos.org>2021-09-12 11:52:16 +0200
commit9132596b8e79a56a1ab0aa146bd837266ed61b09 (patch)
tree33ff453378549b12a0bbd43b5e7d56a7eca8f181 /Kernel/Firmware/ACPI/MultiProcessorParser.cpp
parenta9ec98028b7c50a7fd0308ff78cd86480e224d32 (diff)
downloadserenity-9132596b8e79a56a1ab0aa146bd837266ed61b09.zip
Kernel: Move ACPI and BIOS code into the new Firmware directory
This will somwhat help unify them also under the same SysFS directory in the commit. Also, it feels much more like this change reflects the reality that both ACPI and the BIOS are part of the firmware on x86 computers.
Diffstat (limited to 'Kernel/Firmware/ACPI/MultiProcessorParser.cpp')
-rw-r--r--Kernel/Firmware/ACPI/MultiProcessorParser.cpp157
1 files changed, 157 insertions, 0 deletions
diff --git a/Kernel/Firmware/ACPI/MultiProcessorParser.cpp b/Kernel/Firmware/ACPI/MultiProcessorParser.cpp
new file mode 100644
index 0000000000..745f63d90a
--- /dev/null
+++ b/Kernel/Firmware/ACPI/MultiProcessorParser.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/StringView.h>
+#include <Kernel/Debug.h>
+#include <Kernel/Firmware/ACPI/MultiProcessorParser.h>
+#include <Kernel/Firmware/BIOS.h>
+#include <Kernel/Interrupts/IOAPIC.h>
+#include <Kernel/Memory/TypedMapping.h>
+#include <Kernel/Sections.h>
+#include <Kernel/StdLib.h>
+
+namespace Kernel {
+
+UNMAP_AFTER_INIT OwnPtr<MultiProcessorParser> MultiProcessorParser::autodetect()
+{
+ auto floating_pointer = find_floating_pointer();
+ if (!floating_pointer.has_value())
+ return {};
+ auto parser = adopt_own_if_nonnull(new (nothrow) MultiProcessorParser(floating_pointer.value()));
+ VERIFY(parser != nullptr);
+ return parser;
+}
+
+UNMAP_AFTER_INIT MultiProcessorParser::MultiProcessorParser(PhysicalAddress floating_pointer)
+ : m_floating_pointer(floating_pointer)
+{
+ dbgln("MultiProcessor: Floating Pointer Structure @ {}", m_floating_pointer);
+ parse_floating_pointer_data();
+ parse_configuration_table();
+}
+
+UNMAP_AFTER_INIT void MultiProcessorParser::parse_floating_pointer_data()
+{
+ auto floating_pointer = Memory::map_typed<MultiProcessor::FloatingPointer>(m_floating_pointer);
+ m_configuration_table = PhysicalAddress(floating_pointer->physical_address_ptr);
+ dbgln("Features {}, IMCR? {}", floating_pointer->feature_info[0], (floating_pointer->feature_info[0] & (1 << 7)));
+}
+
+UNMAP_AFTER_INIT void MultiProcessorParser::parse_configuration_table()
+{
+ auto configuration_table_length = Memory::map_typed<MultiProcessor::ConfigurationTableHeader>(m_configuration_table)->length;
+ auto config_table = Memory::map_typed<MultiProcessor::ConfigurationTableHeader>(m_configuration_table, configuration_table_length);
+
+ size_t entry_count = config_table->entry_count;
+ auto* entry = config_table->entries;
+ while (entry_count > 0) {
+ dbgln_if(MULTIPROCESSOR_DEBUG, "MultiProcessor: Entry Type {} detected.", entry->entry_type);
+ switch (entry->entry_type) {
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::Processor):
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::ProcessorEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::Bus):
+ m_bus_entries.append(*(const MultiProcessor::BusEntry*)entry);
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::BusEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::IOAPIC):
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::IOAPICEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::IO_Interrupt_Assignment):
+ m_io_interrupt_assignment_entries.append(*(const MultiProcessor::IOInterruptAssignmentEntry*)entry);
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::IOInterruptAssignmentEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::Local_Interrupt_Assignment):
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::LocalInterruptAssignmentEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::SystemAddressSpaceMapping):
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::SystemAddressSpaceMappingEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::BusHierarchyDescriptor):
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::BusHierarchyDescriptorEntry);
+ break;
+ case ((u8)MultiProcessor::ConfigurationTableEntryType::CompatibilityBusAddressSpaceModifier):
+ entry = (MultiProcessor::EntryHeader*)(FlatPtr)entry + sizeof(MultiProcessor::CompatibilityBusAddressSpaceModifierEntry);
+ break;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+ --entry_count;
+ }
+}
+
+UNMAP_AFTER_INIT Optional<PhysicalAddress> MultiProcessorParser::find_floating_pointer()
+{
+ StringView signature("_MP_");
+ auto mp_floating_pointer = map_ebda().find_chunk_starting_with(signature, 16);
+ if (mp_floating_pointer.has_value())
+ return mp_floating_pointer;
+ return map_bios().find_chunk_starting_with(signature, 16);
+}
+
+UNMAP_AFTER_INIT Vector<u8> MultiProcessorParser::get_pci_bus_ids() const
+{
+ Vector<u8> pci_bus_ids;
+ for (auto& entry : m_bus_entries) {
+ if (!strncmp("PCI ", entry.bus_type, strlen("PCI ")))
+ pci_bus_ids.append(entry.bus_id);
+ }
+ return pci_bus_ids;
+}
+
+UNMAP_AFTER_INIT Vector<PCIInterruptOverrideMetadata> MultiProcessorParser::get_pci_interrupt_redirections()
+{
+ dbgln("MultiProcessor: Get PCI IOAPIC redirections");
+ Vector<PCIInterruptOverrideMetadata> overrides;
+ auto pci_bus_ids = get_pci_bus_ids();
+ for (auto& entry : m_io_interrupt_assignment_entries) {
+ for (auto id : pci_bus_ids) {
+ if (id == entry.source_bus_id) {
+
+ dbgln("Interrupts: Bus {}, polarity {}, trigger mode {}, INT {}, IOAPIC {}, IOAPIC INTIN {}",
+ entry.source_bus_id,
+ entry.polarity,
+ entry.trigger_mode,
+ entry.source_bus_irq,
+ entry.destination_ioapic_id,
+ entry.destination_ioapic_intin_pin);
+ overrides.empend(
+ entry.source_bus_id,
+ entry.polarity,
+ entry.trigger_mode,
+ entry.source_bus_irq,
+ entry.destination_ioapic_id,
+ entry.destination_ioapic_intin_pin);
+ }
+ }
+ }
+
+ for (auto& override_metadata : overrides) {
+ dbgln("Interrupts: Bus {}, polarity {}, PCI device {}, trigger mode {}, INT {}, IOAPIC {}, IOAPIC INTIN {}",
+ override_metadata.bus(),
+ override_metadata.polarity(),
+ override_metadata.pci_device_number(),
+ override_metadata.trigger_mode(),
+ override_metadata.pci_interrupt_pin(),
+ override_metadata.ioapic_id(),
+ override_metadata.ioapic_interrupt_pin());
+ }
+ return overrides;
+}
+
+UNMAP_AFTER_INIT PCIInterruptOverrideMetadata::PCIInterruptOverrideMetadata(u8 bus_id, u8 polarity, u8 trigger_mode, u8 source_irq, u32 ioapic_id, u16 ioapic_int_pin)
+ : m_bus_id(bus_id)
+ , m_polarity(polarity)
+ , m_trigger_mode(trigger_mode)
+ , m_pci_interrupt_pin(source_irq & 0b11)
+ , m_pci_device_number((source_irq >> 2) & 0b11111)
+ , m_ioapic_id(ioapic_id)
+ , m_ioapic_interrupt_pin(ioapic_int_pin)
+{
+}
+
+}