-/* $Id: irq.c,v 1.1 2000/07/10 21:54:51 ekohl Exp $
+/*
+ * ReactOS kernel
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: irq.c,v 1.20 2002/05/06 22:25:50 dwelch Exp $
*
- * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/i386/irq.c
* PURPOSE: IRQ handling
/* INCLUDES ****************************************************************/
#include <ddk/ntddk.h>
-
+#include <roscfg.h>
#include <internal/ke.h>
#include <internal/ps.h>
#include <internal/i386/segment.h>
-#include <internal/halio.h>
+#include <internal/pool.h>
+
+#ifdef MP
+#include <internal/hal/mps.h>
+#endif /* MP */
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *****************************************************************/
+#ifdef MP
+
+#define IRQ_BASE FIRST_DEVICE_VECTOR
+#define NR_IRQS 0x100 - 0x30
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
+#define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
+
+#define BUILD_COMMON_INTERRUPT_HANDLER() \
+__asm__( \
+ "_KiCommonInterrupt:\n\t" \
+ "cld\n\t" \
+ "pushl %ds\n\t" \
+ "pushl %es\n\t" \
+ "pushl %fs\n\t" \
+ "pushl %gs\n\t" \
+ "movl $0xceafbeef,%eax\n\t" \
+ "pushl %eax\n\t" \
+ "movl $" STR(KERNEL_DS) ",%eax\n\t" \
+ "movl %eax,%ds\n\t" \
+ "movl %eax,%es\n\t" \
+ "movl $" STR(PCR_SELECTOR) ",%eax\n\t" \
+ "movl %eax,%fs\n\t" \
+ "pushl %esp\n\t" \
+ "pushl %ebx\n\t" \
+ "call _KiInterruptDispatch\n\t" \
+ "popl %eax\n\t" \
+ "popl %eax\n\t" \
+ "popl %eax\n\t" \
+ "popl %gs\n\t" \
+ "popl %fs\n\t" \
+ "popl %es\n\t" \
+ "popl %ds\n\t" \
+ "popa\n\t" \
+ "iret\n\t");
+
+#define BUILD_INTERRUPT_HANDLER(intnum) \
+VOID INT_NAME2(intnum)(VOID); \
+__asm__( \
+ STR(INT_NAME(intnum)) ":\n\t" \
+ "pusha\n\t" \
+ "movl $0x" STR(intnum) ",%ebx\n\t" \
+ "jmp _KiCommonInterrupt");
+
+
+/* Interrupt handlers and declarations */
+
+#define B(x,y) \
+ BUILD_INTERRUPT_HANDLER(x##y)
+
+#define B16(x) \
+ B(x,0) B(x,1) B(x,2) B(x,3) \
+ B(x,4) B(x,5) B(x,6) B(x,7) \
+ B(x,8) B(x,9) B(x,A) B(x,B) \
+ B(x,C) B(x,D) B(x,E) B(x,F)
+
+
+BUILD_COMMON_INTERRUPT_HANDLER()
+B16(3) B16(4) B16(5) B16(6)
+B16(7) B16(8) B16(9) B16(A)
+B16(B) B16(C) B16(D) B16(E)
+B16(F)
+
+#undef B
+#undef B16
+
+
+/* Interrupt handler list */
+
+#define L(x,y) \
+ (ULONG)& INT_NAME2(x##y)
+
+#define L16(x) \
+ L(x,0), L(x,1), L(x,2), L(x,3), \
+ L(x,4), L(x,5), L(x,6), L(x,7), \
+ L(x,8), L(x,9), L(x,A), L(x,B), \
+ L(x,C), L(x,D), L(x,E), L(x,F)
+
+static ULONG irq_handler[NR_IRQS] = {
+ L16(3), L16(4), L16(5), L16(6),
+ L16(7), L16(8), L16(9), L16(A),
+ L16(B), L16(C), L16(D), L16(E),
+ L16(F)
+};
+
+#undef L
+#undef L16
+
+#else /* MP */
+
#define NR_IRQS (16)
#define IRQ_BASE (0x40)
(int)&irq_handler_15,
};
+#endif /* MP */
+
/*
* PURPOSE: Object describing each isr
* NOTE: The data in this table is only modified at passsive level but can
static PKSPIN_LOCK isr_lock[NR_IRQS] = {NULL,};
static KSPIN_LOCK isr_table_lock = {0,};
+#define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
+#define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R')
/* FUNCTIONS ****************************************************************/
VOID KeInitInterrupts (VOID)
{
int i;
-
- DPRINT("KeInitInterrupts ()\n",0);
-
+
+#ifdef MP
+
/*
- * First mask off all interrupts from pic
+ * Setup the IDT entries to point to the interrupt handlers
*/
- outb(0x21,0xff);
- outb(0xa1,0xff);
-
-
+ for (i=0;i<NR_IRQS;i++)
+ {
+ KiIdt[0x30+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
+ KiIdt[0x30+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
+ I486_INTERRUPT_GATE;
+ InitializeListHead(&isr_table[i]);
+ }
+
+#else
+
/*
* Setup the IDT entries to point to the interrupt handlers
*/
I486_INTERRUPT_GATE;
InitializeListHead(&isr_table[i]);
}
+
+#endif
+
}
+typedef struct _KIRQ_TRAPFRAME
+{
+ ULONG Magic;
+ ULONG Fs;
+ ULONG Es;
+ ULONG Ds;
+ ULONG Eax;
+ ULONG Ecx;
+ ULONG Edx;
+ ULONG Ebx;
+ ULONG Esp;
+ ULONG Ebp;
+ ULONG Esi;
+ ULONG Edi;
+ ULONG Eip;
+ ULONG Cs;
+ ULONG Eflags;
+} KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
+
+#ifdef DBG
+
+VOID
+KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
+ PKTRAP_FRAME TrapFrame)
+{
+ TrapFrame->Fs = IrqTrapFrame->Fs;
+ TrapFrame->Fs = IrqTrapFrame->Es;
+ TrapFrame->Ds = IrqTrapFrame->Ds;
+ TrapFrame->Eax = IrqTrapFrame->Eax;
+ TrapFrame->Ecx = IrqTrapFrame->Ecx;
+ TrapFrame->Edx = IrqTrapFrame->Edx;
+ TrapFrame->Ebx = IrqTrapFrame->Ebx;
+ TrapFrame->Esp = IrqTrapFrame->Esp;
+ TrapFrame->Ebp = IrqTrapFrame->Ebp;
+ TrapFrame->Esi = IrqTrapFrame->Esi;
+ TrapFrame->Edi = IrqTrapFrame->Edi;
+ TrapFrame->Eip = IrqTrapFrame->Eip;
+ TrapFrame->Cs = IrqTrapFrame->Cs;
+ TrapFrame->Eflags = IrqTrapFrame->Eflags;
+}
+
+#endif
-VOID KiInterruptDispatch (ULONG irq)
+#ifdef MP
+
+VOID
+KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
/*
* FUNCTION: Calls the irq specific handler for an irq
* ARGUMENTS:
- * irq = IRQ that has interrupted
+ * Vector = Interrupt vector
+ * Trapframe = CPU context
*/
{
KIRQL old_level;
PKINTERRUPT isr;
PLIST_ENTRY current;
-
-// DbgPrint("{");
-
+ ULONG irq;
+
+#ifdef DBG
+
+ KTRAP_FRAME KernelTrapFrame;
+
+ KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
+ KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
+
+#endif /* DBG */
+
+ DPRINT("I(%d) ", Vector);
+
/*
* Notify the rest of the kernel of the raised irq level
*/
- old_level = KeGetCurrentIrql();
- if (irq != 0)
- {
- DPRINT("old_level %d\n",old_level);
- }
- KeSetCurrentIrql(HIGH_LEVEL - irq);
-
+ HalBeginSystemInterrupt (Vector,
+ VECTOR2IRQL(Vector),
+ &old_level);
+
+ irq = VECTOR2IRQ(Vector);
+
/*
* Enable interrupts
* NOTE: Only higher priority interrupts will get through
*/
__asm__("sti\n\t");
- if (irq==0)
- {
- KiUpdateSystemTime();
- }
+ if (irq == 0)
+ {
+ if (KeGetCurrentProcessorNumber() == 0)
+ {
+ KiUpdateSystemTime(old_level, Trapframe->Eip);
+ }
+ }
else
- {
- DPRINT("KiInterruptDispatch(irq %d)\n",irq);
+ {
+ DPRINT("KiInterruptDispatch(Vector %d)\n", Vector);
/*
* Iterate the list until one of the isr tells us its device interrupted
*/
current = isr_table[irq].Flink;
isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
- DPRINT("current %x isr %x\n",current,isr);
+ //DPRINT("current %x isr %x\n",current,isr);
while (current!=(&isr_table[irq]) &&
!isr->ServiceRoutine(isr,isr->ServiceContext))
{
current = current->Flink;
isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
- DPRINT("current %x isr %x\n",current,isr);
+ //DPRINT("current %x isr %x\n",current,isr);
}
- }
-
+ }
/*
* Disable interrupts
*/
__asm__("cli\n\t");
-
- /*
- * Send EOI to the PIC
- */
- outb(0x20,0x20);
- if (irq>=8)
- {
- outb(0xa0,0x20);
- }
-
+
/*
* Unmask the related irq
*/
- if (irq<8)
- {
- outb(0x21,inb(0x21)&(~(1<<irq)));
- }
- else
- {
- outb(0xa1,inb(0xa1)&(~(1<<(irq-8))));
- }
-
+ HalEnableSystemInterrupt (Vector, 0, 0);
+
/*
* If the processor level will drop below dispatch level on return then
* issue a DPC queue drain interrupt
*/
+
+ __asm__("sti\n\t");
+
if (old_level < DISPATCH_LEVEL)
{
- KeSetCurrentIrql(DISPATCH_LEVEL);
- __asm__("sti\n\t");
- if (irq == 0)
+ HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
+
+ if (KeGetCurrentThread() != NULL)
{
- KeExpireTimers();
+ KeGetCurrentThread()->LastEip = Trapframe->Eip;
}
KiDispatchInterrupt();
- PsDispatchThread(THREAD_STATE_RUNNABLE);
+ if (KeGetCurrentThread() != NULL &&
+ KeGetCurrentThread()->Alerted[1] != 0 &&
+ Trapframe->Cs != KERNEL_CS)
+ {
+ HalEndSystemInterrupt (APC_LEVEL, 0);
+ KiDeliverNormalApc();
+ }
+ }
+
+ HalEndSystemInterrupt (old_level, 0);
+}
+
+#else /* MP */
+
+VOID STDCALL
+KiInterruptDispatch2 (ULONG Irq, KIRQL old_level)
+/*
+ * FUNCTION: Calls all the interrupt handlers for a given irq.
+ * ARGUMENTS:
+ * Irq - The number of the irq to call handlers for.
+ * old_level - The irql of the processor when the irq took place.
+ * NOTES: Must be called at DIRQL.
+ */
+{
+ PKINTERRUPT isr;
+ PLIST_ENTRY current;
+
+ if (Irq == 0)
+ {
+ KiUpdateSystemTime(old_level, 0);
+ }
+ else
+ {
+ /*
+ * Iterate the list until one of the isr tells us its device interrupted
+ */
+ current = isr_table[Irq].Flink;
+ isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
+ while (current != &isr_table[Irq] &&
+ !isr->ServiceRoutine(isr, isr->ServiceContext))
+ {
+ current = current->Flink;
+ isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
+ }
+ }
+}
+
+VOID
+KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
+/*
+ * FUNCTION: Calls the irq specific handler for an irq
+ * ARGUMENTS:
+ * irq = IRQ that has interrupted
+ */
+{
+ KIRQL old_level;
+
+ /*
+ * At this point we have interrupts disabled, nothing has been done to
+ * the PIC.
+ */
+
+ /*
+ * Notify the rest of the kernel of the raised irq level. For the
+ * default HAL this will send an EOI to the PIC and alter the IRQL.
+ */
+ if (!HalBeginSystemInterrupt (irq + IRQ_BASE,
+ PROFILE_LEVEL - irq,
+ &old_level))
+ {
+ return;
}
- else
+
+ /*
+ * Enable interrupts
+ * NOTE: Only higher priority interrupts will get through
+ */
+ __asm__("sti\n\t");
+
+ /*
+ * Actually call the ISR.
+ */
+ KiInterruptDispatch2(irq, old_level);
+
+ /*
+ * End the system interrupt.
+ */
+ HalEndSystemInterrupt (old_level, 0);
+
+ /*
+ * Maybe do a reschedule as well.
+ */
+ if (old_level < DISPATCH_LEVEL && irq == 0)
{
-// DbgPrint("$");
+ PsDispatchThread(THREAD_STATE_RUNNABLE);
}
- KeSetCurrentIrql(old_level);
-// DbgPrint("}");
}
+#endif /* MP */
-static VOID KeDumpIrqList(VOID)
+static VOID
+KeDumpIrqList(VOID)
{
PKINTERRUPT current;
PLIST_ENTRY current_entry;
{
DPRINT("For irq %x ",i);
current_entry = isr_table[i].Flink;
- current = CONTAINING_RECORD(current,KINTERRUPT,Entry);
+ current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
while (current_entry!=(&isr_table[i]))
{
DPRINT("Isr %x ",current);
}
}
-
-NTSTATUS
-STDCALL
+NTSTATUS STDCALL
KeConnectInterrupt(PKINTERRUPT InterruptObject)
{
KIRQL oldlvl;
}
else
{
- isr_lock[Vector]=ExAllocatePool(NonPagedPool,sizeof(KSPIN_LOCK));
+ isr_lock[Vector] =
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK),
+ TAG_ISR_LOCK);
KeInitializeSpinLock(isr_lock[Vector]);
}
}
-VOID
-STDCALL
+VOID STDCALL
KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
/*
* FUNCTION: Releases a drivers isr
}
-NTSTATUS
-STDCALL
+NTSTATUS STDCALL
IoConnectInterrupt(PKINTERRUPT* InterruptObject,
- PKSERVICE_ROUTINE ServiceRoutine,
- PVOID ServiceContext,
- PKSPIN_LOCK SpinLock,
- ULONG Vector,
- KIRQL Irql,
- KIRQL SynchronizeIrql,
- KINTERRUPT_MODE InterruptMode,
- BOOLEAN ShareVector,
- KAFFINITY ProcessorEnableMask,
- BOOLEAN FloatingSave)
+ PKSERVICE_ROUTINE ServiceRoutine,
+ PVOID ServiceContext,
+ PKSPIN_LOCK SpinLock,
+ ULONG Vector,
+ KIRQL Irql,
+ KIRQL SynchronizeIrql,
+ KINTERRUPT_MODE InterruptMode,
+ BOOLEAN ShareVector,
+ KAFFINITY ProcessorEnableMask,
+ BOOLEAN FloatingSave)
/*
* FUNCTION: Registers a driver's isr to be called when its device interrupts
* ARGUMENTS:
/*
* Initialize interrupt object
*/
- Interrupt=ExAllocatePool(NonPagedPool,sizeof(KINTERRUPT));
+ Interrupt=ExAllocatePoolWithTag(NonPagedPool,sizeof(KINTERRUPT),
+ TAG_KINTERRUPT);
if (Interrupt==NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
-VOID
-STDCALL
+VOID STDCALL
IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
/*
* FUNCTION: Releases a drivers isr
* InterruptObject = isr to release
*/
{
- KeDisconnectInterrupt(InterruptObject);
- ExFreePool(InterruptObject);
+ KeDisconnectInterrupt(InterruptObject);
+ ExFreePool(InterruptObject);
}
/* EOF */