introduce irqHandlersLock

This commit is contained in:
nakst 2021-09-17 17:23:19 +01:00
parent 4f8618bd23
commit be09af9014
1 changed files with 24 additions and 13 deletions

View File

@ -95,6 +95,7 @@ struct IRQHandler {
MSIHandler msiHandlers[INTERRUPT_VECTOR_MSI_COUNT]; MSIHandler msiHandlers[INTERRUPT_VECTOR_MSI_COUNT];
IRQHandler irqHandlers[0x40]; IRQHandler irqHandlers[0x40];
KSpinlock irqHandlersLock; // Also for msiHandlers.
extern uintptr_t bootloaderInformationOffset; extern uintptr_t bootloaderInformationOffset;
extern "C" bool simdSSE3Support; extern "C" bool simdSSE3Support;
@ -693,14 +694,14 @@ bool SetupInterruptRedirectionEntry(uintptr_t _line) {
} }
void KUnregisterMSI(uintptr_t tag) { void KUnregisterMSI(uintptr_t tag) {
KSpinlockAcquire(&scheduler.lock); KSpinlockAcquire(&irqHandlersLock);
EsDefer(KSpinlockRelease(&scheduler.lock)); EsDefer(KSpinlockRelease(&irqHandlersLock));
msiHandlers[tag].callback = nullptr; msiHandlers[tag].callback = nullptr;
} }
KMSIInformation KRegisterMSI(KIRQHandler handler, void *context, const char *cOwnerName) { KMSIInformation KRegisterMSI(KIRQHandler handler, void *context, const char *cOwnerName) {
KSpinlockAcquire(&scheduler.lock); KSpinlockAcquire(&irqHandlersLock);
EsDefer(KSpinlockRelease(&scheduler.lock)); EsDefer(KSpinlockRelease(&irqHandlersLock));
for (uintptr_t i = 0; i < INTERRUPT_VECTOR_MSI_COUNT; i++) { for (uintptr_t i = 0; i < INTERRUPT_VECTOR_MSI_COUNT; i++) {
if (msiHandlers[i].callback) continue; if (msiHandlers[i].callback) continue;
@ -735,6 +736,8 @@ bool KRegisterIRQ(intptr_t line, KIRQHandler handler, void *context, const char
if (line > 0x20 || line < -1) KernelPanic("KRegisterIRQ - Unexpected IRQ %d\n", line); if (line > 0x20 || line < -1) KernelPanic("KRegisterIRQ - Unexpected IRQ %d\n", line);
bool found = false; bool found = false;
KSpinlockAcquire(&irqHandlersLock);
for (uintptr_t i = 0; i < sizeof(irqHandlers) / sizeof(irqHandlers[0]); i++) { for (uintptr_t i = 0; i < sizeof(irqHandlers) / sizeof(irqHandlers[0]); i++) {
if (!irqHandlers[i].callback) { if (!irqHandlers[i].callback) {
found = true; found = true;
@ -747,6 +750,8 @@ bool KRegisterIRQ(intptr_t line, KIRQHandler handler, void *context, const char
} }
} }
KSpinlockRelease(&irqHandlersLock);
if (!found) { if (!found) {
KernelLog(LOG_ERROR, "Arch", "too many IRQ handlers", "The limit of IRQ handlers was reached (%d), and the handler for '%z' was not registered.\n", KernelLog(LOG_ERROR, "Arch", "too many IRQ handlers", "The limit of IRQ handlers was reached (%d), and the handler for '%z' was not registered.\n",
sizeof(irqHandlers) / sizeof(irqHandlers[0]), cOwnerName); sizeof(irqHandlers) / sizeof(irqHandlers[0]), cOwnerName);
@ -1080,13 +1085,15 @@ extern "C" void InterruptHandler(InterruptContext *context) {
acpi.lapic.EndOfInterrupt(); acpi.lapic.EndOfInterrupt();
} else if (interrupt >= INTERRUPT_VECTOR_MSI_START && interrupt < INTERRUPT_VECTOR_MSI_START + INTERRUPT_VECTOR_MSI_COUNT && local) { } else if (interrupt >= INTERRUPT_VECTOR_MSI_START && interrupt < INTERRUPT_VECTOR_MSI_START + INTERRUPT_VECTOR_MSI_COUNT && local) {
MSIHandler *handler = &msiHandlers[interrupt - INTERRUPT_VECTOR_MSI_START]; KSpinlockAcquire(&irqHandlersLock);
MSIHandler handler = msiHandlers[interrupt - INTERRUPT_VECTOR_MSI_START];
KSpinlockRelease(&irqHandlersLock);
local->irqSwitchThread = false; local->irqSwitchThread = false;
if (!handler->callback) { if (!handler.callback) {
KernelLog(LOG_ERROR, "Arch", "unexpected MSI", "Unexpected MSI vector %X (no handler).\n", interrupt); KernelLog(LOG_ERROR, "Arch", "unexpected MSI", "Unexpected MSI vector %X (no handler).\n", interrupt);
} else { } else {
handler->callback(interrupt - INTERRUPT_VECTOR_MSI_START, handler->context); handler.callback(interrupt - INTERRUPT_VECTOR_MSI_START, handler.context);
} }
acpi.lapic.EndOfInterrupt(); acpi.lapic.EndOfInterrupt();
@ -1110,12 +1117,13 @@ extern "C" void InterruptHandler(InterruptContext *context) {
uintptr_t line = interrupt - IRQ_BASE; uintptr_t line = interrupt - IRQ_BASE;
KernelLog(LOG_VERBOSE, "Arch", "IRQ start", "IRQ start %d.\n", line); KernelLog(LOG_VERBOSE, "Arch", "IRQ start", "IRQ start %d.\n", line);
KSpinlockAcquire(&irqHandlersLock);
for (uintptr_t i = 0; i < sizeof(irqHandlers) / sizeof(irqHandlers[0]); i++) { for (uintptr_t i = 0; i < sizeof(irqHandlers) / sizeof(irqHandlers[0]); i++) {
IRQHandler *handler = &irqHandlers[i]; IRQHandler handler = irqHandlers[i];
if (!handler->callback) continue; if (!handler.callback) continue;
if (handler->line == -1) { if (handler.line == -1) {
// Before we get the actual IRQ line information from ACPI (which might take it a while), // Before we get the actual IRQ line information from ACPI (which might take it a while),
// only test that the IRQ is in the correct range for PCI interrupts. // only test that the IRQ is in the correct range for PCI interrupts.
// This is a bit slower because we have to dispatch the interrupt to more drivers, // This is a bit slower because we have to dispatch the interrupt to more drivers,
@ -1125,21 +1133,24 @@ extern "C" void InterruptHandler(InterruptContext *context) {
if (line != 9 && line != 10 && line != 11) { if (line != 9 && line != 10 && line != 11) {
continue; continue;
} else { } else {
uint8_t mappedLine = pciIRQLines[handler->pciDevice->slot][handler->pciDevice->interruptPin - 1]; uint8_t mappedLine = pciIRQLines[handler.pciDevice->slot][handler.pciDevice->interruptPin - 1];
if (mappedLine && line != mappedLine) { if (mappedLine && line != mappedLine) {
continue; continue;
} }
} }
} else { } else {
if ((uintptr_t) handler->line != line) { if ((uintptr_t) handler.line != line) {
continue; continue;
} }
} }
handler->callback(interrupt - IRQ_BASE, handler->context); KSpinlockRelease(&irqHandlersLock);
handler.callback(interrupt - IRQ_BASE, handler.context);
KSpinlockAcquire(&irqHandlersLock);
} }
KSpinlockRelease(&irqHandlersLock);
KernelLog(LOG_VERBOSE, "Arch", "IRQ end", "IRQ end %d.\n", line); KernelLog(LOG_VERBOSE, "Arch", "IRQ end", "IRQ end %d.\n", line);
GetLocalStorage()->inIRQ = false; GetLocalStorage()->inIRQ = false;