Kernel: Fix interrupt system
I had not understood how MSIs work and I was unnecessarily routing them through IOAPIC. This is not necessary and should not be done :D Also MSIs were reserving interrupts that IOAPIC was capable of generating. Now IOAPIC and MSIs use different set of interrupts so IOAPIC can use more interrupts if needed.
This commit is contained in:
@@ -60,13 +60,15 @@ namespace Kernel
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr uint8_t m_irq_count = IRQ_MSI_BASE - IRQ_VECTOR_BASE;
|
||||
|
||||
SpinLock m_lock;
|
||||
BAN::Vector<Processor> m_processors;
|
||||
Kernel::paddr_t m_local_apic_paddr = 0;
|
||||
Kernel::vaddr_t m_local_apic_vaddr = 0;
|
||||
BAN::Vector<IOAPIC> m_io_apics;
|
||||
uint8_t m_irq_overrides[0x100] {};
|
||||
uint8_t m_reserved_gsis[0x100 / 8] {};
|
||||
uint8_t m_reserved_gsis[m_irq_count / 8] {};
|
||||
uint64_t m_lapic_timer_frequency_hz { 0 };
|
||||
};
|
||||
|
||||
|
||||
@@ -7,14 +7,22 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
||||
constexpr uint8_t IRQ_YIELD = 32;
|
||||
constexpr uint8_t IRQ_IPI = 33;
|
||||
constexpr uint8_t IRQ_TIMER = 34;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
// IDT entries
|
||||
// 0x00->0x1F (32): ISR
|
||||
// 0x20->0x7F (96): PIC/IOAPIC
|
||||
// 0x80->0xEF (112): MSI
|
||||
// 0xF0->0xFE (15): internal
|
||||
|
||||
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
|
||||
constexpr uint8_t IRQ_MSI_BASE = 0x80;
|
||||
constexpr uint8_t IRQ_SYSCALL = 0xF0;
|
||||
constexpr uint8_t IRQ_YIELD = 0xF1;
|
||||
constexpr uint8_t IRQ_IPI = 0xF2;
|
||||
constexpr uint8_t IRQ_TIMER = 0xF3;
|
||||
|
||||
#if ARCH(x86_64)
|
||||
struct GateDescriptor
|
||||
{
|
||||
|
||||
@@ -7,8 +7,6 @@ namespace Kernel
|
||||
{
|
||||
public:
|
||||
void set_irq(int irq);
|
||||
void enable_interrupt();
|
||||
void disable_interrupt();
|
||||
|
||||
virtual void handle_irq() = 0;
|
||||
|
||||
|
||||
@@ -55,6 +55,15 @@ namespace Kernel::PCI
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
enum class InterruptMechanism
|
||||
{
|
||||
NONE,
|
||||
MSIX,
|
||||
MSI,
|
||||
PIN,
|
||||
};
|
||||
|
||||
public:
|
||||
Device() = default;
|
||||
|
||||
@@ -84,8 +93,9 @@ namespace Kernel::PCI
|
||||
uint16_t vendor_id() const { return m_vendor_id; }
|
||||
uint16_t device_id() const { return m_device_id; }
|
||||
|
||||
BAN::ErrorOr<void> reserve_irqs(uint8_t count);
|
||||
uint8_t get_irq(uint8_t index);
|
||||
uint8_t get_interrupt(uint8_t index) const;
|
||||
BAN::ErrorOr<void> reserve_interrupts(uint8_t count);
|
||||
void enable_interrupt(uint8_t index, Interruptable&);
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
|
||||
|
||||
@@ -123,8 +133,9 @@ namespace Kernel::PCI
|
||||
uint16_t m_vendor_id { 0 };
|
||||
uint16_t m_device_id { 0 };
|
||||
|
||||
uint32_t m_reserved_irqs { 0 };
|
||||
uint8_t m_reserved_irq_count { 0 };
|
||||
InterruptMechanism m_interrupt_mechanism { InterruptMechanism::NONE };
|
||||
uint8_t m_reserved_interrupts[0x100 / 8] {};
|
||||
uint8_t m_reserved_interrupt_count { 0 };
|
||||
|
||||
BAN::Optional<uint8_t> m_offset_msi;
|
||||
BAN::Optional<uint8_t> m_offset_msi_x;
|
||||
@@ -159,6 +170,8 @@ namespace Kernel::PCI
|
||||
void write_config_word(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint16_t value);
|
||||
void write_config_byte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t offset, uint8_t value);
|
||||
|
||||
BAN::Optional<uint8_t> reserve_msi();
|
||||
|
||||
private:
|
||||
PCIManager() : m_bus_pcie_paddr(0) {}
|
||||
void check_function(uint8_t bus, uint8_t dev, uint8_t func);
|
||||
@@ -168,10 +181,14 @@ namespace Kernel::PCI
|
||||
void initialize_impl();
|
||||
|
||||
private:
|
||||
static constexpr uint8_t m_msi_count = IRQ_SYSCALL - IRQ_MSI_BASE;
|
||||
using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>;
|
||||
BAN::Array<PCIBus, 256> m_buses;
|
||||
BAN::Array<paddr_t, 256> m_bus_pcie_paddr;
|
||||
bool m_is_pcie { false };
|
||||
BAN::Array<PCIBus, 256> m_buses;
|
||||
BAN::Array<paddr_t, 256> m_bus_pcie_paddr;
|
||||
bool m_is_pcie { false };
|
||||
|
||||
SpinLock m_reserved_msi_lock;
|
||||
BAN::Array<uint8_t, m_msi_count / 8> m_reserved_msi_bitmap;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Kernel
|
||||
class NVMeQueue : public Interruptable
|
||||
{
|
||||
public:
|
||||
NVMeQueue(BAN::UniqPtr<Kernel::DMARegion>&& cq, BAN::UniqPtr<Kernel::DMARegion>&& sq, volatile NVMe::DoorbellRegisters& db, uint32_t qdepth, uint8_t irq);
|
||||
NVMeQueue(BAN::UniqPtr<Kernel::DMARegion>&& cq, BAN::UniqPtr<Kernel::DMARegion>&& sq, volatile NVMe::DoorbellRegisters& db, uint32_t qdepth);
|
||||
|
||||
uint16_t submit_command(NVMe::SubmissionQueueEntry& sqe);
|
||||
|
||||
@@ -31,11 +31,11 @@ namespace Kernel
|
||||
uint32_t m_cq_head { 0 };
|
||||
uint16_t m_cq_valid_phase { 1 };
|
||||
|
||||
ThreadBlocker m_thread_blocker;
|
||||
SpinLock m_lock;
|
||||
BAN::Atomic<size_t> m_used_mask { 0 };
|
||||
BAN::Atomic<size_t> m_done_mask { 0 };
|
||||
volatile uint16_t m_status_codes[64] { };
|
||||
ThreadBlocker m_thread_blocker;
|
||||
SpinLock m_lock;
|
||||
BAN::Atomic<size_t> m_used_mask { 0 };
|
||||
BAN::Atomic<size_t> m_done_mask { 0 };
|
||||
volatile uint16_t m_status_codes[64] { };
|
||||
|
||||
static constexpr size_t m_mask_bits = sizeof(size_t) * 8;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Attributes.h>
|
||||
#include <kernel/IDT.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
@@ -10,7 +11,16 @@ namespace Kernel
|
||||
ALWAYS_INLINE long syscall(int syscall, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0, uintptr_t arg4 = 0, uintptr_t arg5 = 0)
|
||||
{
|
||||
long ret;
|
||||
asm volatile("int $0x80" : "=a"(ret) : "a"(syscall), "b"((uintptr_t)arg1), "c"((uintptr_t)arg2), "d"((uintptr_t)arg3), "S"((uintptr_t)arg4), "D"((uintptr_t)arg5) : "memory");
|
||||
asm volatile("int %[irq]"
|
||||
: "=a"(ret)
|
||||
: [irq]"i"(IRQ_SYSCALL)
|
||||
, "a"(syscall)
|
||||
, "b"((uintptr_t)arg1)
|
||||
, "c"((uintptr_t)arg2)
|
||||
, "d"((uintptr_t)arg3)
|
||||
, "S"((uintptr_t)arg4)
|
||||
, "D"((uintptr_t)arg5)
|
||||
: "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user