Serenity Operating System
at portability 252 lines 9.6 kB view raw
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#include <AK/FixedArray.h> 28#include <Kernel/ACPI/MultiProcessorParser.h> 29#include <Kernel/Arch/i386/CPU.h> 30#include <Kernel/Interrupts/IOAPIC.h> 31#include <Kernel/Interrupts/InterruptManagement.h> 32#include <Kernel/Interrupts/PIC.h> 33#include <Kernel/VM/MemoryManager.h> 34 35#define PCAT_COMPAT_FLAG 0x1 36 37namespace Kernel { 38 39static InterruptManagement* s_interrupt_management; 40 41bool InterruptManagement::initialized() 42{ 43 return (s_interrupt_management != nullptr); 44} 45 46InterruptManagement& InterruptManagement::the() 47{ 48 ASSERT(InterruptManagement::initialized()); 49 return *s_interrupt_management; 50} 51 52void InterruptManagement::initialize() 53{ 54 ASSERT(!InterruptManagement::initialized()); 55 s_interrupt_management = new InterruptManagement(true); 56} 57 58InterruptManagement::InterruptManagement(bool create_default_controller) 59{ 60 if (create_default_controller) 61 m_interrupt_controllers[0] = make<PIC>(); 62} 63 64void InterruptManagement::enable(u8 interrupt_vector) 65{ 66 for (auto& irq_controller : InterruptManagement::the().m_interrupt_controllers) { 67 if (irq_controller->get_gsi_base() <= interrupt_vector) 68 if (!irq_controller->is_hard_disabled()) 69 irq_controller->enable(interrupt_vector); 70 } 71} 72 73void InterruptManagement::enumerate_interrupt_handlers(Function<void(GenericInterruptHandler&)> callback) 74{ 75 for (int i = 0; i < GENERIC_INTERRUPT_HANDLERS_COUNT; i++) { 76 auto& handler = get_interrupt_handler(i); 77 if (handler.get_invoking_count() > 0) 78 callback(handler); 79 } 80} 81 82void InterruptManagement::disable(u8 interrupt_vector) 83{ 84 for (auto& irq_controller : InterruptManagement::the().m_interrupt_controllers) { 85 ASSERT(irq_controller != nullptr); 86 if (irq_controller->get_gsi_base() <= interrupt_vector) 87 if (!irq_controller->is_hard_disabled()) 88 irq_controller->disable(interrupt_vector); 89 } 90} 91 92void InterruptManagement::eoi(u8 interrupt_vector) 93{ 94 for (auto& irq_controller : InterruptManagement::the().m_interrupt_controllers) { 95 ASSERT(irq_controller != nullptr); 96 if (irq_controller->get_gsi_base() <= interrupt_vector) 97 if (!irq_controller->is_hard_disabled()) 98 irq_controller->eoi(interrupt_vector); 99 } 100} 101 102IRQController& InterruptManagement::get_interrupt_controller(int index) 103{ 104 ASSERT(index >= 0); 105 ASSERT(m_interrupt_controllers[index] != nullptr); 106 return *m_interrupt_controllers[index]; 107} 108 109void InterruptManagement::switch_to_pic_mode() 110{ 111 kprintf("Interrupts: PIC mode by default\n"); 112} 113 114void InterruptManagement::switch_to_ioapic_mode() 115{ 116 kprintf("Interrupts: Switch to IOAPIC mode failed, Reverting to PIC mode\n"); 117} 118 119void AdvancedInterruptManagement::initialize(PhysicalAddress p_madt) 120{ 121 ASSERT(!InterruptManagement::initialized()); 122 s_interrupt_management = new AdvancedInterruptManagement(p_madt); 123} 124 125AdvancedInterruptManagement::AdvancedInterruptManagement(PhysicalAddress p_madt) 126 : InterruptManagement(false) 127 , m_madt(p_madt) 128{ 129 // FIXME: Check what is the actual data size then map accordingly 130 dbg() << "Interrupts: MADT @ P " << p_madt.as_ptr(); 131 locate_isa_interrupt_overrides(p_madt); 132 locate_ioapics(p_madt); 133} 134 135void AdvancedInterruptManagement::switch_to_pic_mode() 136{ 137 kprintf("Interrupts: Switch to Legacy PIC mode\n"); 138 for (auto& irq_controller : m_interrupt_controllers) { 139 ASSERT(irq_controller); 140 if (irq_controller->type() == IRQControllerType::i82093AA) { 141 irq_controller->hard_disable(); 142 dbg() << "Interrupts: Detected " << irq_controller->model() << " - Disabled"; 143 } else { 144 dbg() << "Interrupts: Detected " << irq_controller->model(); 145 } 146 } 147} 148 149void AdvancedInterruptManagement::switch_to_ioapic_mode() 150{ 151 kprintf("Interrupts: Switch to IOAPIC mode\n"); 152 if (m_interrupt_controllers.size() == 1) { 153 if (get_interrupt_controller(0).type() == IRQControllerType::i8259) { 154 kprintf("Interrupts: NO IOAPIC detected, Reverting to PIC mode.\n"); 155 return; 156 } 157 } 158 for (auto& irq_controller : m_interrupt_controllers) { 159 ASSERT(irq_controller); 160 if (irq_controller->type() == IRQControllerType::i8259) { 161 irq_controller->hard_disable(); 162 dbg() << "Interrupts: Detected " << irq_controller->model() << " Disabled"; 163 } else { 164 dbg() << "Interrupts: Detected " << irq_controller->model(); 165 } 166 } 167} 168 169void AdvancedInterruptManagement::locate_ioapics(PhysicalAddress p_madt) 170{ 171 auto region = MM.allocate_kernel_region(p_madt.page_base(), (PAGE_SIZE * 2), "Initializing Interrupts", Region::Access::Read); 172 auto& madt = *(const ACPI_RAW::MADT*)region->vaddr().offset(p_madt.offset_in_page().get()).as_ptr(); 173 174 int index = 0; 175 if (madt.flags & PCAT_COMPAT_FLAG) { 176 m_interrupt_controllers[0] = make<PIC>(); 177 index++; 178 } 179 size_t entry_index = 0; 180 size_t entries_length = madt.h.length - sizeof(ACPI_RAW::MADT); 181 auto* madt_entry = madt.entries; 182 while (entries_length > 0) { 183 size_t entry_length = madt_entry->length; 184 if (madt_entry->type == (u8)ACPI_RAW::MADTEntryType::IOAPIC) { 185 auto* ioapic_entry = (const ACPI_RAW::MADT_IOAPIC*)madt_entry; 186 dbg() << "IOAPIC found @ MADT entry " << entry_index << ", MMIO Registers @ Px" << String::format("%x", ioapic_entry->ioapic_address); 187 m_interrupt_controllers.resize(1 + index); 188 m_interrupt_controllers[index] = make<IOAPIC>(*(ioapic_mmio_regs*)ioapic_entry->ioapic_address, ioapic_entry->gsi_base, m_isa_interrupt_overrides, m_pci_interrupt_overrides); 189 index++; 190 } 191 madt_entry = (ACPI_RAW::MADTEntryHeader*)(VirtualAddress((u32)madt_entry).offset(entry_length).get()); 192 entries_length -= entry_length; 193 entry_index++; 194 } 195} 196void AdvancedInterruptManagement::locate_pci_interrupt_overrides() 197{ 198 // FIXME: calling the MultiProcessorParser causes a pagefault. 199 ASSERT_NOT_REACHED(); 200 m_pci_interrupt_overrides = MultiProcessorParser::the().get_pci_interrupt_redirections(); 201} 202 203void AdvancedInterruptManagement::locate_isa_interrupt_overrides(PhysicalAddress p_madt) 204{ 205 auto region = MM.allocate_kernel_region(p_madt.page_base(), (PAGE_SIZE * 2), "Initializing Interrupts", Region::Access::Read); 206 auto& madt = *(const ACPI_RAW::MADT*)region->vaddr().offset(p_madt.offset_in_page().get()).as_ptr(); 207 208 size_t entry_index = 0; 209 size_t entries_length = madt.h.length - sizeof(ACPI_RAW::MADT); 210 auto* madt_entry = madt.entries; 211 while (entries_length > 0) { 212 size_t entry_length = madt_entry->length; 213 if (madt_entry->type == (u8)ACPI_RAW::MADTEntryType::InterruptSourceOverride) { 214 auto* interrupt_override_entry = (const ACPI_RAW::MADT_InterruptSourceOverride*)madt_entry; 215 m_isa_interrupt_overrides.append(adopt(*new ISAInterruptOverrideMetadata( 216 interrupt_override_entry->bus, 217 interrupt_override_entry->source, 218 interrupt_override_entry->global_system_interrupt, 219 interrupt_override_entry->flags))); 220 dbg() << "Interrupts: Overriding INT 0x" << String::format("%x", interrupt_override_entry->source) << " with GSI " << interrupt_override_entry->global_system_interrupt << ", for bus 0x" << String::format("%x", interrupt_override_entry->bus); 221 } 222 madt_entry = (ACPI_RAW::MADTEntryHeader*)(VirtualAddress((u32)madt_entry).offset(entry_length).get()); 223 entries_length -= entry_length; 224 entry_index++; 225 } 226} 227 228ISAInterruptOverrideMetadata::ISAInterruptOverrideMetadata(u8 bus, u8 source, u32 global_system_interrupt, u16 flags) 229 : m_bus(bus) 230 , m_source(source) 231 , m_global_system_interrupt(global_system_interrupt) 232 , m_flags(flags) 233{ 234} 235 236u8 ISAInterruptOverrideMetadata::bus() const 237{ 238 return m_bus; 239} 240u8 ISAInterruptOverrideMetadata::source() const 241{ 242 return m_source; 243} 244u32 ISAInterruptOverrideMetadata::gsi() const 245{ 246 return m_global_system_interrupt; 247} 248u16 ISAInterruptOverrideMetadata::flags() const 249{ 250 return m_flags; 251} 252}