Compare commits

...

2 Commits

Author SHA1 Message Date
Bananymous 7223e581a2 WindowServer: Fix 32 bit compilation with -Werror
There was a always false statement on 32 bit that the compliler was
warning about.
2024-09-27 15:33:25 +03:00
Bananymous 2d11ce9669 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.
2024-09-27 15:31:31 +03:00
26 changed files with 619 additions and 200 deletions

View File

@ -218,3 +218,179 @@ irq 28
irq 29 irq 29
irq 30 irq 30
irq 31 irq 31
irq 32
irq 33
irq 34
irq 35
irq 36
irq 37
irq 38
irq 39
irq 40
irq 41
irq 42
irq 43
irq 44
irq 45
irq 46
irq 47
irq 48
irq 49
irq 50
irq 51
irq 52
irq 53
irq 54
irq 55
irq 56
irq 57
irq 58
irq 59
irq 60
irq 61
irq 62
irq 63
irq 64
irq 65
irq 66
irq 67
irq 68
irq 69
irq 70
irq 71
irq 72
irq 73
irq 74
irq 75
irq 76
irq 77
irq 78
irq 79
irq 80
irq 81
irq 82
irq 83
irq 84
irq 85
irq 86
irq 87
irq 88
irq 89
irq 90
irq 91
irq 92
irq 93
irq 94
irq 95
irq 96
irq 97
irq 98
irq 99
irq 100
irq 101
irq 102
irq 103
irq 104
irq 105
irq 106
irq 107
irq 108
irq 109
irq 110
irq 111
irq 112
irq 113
irq 114
irq 115
irq 116
irq 117
irq 118
irq 119
irq 120
irq 121
irq 122
irq 123
irq 124
irq 125
irq 126
irq 127
irq 128
irq 129
irq 130
irq 131
irq 132
irq 133
irq 134
irq 135
irq 136
irq 137
irq 138
irq 139
irq 140
irq 141
irq 142
irq 143
irq 144
irq 145
irq 146
irq 147
irq 148
irq 149
irq 150
irq 151
irq 152
irq 153
irq 154
irq 155
irq 156
irq 157
irq 158
irq 159
irq 160
irq 161
irq 162
irq 163
irq 164
irq 165
irq 166
irq 167
irq 168
irq 169
irq 170
irq 171
irq 172
irq 173
irq 174
irq 175
irq 176
irq 177
irq 178
irq 179
irq 180
irq 181
irq 182
irq 183
irq 184
irq 185
irq 186
irq 187
irq 188
irq 189
irq 190
irq 191
irq 192
irq 193
irq 194
irq 195
irq 196
irq 197
irq 198
irq 199
irq 200
irq 201
irq 202
irq 203
irq 204
irq 205
irq 206
irq 207

View File

@ -172,3 +172,179 @@ irq 28
irq 29 irq 29
irq 30 irq 30
irq 31 irq 31
irq 32
irq 33
irq 34
irq 35
irq 36
irq 37
irq 38
irq 39
irq 40
irq 41
irq 42
irq 43
irq 44
irq 45
irq 46
irq 47
irq 48
irq 49
irq 50
irq 51
irq 52
irq 53
irq 54
irq 55
irq 56
irq 57
irq 58
irq 59
irq 60
irq 61
irq 62
irq 63
irq 64
irq 65
irq 66
irq 67
irq 68
irq 69
irq 70
irq 71
irq 72
irq 73
irq 74
irq 75
irq 76
irq 77
irq 78
irq 79
irq 80
irq 81
irq 82
irq 83
irq 84
irq 85
irq 86
irq 87
irq 88
irq 89
irq 90
irq 91
irq 92
irq 93
irq 94
irq 95
irq 96
irq 97
irq 98
irq 99
irq 100
irq 101
irq 102
irq 103
irq 104
irq 105
irq 106
irq 107
irq 108
irq 109
irq 110
irq 111
irq 112
irq 113
irq 114
irq 115
irq 116
irq 117
irq 118
irq 119
irq 120
irq 121
irq 122
irq 123
irq 124
irq 125
irq 126
irq 127
irq 128
irq 129
irq 130
irq 131
irq 132
irq 133
irq 134
irq 135
irq 136
irq 137
irq 138
irq 139
irq 140
irq 141
irq 142
irq 143
irq 144
irq 145
irq 146
irq 147
irq 148
irq 149
irq 150
irq 151
irq 152
irq 153
irq 154
irq 155
irq 156
irq 157
irq 158
irq 159
irq 160
irq 161
irq 162
irq 163
irq 164
irq 165
irq 166
irq 167
irq 168
irq 169
irq 170
irq 171
irq 172
irq 173
irq 174
irq 175
irq 176
irq 177
irq 178
irq 179
irq 180
irq 181
irq 182
irq 183
irq 184
irq 185
irq 186
irq 187
irq 188
irq 189
irq 190
irq 191
irq 192
irq 193
irq 194
irq 195
irq 196
irq 197
irq 198
irq 199
irq 200
irq 201
irq 202
irq 203
irq 204
irq 205
irq 206
irq 207

View File

@ -60,13 +60,15 @@ namespace Kernel
}; };
private: private:
static constexpr uint8_t m_irq_count = IRQ_MSI_BASE - IRQ_VECTOR_BASE;
SpinLock m_lock; SpinLock m_lock;
BAN::Vector<Processor> m_processors; BAN::Vector<Processor> m_processors;
Kernel::paddr_t m_local_apic_paddr = 0; Kernel::paddr_t m_local_apic_paddr = 0;
Kernel::vaddr_t m_local_apic_vaddr = 0; Kernel::vaddr_t m_local_apic_vaddr = 0;
BAN::Vector<IOAPIC> m_io_apics; BAN::Vector<IOAPIC> m_io_apics;
uint8_t m_irq_overrides[0x100] {}; 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 }; uint64_t m_lapic_timer_frequency_hz { 0 };
}; };

View File

@ -7,14 +7,22 @@
#include <stdint.h> #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 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) #if ARCH(x86_64)
struct GateDescriptor struct GateDescriptor
{ {

View File

@ -7,8 +7,6 @@ namespace Kernel
{ {
public: public:
void set_irq(int irq); void set_irq(int irq);
void enable_interrupt();
void disable_interrupt();
virtual void handle_irq() = 0; virtual void handle_irq() = 0;

View File

@ -55,6 +55,15 @@ namespace Kernel::PCI
class Device class Device
{ {
public:
enum class InterruptMechanism
{
NONE,
MSIX,
MSI,
PIN,
};
public: public:
Device() = default; Device() = default;
@ -84,8 +93,9 @@ namespace Kernel::PCI
uint16_t vendor_id() const { return m_vendor_id; } uint16_t vendor_id() const { return m_vendor_id; }
uint16_t device_id() const { return m_device_id; } uint16_t device_id() const { return m_device_id; }
BAN::ErrorOr<void> reserve_irqs(uint8_t count); uint8_t get_interrupt(uint8_t index) const;
uint8_t get_irq(uint8_t index); 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); 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_vendor_id { 0 };
uint16_t m_device_id { 0 }; uint16_t m_device_id { 0 };
uint32_t m_reserved_irqs { 0 }; InterruptMechanism m_interrupt_mechanism { InterruptMechanism::NONE };
uint8_t m_reserved_irq_count { 0 }; 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;
BAN::Optional<uint8_t> m_offset_msi_x; 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_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); 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: private:
PCIManager() : m_bus_pcie_paddr(0) {} PCIManager() : m_bus_pcie_paddr(0) {}
void check_function(uint8_t bus, uint8_t dev, uint8_t func); void check_function(uint8_t bus, uint8_t dev, uint8_t func);
@ -168,10 +181,14 @@ namespace Kernel::PCI
void initialize_impl(); void initialize_impl();
private: private:
static constexpr uint8_t m_msi_count = IRQ_SYSCALL - IRQ_MSI_BASE;
using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>; using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>;
BAN::Array<PCIBus, 256> m_buses; BAN::Array<PCIBus, 256> m_buses;
BAN::Array<paddr_t, 256> m_bus_pcie_paddr; BAN::Array<paddr_t, 256> m_bus_pcie_paddr;
bool m_is_pcie { false }; bool m_is_pcie { false };
SpinLock m_reserved_msi_lock;
BAN::Array<uint8_t, m_msi_count / 8> m_reserved_msi_bitmap;
}; };
} }

View File

@ -13,7 +13,7 @@ namespace Kernel
class NVMeQueue : public Interruptable class NVMeQueue : public Interruptable
{ {
public: 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); uint16_t submit_command(NVMe::SubmissionQueueEntry& sqe);
@ -31,11 +31,11 @@ namespace Kernel
uint32_t m_cq_head { 0 }; uint32_t m_cq_head { 0 };
uint16_t m_cq_valid_phase { 1 }; uint16_t m_cq_valid_phase { 1 };
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
SpinLock m_lock; SpinLock m_lock;
BAN::Atomic<size_t> m_used_mask { 0 }; BAN::Atomic<size_t> m_used_mask { 0 };
BAN::Atomic<size_t> m_done_mask { 0 }; BAN::Atomic<size_t> m_done_mask { 0 };
volatile uint16_t m_status_codes[64] { }; volatile uint16_t m_status_codes[64] { };
static constexpr size_t m_mask_bits = sizeof(size_t) * 8; static constexpr size_t m_mask_bits = sizeof(size_t) * 8;
}; };

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <kernel/Attributes.h> #include <kernel/Attributes.h>
#include <kernel/IDT.h>
#include <stdint.h> #include <stdint.h>
#include <sys/syscall.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) 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; 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; return ret;
} }

View File

@ -703,10 +703,9 @@ acpi_release_global_lock:
); );
} }
set_irq(irq); set_irq(irq);
enable_interrupt(); InterruptController::get().enable_irq(irq);
Process::create_kernel([](void*) { get().acpi_event_task(); }, nullptr); Process::create_kernel([](void*) { get().acpi_event_task(); }, nullptr);
} }

View File

@ -371,7 +371,7 @@ namespace Kernel
| ICR_LO_level_assert | ICR_LO_level_assert
| ICR_LO_trigger_mode_level | ICR_LO_trigger_mode_level
| ICR_LO_destination_shorthand_none | ICR_LO_destination_shorthand_none
| (IRQ_VECTOR_BASE + IRQ_IPI) | IRQ_IPI
); );
} }
@ -388,7 +388,7 @@ namespace Kernel
| ICR_LO_level_assert | ICR_LO_level_assert
| ICR_LO_trigger_mode_level | ICR_LO_trigger_mode_level
| ICR_LO_destination_shorthand_all_excluding_self | ICR_LO_destination_shorthand_all_excluding_self
| (IRQ_VECTOR_BASE + IRQ_IPI) | IRQ_IPI
); );
} }
@ -423,7 +423,7 @@ namespace Kernel
dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz); dprintln("CPU {}: lapic timer frequency: {} Hz", Kernel::Processor::current_id(), m_lapic_timer_frequency_hz);
write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | (IRQ_VECTOR_BASE + IRQ_TIMER)); write_to_local_apic(LAPIC_TIMER_LVT, TimerModePeriodic | IRQ_TIMER);
write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100); write_to_local_apic(LAPIC_TIMER_INITIAL_REG, m_lapic_timer_frequency_hz / 2 / 100);
} }
@ -536,9 +536,9 @@ namespace Kernel
BAN::Optional<uint8_t> APIC::get_free_irq() BAN::Optional<uint8_t> APIC::get_free_irq()
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (int irq = 0; irq <= 0xFF; irq++) for (uint8_t irq = 0; irq < m_irq_count; irq++)
{ {
uint32_t gsi = m_irq_overrides[irq]; const uint8_t gsi = m_irq_overrides[irq];
IOAPIC* ioapic = nullptr; IOAPIC* ioapic = nullptr;
for (IOAPIC& io : m_io_apics) for (IOAPIC& io : m_io_apics)
@ -553,8 +553,8 @@ namespace Kernel
if (!ioapic) if (!ioapic)
continue; continue;
int byte = gsi / 8; const uint8_t byte = gsi / 8;
int bit = gsi % 8; const uint8_t bit = gsi % 8;
if (m_reserved_gsis[byte] & (1 << bit)) if (m_reserved_gsis[byte] & (1 << bit))
continue; continue;
m_reserved_gsis[byte] |= 1 << bit; m_reserved_gsis[byte] |= 1 << bit;

View File

@ -10,7 +10,15 @@
#include <kernel/Timer/PIT.h> #include <kernel/Timer/PIT.h>
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) #define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) #define IRQ_LIST_X X( 0) X( 1) X( 2) X( 3) X( 4) X( 5) X( 6) X( 7) X( 8) X( 9) X( 10) X( 11) X( 12) X( 13) X( 14) X( 15) X( 16) X( 17) X( 18) X( 19) X( 20) X( 21) X( 22) X( 23) X( 24) X( 25) X( 26) X( 27) X( 28) X( 29) X( 30) X( 31) \
X( 32) X( 33) X( 34) X( 35) X( 36) X( 37) X( 38) X( 39) X( 40) X( 41) X( 42) X( 43) X( 44) X( 45) X( 46) X( 47) X( 48) X( 49) X( 50) X( 51) X( 52) X( 53) X( 54) X( 55) X( 56) X( 57) X( 58) X( 59) X( 60) X( 61) X( 62) X( 63) \
X( 64) X( 65) X( 66) X( 67) X( 68) X( 69) X( 70) X( 71) X( 72) X( 73) X( 74) X( 75) X( 76) X( 77) X( 78) X( 79) X( 80) X( 81) X( 82) X( 83) X( 84) X( 85) X( 86) X( 87) X( 88) X( 89) X( 90) X( 91) X( 92) X( 93) X( 94) X( 95) \
X( 96) X( 97) X( 98) X( 99) X(100) X(101) X(102) X(103) X(104) X(105) X(106) X(107) X(108) X(109) X(110) X(111) X(112) X(113) X(114) X(115) X(116) X(117) X(118) X(119) X(120) X(121) X(122) X(123) X(124) X(125) X(126) X(127) \
X(128) X(129) X(130) X(131) X(132) X(133) X(134) X(135) X(136) X(137) X(138) X(139) X(140) X(141) X(142) X(143) X(144) X(145) X(146) X(147) X(148) X(149) X(150) X(151) X(152) X(153) X(154) X(155) X(156) X(157) X(158) X(159) \
X(160) X(161) X(162) X(163) X(164) X(165) X(166) X(167) X(168) X(169) X(170) X(171) X(172) X(173) X(174) X(175) X(176) X(177) X(178) X(179) X(180) X(181) X(182) X(183) X(184) X(185) X(186) X(187) X(188) X(189) X(190) X(191) \
X(192) X(193) X(194) X(195) X(196) X(197) X(198) X(199) X(200) X(201) X(202) X(203) X(204) X(205) X(206) X(207)
static_assert(Kernel::IRQ_SYSCALL == Kernel::IRQ_VECTOR_BASE + 208);
namespace Kernel namespace Kernel
{ {
@ -321,15 +329,15 @@ done:
extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers) extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
{ {
// yield is raised through kernel software interrupt // yield is raised through kernel software interrupt
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD)); ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD - IRQ_VECTOR_BASE));
ASSERT(!GDT::is_user_segment(interrupt_stack->cs)); ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
Processor::scheduler().reschedule(interrupt_stack, interrupt_registers); Processor::scheduler().reschedule(interrupt_stack, interrupt_registers);
} }
extern "C" void cpp_ipi_handler() extern "C" void cpp_ipi_handler()
{ {
ASSERT(InterruptController::get().is_in_service(IRQ_IPI)); ASSERT(InterruptController::get().is_in_service(IRQ_IPI - IRQ_VECTOR_BASE));
InterruptController::get().eoi(IRQ_IPI); InterruptController::get().eoi(IRQ_IPI - IRQ_VECTOR_BASE);
Processor::handle_ipi(); Processor::handle_ipi();
} }
@ -343,8 +351,8 @@ done:
asm volatile("cli; 1: hlt; jmp 1b"); asm volatile("cli; 1: hlt; jmp 1b");
} }
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER)); ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE));
InterruptController::get().eoi(IRQ_TIMER); InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
if (Processor::current_is_bsb()) if (Processor::current_is_bsb())
Process::update_alarm_queue(); Process::update_alarm_queue();
@ -452,11 +460,10 @@ done:
IRQ_LIST_X IRQ_LIST_X
#undef X #undef X
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_YIELD, asm_yield_handler); idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_IPI, asm_ipi_handler); idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_TIMER, asm_timer_handler); idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
idt->register_syscall_handler(IRQ_SYSCALL, asm_syscall_handler);
idt->register_syscall_handler(0x80, asm_syscall_handler);
return idt; return idt;
} }

View File

@ -342,13 +342,13 @@ namespace Kernel::Input
if (m_devices[0]) if (m_devices[0])
{ {
m_devices[0]->set_irq(PS2::IRQ::DEVICE0); m_devices[0]->set_irq(PS2::IRQ::DEVICE0);
m_devices[0]->enable_interrupt(); InterruptController::get().enable_irq(PS2::IRQ::DEVICE0);
config |= PS2::Config::INTERRUPT_FIRST_PORT; config |= PS2::Config::INTERRUPT_FIRST_PORT;
} }
if (m_devices[1]) if (m_devices[1])
{ {
m_devices[1]->set_irq(PS2::IRQ::DEVICE1); m_devices[1]->set_irq(PS2::IRQ::DEVICE1);
m_devices[1]->enable_interrupt(); InterruptController::get().enable_irq(PS2::IRQ::DEVICE1);
config |= PS2::Config::INTERRUPT_SECOND_PORT; config |= PS2::Config::INTERRUPT_SECOND_PORT;
} }

View File

@ -14,15 +14,4 @@ namespace Kernel
Processor::idt().register_irq_handler(irq, this); Processor::idt().register_irq_handler(irq, this);
} }
void Interruptable::enable_interrupt()
{
ASSERT(m_irq != -1);
InterruptController::get().enable_irq(m_irq);
}
void Interruptable::disable_interrupt()
{
ASSERT_NOT_REACHED();
}
} }

View File

@ -245,9 +245,8 @@ namespace Kernel
write32(REG_IMS, IMC_RxQ0); write32(REG_IMS, IMC_RxQ0);
read32(REG_ICR); read32(REG_ICR);
TRY(m_pci_device.reserve_irqs(1)); TRY(m_pci_device.reserve_interrupts(1));
set_irq(m_pci_device.get_irq(0)); m_pci_device.enable_interrupt(0, *this);
Interruptable::enable_interrupt();
return {}; return {};
} }

View File

@ -161,9 +161,8 @@ namespace Kernel
BAN::ErrorOr<void> RTL8169::enable_interrupt() BAN::ErrorOr<void> RTL8169::enable_interrupt()
{ {
TRY(m_pci_device.reserve_irqs(1)); TRY(m_pci_device.reserve_interrupts(1));
set_irq(m_pci_device.get_irq(0)); m_pci_device.enable_interrupt(0, *this);
Interruptable::enable_interrupt();
m_io_bar_region->write16(RTL8169_IO_IMR, m_io_bar_region->write16(RTL8169_IO_IMR,
RTL8169_IR_ROK RTL8169_IR_ROK

View File

@ -175,6 +175,23 @@ namespace Kernel::PCI
} }
} }
BAN::Optional<uint8_t> PCIManager::reserve_msi()
{
SpinLockGuard _(m_reserved_msi_lock);
for (uint8_t i = 0; i < m_msi_count; i++)
{
const uint8_t byte = i / 8;
const uint8_t bit = i % 8;
if (m_reserved_msi_bitmap[byte] & (1 << bit))
continue;
m_reserved_msi_bitmap[byte] |= 1 << bit;
return IRQ_MSI_BASE - IRQ_VECTOR_BASE + i;
}
return {};
}
void PCIManager::initialize_devices(bool disable_usb) void PCIManager::initialize_devices(bool disable_usb)
{ {
for_each_device( for_each_device(
@ -360,63 +377,24 @@ namespace Kernel::PCI
} }
} }
BAN::ErrorOr<void> PCI::Device::reserve_irqs(uint8_t count) uint8_t PCI::Device::get_interrupt(uint8_t index) const
{ {
if (!InterruptController::get().is_using_apic()) ASSERT(m_offset_msi.has_value() || m_offset_msi_x.has_value() || !InterruptController::get().is_using_apic());
ASSERT(index < m_reserved_interrupt_count);
uint8_t count_found = 0;
for (uint32_t irq = 0; irq < 0x100; irq++)
{ {
if (count > 1) const uint8_t byte = irq / 8;
{ const uint8_t bit = irq % 8;
dwarnln("PIC: could not allocate {} interrupts, (currently) only {} supported", count, 1);
return BAN::Error::from_errno(EFAULT); if (m_reserved_interrupts[byte] & (1 << bit))
} count_found++;
enable_pin_interrupts(); if (index + 1 == count_found)
} return irq;
else if (m_offset_msi_x.has_value())
{
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
if (count > (msg_ctrl & 0x7FF) + 1)
{
dwarnln("MSI-X: could not allocate {} interrupts, only {} supported", count, (msg_ctrl & 0x7FF) + 1);
return BAN::Error::from_errno(EFAULT);
}
msg_ctrl |= 1 << 15; // Enable
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
disable_pin_interrupts();
}
else if (m_offset_msi.has_value())
{
if (count > 1)
{
dwarnln("MSI: could not allocate {} interrupts, (currently) only {} supported", count, 1);
return BAN::Error::from_errno(EFAULT);
}
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
msg_ctrl |= 1u << 0; // Enable
write_word(*m_offset_msi + 0x02, msg_ctrl);
disable_pin_interrupts();
}
else
{
dwarnln("Could not reserve interrupt for PCI device. No MSI, MSI-X or interrupt line is used");
return BAN::Error::from_errno(EFAULT);
} }
for (; m_reserved_irq_count < count; m_reserved_irq_count++) ASSERT_NOT_REACHED();
{
auto irq = InterruptController::get().get_free_irq();
if (!irq.has_value())
{
dwarnln("Could not reserve interrupt for PCI {}:{}.{}", m_bus, m_dev, m_func);
return BAN::Error::from_errno(EFAULT);
}
ASSERT(*irq < 32);
ASSERT(!(m_reserved_irqs & (1 << *irq)));
m_reserved_irqs |= 1 << *irq;
}
return {};
} }
static constexpr uint64_t msi_message_address() static constexpr uint64_t msi_message_address()
@ -429,79 +407,145 @@ namespace Kernel::PCI
return (IRQ_VECTOR_BASE + irq) & 0xFF; return (IRQ_VECTOR_BASE + irq) & 0xFF;
} }
uint8_t PCI::Device::get_irq(uint8_t index) void PCI::Device::enable_interrupt(uint8_t index, Interruptable& interruptable)
{ {
ASSERT(m_offset_msi.has_value() || m_offset_msi_x.has_value() || !InterruptController::get().is_using_apic()); const uint8_t irq = get_interrupt(index);
ASSERT(index < m_reserved_irq_count); interruptable.set_irq(irq);
uint8_t count_found = 0; switch (m_interrupt_mechanism)
uint8_t irq = 0xFF;
for (uint8_t i = 0; i < 32; i++)
{ {
if (m_reserved_irqs & (1 << i)) case InterruptMechanism::NONE:
count_found++; ASSERT_NOT_REACHED();
if (count_found > index) case InterruptMechanism::PIN:
enable_pin_interrupts();
write_byte(PCI_REG_IRQ_LINE, irq);
InterruptController::get().enable_irq(irq);
break;
case InterruptMechanism::MSI:
{ {
irq = i; disable_pin_interrupts();
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
msg_ctrl |= 1u << 0; // Enable
write_word(*m_offset_msi + 0x02, msg_ctrl);
const uint64_t msg_addr = msi_message_address();
const uint32_t msg_data = msi_message_data(irq);
if (msg_ctrl & (1 << 7))
{
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
write_dword(*m_offset_msi + 0x08, msg_addr >> 32);
write_word(*m_offset_msi + 0x12, msg_data);
}
else
{
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
write_word(*m_offset_msi + 0x08, msg_data);
}
break;
}
case InterruptMechanism::MSIX:
{
disable_pin_interrupts();
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
msg_ctrl |= 1 << 15; // Enable
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
const uint32_t dword1 = read_dword(*m_offset_msi_x + 0x04);
const uint32_t offset = dword1 & ~7u;
const uint8_t bir = dword1 & 7u;
const uint64_t msg_addr = msi_message_address();
const uint32_t msg_data = msi_message_data(irq);
auto bar = MUST(allocate_bar_region(bir));
ASSERT(bar->type() == BarType::MEM);
auto& msi_x_entry = reinterpret_cast<volatile MSIXEntry*>(bar->vaddr() + offset)[index];
msi_x_entry.msg_addr_low = msg_addr & 0xFFFFFFFF;
msi_x_entry.msg_addr_high = msg_addr >> 32;;
msi_x_entry.msg_data = msg_data;
msi_x_entry.vector_ctrl = msi_x_entry.vector_ctrl & ~1u;
break; break;
} }
} }
ASSERT(irq != 0xFF); }
// Legacy PIC just uses the interrupt line field BAN::ErrorOr<void> PCI::Device::reserve_interrupts(uint8_t count)
if (!InterruptController::get().is_using_apic()) {
{ // FIXME: Allow "late" interrupt reserving
write_byte(PCI_REG_IRQ_LINE, irq); ASSERT(m_reserved_interrupt_count == 0);
return irq;
}
if (m_offset_msi_x.has_value()) const auto mechanism =
{ [&]() -> InterruptMechanism
uint32_t dword0 = read_dword(*m_offset_msi_x);
ASSERT((dword0 & 0xFF) == 0x11);
uint32_t dword1 = read_dword(*m_offset_msi_x + 0x04);
uint32_t offset = dword1 & ~7u;
uint8_t bir = dword1 & 7u;
uint64_t msg_addr = msi_message_address();
uint32_t msg_data = msi_message_data(irq);
auto bar = MUST(allocate_bar_region(bir));
ASSERT(bar->type() == BarType::MEM);
auto& msi_x_entry = reinterpret_cast<volatile MSIXEntry*>(bar->vaddr() + offset)[index];
msi_x_entry.msg_addr_low = msg_addr & 0xFFFFFFFF;
msi_x_entry.msg_addr_high = msg_addr >> 32;;
msi_x_entry.msg_data = msg_data;
msi_x_entry.vector_ctrl = msi_x_entry.vector_ctrl & ~1u;
return irq;
}
if (m_offset_msi.has_value())
{
uint32_t dword0 = read_dword(*m_offset_msi);
ASSERT((dword0 & 0xFF) == 0x05);
uint64_t msg_addr = msi_message_address();
uint32_t msg_data = msi_message_data(irq);
if (dword0 & (1 << 23))
{ {
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF); if (!InterruptController::get().is_using_apic())
write_dword(*m_offset_msi + 0x08, msg_addr >> 32); {
write_word(*m_offset_msi + 0x12, msg_data); // FIXME: support multiple PIN interrupts
} if (count == 1)
else return InterruptMechanism::PIN;
{
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
write_word(*m_offset_msi + 0x08, msg_data);
}
return irq; // MSI cannot be used without LAPIC
return InterruptMechanism::NONE;
}
if (m_offset_msi_x.has_value())
{
const uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
if (count <= (msg_ctrl & 0x7FF) + 1)
return InterruptMechanism::MSIX;
}
if (m_offset_msi.has_value())
{
if (count == 1)
return InterruptMechanism::MSI;
// FIXME: support multiple message
}
// FIXME: support ioapic
return InterruptMechanism::NONE;
}();
auto get_interrupt_func =
[mechanism]() -> BAN::Optional<uint8_t>
{
switch (mechanism)
{
case InterruptMechanism::NONE:
return {};
case InterruptMechanism::PIN:
return InterruptController::get().get_free_irq();
case InterruptMechanism::MSI:
case InterruptMechanism::MSIX:
return PCIManager::get().reserve_msi();
}
ASSERT_NOT_REACHED();
};
for (uint8_t i = 0; i < count; i++)
{
const auto irq = get_interrupt_func();
if (!irq.has_value())
{
dwarnln("Could not reserve {} MSI(-X) interrupts", count);
return BAN::Error::from_errno(EFAULT);
}
const uint8_t byte = irq.value() / 8;
const uint8_t bit = irq.value() % 8;
m_reserved_interrupts[byte] |= 1 << bit;
} }
ASSERT_NOT_REACHED(); m_interrupt_mechanism = mechanism;
m_reserved_interrupt_count = count;
return {};
} }
void PCI::Device::set_command_bits(uint16_t mask) void PCI::Device::set_command_bits(uint16_t mask)

View File

@ -368,7 +368,7 @@ namespace Kernel
// NOTE: This is offset by 2 pointers since interrupt without PL change // NOTE: This is offset by 2 pointers since interrupt without PL change
// does not push SP and SS. This allows accessing "whole" interrupt stack. // does not push SP and SS. This allows accessing "whole" interrupt stack.
:: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)), :: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)),
[yield]"i"(IRQ_VECTOR_BASE + IRQ_YIELD) [yield]"i"(IRQ_YIELD)
: "memory", "rcx" : "memory", "rcx"
); );
#elif ARCH(i686) #elif ARCH(i686)
@ -380,7 +380,7 @@ namespace Kernel
// NOTE: This is offset by 2 pointers since interrupt without PL change // NOTE: This is offset by 2 pointers since interrupt without PL change
// does not push SP and SS. This allows accessing "whole" interrupt stack. // does not push SP and SS. This allows accessing "whole" interrupt stack.
:: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)), :: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)),
[yield]"i"(IRQ_VECTOR_BASE + IRQ_YIELD) [yield]"i"(IRQ_YIELD)
: "memory", "ecx" : "memory", "ecx"
); );
#else #else

View File

@ -25,9 +25,8 @@ namespace Kernel
// Enable interrupts and bus mastering // Enable interrupts and bus mastering
m_pci_device.enable_bus_mastering(); m_pci_device.enable_bus_mastering();
TRY(m_pci_device.reserve_irqs(1)); TRY(m_pci_device.reserve_interrupts(1));
set_irq(m_pci_device.get_irq(0)); m_pci_device.enable_interrupt(0, *this);
enable_interrupt();
abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE; abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE;
m_command_slot_count = ((abar_mem.cap >> 8) & 0x1F) + 1; m_command_slot_count = ((abar_mem.cap >> 8) & 0x1F) + 1;

View File

@ -25,14 +25,13 @@ namespace Kernel
return BAN::Error::from_errno(ENODEV); return BAN::Error::from_errno(ENODEV);
} }
bus->set_irq(irq); bus->set_irq(irq);
InterruptController::get().enable_irq(irq);
TRY(bus->initialize()); TRY(bus->initialize());
return bus; return bus;
} }
BAN::ErrorOr<void> ATABus::initialize() BAN::ErrorOr<void> ATABus::initialize()
{ {
enable_interrupt();
BAN::Vector<uint16_t> identify_buffer; BAN::Vector<uint16_t> identify_buffer;
MUST(identify_buffer.resize(256)); MUST(identify_buffer.resize(256));

View File

@ -82,7 +82,7 @@ namespace Kernel
} }
// One for aq and one for ioq // One for aq and one for ioq
TRY(m_pci_device.reserve_irqs(2)); TRY(m_pci_device.reserve_interrupts(2));
auto& cc = m_controller_registers->cc; auto& cc = m_controller_registers->cc;
@ -237,12 +237,12 @@ namespace Kernel
m_controller_registers->acq = completion_queue->paddr(); m_controller_registers->acq = completion_queue->paddr();
m_controller_registers->asq = submission_queue->paddr(); m_controller_registers->asq = submission_queue->paddr();
uint8_t irq = m_pci_device.get_irq(0); dprintln_if(DEBUG_NVMe, " admin queue using irq {}", m_pci_device.get_interrupt(0));
dprintln_if(DEBUG_NVMe, " admin queue using irq {}", irq);
auto& doorbell = *reinterpret_cast<volatile NVMe::DoorbellRegisters*>(m_bar0->vaddr() + NVMe::ControllerRegisters::SQ0TDBL); auto& doorbell = *reinterpret_cast<volatile NVMe::DoorbellRegisters*>(m_bar0->vaddr() + NVMe::ControllerRegisters::SQ0TDBL);
m_admin_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, admin_queue_depth, irq)); m_admin_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, admin_queue_depth));
m_pci_device.enable_interrupt(0, *m_admin_queue);
return {}; return {};
} }
@ -290,14 +290,14 @@ namespace Kernel
} }
} }
uint8_t irq = m_pci_device.get_irq(1); dprintln_if(DEBUG_NVMe, " io queue using irq {}", m_pci_device.get_interrupt(1));
dprintln_if(DEBUG_NVMe, " io queue using irq {}", irq);
const uint32_t doorbell_stride = 1 << (2 + m_controller_registers->cap.dstrd); const uint32_t doorbell_stride = 1 << (2 + m_controller_registers->cap.dstrd);
const uint32_t doorbell_offset = 2 * doorbell_stride; const uint32_t doorbell_offset = 2 * doorbell_stride;
auto& doorbell = *reinterpret_cast<volatile NVMe::DoorbellRegisters*>(m_bar0->vaddr() + NVMe::ControllerRegisters::SQ0TDBL + doorbell_offset); auto& doorbell = *reinterpret_cast<volatile NVMe::DoorbellRegisters*>(m_bar0->vaddr() + NVMe::ControllerRegisters::SQ0TDBL + doorbell_offset);
m_io_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, queue_elems, irq)); m_io_queue = TRY(BAN::UniqPtr<NVMeQueue>::create(BAN::move(completion_queue), BAN::move(submission_queue), doorbell, queue_elems));
m_pci_device.enable_interrupt(1, *m_io_queue);
return {}; return {};
} }

View File

@ -9,7 +9,7 @@ namespace Kernel
static constexpr uint64_t s_nvme_command_timeout_ms = 1000; static constexpr uint64_t s_nvme_command_timeout_ms = 1000;
static constexpr uint64_t s_nvme_command_poll_timeout_ms = 20; static constexpr uint64_t s_nvme_command_poll_timeout_ms = 20;
NVMeQueue::NVMeQueue(BAN::UniqPtr<Kernel::DMARegion>&& cq, BAN::UniqPtr<Kernel::DMARegion>&& sq, volatile NVMe::DoorbellRegisters& db, uint32_t qdepth, uint8_t irq) NVMeQueue::NVMeQueue(BAN::UniqPtr<Kernel::DMARegion>&& cq, BAN::UniqPtr<Kernel::DMARegion>&& sq, volatile NVMe::DoorbellRegisters& db, uint32_t qdepth)
: m_completion_queue(BAN::move(cq)) : m_completion_queue(BAN::move(cq))
, m_submission_queue(BAN::move(sq)) , m_submission_queue(BAN::move(sq))
, m_doorbell(db) , m_doorbell(db)
@ -17,8 +17,6 @@ namespace Kernel
{ {
for (uint32_t i = qdepth; i < m_mask_bits; i++) for (uint32_t i = qdepth; i < m_mask_bits; i++)
m_used_mask |= (size_t)1 << i; m_used_mask |= (size_t)1 << i;
set_irq(irq);
enable_interrupt();
} }
void NVMeQueue::handle_irq() void NVMeQueue::handle_irq()

View File

@ -188,14 +188,14 @@ namespace Kernel
IO::outb(COM1_PORT + 1, 1); IO::outb(COM1_PORT + 1, 1);
TRY(InterruptController::get().reserve_irq(COM1_IRQ)); TRY(InterruptController::get().reserve_irq(COM1_IRQ));
tty->set_irq(COM1_IRQ); tty->set_irq(COM1_IRQ);
tty->enable_interrupt(); InterruptController::get().enable_irq(COM1_IRQ);
} }
else if (serial.port() == COM2_PORT) else if (serial.port() == COM2_PORT)
{ {
IO::outb(COM2_PORT + 1, 1); IO::outb(COM2_PORT + 1, 1);
TRY(InterruptController::get().reserve_irq(COM2_IRQ)); TRY(InterruptController::get().reserve_irq(COM2_IRQ));
tty->set_irq(COM2_IRQ); tty->set_irq(COM2_IRQ);
tty->enable_interrupt(); InterruptController::get().enable_irq(COM2_IRQ);
} }
auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty); auto ref_ptr = BAN::RefPtr<SerialTTY>::adopt(tty);

View File

@ -223,7 +223,7 @@ namespace Kernel
TRY(InterruptController::get().reserve_irq(0)); TRY(InterruptController::get().reserve_irq(0));
set_irq(0); set_irq(0);
enable_interrupt(); InterruptController::get().enable_irq(0);
return {}; return {};
} }

View File

@ -48,7 +48,7 @@ namespace Kernel
MUST(InterruptController::get().reserve_irq(PIT_IRQ)); MUST(InterruptController::get().reserve_irq(PIT_IRQ));
set_irq(PIT_IRQ); set_irq(PIT_IRQ);
enable_interrupt(); InterruptController::get().enable_irq(PIT_IRQ);
} }
void PIT::handle_irq() void PIT::handle_irq()

View File

@ -204,7 +204,7 @@ namespace Kernel
BAN::ErrorOr<void> XHCIController::initialize_primary_interrupter() BAN::ErrorOr<void> XHCIController::initialize_primary_interrupter()
{ {
TRY(m_pci_device.reserve_irqs(1)); TRY(m_pci_device.reserve_interrupts(1));
auto& runtime = runtime_regs(); auto& runtime = runtime_regs();
@ -227,8 +227,7 @@ namespace Kernel
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable; primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
set_irq(m_pci_device.get_irq(0)); m_pci_device.enable_interrupt(0, *this);
enable_interrupt();
return {}; return {};
} }

View File

@ -92,7 +92,7 @@ Config parse_config()
else if (variable == "corner-radius"_sv) else if (variable == "corner-radius"_sv)
{ {
char* endptr = nullptr; char* endptr = nullptr;
long corner_radius = strtol(value.data(), &endptr, 0); long long corner_radius = strtoll(value.data(), &endptr, 0);
if (corner_radius < 0 || corner_radius == LONG_MAX || corner_radius >= INT32_MAX) if (corner_radius < 0 || corner_radius == LONG_MAX || corner_radius >= INT32_MAX)
dwarnln("invalid corner-radius: '{}'", value); dwarnln("invalid corner-radius: '{}'", value);
else else