Added some comments.
[reactos.git] / reactos / ntoskrnl / ke / i386 / irq.c
index 4cf91e7..a376692 100644 (file)
@@ -1,6 +1,23 @@
-/* $Id: irq.c,v 1.6 2001/03/07 16:48:43 dwelch 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/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)
 
@@ -70,6 +184,8 @@ static unsigned int irq_handler[NR_IRQS]=
                 (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
@@ -91,9 +207,22 @@ static KSPIN_LOCK isr_table_lock = {0,};
 VOID KeInitInterrupts (VOID)
 {
    int i;
-   
-   DPRINT("KeInitInterrupts ()\n",0);
-   
+
+#ifdef MP
+
+   /*
+    * Setup the IDT entries to point to the interrupt handlers
+    */
+   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
     */
@@ -104,6 +233,9 @@ VOID KeInitInterrupts (VOID)
                            I486_INTERRUPT_GATE;
        InitializeListHead(&isr_table[i]);
      }
+
+#endif
+
 }
 
 typedef struct _KIRQ_TRAPFRAME
@@ -125,83 +257,123 @@ typedef struct _KIRQ_TRAPFRAME
    ULONG Eflags;
 } KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
 
-VOID 
-KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME 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
+
+#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
     */
-   HalBeginSystemInterrupt (irq+IRQ_BASE,
-                           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");
-   
+
    /*
     * Unmask the related irq
     */
-   HalEnableSystemInterrupt (irq + IRQ_BASE, 0, 0);
-   
+   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)
      {
-       HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
-       __asm__("sti\n\t");
 
-       if (KeGetCurrentThread() != NULL)
+  HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
+
+       if (KeGetCurrentThread() != NULL)
          {
             KeGetCurrentThread()->LastEip = Trapframe->Eip;
          }
        KiDispatchInterrupt();
-       if (irq == 0)
-         {
-           PsDispatchThread(THREAD_STATE_RUNNABLE);
-         }
        if (KeGetCurrentThread() != NULL &&
            KeGetCurrentThread()->Alerted[1] != 0 &&
            Trapframe->Cs != KERNEL_CS)
@@ -209,11 +381,98 @@ KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
            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;
      }
 
+   /*
+    * 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)
+     {
+       PsDispatchThread(THREAD_STATE_RUNNABLE);
+     }
 }
 
+#endif /* MP */
 
 static VOID 
 KeDumpIrqList(VOID)
@@ -226,7 +485,7 @@ KeDumpIrqList(VOID)
      {
        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);
@@ -237,7 +496,6 @@ KeDumpIrqList(VOID)
      }
 }
 
-
 NTSTATUS STDCALL
 KeConnectInterrupt(PKINTERRUPT InterruptObject)
 {
@@ -339,19 +597,18 @@ KeInitializeInterrupt(PKINTERRUPT InterruptObject,
 }
 
 
-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:
@@ -447,8 +704,8 @@ IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
  *        InterruptObject = isr to release
  */
 {
-   KeDisconnectInterrupt(InterruptObject);
-   ExFreePool(InterruptObject);
+  KeDisconnectInterrupt(InterruptObject);
+  ExFreePool(InterruptObject);
 }
 
 /* EOF */