diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index 4e6fef645..cb12fbae6 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -13,7 +13,7 @@ #define REGISTER_ISR_HANDLER(i) register_interrupt_handler(i, isr ## i) #define REGISTER_IRQ_HANDLER(i) register_interrupt_handler(IRQ_VECTOR_BASE + i, irq ## i) -namespace IDT +namespace Kernel::IDT { struct Registers @@ -63,7 +63,7 @@ namespace IDT static IDTR s_idtr; static GateDescriptor* s_idt = nullptr; - static void(*s_irq_handlers[0x10])() { nullptr }; + static Interruptable* s_interruptables[0x10] {}; enum ISR { @@ -160,53 +160,62 @@ namespace IDT "Unkown Exception 0x1F", }; - extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, Kernel::InterruptStack& interrupt_stack, const Registers* regs) + extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs) { #if __enable_sse bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11; if (from_userspace) - Kernel::Thread::current().save_sse(); + Thread::current().save_sse(); #endif - pid_t tid = Kernel::Scheduler::current_tid(); - pid_t pid = tid ? Kernel::Process::current().pid() : 0; + pid_t tid = Scheduler::current_tid(); + pid_t pid = tid ? Process::current().pid() : 0; - if (pid && isr == ISR::PageFault) + if (tid) { - PageFaultError page_fault_error; - page_fault_error.raw = error; + Thread::current().set_return_rsp(interrupt_stack.rsp); + Thread::current().set_return_rip(interrupt_stack.rip); - // Try demand paging on non present pages - if (!page_fault_error.present) + if (isr == ISR::PageFault) { - asm volatile("sti"); - auto result = Kernel::Process::current().allocate_page_for_demand_paging(regs->cr2); - asm volatile("cli"); - - if (!result.is_error() && result.value()) - return; - - if (result.is_error()) + // Check if stack is OOB + auto& stack = Thread::current().stack(); + if (interrupt_stack.rsp < stack.vaddr()) { - dwarnln("Demand paging: {}", result.error()); - Kernel::Thread::current().handle_signal(SIGTERM); + derrorln("Stack overflow"); + goto done; + } + if (interrupt_stack.rsp >= stack.vaddr() + stack.size()) + { + derrorln("Stack underflow"); + goto done; + } + + // Try demand paging on non present pages + PageFaultError page_fault_error; + page_fault_error.raw = error; + if (!page_fault_error.present) + { + asm volatile("sti"); + auto result = Process::current().allocate_page_for_demand_paging(regs->cr2); + asm volatile("cli"); + + if (!result.is_error() && result.value()) + goto done; + + if (result.is_error()) + { + dwarnln("Demand paging: {}", result.error()); + Thread::current().handle_signal(SIGTERM); + goto done; + } } } } - if (tid) + if (PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & PageTable::Flags::Present) { - auto start = Kernel::Thread::current().stack_base(); - auto end = start + Kernel::Thread::current().stack_size(); - if (interrupt_stack.rsp < start) - derrorln("Stack overflow"); - if (interrupt_stack.rsp >= end) - derrorln("Stack underflow"); - } - - if (Kernel::PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & Kernel::PageTable::Flags::Present) - { - uint8_t* machine_code = (uint8_t*)interrupt_stack.rip; + auto* machine_code = (const uint8_t*)interrupt_stack.rip; dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}", machine_code[0], machine_code[1], @@ -233,16 +242,10 @@ namespace IDT regs->cr0, regs->cr2, regs->cr3, regs->cr4 ); if (isr == ISR::PageFault) - Kernel::PageTable::current().debug_dump(); + PageTable::current().debug_dump(); Debug::dump_stack_trace(); - if (tid) - { - Kernel::Thread::current().set_return_rsp(interrupt_stack.rsp); - Kernel::Thread::current().set_return_rip(interrupt_stack.rip); - } - - if (tid && Kernel::Thread::current().is_userspace()) + if (tid && Thread::current().is_userspace()) { // TODO: Confirm and fix the exception to signal mappings @@ -270,36 +273,38 @@ namespace IDT break; } - Kernel::Thread::current().handle_signal(signal); + Thread::current().handle_signal(signal); } else { - Kernel::panic("Unhandled exception"); + panic("Unhandled exception"); } - ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminated); - + ASSERT(Thread::current().state() != Thread::State::Terminated); + +done: #if __enable_sse if (from_userspace) { - ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing); - Kernel::Thread::current().load_sse(); + ASSERT(Thread::current().state() == Thread::State::Executing); + Thread::current().load_sse(); } #endif + return; } - extern "C" void cpp_irq_handler(uint64_t irq, Kernel::InterruptStack& interrupt_stack) + extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack) { #if __enable_sse bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11; if (from_userspace) - Kernel::Thread::current().save_sse(); + Thread::current().save_sse(); #endif - if (Kernel::Scheduler::current_tid()) + if (Scheduler::current_tid()) { - Kernel::Thread::current().set_return_rsp(interrupt_stack.rsp); - Kernel::Thread::current().set_return_rip(interrupt_stack.rip); + Thread::current().set_return_rsp(interrupt_stack.rsp); + Thread::current().set_return_rip(interrupt_stack.rip); } if (!InterruptController::get().is_in_service(irq)) @@ -307,21 +312,21 @@ namespace IDT else { InterruptController::get().eoi(irq); - if (s_irq_handlers[irq]) - s_irq_handlers[irq](); + if (s_interruptables[irq]) + s_interruptables[irq]->handle_irq(); else dprintln("no handler for irq 0x{2H}\n", irq); } - Kernel::Scheduler::get().reschedule_if_idling(); + Scheduler::get().reschedule_if_idling(); - ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminated); + ASSERT(Thread::current().state() != Thread::State::Terminated); #if __enable_sse if (from_userspace) { - ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing); - Kernel::Thread::current().load_sse(); + ASSERT(Thread::current().state() == Thread::State::Executing); + Thread::current().load_sse(); } #endif } @@ -349,9 +354,9 @@ namespace IDT s_idt[index].flags = 0xEE; } - void register_irq_handler(uint8_t irq, void(*handler)()) + void register_irq_handler(uint8_t irq, Interruptable* interruptable) { - s_irq_handlers[irq] = handler; + s_interruptables[irq] = interruptable; } extern "C" void isr0(); @@ -480,4 +485,4 @@ namespace IDT ASSERT_NOT_REACHED(); } -} \ No newline at end of file +} diff --git a/kernel/include/kernel/APIC.h b/kernel/include/kernel/APIC.h index ddf3e1a16..02db2597a 100644 --- a/kernel/include/kernel/APIC.h +++ b/kernel/include/kernel/APIC.h @@ -4,51 +4,56 @@ #include #include -class APIC final : public InterruptController +namespace Kernel { -public: - virtual void eoi(uint8_t) override; - virtual void enable_irq(uint8_t) override; - virtual bool is_in_service(uint8_t) override; -private: - uint32_t read_from_local_apic(ptrdiff_t); - void write_to_local_apic(ptrdiff_t, uint32_t); - -private: - ~APIC() { ASSERT_NOT_REACHED(); } - static APIC* create(); - friend class InterruptController; - -private: - struct Processor + class APIC final : public InterruptController { - enum Flags : uint8_t + public: + virtual void eoi(uint8_t) override; + virtual void enable_irq(uint8_t) override; + virtual bool is_in_service(uint8_t) override; + + private: + uint32_t read_from_local_apic(ptrdiff_t); + void write_to_local_apic(ptrdiff_t, uint32_t); + + private: + ~APIC() { ASSERT_NOT_REACHED(); } + static APIC* create(); + friend class InterruptController; + + private: + struct Processor { - Enabled = 1, - OnlineCapable = 2, + enum Flags : uint8_t + { + Enabled = 1, + OnlineCapable = 2, + }; + uint8_t processor_id; + uint8_t apic_id; + uint8_t flags; }; - uint8_t processor_id; - uint8_t apic_id; - uint8_t flags; + + struct IOAPIC + { + uint8_t id; + Kernel::paddr_t paddr; + Kernel::vaddr_t vaddr; + uint32_t gsi_base; + uint8_t max_redirs; + + uint32_t read(uint8_t offset); + void write(uint8_t offset, uint32_t data); + }; + + private: + BAN::Vector m_processors; + Kernel::paddr_t m_local_apic_paddr = 0; + Kernel::vaddr_t m_local_apic_vaddr = 0; + BAN::Vector m_io_apics; + uint8_t m_irq_overrides[0x100] {}; }; - struct IOAPIC - { - uint8_t id; - Kernel::paddr_t paddr; - Kernel::vaddr_t vaddr; - uint32_t gsi_base; - uint8_t max_redirs; - - uint32_t read(uint8_t offset); - void write(uint8_t offset, uint32_t data); - }; - -private: - BAN::Vector m_processors; - Kernel::paddr_t m_local_apic_paddr = 0; - Kernel::vaddr_t m_local_apic_vaddr = 0; - BAN::Vector m_io_apics; - uint8_t m_irq_overrides[0x100] {}; -}; \ No newline at end of file +} diff --git a/kernel/include/kernel/IDT.h b/kernel/include/kernel/IDT.h index 679442e49..ccf7c97b0 100644 --- a/kernel/include/kernel/IDT.h +++ b/kernel/include/kernel/IDT.h @@ -4,11 +4,10 @@ constexpr uint8_t IRQ_VECTOR_BASE = 0x20; -namespace IDT +namespace Kernel::IDT { void initialize(); - void register_irq_handler(uint8_t irq, void(*f)()); [[noreturn]] void force_triple_fault(); } \ No newline at end of file diff --git a/kernel/include/kernel/Input/PS2Config.h b/kernel/include/kernel/Input/PS2Config.h new file mode 100644 index 000000000..71fbdbc20 --- /dev/null +++ b/kernel/include/kernel/Input/PS2Config.h @@ -0,0 +1,97 @@ +#pragma once + +#include + +namespace Kernel::Input::PS2 +{ + + enum IOPort : uint8_t + { + DATA = 0x60, + STATUS = 0x64, + COMMAND = 0x64, + }; + + enum Status : uint8_t + { + OUTPUT_FULL = (1 << 0), + INPUT_FULL = (1 << 1), + SYSTEM = (1 << 2), + DEVICE_OR_CONTROLLER = (1 << 3), + TIMEOUT_ERROR = (1 << 6), + PARITY_ERROR = (1 << 7), + }; + + enum Config : uint8_t + { + INTERRUPT_FIRST_PORT = (1 << 0), + INTERRUPT_SECOND_PORT = (1 << 1), + SYSTEM_FLAG = (1 << 2), + ZERO1 = (1 << 3), + CLOCK_FIRST_PORT = (1 << 4), + CLOCK_SECOND_PORT = (1 << 5), + TRANSLATION_FIRST_PORT = (1 << 6), + ZERO2 = (1 << 7), + }; + + enum Command : uint8_t + { + READ_CONFIG = 0x20, + WRITE_CONFIG = 0x60, + DISABLE_SECOND_PORT = 0xA7, + ENABLE_SECOND_PORT = 0xA8, + TEST_SECOND_PORT = 0xA9, + TEST_CONTROLLER = 0xAA, + TEST_FIRST_PORT = 0xAB, + DISABLE_FIRST_PORT = 0xAD, + ENABLE_FIRST_PORT = 0xAE, + WRITE_TO_SECOND_PORT = 0xD4, + }; + + enum Response : uint8_t + { + TEST_FIRST_PORT_PASS = 0x00, + TEST_SECOND_PORT_PASS = 0x00, + TEST_CONTROLLER_PASS = 0x55, + SELF_TEST_PASS = 0xAA, + ACK = 0xFA, + }; + + enum DeviceCommand : uint8_t + { + ENABLE_SCANNING = 0xF4, + DISABLE_SCANNING = 0xF5, + IDENTIFY = 0xF2, + RESET = 0xFF, + }; + + enum IRQ : uint8_t + { + DEVICE0 = 1, + DEVICE1 = 12, + }; + + enum KBResponse : uint8_t + { + KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00, + SELF_TEST_PASSED = 0xAA, + ECHO_RESPONSE = 0xEE, + RESEND = 0xFE, + KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF, + }; + + enum KBScancode : uint8_t + { + SET_SCANCODE_SET1 = 1, + SET_SCANCODE_SET2 = 2, + SET_SCANCODE_SET3 = 3, + }; + + enum KBLeds : uint8_t + { + SCROLL_LOCK = (1 << 0), + NUM_LOCK = (1 << 1), + CAPS_LOCK = (1 << 2), + }; + +} \ No newline at end of file diff --git a/kernel/include/kernel/Input/PS2Controller.h b/kernel/include/kernel/Input/PS2Controller.h index 9a2dc030b..6c7390825 100644 --- a/kernel/include/kernel/Input/PS2Controller.h +++ b/kernel/include/kernel/Input/PS2Controller.h @@ -1,16 +1,16 @@ #pragma once #include +#include namespace Kernel::Input { - class PS2Device : public CharacterDevice + class PS2Device : public CharacterDevice, public Interruptable { public: virtual ~PS2Device() {} - virtual void on_byte(uint8_t) = 0; - + public: PS2Device() : CharacterDevice(Mode::IRUSR | Mode::IRGRP, 0, 0) @@ -33,11 +33,8 @@ namespace Kernel::Input BAN::ErrorOr reset_device(uint8_t); BAN::ErrorOr set_scanning(uint8_t, bool); - static void device0_irq(); - static void device1_irq(); - private: PS2Device* m_devices[2] { nullptr, nullptr }; }; -} \ No newline at end of file +} diff --git a/kernel/include/kernel/Input/PS2Keyboard.h b/kernel/include/kernel/Input/PS2Keyboard.h index 10b7a76e2..62e8a57e0 100644 --- a/kernel/include/kernel/Input/PS2Keyboard.h +++ b/kernel/include/kernel/Input/PS2Keyboard.h @@ -29,7 +29,7 @@ namespace Kernel::Input public: static BAN::ErrorOr create(PS2Controller&); - virtual void on_byte(uint8_t) override; + virtual void handle_irq() override; virtual void update() override; private: diff --git a/kernel/include/kernel/InterruptController.h b/kernel/include/kernel/InterruptController.h index b2a160ec6..d84966040 100644 --- a/kernel/include/kernel/InterruptController.h +++ b/kernel/include/kernel/InterruptController.h @@ -5,22 +5,42 @@ #define DISABLE_INTERRUPTS() asm volatile("cli") #define ENABLE_INTERRUPTS() asm volatile("sti") -class InterruptController +namespace Kernel { -public: - virtual ~InterruptController() {} - virtual void eoi(uint8_t) = 0; - virtual void enable_irq(uint8_t) = 0; - virtual bool is_in_service(uint8_t) = 0; + class Interruptable + { + public: + Interruptable() = default; - static void initialize(bool force_pic); - static InterruptController& get(); + void set_irq(int irq); + void enable_interrupt(); + void disable_interrupt(); - void enter_acpi_mode(); + virtual void handle_irq() = 0; -private: - bool m_using_apic { false }; -}; + private: + int m_irq { -1 }; + }; -bool interrupts_enabled(); \ No newline at end of file + class InterruptController + { + public: + virtual ~InterruptController() {} + + virtual void eoi(uint8_t) = 0; + virtual void enable_irq(uint8_t) = 0; + virtual bool is_in_service(uint8_t) = 0; + + static void initialize(bool force_pic); + static InterruptController& get(); + + void enter_acpi_mode(); + + private: + bool m_using_apic { false }; + }; + + bool interrupts_enabled(); + +} \ No newline at end of file diff --git a/kernel/include/kernel/PIC.h b/kernel/include/kernel/PIC.h index dc9153c9d..02b016c9e 100644 --- a/kernel/include/kernel/PIC.h +++ b/kernel/include/kernel/PIC.h @@ -2,17 +2,22 @@ #include -class PIC final : public InterruptController +namespace Kernel { -public: - virtual void eoi(uint8_t) override; - virtual void enable_irq(uint8_t) override; - virtual bool is_in_service(uint8_t) override; - static void remap(); - static void mask_all(); + class PIC final : public InterruptController + { + public: + virtual void eoi(uint8_t) override; + virtual void enable_irq(uint8_t) override; + virtual bool is_in_service(uint8_t) override; -private: - static PIC* create(); - friend class InterruptController; -}; \ No newline at end of file + static void remap(); + static void mask_all(); + + private: + static PIC* create(); + friend class InterruptController; + }; + +} diff --git a/kernel/include/kernel/Storage/ATABus.h b/kernel/include/kernel/Storage/ATABus.h index d9aa4a048..f971fe731 100644 --- a/kernel/include/kernel/Storage/ATABus.h +++ b/kernel/include/kernel/Storage/ATABus.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -9,7 +10,7 @@ namespace Kernel class ATADevice; - class ATABus + class ATABus : public Interruptable { public: enum class DeviceType @@ -27,7 +28,7 @@ namespace Kernel ATAController& controller() { return m_controller; } - void on_irq(); + virtual void handle_irq() override; private: ATABus(ATAController& controller, uint16_t base, uint16_t ctrl) diff --git a/kernel/include/kernel/Terminal/Serial.h b/kernel/include/kernel/Terminal/Serial.h index b53310aab..fc6032a41 100644 --- a/kernel/include/kernel/Terminal/Serial.h +++ b/kernel/include/kernel/Terminal/Serial.h @@ -1,6 +1,8 @@ #pragma once +#include #include +#include #include namespace Kernel @@ -34,7 +36,7 @@ namespace Kernel uint32_t m_height { 0 }; }; - class SerialTTY final : public TTY + class SerialTTY final : public TTY, public Interruptable { public: static BAN::ErrorOr> create(Serial); @@ -45,6 +47,8 @@ namespace Kernel virtual void update() override; + virtual void handle_irq() override; + protected: virtual BAN::StringView name() const override { return m_name; } @@ -55,6 +59,7 @@ namespace Kernel private: BAN::String m_name; Serial m_serial; + BAN::CircularQueue m_input; public: virtual dev_t rdev() const override { return m_rdev; } diff --git a/kernel/include/kernel/Timer/HPET.h b/kernel/include/kernel/Timer/HPET.h index fcf99c59b..e37729745 100644 --- a/kernel/include/kernel/Timer/HPET.h +++ b/kernel/include/kernel/Timer/HPET.h @@ -1,11 +1,12 @@ #pragma once +#include #include namespace Kernel { - class HPET final : public Timer + class HPET final : public Timer, public Interruptable { public: static BAN::ErrorOr> create(bool force_pic); @@ -13,6 +14,8 @@ namespace Kernel virtual uint64_t ms_since_boot() const override; virtual timespec time_since_boot() const override; + virtual void handle_irq() override; + private: HPET() = default; BAN::ErrorOr initialize(bool force_pic); diff --git a/kernel/include/kernel/Timer/PIT.h b/kernel/include/kernel/Timer/PIT.h index 23e5000e6..d0750984c 100644 --- a/kernel/include/kernel/Timer/PIT.h +++ b/kernel/include/kernel/Timer/PIT.h @@ -1,14 +1,12 @@ #pragma once +#include #include -#include - -#define PIT_IRQ 0 namespace Kernel { - class PIT final : public Timer + class PIT final : public Timer, public Interruptable { public: static BAN::ErrorOr> create(); @@ -16,8 +14,13 @@ namespace Kernel virtual uint64_t ms_since_boot() const override; virtual timespec time_since_boot() const override; + virtual void handle_irq() override; + private: void initialize(); + + private: + volatile uint64_t m_system_time { 0 }; }; } \ No newline at end of file diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index c181d0248..02cfa9cc4 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -20,239 +20,242 @@ // https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt-format -struct MADT : public Kernel::ACPI::SDTHeader +namespace Kernel { - uint32_t local_apic; - uint32_t flags; -} __attribute__((packed)); -struct MADTEntry -{ - uint8_t type; - uint8_t length; - union + struct MADT : public Kernel::ACPI::SDTHeader + { + uint32_t local_apic; + uint32_t flags; + } __attribute__((packed)); + + struct MADTEntry + { + uint8_t type; + uint8_t length; + union + { + struct + { + uint8_t acpi_processor_id; + uint8_t apic_id; + uint32_t flags; + } __attribute__((packed)) entry0; + struct + { + uint8_t ioapic_id; + uint8_t reserved; + uint32_t ioapic_address; + uint32_t gsi_base; + } __attribute__((packed)) entry1; + struct + { + uint8_t bus_source; + uint8_t irq_source; + uint32_t gsi; + uint16_t flags; + } __attribute__((packed)) entry2; + struct + { + uint16_t reserved; + uint64_t address; + } __attribute__((packed)) entry5; + }; + } __attribute__((packed)); + + union RedirectionEntry { struct { - uint8_t acpi_processor_id; - uint8_t apic_id; - uint32_t flags; - } __attribute__((packed)) entry0; + uint64_t vector : 8; + uint64_t delivery_mode : 3; + uint64_t destination_mode : 1; + uint64_t delivery_status : 1; + uint64_t pin_polarity : 1; + uint64_t remote_irr : 1; + uint64_t trigger_mode : 1; + uint64_t mask : 1; + uint64_t reserved : 39; + uint64_t destination : 8; + }; struct { - uint8_t ioapic_id; - uint8_t reserved; - uint32_t ioapic_address; - uint32_t gsi_base; - } __attribute__((packed)) entry1; - struct - { - uint8_t bus_source; - uint8_t irq_source; - uint32_t gsi; - uint16_t flags; - } __attribute__((packed)) entry2; - struct - { - uint16_t reserved; - uint64_t address; - } __attribute__((packed)) entry5; + uint32_t lo_dword; + uint32_t hi_dword; + }; }; -} __attribute__((packed)); -union RedirectionEntry -{ - struct + APIC* APIC::create() { - uint64_t vector : 8; - uint64_t delivery_mode : 3; - uint64_t destination_mode : 1; - uint64_t delivery_status : 1; - uint64_t pin_polarity : 1; - uint64_t remote_irr : 1; - uint64_t trigger_mode : 1; - uint64_t mask : 1; - uint64_t reserved : 39; - uint64_t destination : 8; - }; - struct - { - uint32_t lo_dword; - uint32_t hi_dword; - }; -}; - -using namespace Kernel; - -APIC* APIC::create() -{ - uint32_t ecx, edx; - CPUID::get_features(ecx, edx); - if (!(edx & CPUID::Features::EDX_APIC)) - { - dprintln("Local APIC is not available"); - return nullptr; - } - - const MADT* madt = (const MADT*)Kernel::ACPI::get().get_header("APIC"); - if (madt == nullptr) - { - dprintln("Could not find MADT header"); - return nullptr; - } - - APIC* apic = new APIC; - apic->m_local_apic_paddr = madt->local_apic; - for (uint32_t i = 0x00; i <= 0xFF; i++) - apic->m_irq_overrides[i] = i; - - uintptr_t madt_entry_addr = (uintptr_t)madt + sizeof(MADT); - while (madt_entry_addr < (uintptr_t)madt + madt->length) - { - const MADTEntry* entry = (const MADTEntry*)madt_entry_addr; - switch (entry->type) + uint32_t ecx, edx; + CPUID::get_features(ecx, edx); + if (!(edx & CPUID::Features::EDX_APIC)) { - case 0: - Processor processor; - processor.processor_id = entry->entry0.acpi_processor_id; - processor.apic_id = entry->entry0.apic_id; - processor.flags = entry->entry0.flags & 0x03; - MUST(apic->m_processors.push_back(processor)); - break; - case 1: - IOAPIC ioapic; - ioapic.id = entry->entry1.ioapic_id; - ioapic.paddr = entry->entry1.ioapic_address; - ioapic.gsi_base = entry->entry1.gsi_base; - ioapic.max_redirs = 0; - MUST(apic->m_io_apics.push_back(ioapic)); - break; - case 2: - apic->m_irq_overrides[entry->entry2.irq_source] = entry->entry2.gsi; - break; - case 5: - apic->m_local_apic_paddr = entry->entry5.address; - break; - default: - dprintln("Unhandled madt entry, type {}", entry->type); - break; + dprintln("Local APIC is not available"); + return nullptr; } - madt_entry_addr += entry->length; - } - if (apic->m_local_apic_paddr == 0 || apic->m_io_apics.empty()) - { - dprintln("MADT did not provide necessary information"); - delete apic; - return nullptr; - } - - // Map the local apic to kernel memory - { - vaddr_t vaddr = PageTable::kernel().reserve_free_page(KERNEL_OFFSET); - ASSERT(vaddr); - dprintln("lapic paddr {8H}", apic->m_local_apic_paddr); - apic->m_local_apic_vaddr = vaddr + (apic->m_local_apic_paddr % PAGE_SIZE); - dprintln("lapic vaddr {8H}", apic->m_local_apic_vaddr); - PageTable::kernel().map_page_at( - apic->m_local_apic_paddr & PAGE_ADDR_MASK, - apic->m_local_apic_vaddr & PAGE_ADDR_MASK, - PageTable::Flags::ReadWrite | PageTable::Flags::Present - ); - } - - // Map io apics to kernel memory - for (auto& io_apic : apic->m_io_apics) - { - vaddr_t vaddr = PageTable::kernel().reserve_free_page(KERNEL_OFFSET); - ASSERT(vaddr); - - io_apic.vaddr = vaddr + (io_apic.paddr % PAGE_SIZE); - - PageTable::kernel().map_page_at( - io_apic.paddr & PAGE_ADDR_MASK, - io_apic.vaddr & PAGE_ADDR_MASK, - PageTable::Flags::ReadWrite | PageTable::Flags::Present - ); - io_apic.max_redirs = io_apic.read(IOAPIC_MAX_REDIRS); - } - - // Mask all interrupts - uint32_t sivr = apic->read_from_local_apic(LAPIC_SIV_REG); - apic->write_to_local_apic(LAPIC_SIV_REG, sivr | 0x1FF); - -#if DEBUG_PRINT_PROCESSORS - for (auto& processor : apic->m_processors) - { - dprintln("Processor{}", processor.processor_id); - dprintln(" lapic id: {}", processor.apic_id); - dprintln(" status: {}", (processor.flags & Processor::Flags::Enabled) ? "enabled" : (processor.flags & Processor::Flags::OnlineCapable) ? "can be enabled" : "disabled"); - } -#endif - - return apic; -} - -uint32_t APIC::read_from_local_apic(ptrdiff_t offset) -{ - return MMIO::read32(m_local_apic_vaddr + offset); -} - -void APIC::write_to_local_apic(ptrdiff_t offset, uint32_t data) -{ - MMIO::write32(m_local_apic_vaddr + offset, data); -} - -uint32_t APIC::IOAPIC::read(uint8_t offset) -{ - MMIO::write32(vaddr, offset); - return MMIO::read32(vaddr + 16); -} - -void APIC::IOAPIC::write(uint8_t offset, uint32_t data) -{ - MMIO::write32(vaddr, offset); - MMIO::write32(vaddr + 16, data); -} - -void APIC::eoi(uint8_t) -{ - write_to_local_apic(LAPIC_EIO_REG, 0); -} - -void APIC::enable_irq(uint8_t irq) -{ - uint32_t gsi = m_irq_overrides[irq]; - - IOAPIC* ioapic = nullptr; - for (IOAPIC& io : m_io_apics) - { - if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs) + const MADT* madt = (const MADT*)Kernel::ACPI::get().get_header("APIC"); + if (madt == nullptr) { - ioapic = &io; - break; + dprintln("Could not find MADT header"); + return nullptr; } + + APIC* apic = new APIC; + apic->m_local_apic_paddr = madt->local_apic; + for (uint32_t i = 0x00; i <= 0xFF; i++) + apic->m_irq_overrides[i] = i; + + uintptr_t madt_entry_addr = (uintptr_t)madt + sizeof(MADT); + while (madt_entry_addr < (uintptr_t)madt + madt->length) + { + const MADTEntry* entry = (const MADTEntry*)madt_entry_addr; + switch (entry->type) + { + case 0: + Processor processor; + processor.processor_id = entry->entry0.acpi_processor_id; + processor.apic_id = entry->entry0.apic_id; + processor.flags = entry->entry0.flags & 0x03; + MUST(apic->m_processors.push_back(processor)); + break; + case 1: + IOAPIC ioapic; + ioapic.id = entry->entry1.ioapic_id; + ioapic.paddr = entry->entry1.ioapic_address; + ioapic.gsi_base = entry->entry1.gsi_base; + ioapic.max_redirs = 0; + MUST(apic->m_io_apics.push_back(ioapic)); + break; + case 2: + apic->m_irq_overrides[entry->entry2.irq_source] = entry->entry2.gsi; + break; + case 5: + apic->m_local_apic_paddr = entry->entry5.address; + break; + default: + dprintln("Unhandled madt entry, type {}", entry->type); + break; + } + madt_entry_addr += entry->length; + } + + if (apic->m_local_apic_paddr == 0 || apic->m_io_apics.empty()) + { + dprintln("MADT did not provide necessary information"); + delete apic; + return nullptr; + } + + // Map the local apic to kernel memory + { + vaddr_t vaddr = PageTable::kernel().reserve_free_page(KERNEL_OFFSET); + ASSERT(vaddr); + dprintln("lapic paddr {8H}", apic->m_local_apic_paddr); + apic->m_local_apic_vaddr = vaddr + (apic->m_local_apic_paddr % PAGE_SIZE); + dprintln("lapic vaddr {8H}", apic->m_local_apic_vaddr); + PageTable::kernel().map_page_at( + apic->m_local_apic_paddr & PAGE_ADDR_MASK, + apic->m_local_apic_vaddr & PAGE_ADDR_MASK, + PageTable::Flags::ReadWrite | PageTable::Flags::Present + ); + } + + // Map io apics to kernel memory + for (auto& io_apic : apic->m_io_apics) + { + vaddr_t vaddr = PageTable::kernel().reserve_free_page(KERNEL_OFFSET); + ASSERT(vaddr); + + io_apic.vaddr = vaddr + (io_apic.paddr % PAGE_SIZE); + + PageTable::kernel().map_page_at( + io_apic.paddr & PAGE_ADDR_MASK, + io_apic.vaddr & PAGE_ADDR_MASK, + PageTable::Flags::ReadWrite | PageTable::Flags::Present + ); + io_apic.max_redirs = io_apic.read(IOAPIC_MAX_REDIRS); + } + + // Mask all interrupts + uint32_t sivr = apic->read_from_local_apic(LAPIC_SIV_REG); + apic->write_to_local_apic(LAPIC_SIV_REG, sivr | 0x1FF); + + #if DEBUG_PRINT_PROCESSORS + for (auto& processor : apic->m_processors) + { + dprintln("Processor{}", processor.processor_id); + dprintln(" lapic id: {}", processor.apic_id); + dprintln(" status: {}", (processor.flags & Processor::Flags::Enabled) ? "enabled" : (processor.flags & Processor::Flags::OnlineCapable) ? "can be enabled" : "disabled"); + } + #endif + + return apic; } - ASSERT(ioapic); - RedirectionEntry redir; - redir.lo_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2); - redir.hi_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2 + 1); - ASSERT(redir.mask); // TODO: handle overlapping interrupts + uint32_t APIC::read_from_local_apic(ptrdiff_t offset) + { + return MMIO::read32(m_local_apic_vaddr + offset); + } - redir.vector = IRQ_VECTOR_BASE + irq; - redir.mask = 0; - redir.destination = m_processors.front().apic_id; + void APIC::write_to_local_apic(ptrdiff_t offset, uint32_t data) + { + MMIO::write32(m_local_apic_vaddr + offset, data); + } + + uint32_t APIC::IOAPIC::read(uint8_t offset) + { + MMIO::write32(vaddr, offset); + return MMIO::read32(vaddr + 16); + } + + void APIC::IOAPIC::write(uint8_t offset, uint32_t data) + { + MMIO::write32(vaddr, offset); + MMIO::write32(vaddr + 16, data); + } + + void APIC::eoi(uint8_t) + { + write_to_local_apic(LAPIC_EIO_REG, 0); + } + + void APIC::enable_irq(uint8_t irq) + { + uint32_t gsi = m_irq_overrides[irq]; + + IOAPIC* ioapic = nullptr; + for (IOAPIC& io : m_io_apics) + { + if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs) + { + ioapic = &io; + break; + } + } + ASSERT(ioapic); + + RedirectionEntry redir; + redir.lo_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2); + redir.hi_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2 + 1); + ASSERT(redir.mask); // TODO: handle overlapping interrupts + + redir.vector = IRQ_VECTOR_BASE + irq; + redir.mask = 0; + redir.destination = m_processors.front().apic_id; + + ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword); + ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); + } + + bool APIC::is_in_service(uint8_t irq) + { + uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32; + uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32; + + uint32_t isr = read_from_local_apic(LAPIC_IS_REG + dword * 0x10); + return isr & (1 << bit); + } - ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword); - ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); } - -bool APIC::is_in_service(uint8_t irq) -{ - uint32_t dword = (irq + IRQ_VECTOR_BASE) / 32; - uint32_t bit = (irq + IRQ_VECTOR_BASE) % 32; - - uint32_t isr = read_from_local_apic(LAPIC_IS_REG + dword * 0x10); - return isr & (1 << bit); -} \ No newline at end of file diff --git a/kernel/kernel/Debug.cpp b/kernel/kernel/Debug.cpp index 25e125d78..ed3389225 100644 --- a/kernel/kernel/Debug.cpp +++ b/kernel/kernel/Debug.cpp @@ -76,13 +76,13 @@ namespace Debug void DebugLock::lock() { - if (interrupts_enabled()) + if (Kernel::interrupts_enabled()) s_debug_lock.lock(); } void DebugLock::unlock() { - if (interrupts_enabled()) + if (Kernel::interrupts_enabled()) s_debug_lock.unlock(); } diff --git a/kernel/kernel/Input/PS2Controller.cpp b/kernel/kernel/Input/PS2Controller.cpp index 344853119..ea6887db6 100644 --- a/kernel/kernel/Input/PS2Controller.cpp +++ b/kernel/kernel/Input/PS2Controller.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -11,77 +12,6 @@ namespace Kernel::Input { - namespace PS2 - { - - enum IOPort : uint8_t - { - DATA = 0x60, - STATUS = 0x64, - COMMAND = 0x64, - }; - - enum Status : uint8_t - { - OUTPUT_FULL = (1 << 0), - INPUT_FULL = (1 << 1), - SYSTEM = (1 << 2), - DEVICE_OR_CONTROLLER = (1 << 3), - TIMEOUT_ERROR = (1 << 6), - PARITY_ERROR = (1 << 7), - }; - - enum Config : uint8_t - { - INTERRUPT_FIRST_PORT = (1 << 0), - INTERRUPT_SECOND_PORT = (1 << 1), - SYSTEM_FLAG = (1 << 2), - ZERO1 = (1 << 3), - CLOCK_FIRST_PORT = (1 << 4), - CLOCK_SECOND_PORT = (1 << 5), - TRANSLATION_FIRST_PORT = (1 << 6), - ZERO2 = (1 << 7), - }; - - enum Command : uint8_t - { - READ_CONFIG = 0x20, - WRITE_CONFIG = 0x60, - DISABLE_SECOND_PORT = 0xA7, - ENABLE_SECOND_PORT = 0xA8, - TEST_SECOND_PORT = 0xA9, - TEST_CONTROLLER = 0xAA, - TEST_FIRST_PORT = 0xAB, - DISABLE_FIRST_PORT = 0xAD, - ENABLE_FIRST_PORT = 0xAE, - WRITE_TO_SECOND_PORT = 0xD4, - }; - - enum Response - { - TEST_FIRST_PORT_PASS = 0x00, - TEST_SECOND_PORT_PASS = 0x00, - TEST_CONTROLLER_PASS = 0x55, - SELF_TEST_PASS = 0xAA, - ACK = 0xFA, - }; - - enum DeviceCommand - { - ENABLE_SCANNING = 0xF4, - DISABLE_SCANNING = 0xF5, - IDENTIFY = 0xF2, - RESET = 0xFF, - }; - - enum IRQ - { - DEVICE0 = 1, - DEVICE1 = 12, - }; - - } - static constexpr uint64_t s_device_timeout_ms = 100; static void controller_send_command(PS2::Command command) @@ -136,20 +66,6 @@ namespace Kernel::Input return {}; } - void PS2Controller::device0_irq() - { - auto& controller = PS2Controller::get(); - ASSERT(controller.m_devices[0] != nullptr); - controller.m_devices[0]->on_byte(IO::inb(PS2::IOPort::DATA)); - } - - void PS2Controller::device1_irq() - { - auto& controller = PS2Controller::get(); - ASSERT(controller.m_devices[1] != nullptr); - controller.m_devices[1]->on_byte(IO::inb(PS2::IOPort::DATA)); - } - static PS2Controller* s_instance = nullptr; BAN::ErrorOr PS2Controller::initialize() @@ -256,15 +172,15 @@ namespace Kernel::Input if (m_devices[0]) { - IDT::register_irq_handler(PS2::IRQ::DEVICE0, device0_irq); - InterruptController::get().enable_irq(PS2::IRQ::DEVICE0); + m_devices[0]->set_irq(PS2::IRQ::DEVICE0); + m_devices[0]->enable_interrupt(); config |= PS2::Config::INTERRUPT_FIRST_PORT; DevFileSystem::get().add_device("input0", m_devices[0]); } if (m_devices[1]) { - IDT::register_irq_handler(PS2::IRQ::DEVICE1, device1_irq); - InterruptController::get().enable_irq(PS2::IRQ::DEVICE1); + m_devices[1]->set_irq(PS2::IRQ::DEVICE1); + m_devices[1]->enable_interrupt(); config |= PS2::Config::INTERRUPT_SECOND_PORT; DevFileSystem::get().add_device("input1", m_devices[1]); } diff --git a/kernel/kernel/Input/PS2Keyboard.cpp b/kernel/kernel/Input/PS2Keyboard.cpp index 6623d50df..aba441f11 100644 --- a/kernel/kernel/Input/PS2Keyboard.cpp +++ b/kernel/kernel/Input/PS2Keyboard.cpp @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include #include #include @@ -12,35 +14,6 @@ namespace Kernel::Input { - namespace PS2 - { - - enum Response - { - KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00, - SELF_TEST_PASSED = 0xAA, - ECHO_RESPONSE = 0xEE, - ACK = 0xFA, - RESEND = 0xFE, - KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF, - }; - - enum Scancode - { - SET_SCANCODE_SET1 = 1, - SET_SCANCODE_SET2 = 2, - SET_SCANCODE_SET3 = 3, - }; - - enum Leds - { - SCROLL_LOCK = (1 << 0), - NUM_LOCK = (1 << 1), - CAPS_LOCK = (1 << 2), - }; - - } - BAN::ErrorOr PS2Keyboard::create(PS2Controller& controller) { PS2Keyboard* keyboard = new PS2Keyboard(controller); @@ -57,8 +30,10 @@ namespace Kernel::Input , m_rdev(makedev(DevFileSystem::get().get_next_dev(), 0)) { } - void PS2Keyboard::on_byte(uint8_t byte) + void PS2Keyboard::handle_irq() { + uint8_t byte = IO::inb(PS2::IOPort::DATA); + // NOTE: This implementation does not allow using commands // that respond with more bytes than ACK switch (m_state) @@ -71,11 +46,11 @@ namespace Kernel::Input m_command_queue.pop(); m_state = State::Normal; break; - case PS2::Response::RESEND: + case PS2::KBResponse::RESEND: m_state = State::Normal; break; - case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN1: - case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN2: + case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1: + case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2: dwarnln("Key detection error or internal buffer overrun"); break; default: @@ -97,7 +72,7 @@ namespace Kernel::Input BAN::ErrorOr PS2Keyboard::initialize() { append_command_queue(Command::SET_LEDS, 0x00); - append_command_queue(Command::SCANCODE, PS2::Scancode::SET_SCANCODE_SET2); + append_command_queue(Command::SCANCODE, PS2::KBScancode::SET_SCANCODE_SET2); append_command_queue(Command::ENABLE_SCANNING); return {}; } @@ -234,11 +209,11 @@ namespace Kernel::Input { uint8_t new_leds = 0; if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::ScrollLock) - new_leds |= PS2::Leds::SCROLL_LOCK; + new_leds |= PS2::KBLeds::SCROLL_LOCK; if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::NumLock) - new_leds |= PS2::Leds::NUM_LOCK; + new_leds |= PS2::KBLeds::NUM_LOCK; if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock) - new_leds |= PS2::Leds::CAPS_LOCK; + new_leds |= PS2::KBLeds::CAPS_LOCK; append_command_queue(Command::SET_LEDS, new_leds); } diff --git a/kernel/kernel/InterruptController.cpp b/kernel/kernel/InterruptController.cpp index 45fd79a4b..4b21bc957 100644 --- a/kernel/kernel/InterruptController.cpp +++ b/kernel/kernel/InterruptController.cpp @@ -5,47 +5,73 @@ #include -static InterruptController* s_instance = nullptr; - -InterruptController& InterruptController::get() +namespace Kernel { - ASSERT(s_instance); - return *s_instance; -} -void InterruptController::initialize(bool force_pic) -{ - ASSERT(s_instance == nullptr); + namespace IDT { void register_irq_handler(uint8_t irq, Interruptable*); } - PIC::mask_all(); - PIC::remap(); + static InterruptController* s_instance = nullptr; - if (!force_pic) + void Interruptable::set_irq(int irq) { - s_instance = APIC::create(); - if (s_instance) - { - s_instance->m_using_apic = true; - return; - } + if (m_irq != -1) + IDT::register_irq_handler(m_irq, nullptr); + m_irq = irq; + IDT::register_irq_handler(irq, this); } - dprintln("Using PIC instead of APIC"); - s_instance = PIC::create(); - ASSERT(s_instance); + void Interruptable::enable_interrupt() + { + ASSERT(m_irq != -1); + InterruptController::get().enable_irq(m_irq); + } - s_instance->m_using_apic = false; -} + void Interruptable::disable_interrupt() + { + ASSERT_NOT_REACHED(); + } -void InterruptController::enter_acpi_mode() -{ - if (lai_enable_acpi(m_using_apic ? 1 : 0) != 0) - dwarnln("could not enter acpi mode"); -} + InterruptController& InterruptController::get() + { + ASSERT(s_instance); + return *s_instance; + } + + void InterruptController::initialize(bool force_pic) + { + ASSERT(s_instance == nullptr); + + PIC::mask_all(); + PIC::remap(); + + if (!force_pic) + { + s_instance = APIC::create(); + if (s_instance) + { + s_instance->m_using_apic = true; + return; + } + } + + dprintln("Using PIC instead of APIC"); + s_instance = PIC::create(); + ASSERT(s_instance); + + s_instance->m_using_apic = false; + } + + void InterruptController::enter_acpi_mode() + { + if (lai_enable_acpi(m_using_apic ? 1 : 0) != 0) + dwarnln("could not enter acpi mode"); + } + + bool interrupts_enabled() + { + uintptr_t flags; + asm volatile("pushf; pop %0" : "=r"(flags) :: "memory"); + return flags & (1 << 9); + } -bool interrupts_enabled() -{ - uintptr_t flags; - asm volatile("pushf; pop %0" : "=r"(flags) :: "memory"); - return flags & (1 << 9); } diff --git a/kernel/kernel/Memory/PhysicalRange.cpp b/kernel/kernel/Memory/PhysicalRange.cpp index 4a0bbaf22..e0f9ff76c 100644 --- a/kernel/kernel/Memory/PhysicalRange.cpp +++ b/kernel/kernel/Memory/PhysicalRange.cpp @@ -66,7 +66,7 @@ namespace Kernel ASSERT(page->next == nullptr); // Detatch page from top of the free list - m_free_list = m_free_list->prev ? m_free_list->prev : nullptr; + m_free_list = m_free_list->prev; if (m_free_list) m_free_list->next = nullptr; diff --git a/kernel/kernel/PIC.cpp b/kernel/kernel/PIC.cpp index 6c59d5912..1ac8bf7fc 100644 --- a/kernel/kernel/PIC.cpp +++ b/kernel/kernel/PIC.cpp @@ -17,80 +17,85 @@ #define ICW4_8086 0x01 -PIC* PIC::create() +namespace Kernel { - mask_all(); - remap(); - return new PIC; -} -void PIC::remap() -{ - uint8_t a1 = IO::inb(PIC1_DATA); - uint8_t a2 = IO::inb(PIC2_DATA); - - // Start the initialization sequence (in cascade mode) - IO::outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4); - IO::io_wait(); - IO::outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4); - IO::io_wait(); - - // ICW2 - IO::outb(PIC1_DATA, IRQ_VECTOR_BASE); - IO::io_wait(); - IO::outb(PIC2_DATA, IRQ_VECTOR_BASE + 0x08); - IO::io_wait(); - - // ICW3 - IO::outb(PIC1_DATA, 4); - IO::io_wait(); - IO::outb(PIC2_DATA, 2); - IO::io_wait(); - - // ICW4 - IO::outb(PIC1_DATA, ICW4_8086); - IO::io_wait(); - IO::outb(PIC2_DATA, ICW4_8086); - IO::io_wait(); - - // Restore original masks - IO::outb(PIC1_DATA, a1); - IO::outb(PIC2_DATA, a2); -} - -void PIC::mask_all() -{ - // NOTE: don't mask irq 2 as it is needed for slave pic - IO::outb(PIC1_DATA, 0xFB); - IO::outb(PIC2_DATA, 0xFF); -} - -void PIC::eoi(uint8_t irq) -{ - if (irq >= 8) - IO::outb(PIC2_CMD, PIC_EOI); - IO::outb(PIC1_CMD, PIC_EOI); -} - -void PIC::enable_irq(uint8_t irq) -{ - uint16_t port = PIC1_DATA; - if(irq >= 8) + PIC* PIC::create() { - port = PIC2_DATA; - irq -= 8; + mask_all(); + remap(); + return new PIC; } - IO::outb(port, IO::inb(port) & ~(1 << irq)); -} -bool PIC::is_in_service(uint8_t irq) -{ - uint16_t port = PIC1_CMD; - if (irq >= 8) + void PIC::remap() { - port = PIC2_CMD; - irq -= 8; + uint8_t a1 = IO::inb(PIC1_DATA); + uint8_t a2 = IO::inb(PIC2_DATA); + + // Start the initialization sequence (in cascade mode) + IO::outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4); + IO::io_wait(); + IO::outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4); + IO::io_wait(); + + // ICW2 + IO::outb(PIC1_DATA, IRQ_VECTOR_BASE); + IO::io_wait(); + IO::outb(PIC2_DATA, IRQ_VECTOR_BASE + 0x08); + IO::io_wait(); + + // ICW3 + IO::outb(PIC1_DATA, 4); + IO::io_wait(); + IO::outb(PIC2_DATA, 2); + IO::io_wait(); + + // ICW4 + IO::outb(PIC1_DATA, ICW4_8086); + IO::io_wait(); + IO::outb(PIC2_DATA, ICW4_8086); + IO::io_wait(); + + // Restore original masks + IO::outb(PIC1_DATA, a1); + IO::outb(PIC2_DATA, a2); } - IO::outb(port, PIC_ISR); - return IO::inb(port) & (1 << irq); + + void PIC::mask_all() + { + // NOTE: don't mask irq 2 as it is needed for slave pic + IO::outb(PIC1_DATA, 0xFB); + IO::outb(PIC2_DATA, 0xFF); + } + + void PIC::eoi(uint8_t irq) + { + if (irq >= 8) + IO::outb(PIC2_CMD, PIC_EOI); + IO::outb(PIC1_CMD, PIC_EOI); + } + + void PIC::enable_irq(uint8_t irq) + { + uint16_t port = PIC1_DATA; + if(irq >= 8) + { + port = PIC2_DATA; + irq -= 8; + } + IO::outb(port, IO::inb(port) & ~(1 << irq)); + } + + bool PIC::is_in_service(uint8_t irq) + { + uint16_t port = PIC1_CMD; + if (irq >= 8) + { + port = PIC2_CMD; + irq -= 8; + } + IO::outb(port, PIC_ISR); + return IO::inb(port) & (1 << irq); + } + } diff --git a/kernel/kernel/Storage/ATABus.cpp b/kernel/kernel/Storage/ATABus.cpp index c5dbc415c..dde2bdeb0 100644 --- a/kernel/kernel/Storage/ATABus.cpp +++ b/kernel/kernel/Storage/ATABus.cpp @@ -11,40 +11,6 @@ namespace Kernel { - static void bus_irq_handler0(); - static void bus_irq_handler1(); - - struct BusIRQ - { - ATABus* bus { nullptr }; - void (*handler)() { nullptr }; - uint8_t irq { 0 }; - }; - static BusIRQ s_bus_irqs[] { - { nullptr, bus_irq_handler0, 0 }, - { nullptr, bus_irq_handler1, 0 }, - }; - - static void bus_irq_handler0() { ASSERT(s_bus_irqs[0].bus); s_bus_irqs[0].bus->on_irq(); } - static void bus_irq_handler1() { ASSERT(s_bus_irqs[1].bus); s_bus_irqs[1].bus->on_irq(); } - - static void register_bus_irq_handler(ATABus* bus, uint8_t irq) - { - for (uint8_t i = 0; i < sizeof(s_bus_irqs) / sizeof(BusIRQ); i++) - { - if (s_bus_irqs[i].bus == nullptr) - { - s_bus_irqs[i].bus = bus; - s_bus_irqs[i].irq = irq; - - IDT::register_irq_handler(irq, s_bus_irqs[i].handler); - InterruptController::get().enable_irq(irq); - return; - } - } - ASSERT_NOT_REACHED(); - } - ATABus* ATABus::create(ATAController& controller, uint16_t base, uint16_t ctrl, uint8_t irq) { ATABus* bus = new ATABus(controller, base, ctrl); @@ -55,11 +21,11 @@ namespace Kernel void ATABus::initialize(uint8_t irq) { - register_bus_irq_handler(this, irq); + set_irq(irq); + enable_interrupt(); - uint16_t* identify_buffer = new uint16_t[256]; - ASSERT(identify_buffer); - BAN::ScopeGuard _([identify_buffer] { delete[] identify_buffer; }); + BAN::Vector identify_buffer; + MUST(identify_buffer.resize(256)); for (uint8_t i = 0; i < 2; i++) { @@ -72,11 +38,11 @@ namespace Kernel BAN::ScopeGuard guard([this, i] { m_devices[i] = nullptr; }); - auto type = identify(device, identify_buffer); + auto type = identify(device, identify_buffer.data()); if (type == DeviceType::None) continue; - auto res = device.initialize(type, identify_buffer); + auto res = device.initialize(type, identify_buffer.data()); if (res.is_error()) { dprintln("{}", res.error()); @@ -149,7 +115,7 @@ namespace Kernel return type; } - void ATABus::on_irq() + void ATABus::handle_irq() { ASSERT(!m_has_got_irq); if (io_read(ATA_PORT_STATUS) & ATA_STATUS_ERR) diff --git a/kernel/kernel/Terminal/Serial.cpp b/kernel/kernel/Terminal/Serial.cpp index ec71c97b1..5fd793848 100644 --- a/kernel/kernel/Terminal/Serial.cpp +++ b/kernel/kernel/Terminal/Serial.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -38,37 +37,9 @@ namespace Kernel static BAN::Array s_serial_drivers; static bool s_has_devices { false }; - static BAN::CircularQueue s_com1_input; - static BAN::CircularQueue s_com2_input; static BAN::RefPtr s_com1; static BAN::RefPtr s_com2; - static void irq3_handler() - { - if (!s_serial_drivers[1].is_valid()) - return; - uint8_t ch = IO::inb(COM2_PORT); - if (s_com2_input.full()) - { - dwarnln("COM2 buffer full"); - s_com2_input.pop(); - } - s_com2_input.push(ch); - } - - static void irq4_handler() - { - if (!s_serial_drivers[0].is_valid()) - return; - uint8_t ch = IO::inb(COM1_PORT); - if (s_com1_input.full()) - { - dwarnln("COM1 buffer full"); - s_com1_input.pop(); - } - s_com1_input.push(ch); - } - static dev_t next_rdev() { static dev_t major = DevFileSystem::get().get_next_dev(); @@ -220,14 +191,14 @@ namespace Kernel if (serial.port() == COM1_PORT) { IO::outb(COM1_PORT + 1, 1); - InterruptController::get().enable_irq(COM1_IRQ); - IDT::register_irq_handler(COM1_IRQ, irq4_handler); + tty->set_irq(COM1_IRQ); + tty->enable_interrupt(); } else if (serial.port() == COM2_PORT) { IO::outb(COM2_PORT + 1, 1); - InterruptController::get().enable_irq(COM2_IRQ); - IDT::register_irq_handler(COM2_IRQ, irq3_handler); + tty->set_irq(COM2_IRQ); + tty->enable_interrupt(); } auto ref_ptr = BAN::RefPtr::adopt(tty); @@ -239,41 +210,45 @@ namespace Kernel return ref_ptr; } + void SerialTTY::handle_irq() + { + uint8_t ch = IO::inb(m_serial.port()); + if (m_input.full()) + { + dwarnln("Serial buffer full"); + m_input.pop(); + } + m_input.push(ch); + } + void SerialTTY::update() { if (m_serial.port() != COM1_PORT && m_serial.port() != COM2_PORT) return; - static uint8_t buffer[128]; + uint8_t buffer[128]; - auto update_com = - [&](auto& device, auto& input_queue) + { + CriticalScope _; + if (m_input.empty()) + return; + uint8_t* ptr = buffer; + while (!m_input.empty()) { - if (input_queue.empty()) - return; - uint8_t* ptr = buffer; - while (!input_queue.empty()) - { - *ptr = input_queue.front(); - if (*ptr == '\r') - *ptr = '\n'; - if (*ptr == 127) - *ptr++ = '\b', *ptr++ = ' ', *ptr = '\b'; - input_queue.pop(); - ptr++; - } - *ptr = '\0'; + *ptr = m_input.front(); + if (*ptr == '\r') + *ptr = '\n'; + if (*ptr == 127) + *ptr++ = '\b', *ptr++ = ' ', *ptr = '\b'; + m_input.pop(); + ptr++; + } + *ptr = '\0'; + } - ptr = buffer; - while (*ptr) - device->handle_input_byte(*ptr++); - }; - - CriticalScope _; - if (m_serial.port() == COM1_PORT) - update_com(s_com1, s_com1_input); - if (m_serial.port() == COM2_PORT) - update_com(s_com2, s_com2_input); + const uint8_t* ptr = buffer; + while (*ptr) + handle_input_byte(*ptr++); } uint32_t SerialTTY::width() const diff --git a/kernel/kernel/Timer/HPET.cpp b/kernel/kernel/Timer/HPET.cpp index 130e79759..8813b56e6 100644 --- a/kernel/kernel/Timer/HPET.cpp +++ b/kernel/kernel/Timer/HPET.cpp @@ -131,12 +131,17 @@ namespace Kernel for (int i = 1; i <= header->comparator_count; i++) write_register(HPET_REG_TIMER_CONFIG(i), 0); - IDT::register_irq_handler(irq, [] { Scheduler::get().timer_reschedule(); }); - InterruptController::get().enable_irq(irq); + set_irq(irq); + enable_interrupt(); return {}; } + void HPET::handle_irq() + { + Scheduler::get().timer_reschedule(); + } + uint64_t HPET::ms_since_boot() const { // FIXME: 32 bit CPUs should use 32 bit counter with 32 bit reads diff --git a/kernel/kernel/Timer/PIT.cpp b/kernel/kernel/Timer/PIT.cpp index a5c421bea..b61901edc 100644 --- a/kernel/kernel/Timer/PIT.cpp +++ b/kernel/kernel/Timer/PIT.cpp @@ -4,6 +4,8 @@ #include #include +#define PIT_IRQ 0 + #define TIMER0_CTL 0x40 #define TIMER1_CTL 0x41 #define TIMER2_CTL 0x42 @@ -27,14 +29,6 @@ namespace Kernel { - static volatile uint64_t s_system_time = 0; - - void irq_handler() - { - s_system_time = s_system_time + 1; - Kernel::Scheduler::get().timer_reschedule(); - } - BAN::ErrorOr> PIT::create() { PIT* pit = new PIT(); @@ -53,19 +47,24 @@ namespace Kernel IO::outb(TIMER0_CTL, (timer_reload >> 0) & 0xff); IO::outb(TIMER0_CTL, (timer_reload >> 8) & 0xff); - IDT::register_irq_handler(PIT_IRQ, irq_handler); + set_irq(PIT_IRQ); + enable_interrupt(); + } - InterruptController::get().enable_irq(PIT_IRQ); + void PIT::handle_irq() + { + m_system_time = m_system_time + 1; + Kernel::Scheduler::get().timer_reschedule(); } uint64_t PIT::ms_since_boot() const { - return s_system_time * (MS_PER_S / TICKS_PER_SECOND); + return m_system_time * (MS_PER_S / TICKS_PER_SECOND); } timespec PIT::time_since_boot() const { - uint64_t ticks = s_system_time; + uint64_t ticks = m_system_time; return timespec { .tv_sec = ticks / TICKS_PER_SECOND, .tv_nsec = (long)((ticks % TICKS_PER_SECOND) * (NS_PER_S / TICKS_PER_SECOND))