Added Intel MultiProcessor Specification support
authorCasper Hornstrup <chorns@users.sourceforge.net>
Fri, 13 Apr 2001 16:12:26 +0000 (16:12 +0000)
committerCasper Hornstrup <chorns@users.sourceforge.net>
Fri, 13 Apr 2001 16:12:26 +0000 (16:12 +0000)
svn path=/trunk/; revision=1789

26 files changed:
reactos/ntoskrnl/Makefile
reactos/ntoskrnl/Makefile.i386
reactos/ntoskrnl/hal/x86/halinit.c
reactos/ntoskrnl/hal/x86/mp.c
reactos/ntoskrnl/hal/x86/mps.S [new file with mode: 0644]
reactos/ntoskrnl/hal/x86/mpsboot.asm [new file with mode: 0644]
reactos/ntoskrnl/hal/x86/mpsirql.c [new file with mode: 0644]
reactos/ntoskrnl/hal/x86/sources
reactos/ntoskrnl/hal/x86/time.c
reactos/ntoskrnl/hal/x86/udelay.c
reactos/ntoskrnl/include/internal/hal/mps.h [new file with mode: 0644]
reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/include/internal/ntoskrnl.h
reactos/ntoskrnl/include/internal/ps.h
reactos/ntoskrnl/io/cntrller.c
reactos/ntoskrnl/ke/i386/gdt.c
reactos/ntoskrnl/ke/i386/irq.c
reactos/ntoskrnl/ke/i386/kernel.c
reactos/ntoskrnl/ke/i386/multiboot.S
reactos/ntoskrnl/ke/i386/tskswitch.S
reactos/ntoskrnl/ke/main.c
reactos/ntoskrnl/ke/timer.c
reactos/ntoskrnl/mm/freelist.c
reactos/ntoskrnl/mm/i386/page.c
reactos/ntoskrnl/mm/mminit.c
reactos/ntoskrnl/ps/psmgr.c

index 4ac5c2e..2a92598 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.33 2001/04/11 22:13:21 dwelch Exp $
+# $Id: Makefile,v 1.34 2001/04/13 16:12:24 chorns Exp $
 #
 # ReactOS Operating System
 #
@@ -11,6 +11,7 @@ PATH_TO_TOP := ..
 #
 # Include details of the kernel configuration
 #
+
 include config
 
 #
@@ -56,12 +57,6 @@ all: $(EXE_PREFIX)depends$(EXE_POSTFIX) \
 $(EXE_PREFIX)depends$(EXE_POSTFIX): depends.c
        $(HOST_CC) -o depends$(EXE_POSTFIX) depends.c
 
-#
-# Hardware Abstraction Layer (Hal)
-# Defines $(OBJECTS_HAL)
-#
-include hal/x86/sources
-
 #
 # Architecture specific Makefile
 # Defines $(OBJECTS_ARCH)
@@ -110,7 +105,6 @@ OBJECTS_RTL = \
        rtl/memcmp.o
 
 # Kernel (Ke)
-# Note: head.o MUST be the first file!!!
 OBJECTS_KE = \
        ke/apc.o \
        ke/bug.o \
@@ -451,7 +445,7 @@ $(OBJECTS_PATH)/kd.o: $(OBJECTS_KD)
 $(TARGETNAME).coff: $(TARGETNAME).rc ../include/reactos/resource.h
 
 
-# Note: ke.o MUST be the first file!!!
+# Note: arch.o MUST be the first file!!!
 OBJECTS := \
        $(OBJECTS_PATH)/arch.o \
        $(OBJECTS_PATH)/ke.o \
@@ -601,6 +595,9 @@ ke/main.o: ke/main.c ../include/reactos/buildno.h
 mkconfig$(EXE_SUFFIX): mkconfig.c
        $(HOST_CC) -g -o mkconfig$(EXE_SUFFIX) mkconfig.c
 
+config:
+       $(EXE_PREFIX)mkconfig$(EXE_SUFFIX) include/internal/config.h $(CONFIG)
+
 include/internal/config.h: config mkconfig$(EXE_SUFFIX)
        $(EXE_PREFIX)mkconfig$(EXE_SUFFIX) include/internal/config.h$(CONFIG)
 
@@ -617,6 +614,7 @@ endif
 .%.d: %.S
        $(CC) $(CFLAGS) -M $< | $(EXE_PREFIX)depends$(EXE_POSTFIX) $(@D) $@
 
-
+.%.d: %.asm
+       $(NASM_CMD) $< | $(EXE_PREFIX)depends$(EXE_POSTFIX) $(@D) $@
 
 # EOF
index 1c00d8f..bee30e9 100644 (file)
@@ -1,3 +1,10 @@
+#
+# Hardware Abstraction Layer (Hal) for x86 systems
+#
+
+# Defines $(OBJECTS_HAL)
+include hal/x86/sources
+
 OBJECTS_BOOT := ke/i386/multiboot.o
 
 OBJECTS_KE_I386 := \
@@ -13,7 +20,7 @@ OBJECTS_KE_I386 := \
        ke/i386/v86m.o \
        ke/i386/v86m_sup.o \
        ke/i386/bios.o \
-        ke/i386/i386-mcount.o \
+  ke/i386/i386-mcount.o \
        ke/i386/gdt.o \
        ke/i386/idt.o \
        ke/i386/ldt.o \
index a521276..cca0f78 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: halinit.c,v 1.17 2001/03/16 18:11:21 dwelch Exp $
+/* $Id: halinit.c,v 1.18 2001/04/13 16:12:25 chorns Exp $
  *
  * COPYRIGHT:     See COPYING in the top level directory
  * PROJECT:       ReactOS kernel
  * FILE:          ntoskrnl/hal/x86/halinit.c
- * PURPOSE:       Initalize the uniprocessor, x86 hal
+ * PURPOSE:       Initalize the x86 hal
  * PROGRAMMER:    David Welch (welch@cwcom.net)
  * UPDATE HISTORY:
  *              11/06/98: Created
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
+#include <internal/config.h>
 #include <internal/hal/hal.h>
 #include <internal/ntoskrnl.h>
 
+#ifdef MP
+#include <internal/hal/mps.h>
+#endif /* MP */
+
 #define NDEBUG
 #include <internal/debug.h>
 
+
 /* FUNCTIONS ***************************************************************/
 
 BOOLEAN STDCALL
-HalInitSystem (ULONG                   BootPhase,
-              PLOADER_PARAMETER_BLOCK  LoaderBlock)
+HalInitSystem (ULONG BootPhase,
+               PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
    if (BootPhase == 0)
    {
       HalInitializeDisplay (LoaderBlock);
-      HalpInitPICs ();
+
+#ifdef MP
+
+      HalpInitMPS();
+
+#else
+
+      HalpInitPICs();
+
+      /* Setup busy waiting */
+      HalpCalibrateStallExecution();
+
+#endif /* MP */
+
    }
    else
    {
       HalpInitBusHandlers ();
-
    }
 
    return TRUE;
index 5bf5813..bc7f285 100644 (file)
-/* $Id: mp.c,v 1.5 2000/07/02 10:49:04 ekohl Exp $
+/* $Id: mp.c,v 1.6 2001/04/13 16:12:25 chorns Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/hal/x86/mp.c
- * PURPOSE:         Multiprocessor stubs
+ * PURPOSE:         Intel MultiProcessor specification support
  * PROGRAMMER:      David Welch (welch@cwcom.net)
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * NOTES:           Parts adapted from linux SMP code
  * UPDATE HISTORY:
- *                  Created 22/05/98
+ *     22/05/1998  DW   Created
+ *     12/04/2001  CSH  Added MultiProcessor specification support
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
+#include <internal/config.h>
 
+#define NDEBUG
 #include <internal/debug.h>
 
+#ifdef MP
+
+#include <internal/hal/hal.h>
+#include <internal/hal/mps.h>
+#include <internal/ntoskrnl.h>
+#include <internal/i386/segment.h>
+#include <internal/ke.h>
+#include <internal/ps.h>
+
+/*
+   Address of area to be used for communication between Application
+   Processors (APs) and the BootStrap Processor (BSP)
+ */
+#define COMMON_AREA  0x2000
+
+#define BIOS_AREA    0x0
+
+typedef struct __attribute__((packed)) _COMMON_AREA_INFO
+{
+   ULONG Stack;      /* Location of AP stack */
+   ULONG Debug[16];  /* For debugging */
+} COMMON_AREA_INFO, *PCOMMON_AREA_INFO;
+
+
+CPU_INFO CPUMap[MAX_CPU];          /* Map of all CPUs in the system */
+ULONG CPUCount;                    /* Total number of CPUs */
+ULONG OnlineCPUs;                  /* Bitmask of online CPUs */
+
+UCHAR BUSMap[MAX_BUS];             /* Map of all buses in the system */
+UCHAR PCIBUSMap[MAX_BUS];          /* Map of all PCI buses in the system */
+
+IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */
+ULONG IOAPICCount;                 /* Number of I/O APICs in the system */
+
+MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */
+ULONG IRQVectorMap[MAX_IRQ_SOURCE];             /* IRQ to vector map */
+ULONG IRQCount;                                 /* Number of IRQs  */
+
+ULONG APICMode;                     /* APIC mode at startup */
+ULONG BootCPU;                      /* Bootstrap processor */
+ULONG NextCPU;                      /* Next CPU to start */
+PULONG BIOSBase;                    /* Virtual address of BIOS data segment */
+PULONG APICBase;                    /* Virtual address of local APIC */
+PULONG CommonBase;                  /* Virtual address of common area */
+
+extern CHAR *APstart, *APend;
+extern VOID (*APflush)(VOID);
+
+extern VOID MpsTimerInterrupt(VOID);
+extern VOID MpsErrorInterrupt(VOID);
+extern VOID MpsSpuriousInterrupt(VOID);
+
+#define CMOS_READ(address) ({ \
+   WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
+   READ_PORT_UCHAR((PUCHAR)0x71)); \
+})
+
+#define CMOS_WRITE(address, value) ({ \
+   WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
+   WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
+})
+
+BOOLEAN MPSInitialized = FALSE;  /* Is the MP system initialized? */
+
+VOID APICDisable(VOID);
+static VOID APICSyncArbIDs(VOID);
+
+/* For debugging */
+ULONG lastregr = 0;
+ULONG lastvalr = 0;
+ULONG lastregw = 0;
+ULONG lastvalw = 0;
+
+#endif /* MP */
+
+
+BOOLEAN BSPInitialized = FALSE;  /* Is the BSP initialized? */
+
+
 /* FUNCTIONS *****************************************************************/
 
+#ifdef MP
+
+/* Functions for handling 8259A PICs */
+
+VOID Disable8259AIrq(
+  ULONG irq)
+{
+       ULONG tmp;
+
+       if (irq & 8) {
+    tmp = READ_PORT_UCHAR((PUCHAR)0xA1);
+    tmp |= (1 << irq);
+    WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp);
+       } else {
+    tmp = READ_PORT_UCHAR((PUCHAR)0x21);
+    tmp |= (1 << irq);
+    WRITE_PORT_UCHAR((PUCHAR)0x21, tmp);
+  }
+}
+
+
+VOID Enable8259AIrq(
+  ULONG irq)
+{
+  ULONG tmp;
+
+       if (irq & 8) {
+    tmp = READ_PORT_UCHAR((PUCHAR)0xA1);
+    tmp &= ~(1 << irq);
+    WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp);
+       } else {
+    tmp = READ_PORT_UCHAR((PUCHAR)0x21);
+    tmp &= ~(1 << irq);
+    WRITE_PORT_UCHAR((PUCHAR)0x21, tmp);
+  }
+}
+
+
+/* Functions for handling I/O APICs */
+
+volatile ULONG IOAPICRead(
+   ULONG Apic,
+   ULONG Offset)
+{
+  PULONG Base;
+
+  Base = (PULONG)IOAPICMap[Apic].ApicAddress;
+
+       *Base = Offset;
+       return *((PULONG)((ULONG)Base + IOAPIC_IOWIN));
+}
+
+
+VOID IOAPICWrite(
+   ULONG Apic,
+   ULONG Offset,
+   ULONG Value)
+{
+  PULONG Base;
+
+  Base = (PULONG)IOAPICMap[Apic].ApicAddress;
+
+  *Base = Offset;
+       *((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value;
+}
+
+
+VOID IOAPICClearPin(
+  ULONG Apic,
+  ULONG Pin)
+{
+  IOAPIC_ROUTE_ENTRY Entry;
+
+  /*
+   * Disable it in the IO-APIC irq-routing table
+   */
+       memset(&Entry, 0, sizeof(Entry));
+       Entry.mask = 1;
+       IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0));
+       IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1));
+}
+
+static VOID IOAPICClear(
+  ULONG Apic)
+{
+       ULONG Pin;
+
+  for (Pin = 0; Pin < IOAPICMap[Apic].EntryCount; Pin++)
+               IOAPICClearPin(Apic, Pin);
+}
+
+static VOID IOAPICClearAll(
+  VOID)
+{
+  ULONG Apic;
+
+       for (Apic = 0; Apic < IOAPICCount; Apic++)
+               IOAPICClear(Apic);
+}
+
+/* This is performance critical and should probably be done in assembler */
+VOID IOAPICMaskIrq(
+  ULONG Apic,
+  ULONG Irq)
+{
+  IOAPIC_ROUTE_ENTRY Entry;
+
+       *((PULONG)&Entry) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq);
+  Entry.mask = 1;
+       IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *((PULONG)&Entry));
+}
+
+
+/* This is performance critical and should probably be done in assembler */
+VOID IOAPICUnmaskIrq(
+  ULONG Apic,
+  ULONG Irq)
+{
+  IOAPIC_ROUTE_ENTRY Entry;
+
+  *((PULONG)&Entry) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq);
+  Entry.mask = 0;
+  IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *((PULONG)&Entry));
+}
+
+static VOID IOAPICSetupIds(
+  VOID)
+{
+       ULONG tmp, apic, i;
+       UCHAR old_id;
+
+       /*
+        * Set the IOAPIC ID to the value stored in the MPC table.
+        */
+       for (apic = 0; apic < IOAPICCount; apic++) {
+
+               /* Read the register 0 value */
+    tmp = IOAPICRead(apic, IOAPIC_ID);
+               
+               old_id = IOAPICMap[apic].ApicId;
+
+               if (IOAPICMap[apic].ApicId >= 0xf) {
+                       DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
+                               apic, IOAPICMap[apic].ApicId);
+                       DPRINT1("... fixing up to %d. (tell your hw vendor)\n", GET_IOAPIC_ID(tmp));
+      IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp);
+               }
+
+               /*
+                * We need to adjust the IRQ routing table
+                * if the ID changed.
+                */
+               if (old_id != IOAPICMap[apic].ApicId)
+                       for (i = 0; i < IRQCount; i++)
+                               if (IRQMap[i].DstApicId == old_id)
+                                       IRQMap[i].DstApicId = IOAPICMap[apic].ApicId;
+
+               /*
+                * Read the right value from the MPC table and
+                * write it into the ID register.
+                */
+               DPRINT("Changing IO-APIC physical APIC ID to %d\n",
+                                       IOAPICMap[apic].ApicId);
+
+               tmp &= ~IOAPIC_ID_MASK;
+    tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId);
+
+               IOAPICWrite(apic, IOAPIC_ID, tmp);
+
+               /*
+                * Sanity check
+                */
+               tmp = IOAPICRead(apic, 0);
+               if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) {
+                       DPRINT1("Could not set I/O APIC ID!\n");
+      KeBugCheck(0);
+     }
+       }
+}
+
+
+/*
+ * EISA Edge/Level control register, ELCR
+ */
+static ULONG EISA_ELCR(
+  ULONG irq)
+{
+       if (irq < 16) {
+               PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3));
+               return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1;
+       }
+       DPRINT("Broken MPtable reports ISA irq %d\n", irq);
+       return 0;
+}
+
+/* EISA interrupts are always polarity zero and can be edge or level
+ * trigger depending on the ELCR value.  If an interrupt is listed as
+ * EISA conforming in the MP table, that means its trigger type must
+ * be read in from the ELCR */
+
+#define default_EISA_trigger(idx)      (EISA_ELCR(IRQMap[idx].SrcBusIrq))
+#define default_EISA_polarity(idx)     (0)
+
+/* ISA interrupts are always polarity zero edge triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_ISA_trigger(idx)       (0)
+#define default_ISA_polarity(idx)      (0)
+
+/* PCI interrupts are always polarity one level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_PCI_trigger(idx)       (1)
+#define default_PCI_polarity(idx)      (1)
+
+/* MCA interrupts are always polarity zero level triggered,
+ * when listed as conforming in the MP table. */
+
+#define default_MCA_trigger(idx)       (1)
+#define default_MCA_polarity(idx)      (0)
+
+static ULONG IRQPolarity(
+  ULONG idx)
+{
+       ULONG bus = IRQMap[idx].SrcBusId;
+       ULONG polarity;
+
+       /*
+        * Determine IRQ line polarity (high active or low active):
+        */
+       switch (IRQMap[idx].IrqFlag & 3)
+       {
+               case 0: /* conforms, ie. bus-type dependent polarity */
+               {
+                       switch (BUSMap[bus])
+                       {
+                               case MP_BUS_ISA: /* ISA pin */
+                               {
+                                       polarity = default_ISA_polarity(idx);
+                                       break;
+                               }
+                               case MP_BUS_EISA: /* EISA pin */
+                               {
+                                       polarity = default_EISA_polarity(idx);
+                                       break;
+                               }
+                               case MP_BUS_PCI: /* PCI pin */
+                               {
+                                       polarity = default_PCI_polarity(idx);
+                                       break;
+                               }
+                               case MP_BUS_MCA: /* MCA pin */
+                               {
+                                       polarity = default_MCA_polarity(idx);
+                                       break;
+                               }
+                               default:
+                               {
+                                       DPRINT("Broken BIOS!!\n");
+                                       polarity = 1;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+               case 1: /* high active */
+               {
+                       polarity = 0;
+                       break;
+               }
+               case 2: /* reserved */
+               {
+                       DPRINT("Broken BIOS!!\n");
+                       polarity = 1;
+                       break;
+               }
+               case 3: /* low active */
+               {
+                       polarity = 1;
+                       break;
+               }
+               default: /* invalid */
+               {
+                       DPRINT("Broken BIOS!!\n");
+                       polarity = 1;
+                       break;
+               }
+       }
+       return polarity;
+}
+
+static ULONG IRQTrigger(
+  ULONG idx)
+{
+       ULONG bus = IRQMap[idx].SrcBusId;
+       ULONG trigger;
+
+       /*
+        * Determine IRQ trigger mode (edge or level sensitive):
+        */
+       switch ((IRQMap[idx].IrqFlag >> 2) & 3)
+       {
+               case 0: /* conforms, ie. bus-type dependent */
+               {
+                       switch (BUSMap[bus])
+                       {
+                               case MP_BUS_ISA: /* ISA pin */
+                               {
+                                       trigger = default_ISA_trigger(idx);
+                                       break;
+                               }
+                               case MP_BUS_EISA: /* EISA pin */
+                               {
+                                       trigger = default_EISA_trigger(idx);
+                                       break;
+                               }
+                               case MP_BUS_PCI: /* PCI pin */
+                               {
+                                       trigger = default_PCI_trigger(idx);
+                                       break;
+                               }
+                               case MP_BUS_MCA: /* MCA pin */
+                               {
+                                       trigger = default_MCA_trigger(idx);
+                                       break;
+                               }
+                               default:
+                               {
+                                       DPRINT("Broken BIOS!!\n");
+                                       trigger = 1;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+               case 1: /* edge */
+               {
+                       trigger = 0;
+                       break;
+               }
+               case 2: /* reserved */
+               {
+                       DPRINT("Broken BIOS!!\n");
+                       trigger = 1;
+                       break;
+               }
+               case 3: /* level */
+               {
+                       trigger = 1;
+                       break;
+               }
+               default: /* invalid */
+               {
+                       DPRINT("Broken BIOS!!\n");
+                       trigger = 0;
+                       break;
+               }
+       }
+       return trigger;
+}
+
+
+static ULONG Pin2Irq(
+  ULONG idx,
+  ULONG apic,
+  ULONG pin)
+{
+       ULONG irq, i;
+       ULONG bus = IRQMap[idx].SrcBusId;
+
+       /*
+        * Debugging check, we are in big trouble if this message pops up!
+        */
+       if (IRQMap[idx].DstApicInt != pin) {
+               DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
+  }
+
+       switch (BUSMap[bus])
+       {
+               case MP_BUS_ISA: /* ISA pin */
+               case MP_BUS_EISA:
+               case MP_BUS_MCA:
+               {
+                       irq = IRQMap[idx].SrcBusIrq;
+                       break;
+               }
+               case MP_BUS_PCI: /* PCI pin */
+               {
+                       /*
+                        * PCI IRQs are mapped in order
+                        */
+                       i = irq = 0;
+                       while (i < apic)
+                               irq += IOAPICMap[i++].EntryCount;
+                       irq += pin;
+                       break;
+               }
+               default:
+               {
+                       DPRINT("Unknown bus type %d.\n",bus);
+                       irq = 0;
+                       break;
+               }
+       }
+
+       return irq;
+}
+
+
+/*
+ * Rough estimation of how many shared IRQs there are, can
+ * be changed anytime.
+ */
+#define MAX_PLUS_SHARED_IRQS PIC_IRQS
+#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + PIC_IRQS)
+
+/*
+ * This is performance-critical, we want to do it O(1)
+ *
+ * the indexing order of this array favors 1:1 mappings
+ * between pins and IRQs.
+ */
+
+static struct irq_pin_list {
+       ULONG apic, pin, next;
+} irq_2_pin[PIN_MAP_SIZE];
+
+/*
+ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
+ * shared ISA-space IRQs, so we have to support them. We are super
+ * fast in the common case, and fast for shared ISA-space IRQs.
+ */
+static VOID AddPinToIrq(
+  ULONG irq,
+  ULONG apic,
+  ULONG pin)
+{
+       static ULONG first_free_entry = PIC_IRQS;
+       struct irq_pin_list *entry = irq_2_pin + irq;
+
+       while (entry->next)
+               entry = irq_2_pin + entry->next;
+
+       if (entry->pin != -1) {
+               entry->next = first_free_entry;
+               entry = irq_2_pin + entry->next;
+               if (++first_free_entry >= PIN_MAP_SIZE) {
+      DPRINT1("Ohh no!");
+                       KeBugCheck(0);
+     }
+       }
+       entry->apic = apic;
+       entry->pin = pin;
+}
+
+
+/*
+ * Find the IRQ entry number of a certain pin.
+ */
+static ULONG IOAPICGetIrqEntry(
+  ULONG apic,
+  ULONG pin,
+  ULONG type)
+{
+       ULONG i;
+
+       for (i = 0; i < IRQCount; i++)
+               if (IRQMap[i].IrqType == type &&
+                   (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId ||
+                    IRQMap[i].DstApicId == MP_APIC_ALL) &&
+                    IRQMap[i].DstApicInt == pin)
+                       return i;
+
+       return -1;
+}
+
+
+static ULONG AssignIrqVector(
+  ULONG irq)
+{
+       static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0;
+  ULONG vector;
+
+  /* There may already have been assigned a vector for this IRQ */
+  vector = IRQVectorMap[irq];
+       if (vector > 0)
+               return vector;
+
+  current_vector += 8;
+  if (current_vector > FIRST_SYSTEM_VECTOR) {
+               vector_offset++;
+         current_vector = FIRST_DEVICE_VECTOR + vector_offset;
+  } else if (current_vector == FIRST_SYSTEM_VECTOR) {
+     DPRINT1("Ran out of interrupt sources!");
+     KeBugCheck(0);
+  }
+
+       IRQVectorMap[irq] = current_vector;
+       return current_vector;
+}
+
+
+VOID IOAPICSetupIrqs(
+  VOID)
+{
+       IOAPIC_ROUTE_ENTRY entry;
+       ULONG apic, pin, idx, irq, first_notcon = 1, vector;
+
+       DPRINT("Init IO_APIC IRQs\n");
+
+       for (apic = 0; apic < IOAPICCount; apic++) {
+       for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) {
+
+               /*
+                * add it to the IO-APIC irq-routing table
+                */
+               memset(&entry,0,sizeof(entry));
+
+               entry.delivery_mode = APIC_DM_LOWEST;
+               entry.dest_mode = 1;  /* logical delivery */
+               entry.mask = 0;       /* enable IRQ */
+               entry.dest.logical.logical_dest = OnlineCPUs;
+
+               idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED);
+               if (idx == -1) {
+                       if (first_notcon) {
+                               DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin);
+                               first_notcon = 0;
+                       } else {
+                               DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin);
+      }
+                       continue;
+               }
+
+               entry.trigger = IRQTrigger(idx);
+               entry.polarity = IRQPolarity(idx);
+
+               if (entry.trigger) {
+                       entry.trigger = 1;
+                       entry.mask = 1;
+                       entry.dest.logical.logical_dest = OnlineCPUs;
+               }
+
+               irq = Pin2Irq(idx, apic, pin);
+               AddPinToIrq(irq, apic, pin);
+
+       vector = AssignIrqVector(irq);
+               entry.vector = vector;
+
+    if (irq == 0)
+    {
+      /* Mask timer IRQ */
+      entry.mask = 1;
+    }
+
+    if ((apic == 0) && (irq < 16))
+                 Disable8259AIrq(irq);
+
+    IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1));
+               IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0));
+       }
+       }
+}
+
+
+static VOID IOAPICEnable(
+  VOID)
+{
+       ULONG i, tmp;
+
+       for (i = 0; i < PIN_MAP_SIZE; i++) {
+               irq_2_pin[i].pin = -1;
+               irq_2_pin[i].next = 0;
+       }
+
+       /*
+        * The number of IO-APIC IRQ registers (== #pins):
+        */
+  for (i = 0; i < IOAPICCount; i++) {
+               tmp = IOAPICRead(i, IOAPIC_VER);
+               IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1;
+       }
+
+       /*
+        * Do not trust the IO-APIC being empty at bootup
+        */
+       IOAPICClearAll();
+}
+
+#if 0
+static VOID IOAPICDisable(
+  VOID)
+{
+       /*
+        * Clear the IO-APIC before rebooting
+        */
+       IOAPICClearAll();
+
+       APICDisable();
+}
+#endif
+
+
+static VOID IOAPICSetup(
+  VOID)
+{
+  IOAPICEnable();
+  IOAPICSetupIds();
+  if (0) {
+    // FIXME: This causes application processors to not boot if asked to
+    APICSyncArbIDs();
+  }
+  IOAPICSetupIrqs();
+}
+
+
+VOID IOAPICDump(VOID)
+{
+       ULONG apic, i;
+  ULONG reg0, reg1, reg2;
+
+       DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount);
+       for (i = 0; i < IOAPICCount; i++) {
+               DbgPrint("Number of IO-APIC #%d registers: %d.\n",
+                       IOAPICMap[i].ApicId,
+            IOAPICMap[i].EntryCount);
+  }
+
+       /*
+        * We are a bit conservative about what we expect.  We have to
+        * know about every hardware change ASAP.
+        */
+       DbgPrint("Testing the IO APIC.......................\n");
+
+       for (apic = 0; apic < IOAPICCount; apic++) {
+
+  reg0 = IOAPICRead(apic, IOAPIC_ID);
+       reg1 = IOAPICRead(apic, IOAPIC_VER);
+       if (GET_IOAPIC_VERSION(reg1) >= 0x10) {
+    reg2 = IOAPICRead(apic, IOAPIC_ARB);
+  }
+
+       DbgPrint("\n");
+       DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId);
+       DbgPrint(".... register #00: %08X\n", reg0);
+       DbgPrint(".......    : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0));
+       if (reg0 & 0xF0FFFFFF) {
+    DbgPrint("  WARNING: Unexpected IO-APIC\n");
+  }
+
+       DbgPrint(".... register #01: %08X\n", reg1);
+  i = GET_IOAPIC_MRE(reg1);
+
+       DbgPrint(".......     : max redirection entries: %04X\n", i);
+       if ((i != 0x0f) && /* older (Neptune) boards */
+               (i != 0x17) &&   /* typical ISA+PCI boards */
+               (i != 0x1b) &&   /* Compaq Proliant boards */
+               (i != 0x1f) &&   /* dual Xeon boards */
+               (i != 0x22) &&   /* bigger Xeon boards */
+               (i != 0x2E) &&
+               (i != 0x3F)) {
+    DbgPrint("  WARNING: Unexpected IO-APIC\n");
+  }
+
+  i =  GET_IOAPIC_VERSION(reg1);
+  DbgPrint(".......     : IO APIC version: %04X\n", i);
+       if ((i != 0x01) && /* 82489DX IO-APICs */
+               (i != 0x10) &&   /* oldest IO-APICs */
+               (i != 0x11) &&   /* Pentium/Pro IO-APICs */
+               (i != 0x13)) {   /* Xeon IO-APICs */
+    DbgPrint("  WARNING: Unexpected IO-APIC\n");
+  }
+
+       if (reg1 & 0xFF00FF00) {
+    DbgPrint("  WARNING: Unexpected IO-APIC\n");
+  }
+
+       if (GET_IOAPIC_VERSION(reg1) >= 0x10) {
+               DbgPrint(".... register #02: %08X\n", reg2);
+               DbgPrint(".......     : arbitration: %02X\n",
+      GET_IOAPIC_ARB(reg2));
+       if (reg2 & 0xF0FFFFFF) {
+      DbgPrint("  WARNING: Unexpected IO-APIC\n");
+    }
+       }
+
+       DbgPrint(".... IRQ redirection table:\n");
+  DbgPrint(" NR Log Phy Mask Trig IRR Pol"
+                         " Stat Dest Deli Vect:   \n");
+
+       for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++) {
+               IOAPIC_ROUTE_ENTRY entry;
+
+               *(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2);
+               *(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2);
+
+               DbgPrint(" %02x %03X %02X  ",
+                       i,
+                       entry.dest.logical.logical_dest,
+                       entry.dest.physical.physical_dest
+               );
+
+  DbgPrint("%C    %C    %1d  %C    %C    %C     %03X    %02X\n",
+                       (entry.mask == 0) ? 'U' : 'M',            // Unmasked/masked
+                       (entry.trigger == 0) ? 'E' : 'L',         // Edge/level sensitive
+                       entry.irr,
+                       (entry.polarity == 0) ? 'H' : 'L',        // Active high/active low
+                       (entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending
+                       (entry.dest_mode == 0) ? 'P' : 'L',       // Physical logical
+                       entry.delivery_mode,
+                       entry.vector
+               );
+       }
+       }
+       DbgPrint("IRQ to pin mappings:\n");
+       for (i = 0; i < PIC_IRQS; i++) {
+               struct irq_pin_list *entry = irq_2_pin + i;
+               if (entry->pin < 0)
+                       continue;
+               DbgPrint("IRQ%d ", i);
+               for (;;) {
+                       DbgPrint("-> %d", entry->pin);
+                       if (!entry->next)
+                               break;
+                       entry = irq_2_pin + entry->next;
+               }
+    if (i % 2) {
+      DbgPrint("\n");
+    } else {
+      DbgPrint("        ");
+    }
+       }
+
+       DbgPrint(".................................... done.\n");
+}
+
+
+
+/* Functions for handling local APICs */
+
+#if 0
+volatile inline ULONG APICRead(
+   ULONG Offset)
+{
+   PULONG p;
+
+   p = (PULONG)((ULONG)APICBase + Offset);
+   return *p;
+}
+#else
+volatile inline ULONG APICRead(
+   ULONG Offset)
+{
+   PULONG p;
+
+   lastregr = Offset;
+   lastvalr = 0;
+
+   //DPRINT1("R(0x%X)", Offset);
+   p = (PULONG)((ULONG)APICBase + Offset);
+   lastvalr = *p;
+   //DPRINT1("(0x%08X)\n", *p);
+
+   return lastvalr;
+}
+#endif
+
+#if 0
+inline VOID APICWrite(
+   ULONG Offset,
+   ULONG Value)
+{
+   PULONG p;
+
+   p = (PULONG)((ULONG)APICBase + Offset);
+
+   *p = Value;
+}
+#else
+inline VOID APICWrite(
+   ULONG Offset,
+   ULONG Value)
+{
+   PULONG p;
+
+   lastregw = Offset;
+   lastvalw = Value;
+
+   //DPRINT1("W(0x%X, 0x%08X)\n", Offset, Value);
+   p = (PULONG)((ULONG)APICBase + Offset);
+
+   *p = Value;
+}
+#endif
+
+
+inline VOID APICSendEOI(VOID)
+{
+  // Dummy read
+  APICRead(APIC_SIVR);
+  // Send the EOI
+  APICWrite(APIC_EOI, 0);
+}
+
+
+VOID DumpESR(VOID)
+{
+  ULONG tmp;
+
+  if (CPUMap[ThisCPU()].MaxLVT > 3)
+    APICWrite(APIC_ESR, 0);
+  tmp = APICRead(APIC_ESR);
+  DbgPrint("ESR %08x\n", tmp);
+}
+
+
+ULONG APICGetMaxLVT(VOID)
+{
+       ULONG tmp, ver, maxlvt;
+
+  tmp = APICRead(APIC_VER);
+       ver = GET_APIC_VERSION(tmp);
+       /* 82489DXs do not report # of LVT entries. */
+       maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(tmp) : 2;
+
+       return maxlvt;
+}
+
+
+static VOID APICClear(
+  VOID)
+{
+  ULONG tmp, maxlvt;
+
+  maxlvt = CPUMap[ThisCPU()].MaxLVT;
+
+  /*
+   * Careful: we have to set masks only first to deassert
+   * any level-triggered sources.
+   */
+  tmp = APICRead(APIC_LVTT);
+  APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED);
+
+  tmp = APICRead(APIC_LINT0);
+  APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED);
+
+  tmp = APICRead(APIC_LINT1);
+  APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED);
+
+  if (maxlvt >= 3) {
+    tmp = APICRead(APIC_LVT3);
+    APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED);
+  }
+  
+  if (maxlvt >= 4) {
+    tmp = APICRead(APIC_LVTPC);
+    APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED);
+  }
+
+  /*
+   * Clean APIC state for other OSs:
+   */
+  APICRead(APIC_SIVR);    // Dummy read
+  APICWrite(APIC_LVTT, APIC_LVT_MASKED);
+
+  APICRead(APIC_SIVR);    // Dummy read
+  APICWrite(APIC_LINT0, APIC_LVT_MASKED);
+
+  APICRead(APIC_SIVR);    // Dummy read
+  APICWrite(APIC_LINT1, APIC_LVT_MASKED);
+
+  if (maxlvt >= 3) {
+    APICRead(APIC_SIVR);  // Dummy read
+    APICWrite(APIC_LVT3, APIC_LVT3_MASKED);
+  }
+
+  if (maxlvt >= 4) {
+    APICRead(APIC_SIVR);  // Dummy read
+    APICWrite(APIC_LVTPC, APIC_LVT_MASKED);
+  }
+}
+
+/* Enable symetric I/O mode ie. connect the BSP's
+   local APIC to INT and NMI lines */
+inline VOID EnableSMPMode(
+   VOID)
+{
+   /*
+    * Do not trust the local APIC being empty at bootup.
+    */
+   APICClear();
+
+   WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
+   WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01);
+}
+
+
+/* Disable symetric I/O mode ie. go to PIC mode */
+inline VOID DisableSMPMode(
+   VOID)
+{
+   /*
+    * Put the board back into PIC mode (has an effect
+    * only on certain older boards).  Note that APIC
+    * interrupts, including IPIs, won't work beyond
+    * this point!  The only exception are INIT IPIs.
+    */
+   WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
+   WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00);
+}
+
+
+VOID APICDisable(
+  VOID)
+{
+  ULONG tmp;
+
+  APICClear();
+
+  /*
+   * Disable APIC (implies clearing of registers for 82489DX!).
+   */
+  tmp = APICRead(APIC_SIVR);
+  tmp &= ~APIC_SIVR_ENABLE;
+  APICWrite(APIC_SIVR, tmp);
+}
+
+
+inline ULONG ThisCPU(
+   VOID)
+{
+   return (APICRead(APIC_ID) & APIC_ID_MASK) >> 24;
+}
+
+
+static VOID APICDumpBit(ULONG base)
+{
+       ULONG v, i, j;
+
+       DbgPrint("0123456789abcdef0123456789abcdef\n");
+       for (i = 0; i < 8; i++) {
+               APICRead(base + i*0x10);
+               for (j = 0; j < 32; j++) {
+                       if (v & (1<<j))
+                               DbgPrint("1");
+                       else
+                               DbgPrint("0");
+               }
+               DbgPrint("\n");
+       }
+}
+
+
+VOID APICDump(VOID)
+/*
+ * Dump the contents of the local APIC registers
+ */
+{
+  ULONG v, ver, maxlvt;
+  ULONG r1, r2, w1, w2;
+
+  r1 = lastregr;
+  r2 = lastvalr;
+  w1 = lastregw;
+  w2 = lastvalw;
+
+       DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
+       v = APICRead(APIC_ID);
+       DbgPrint("... ID     : %08x (%01x) ", v, GET_APIC_ID(v));
+       v = APICRead(APIC_VER);
+       DbgPrint("... VERSION: %08x\n", v);
+       ver = GET_APIC_VERSION(v);
+       maxlvt = CPUMap[ThisCPU()].MaxLVT;
+
+       v = APICRead(APIC_TPR);
+       DbgPrint("... TPR    : %08x (%02x)", v, v & ~0);
+
+       if (APIC_INTEGRATED(ver)) {                     /* !82489DX */
+               v = APICRead(APIC_APR);
+               DbgPrint("... APR    : %08x (%02x)\n", v, v & ~0);
+               v = APICRead(APIC_PPR);
+               DbgPrint("... PPR    : %08x\n", v);
+       }
+
+       v = APICRead(APIC_EOI);
+       DbgPrint("... EOI    : %08x  !  ", v);
+       v = APICRead(APIC_LDR);
+       DbgPrint("... LDR    : %08x\n", v);
+       v = APICRead(APIC_DFR);
+       DbgPrint("... DFR    : %08x  !  ", v);
+       v = APICRead(APIC_SIVR);
+       DbgPrint("... SIVR   : %08x\n", v);
+
+  if (0)
+  {
+       DbgPrint("... ISR field:\n");
+       APICDumpBit(APIC_ISR);
+       DbgPrint("... TMR field:\n");
+       APICDumpBit(APIC_TMR);
+       DbgPrint("... IRR field:\n");
+       APICDumpBit(APIC_IRR);
+  }
+
+       if (APIC_INTEGRATED(ver)) {             /* !82489DX */
+               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
+                       APICWrite(APIC_ESR, 0);
+               v = APICRead(APIC_ESR);
+               DbgPrint("... ESR    : %08x\n", v);
+       }
+
+       v = APICRead(APIC_ICR0);
+       DbgPrint("... ICR0   : %08x  !  ", v);
+       v = APICRead(APIC_ICR1);
+       DbgPrint("... ICR1   : %08x  !  ", v);
+
+       v = APICRead(APIC_LVTT);
+       DbgPrint("... LVTT   : %08x\n", v);
+
+       if (maxlvt > 3) {                       /* PC is LVT#4. */
+               v = APICRead(APIC_LVTPC);
+               DbgPrint("... LVTPC  : %08x  !  ", v);
+       }
+       v = APICRead(APIC_LINT0);
+       DbgPrint("... LINT0  : %08x  !  ", v);
+       v = APICRead(APIC_LINT1);
+       DbgPrint("... LINT1  : %08x\n", v);
+
+       if (maxlvt > 2) {
+               v = APICRead(APIC_LVT3);
+               DbgPrint("... LVT3   : %08x\n", v);
+       }
+
+       v = APICRead(APIC_ICRT);
+       DbgPrint("... ICRT   : %08x  !  ", v);
+       v = APICRead(APIC_CCRT);
+       DbgPrint("... CCCT   : %08x  !  ", v);
+       v = APICRead(APIC_TDCR);
+       DbgPrint("... TDCR   : %08x\n", v);
+       DbgPrint("\n");
+  DbgPrint("Last register read (offset): 0x%08X\n", r1);
+  DbgPrint("Last register read (value): 0x%08X\n", r2);
+  DbgPrint("Last register written (offset): 0x%08X\n", w1);
+  DbgPrint("Last register written (value): 0x%08X\n", w2);
+  DbgPrint("\n");
+}
+
+
+ULONG Read8254Timer(VOID)
+{
+       ULONG Count;
+
+       WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
+       Count = READ_PORT_UCHAR((PUCHAR)0x40);
+       Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
+
+       return Count;
+}
+
+
+VOID WaitFor8254Wraparound(VOID)
+{
+       ULONG CurCount, PrevCount = ~0;
+       LONG Delta;
+
+       CurCount = Read8254Timer();
+
+       do {
+               PrevCount = CurCount;
+               CurCount = Read8254Timer();
+               Delta = CurCount - PrevCount;
+
+       /*
+        * This limit for delta seems arbitrary, but it isn't, it's
+        * slightly above the level of error a buggy Mercury/Neptune
+        * chipset timer can cause.
+        */
+
+       } while (Delta < 300);
+}
+
+#define HZ (100)
+#define APIC_DIVISOR (16)
+
+VOID APICSetupLVTT(
+   ULONG ClockTicks)
+{
+       ULONG tmp;
+
+  /* Periodic timer */
+       tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
+    APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
+       APICWrite(APIC_LVTT, tmp);
+
+  tmp = APICRead(APIC_TDCR);
+  tmp &= ~(APIC_TDCR_1 | APIC_TDCR_TMBASE | APIC_TDCR_16);
+       APICWrite(APIC_TDCR, tmp);
+       APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR);
+}
+
+
+VOID APICCalibrateTimer(
+   ULONG CPU)
+{
+       ULARGE_INTEGER t1, t2;
+       LONG tt1, tt2;
+
+       DPRINT("Calibrating APIC timer...\n");
+
+       APICSetupLVTT(~0);
+
+       /*
+        * The timer chip counts down to zero. Let's wait
+        * for a wraparound to start exact measurement:
+        * (the current tick might have been already half done)
+        */
+       WaitFor8254Wraparound();
+
+       /*
+        * We wrapped around just now. Let's start
+        */
+  ReadPentiumClock(&t1);
+  tt1 = APICRead(APIC_CCRT);
+
+       WaitFor8254Wraparound();
+
+       tt2 = APICRead(APIC_CCRT);
+  ReadPentiumClock(&t2);
+
+       CPUMap[CPU].BusSpeed = (HZ * (tt2 - tt1) * APIC_DIVISOR);
+       CPUMap[CPU].CoreSpeed = (HZ * (t2.QuadPart - t1.QuadPart));
+
+       /* Setup timer for normal operation */
+  //APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100); // 100ns
+  //APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000); // 10ms
+  APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
+
+  DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
+         CPUMap[CPU].CoreSpeed/1000000,
+               CPUMap[CPU].CoreSpeed%1000000);
+
+       DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
+               CPUMap[CPU].BusSpeed/1000000,
+               CPUMap[CPU].BusSpeed%1000000);
+}
+
+
+static VOID APICSleep(
+   ULONG Count)
+/*
+   PARAMETERS:
+      Count = Number of microseconds to busy wait
+ */
+{
+  KeStallExecutionProcessor(Count);
+}
+
+
+static VOID APICSyncArbIDs(
+  VOID)
+{
+  ULONG i, tmp;
+
+   /* Wait up to 100ms for the APIC to become ready */
+   for (i = 0; i < 10000; i++) {
+      tmp = APICRead(APIC_ICR0);
+      /* Check Delivery Status */
+      if ((tmp & APIC_ICR0_DS) == 0)
+         break;
+      APICSleep(10);
+   }
+
+   if (i == 10000) {
+      DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
+   }
+
+       DPRINT("Synchronizing Arb IDs.\n");
+       APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
+}
+
+
+VOID APICSendIPI(
+   ULONG Target,
+   ULONG DeliveryMode,
+   ULONG IntNum,
+   ULONG Level)
+{
+   ULONG tmp, i, flags;
+
+   pushfl(flags);
+   __asm__ ("\n\tcli\n\t");
+
+   /* Wait up to 100ms for the APIC to become ready */
+   for (i = 0; i < 10000; i++) {
+      tmp = APICRead(APIC_ICR0);
+      /* Check Delivery Status */
+      if ((tmp & APIC_ICR0_DS) == 0)
+         break;
+      APICSleep(10);
+   }
+
+   if (i == 10000) {
+      DPRINT("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
+   }
+
+   /* Setup the APIC to deliver the IPI */
+   tmp = APICRead(APIC_ICR1);
+   tmp &= 0x00FFFFFF;
+   APICWrite(APIC_ICR1, tmp | SET_APIC_DEST_FIELD(Target));
+
+   tmp  = APICRead(APIC_ICR0);
+   tmp &= ~(APIC_ICR0_LEVEL | APIC_ICR0_DESTM | APIC_ICR0_DM | APIC_ICR0_VECTOR);
+   tmp |= (DeliveryMode | IntNum | Level);
+
+   if (Target == APIC_TARGET_SELF) {
+      tmp |= APIC_ICR0_DESTS_SELF;
+   } else if (Target == APIC_TARGET_ALL) {
+      tmp |= APIC_ICR0_DESTS_ALL;
+   } else if (Target == APIC_TARGET_ALL_BUT_SELF) {
+      tmp |= APIC_ICR0_DESTS_ALL_BUT_SELF;
+   } else {
+      tmp |= APIC_ICR0_DESTS_FIELD;
+   }
+
+   /* Now, fire off the IPI */
+   APICWrite(APIC_ICR0, tmp);
+
+   popfl(flags);
+}
+
+
+BOOLEAN VerifyLocalAPIC(
+  VOID)
+{
+       UINT reg0, reg1;
+  
+  /* The version register is read-only in a real APIC */
+       reg0 = APICRead(APIC_VER);
+       APICWrite(APIC_VER, reg0 ^ APIC_VER_MASK);
+       reg1 = APICRead(APIC_VER);
+
+       if (reg1 != reg0)
+               return FALSE;
+
+       /* The ID register is read/write in a real APIC */
+       reg0 = APICRead(APIC_ID);
+       APICWrite(APIC_ID, reg0 ^ APIC_ID_MASK);
+  reg1 = APICRead(APIC_ID);
+       APICWrite(APIC_ID, reg0);
+       if (reg1 != (reg0 ^ APIC_ID_MASK))
+               return FALSE;
+
+  return TRUE;
+}
+
+
+static VOID SetInterruptGate(
+  ULONG index,
+  ULONG address)
+{
+  IDT_DESCRIPTOR *idt;
+
+  idt = (IDT_DESCRIPTOR*)((ULONG)CURRENT_KPCR->IDT + index * sizeof(IDT_DESCRIPTOR));
+  idt->a = (((ULONG)address)&0xffff) + (KERNEL_CS << 16);
+  idt->b = 0x8f00 + (((ULONG)address)&0xffff0000);
+}
+
+
+VOID MpsTimerHandler(
+  VOID)
+{
+  KIRQL OldIrql;
+
+  /* FIXME: Pass EIP for profiling */
+
+  /*
+   * Acknowledge the interrupt
+   */
+  APICSendEOI();
+
+  /*
+   * Notify the rest of the kernel of the raised irq level
+   */
+  OldIrql = KeRaiseIrqlToSynchLevel();
+
+  /*
+   * Enable interrupts
+   */
+  __asm__("sti\n\t");
+
+  KiUpdateSystemTime(OldIrql, 0);
+
+  /*
+   * Disable interrupts
+   */
+   __asm__("cli\n\t");
+
+  /*
+   * Lower irq level
+   */
+  KeLowerIrql(OldIrql);
+
+  /*
+   * Call the dispatcher
+   */
+
+  /* FIXME: Does not seem to work */
+  PsDispatchThread(THREAD_STATE_RUNNABLE);
+}
+
+
+VOID MpsErrorHandler(
+  VOID)
+{
+  ULONG tmp1, tmp2;
+
+  APICDump();
+
+  tmp1 = APICRead(APIC_ESR);
+       APICWrite(APIC_ESR, 0);
+       tmp2 = APICRead(APIC_ESR);
+
+  /*
+   * Acknowledge the interrupt
+   */
+  APICSendEOI();
+
+       /* Here is what the APIC error bits mean:
+          0: Send CS error
+          1: Receive CS error
+          2: Send accept error
+          3: Receive accept error
+          4: Reserved
+          5: Send illegal vector
+          6: Received illegal vector
+          7: Illegal register address
+       */
+       DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
+  KeBugCheck(0);
+}
+
+
+VOID MpsSpuriousHandler(
+  VOID)
+{
+  DPRINT1("Spurious interrupt on CPU(%d)\n", ThisCPU());
+
+       /*
+   * Acknowledge the interrupt
+   */
+  APICSendEOI();
+
+  APICDump();
+  KeBugCheck(0);
+}
+
+
+VOID APICSetup(
+  VOID)
+{
+  ULONG CPU, tmp;
+
+  CPU = ThisCPU();
+
+  /*
+        * Intel recommends to set DFR, LDR and TPR before enabling
+        * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+        * document number 292116).  So here it goes...
+        */
+
+       /*
+        * Put the APIC into flat delivery mode.
+        * Must be "all ones" explicitly for 82489DX.
+        */
+       APICWrite(APIC_DFR, 0xFFFFFFFF);
+
+  /*
+        * Set up the logical destination ID.
+        */
+       tmp = APICRead(APIC_LDR);
+       tmp &= ~APIC_LDR_MASK;
+       tmp |= (1 << (CPU + 24));
+       APICWrite(APIC_LDR, tmp);
+
+       /* Accept all interrupts */
+       tmp = (APICRead(APIC_TPR) & ~APIC_TPR_PRI);
+       APICWrite(APIC_TPR, tmp);
+
+       /* Enable local APIC */
+       tmp = APICRead(APIC_SIVR) | APIC_SIVR_ENABLE | APIC_SIVR_FOCUS; // No focus processor
+
+  /* Set spurious interrupt vector */
+       tmp |= SPURIOUS_VECTOR;
+
+       APICWrite(APIC_SIVR, tmp);
+
+  /*
+   * Only the BP should see the LINT1 NMI signal, obviously.
+   */
+  if (CPU == 0)
+               tmp = APIC_DM_NMI;
+       else
+               tmp = APIC_DM_NMI | APIC_LVT_MASKED;
+       if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) /* 82489DX */
+               tmp |= APIC_LVT_LEVEL_TRIGGER;
+       APICWrite(APIC_LINT1, tmp);
+
+       if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) { /* !82489DX */
+    if (CPUMap[CPU].MaxLVT > 3) {              /* Due to the Pentium erratum 3AP */
+                       APICWrite(APIC_ESR, 0);
+    }
+
+    tmp = APICRead(APIC_ESR);
+    DPRINT("ESR value before enabling vector: 0x%X\n", tmp);
+
+    /* Enable sending errors */
+         tmp = ERROR_VECTOR;
+         APICWrite(APIC_LVT3, tmp);
+
+    /*
+     * Spec says clear errors after enabling vector
+     */
+    if (CPUMap[CPU].MaxLVT > 3)
+      APICWrite(APIC_ESR, 0);
+    tmp = APICRead(APIC_ESR);
+    DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
+       }
+}
+
+VOID
+HaliInitBSP(
+   VOID)
+{
+       PUSHORT ps;
+
+       /* Only initialize the BSP once */
+       if (BSPInitialized)
+               return;
+
+       BSPInitialized = TRUE;
+
+       DPRINT("APIC is mapped at 0x%X\n", APICBase);
+
+       if (VerifyLocalAPIC()) {
+               DPRINT("APIC found\n");
+       } else {
+               DPRINT1("No APIC found\n");
+               KeBugCheck(0);
+       }
+
+  CPUMap[BootCPU].MaxLVT = APICGetMaxLVT();
+
+  SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG)MpsTimerInterrupt);
+  SetInterruptGate(ERROR_VECTOR, (ULONG)MpsErrorInterrupt);
+  SetInterruptGate(SPURIOUS_VECTOR, (ULONG)MpsSpuriousInterrupt);
+
+  if (APICMode == amPIC) {
+    EnableSMPMode();
+  }
+
+  APICSetup();
+
+       /* BIOS data segment */
+       BIOSBase = (PULONG)BIOS_AREA;
+
+       /* Area for communicating with the APs */
+       CommonBase = (PULONG)COMMON_AREA;
+
+  /* Copy bootstrap code to common area */
+       memcpy((PVOID)((ULONG)CommonBase + PAGESIZE),
+                   &APstart,
+                   (ULONG)&APend - (ULONG)&APstart + 1);
+
+       /* Set shutdown code */
+       CMOS_WRITE(0xF, 0xA);
+
+       /* Set warm reset vector */
+       ps = (PUSHORT)((ULONG)BIOSBase + 0x467);
+       *ps = (COMMON_AREA + PAGESIZE) & 0xF;
+
+       ps = (PUSHORT)((ULONG)BIOSBase + 0x469);
+       *ps = (COMMON_AREA + PAGESIZE) >> 4;
+
+  /* Calibrate APIC timer */
+       APICCalibrateTimer(0);
+
+  /* The boot processor is online */
+  OnlineCPUs = (1 << 0);
+}
+
+#endif /* MP */
+
 VOID
 STDCALL
 HalInitializeProcessor (
-       ULONG   ProcessorNumber
-       )
+       ULONG   ProcessorNumber)
 {
-       return;
+
+#ifdef MP
+
+   PCOMMON_AREA_INFO Common;
+   ULONG StartupCount;
+   ULONG DeliveryStatus;
+   ULONG AcceptStatus;
+        ULONG CPU, i, j;
+        ULONG tmp, maxlvt;
+
+   if (ProcessorNumber == 0) {
+       /* Boot processor is already initialized */
+       NextCPU = 1;
+       return;
+   }
+
+   if (NextCPU < CPUCount) {
+      CPU = NextCPU;
+
+      DPRINT("Attempting to boot CPU %d\n", CPU);
+
+           /* Send INIT IPI */
+           APICSendIPI(CPUMap[CPU].APICId, APIC_DM_INIT, 0, APIC_ICR0_LEVEL_ASSERT);
+
+           APICSleep(200);
+
+           /* Deassert INIT */
+      APICSendIPI(CPUMap[CPU].APICId, APIC_DM_INIT, 0, APIC_ICR0_LEVEL_DEASSERT);
+
+      if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) {
+                          /* Clear APIC errors */
+         APICWrite(APIC_ESR, 0);
+         tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
+      }
+
+      Common = (PCOMMON_AREA_INFO)CommonBase;
+
+      /* Write the location of the AP stack */
+      Common->Stack = (ULONG)ExAllocatePool(NonPagedPool, MM_STACK_SIZE) + MM_STACK_SIZE;
+
+      DPRINT("CPU %d got stack at 0x%X\n", CPU, Common->Stack);
+#if 0
+      for (j = 0; j < 16; j++) {
+         Common->Debug[j] = 0;
+      }
+#endif
+
+      maxlvt = APICGetMaxLVT();
+
+                 /* Is this a local APIC or an 82489DX? */
+      StartupCount = (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) ? 2 : 0;
+
+                 for (i = 1; i <= StartupCount; i++)
+                 {
+         /* It's a local APIC, so send STARTUP IPI */
+         DPRINT("Sending startup signal %d\n", i);
+         /* Clear errors */
+         APICWrite(APIC_ESR, 0);
+         APICRead(APIC_ESR);
+
+         APICSendIPI(CPUMap[CPU].APICId,
+            0,
+            APIC_DM_STARTUP | ((COMMON_AREA + PAGESIZE) >> 12),
+            APIC_ICR0_LEVEL_DEASSERT);
+
+         /* Wait up to 10ms for IPI to be delivered */
+         j = 0;
+         do {
+            APICSleep(10);
+
+            /* Check Delivery Status */
+            DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;
+
+            j++;
+         } while ((DeliveryStatus) && (j < 1000));
+
+         APICSleep(200);
+
+                    /*
+                     * Due to the Pentium erratum 3AP.
+                     */
+                    if (maxlvt > 3) {
+                            APICRead(APIC_SIVR);
+                            APICWrite(APIC_ESR, 0);
+                    }
+
+         AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;
+
+         if (DeliveryStatus || AcceptStatus) {
+            break;
+         }
+      }
+
+      if (DeliveryStatus) {
+         DPRINT("STARTUP IPI for CPU %d was never delivered.\n", CPU);
+      }
+
+      if (AcceptStatus) {
+         DPRINT("STARTUP IPI for CPU %d was never accepted.\n", CPU);
+      }
+
+      if (!(DeliveryStatus || AcceptStatus)) {
+
+         /* Wait no more than 5 seconds for processor to boot */
+         DPRINT("Waiting for 5 seconds for CPU %d to boot\n", CPU);
+
+         /* Wait no more than 5 seconds */
+         for (j = 0; j < 50000; j++) {
+
+            if (CPUMap[CPU].Flags & CPU_ENABLED)
+               break;
+
+            APICSleep(100);
+         }
+      }
+
+      if (CPUMap[CPU].Flags & CPU_ENABLED) {
+         DbgPrint("CPU %d is now running\n", CPU);
+      } else {
+         DbgPrint("Initialization of CPU %d failed\n", CPU);
+      }
+
+#if 0
+      DPRINT("Debug bytes are:\n");
+
+      for (j = 0; j < 4; j++) {
+         DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
+            Common->Debug[j*4+0],
+            Common->Debug[j*4+1],
+            Common->Debug[j*4+2],
+            Common->Debug[j*4+3]);
+      }
+#endif
+      NextCPU++;
+   }
+
+#endif /* MP */
+
 }
 
 BOOLEAN
@@ -32,7 +1743,22 @@ HalAllProcessorsStarted (
        VOID
        )
 {
-       return TRUE;
+
+#ifdef MP
+
+  return (NextCPU >= CPUCount);
+
+#else /* MP */
+
+       if (BSPInitialized) {
+               return TRUE;
+       } else {
+               BSPInitialized = TRUE;
+               return FALSE;
+       }
+
+#endif /* MP */
+
 }
 
 BOOLEAN
@@ -42,7 +1768,598 @@ HalStartNextProcessor (
        ULONG   Unknown2
        )
 {
-       return FALSE;
+#ifdef MP
+
+  /* Display the APIC registers for debugging */
+  switch (Unknown1) {
+  case 0:
+    APICDump();
+    break;
+  case 1:
+    IOAPICDump();
+  }
+  for(;;);
+
+  return (NextCPU >= CPUCount);
+
+#endif /* MP */
+
+  return FALSE;
+}
+
+
+#ifdef MP
+
+ULONG MPChecksum(
+   PUCHAR Base,
+   ULONG Size)
+/*
+ *     Checksum an MP configuration block
+ */
+{
+   ULONG Sum = 0;
+
+   while (Size--)
+      Sum += *Base++;
+
+   return (Sum & 0xFF);
+}
+
+
+PCHAR HaliMPFamily(
+   ULONG Family,
+   ULONG Model)
+{
+   static CHAR str[32];
+   static PCHAR CPUs[] =
+   {
+      "80486DX", "80486DX",
+      "80486SX", "80486DX/2 or 80487",
+      "80486SL", "Intel5X2(tm)",
+      "Unknown", "Unknown",
+      "80486DX/4"
+   };
+   if (Family == 0x6)
+      return ("Pentium(tm) Pro");
+   if (Family == 0x5)
+      return ("Pentium(tm)");
+   if (Family == 0x0F && Model == 0x0F)
+      return("Special controller");
+   if (Family == 0x0F && Model == 0x00)
+      return("Pentium 4(tm)");
+   if (Family == 0x04 && Model < 9)
+      return CPUs[Model];
+   sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model);
+   return str;
+}
+
+
+static VOID HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m)
+{
+  ULONG ver;
+
+  if (!(m->CpuFlags & CPU_FLAG_ENABLED))
+    return;
+
+  DPRINT("Processor #%d %s APIC version %d\n",
+    m->ApicId,
+    HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8,
+      (m->FeatureFlags & CPU_MODEL_MASK) >> 4),
+      m->ApicVersion);
+
+  if (m->FeatureFlags & (1 << 0))
+    DPRINT("    Floating point unit present.\n");
+  if (m->FeatureFlags & (1 << 7))
+    DPRINT("    Machine Exception supported.\n");
+  if (m->FeatureFlags & (1 << 8))
+    DPRINT("    64 bit compare & exchange supported.\n");
+  if (m->FeatureFlags & (1 << 9))
+    DPRINT("    Internal APIC present.\n");
+  if (m->FeatureFlags & (1 << 11))
+    DPRINT("    SEP present.\n");
+  if (m->FeatureFlags & (1 << 12))
+    DPRINT("    MTRR present.\n");
+  if (m->FeatureFlags & (1 << 13))
+    DPRINT("    PGE  present.\n");
+  if (m->FeatureFlags & (1 << 14))
+    DPRINT("    MCA  present.\n");
+  if (m->FeatureFlags & (1 << 15))
+    DPRINT("    CMOV  present.\n");
+  if (m->FeatureFlags & (1 << 16))
+    DPRINT("    PAT  present.\n");
+  if (m->FeatureFlags & (1 << 17))
+    DPRINT("    PSE  present.\n");
+  if (m->FeatureFlags & (1 << 18))
+    DPRINT("    PSN  present.\n");
+  if (m->FeatureFlags & (1 << 19))
+    DPRINT("    Cache Line Flush Instruction present.\n");
+  /* 20 Reserved */
+  if (m->FeatureFlags & (1 << 21))
+    DPRINT("    Debug Trace and EMON Store present.\n");
+  if (m->FeatureFlags & (1 << 22))
+    DPRINT("    ACPI Thermal Throttle Registers present.\n");
+  if (m->FeatureFlags & (1 << 23))
+    DPRINT("    MMX  present.\n");
+  if (m->FeatureFlags & (1 << 24))
+    DPRINT("    FXSR  present.\n");
+  if (m->FeatureFlags & (1 << 25))
+    DPRINT("    XMM  present.\n");
+  if (m->FeatureFlags & (1 << 26))
+    DPRINT("    Willamette New Instructions present.\n");
+  if (m->FeatureFlags & (1 << 27))
+    DPRINT("    Self Snoop present.\n");
+  /* 28 Reserved */
+  if (m->FeatureFlags & (1 << 29))
+    DPRINT("    Thermal Monitor present.\n");
+  /* 30, 31 Reserved */
+
+  CPUMap[CPUCount].APICId = m->ApicId;
+
+  CPUMap[CPUCount].Flags = CPU_USABLE;
+
+  if (m->CpuFlags & CPU_FLAG_BSP) {
+    DPRINT("    Bootup CPU\n");
+    CPUMap[CPUCount].Flags |= CPU_BSP;
+    BootCPU = m->ApicId;
+  }
+
+  if (m->ApicId > MAX_CPU) {
+    DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU);
+    return;
+  }
+  ver = m->ApicVersion;
+
+  /*
+  * Validate version
+  */
+  if (ver == 0x0) {
+    DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId);
+    ver = 0x10;
+  }
+  CPUMap[CPUCount].APICVersion = ver;
+  
+  CPUCount++;
+}
+
+static VOID HaliMPBusInfo(PMP_CONFIGURATION_BUS m)
+{
+  static ULONG CurrentPCIBusId = 0;
+       CHAR str[7];
+
+       memcpy(str, m->BusType, 6);
+       str[6] = 0;
+       DPRINT("Bus #%d is %s\n", m->BusId, str);
+
+       if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
+               BUSMap[m->BusId] = MP_BUS_ISA;
+       } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
+               BUSMap[m->BusId] = MP_BUS_EISA;
+       } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) {
+               BUSMap[m->BusId] = MP_BUS_PCI;
+               PCIBUSMap[m->BusId] = CurrentPCIBusId;
+               CurrentPCIBusId++;
+       } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) {
+               BUSMap[m->BusId] = MP_BUS_MCA;
+       } else {
+               DPRINT("Unknown bustype %s - ignoring\n", str);
+       }
+}
+
+static VOID HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m)
+{
+  if (!(m->ApicFlags & CPU_FLAG_ENABLED))
+    return;
+
+  DPRINT("I/O APIC #%d Version %d at 0x%lX.\n",
+    m->ApicId, m->ApicVersion, m->ApicAddress);
+  if (IOAPICCount > MAX_IOAPIC) {
+    DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n",
+      MAX_IOAPIC, IOAPICCount);
+    DPRINT1("Recompile with bigger MAX_IOAPIC!.\n");
+    KeBugCheck(0);
+  }
+  IOAPICMap[IOAPICCount].ApicId = m->ApicId;
+  IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion;
+  IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress;
+  IOAPICCount++;
+}
+
+static VOID HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m)
+{
+  DPRINT("Int: type %d, pol %d, trig %d, bus %d,"
+    " IRQ %02x, APIC ID %x, APIC INT %02x\n",
+    m->IrqType, m->IrqFlag & 3,
+    (m->IrqFlag >> 2) & 3, m->SrcBusId,
+    m->SrcBusIrq, m->DstApicId, m->DstApicInt);
+  if (IRQCount > MAX_IRQ_SOURCE) {
+    DPRINT1("Max # of irq sources exceeded!!\n");
+    KeBugCheck(0);
+  }
+
+  IRQMap[IRQCount] = *m;
+  IRQCount++;
+}
+
+static VOID HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m)
+{
+  DPRINT("Lint: type %d, pol %d, trig %d, bus %d,"
+    " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
+    m->IrqType, m->IrqFlag & 3,
+    (m->IrqFlag >> 2) & 3, m->SrcBusId,
+    m->SrcBusIrq, m->DstApicId, m->DstApicLInt);
+  /*
+   * Well it seems all SMP boards in existence
+   * use ExtINT/LVT1 == LINT0 and
+   * NMI/LVT2 == LINT1 - the following check
+   * will show us if this assumptions is false.
+   * Until then we do not have to add baggage.
+   */
+  if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) {
+    DPRINT1("Invalid MP table!\n");
+    KeBugCheck(0);
+  }
+  if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) {
+    DPRINT1("Invalid MP table!\n");
+    KeBugCheck(0);
+  }
+}
+
+
+VOID
+HaliReadMPConfigTable(
+   PMP_CONFIGURATION_TABLE Table)
+/*
+   PARAMETERS:
+      Table = Pointer to MP configuration table
+ */
+{
+   PUCHAR Entry;
+   ULONG Count;
+
+   if ((ULONG)Table->Signature != MPC_SIGNATURE)
+   {
+      PCHAR pc = (PCHAR)&Table->Signature;
+
+      DbgPrint("Bad MP configuration block signature: %c%c%c%c\n", pc[0], pc[1], pc[2], pc[3]);
+      KeBugCheck(0);
+      return;
+   }
+
+   if (MPChecksum((PUCHAR)Table, Table->Length))
+   {
+      DbgPrint("Bad MP configuration block checksum\n");
+      KeBugCheck(0);
+      return;
+   }
+
+       if (Table->Specification < 0x04)
+   {
+      DbgPrint("Bad MP configuration table version (%d)\n",
+        Table->Specification);
+      KeBugCheck(0);
+      return;
+   }
+
+   APICBase = (PULONG)Table->LocalAPICAddress;
+   if (APICBase != (PULONG)APIC_DEFAULT_BASE)
+   {
+      DbgPrint("APIC base address is at 0x%X. " \
+        "I cannot handle non-standard adresses\n", APICBase);
+      KeBugCheck(0);
+   }
+
+   Entry = (PUCHAR)(Table + sizeof(MP_CONFIGURATION_TABLE));
+   Count = 0;
+   while (Count < Table->Length)
+   {
+      /* Switch on type */
+      switch (*Entry)
+      {
+         case MPCTE_PROCESSOR:
+         {
+            HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry);
+            Entry += sizeof(MP_CONFIGURATION_PROCESSOR);
+                             Count += sizeof(MP_CONFIGURATION_PROCESSOR);
+                             break;
+                    }
+                    case MPCTE_BUS:
+                    {
+                           HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry);
+                             Entry += sizeof(MP_CONFIGURATION_BUS);
+                           Count += sizeof(MP_CONFIGURATION_BUS);
+                           break;
+                  }
+                  case MPCTE_IOAPIC:
+                  {
+                           HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry);
+                             Entry += sizeof(MP_CONFIGURATION_IOAPIC);
+                             Count += sizeof(MP_CONFIGURATION_IOAPIC);
+                           break;
+                    }
+                    case MPCTE_INTSRC:
+                    {
+                         HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry);
+                             Entry += sizeof(MP_CONFIGURATION_INTSRC);
+                             Count += sizeof(MP_CONFIGURATION_INTSRC);
+                           break;
+                    }
+                    case MPCTE_LINTSRC:
+                    {
+            HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry);
+                             Entry += sizeof(MP_CONFIGURATION_INTLOCAL);
+                             Count += sizeof(MP_CONFIGURATION_INTLOCAL);
+                             break;
+                    }
+                 }
+        }
+}
+
+
+static VOID HaliConstructDefaultIOIrqMPTable(
+  ULONG Type)
+{
+       MP_CONFIGURATION_INTSRC intsrc;
+       ULONG i;
+
+       intsrc.Type = MPCTE_INTSRC;
+       intsrc.IrqFlag = 0;                     /* conforming */
+       intsrc.SrcBusId = 0;
+       intsrc.DstApicId = IOAPICMap[0].ApicId;
+
+       intsrc.IrqType = INT_VECTORED;
+       for (i = 0; i < 16; i++) {
+               switch (Type) {
+               case 2:
+                       if (i == 0 || i == 13)
+                               continue;       /* IRQ0 & IRQ13 not connected */
+                       /* Fall through */
+               default:
+                       if (i == 2)
+                               continue;       /* IRQ2 is never connected */
+               }
+
+               intsrc.SrcBusIrq = i;
+               intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */
+               HaliMPIntSrcInfo(&intsrc);
+       }
+
+       intsrc.IrqType = INT_EXTINT;
+       intsrc.SrcBusIrq = 0;
+       intsrc.DstApicInt = 0; /* 8259A to INTIN0 */
+       HaliMPIntSrcInfo(&intsrc);
+}
+
+
+static VOID HaliConstructDefaultISAMPTable(
+  ULONG Type)
+{
+       MP_CONFIGURATION_PROCESSOR processor;
+       MP_CONFIGURATION_BUS bus;
+       MP_CONFIGURATION_IOAPIC ioapic;
+       MP_CONFIGURATION_INTLOCAL lintsrc;
+       ULONG linttypes[2] = { INT_EXTINT, INT_NMI };
+       ULONG i;
+
+  APICBase = (PULONG)APIC_DEFAULT_BASE;
+
+  /*
+   * 2 CPUs, numbered 0 & 1.
+   */
+  processor.Type = MPCTE_PROCESSOR;
+       /* Either an integrated APIC or a discrete 82489DX. */
+  processor.ApicVersion = Type > 4 ? 0x10 : 0x01;
+  processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP;
+  /* FIXME: Get this from the bootstrap processor */
+  processor.CpuSignature = 0;
+  processor.FeatureFlags = 0;
+  processor.Reserved[0] = 0;
+  processor.Reserved[1] = 0;
+  for (i = 0; i < 2; i++) {
+    processor.ApicId = i;
+    HaliMPProcessorInfo(&processor);
+    processor.CpuFlags &= ~CPU_FLAG_BSP;
+  }
+
+  bus.Type = MPCTE_BUS;
+  bus.BusId = 0;
+  switch (Type) {
+    default:
+    DPRINT("Unknown standard configuration %d\n", Type);
+      /* Fall through */
+    case 1:
+    case 5:
+      memcpy(bus.BusType, "ISA   ", 6);
+      break;
+    case 2:
+    case 6:
+    case 3:
+      memcpy(bus.BusType, "EISA  ", 6);
+      break;
+    case 4:
+    case 7:
+      memcpy(bus.BusType, "MCA   ", 6);
+  }
+  HaliMPBusInfo(&bus);
+  if (Type > 4) {
+    bus.Type = MPCTE_BUS;
+    bus.BusId = 1;
+    memcpy(bus.BusType, "PCI   ", 6);
+    HaliMPBusInfo(&bus);
+  }
+
+  ioapic.Type = MPCTE_IOAPIC;
+  ioapic.ApicId = 2;
+  ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01;
+  ioapic.ApicFlags = MP_IOAPIC_USABLE;
+  ioapic.ApicAddress = IOAPIC_DEFAULT_BASE;
+  HaliMPIOApicInfo(&ioapic);
+
+  /*
+   * We set up most of the low 16 IO-APIC pins according to MPS rules.
+   */
+  HaliConstructDefaultIOIrqMPTable(Type);
+
+  lintsrc.Type = MPCTE_LINTSRC;
+  lintsrc.IrqType = 0;
+  lintsrc.IrqFlag = 0;  /* conforming */
+  lintsrc.SrcBusId = 0;
+  lintsrc.SrcBusIrq = 0;
+  lintsrc.DstApicId = MP_APIC_ALL;
+  for (i = 0; i < 2; i++) {
+    lintsrc.IrqType = linttypes[i];
+    lintsrc.DstApicLInt = i;
+    HaliMPIntLocalInfo(&lintsrc);
+  }
+}
+
+BOOLEAN
+HaliScanForMPConfigTable(
+   ULONG Base,
+   ULONG Size)
+/*
+   PARAMETERS:
+      Base = Base address of region
+      Size = Length of region to check
+   RETURNS:
+      TRUE if a valid MP configuration table was found
+ */
+{
+        PULONG bp = (PULONG)Base;
+        PMP_FLOATING_POINTER mpf;
+
+   while (Size > 0)
+   {
+      if (*bp == MPF_SIGNATURE)
+      {
+         if (!MPChecksum((PUCHAR)bp, 16))
+         {
+            mpf = (PMP_FLOATING_POINTER)bp;
+
+            DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n",
+              mpf->Specification);
+
+            if (mpf->Feature2 & FEATURE2_IMCRP) {
+               APICMode = amPIC;
+               DPRINT("Running in IMCR and PIC compatibility mode.\n")
+            } else {
+               APICMode = amVWIRE;
+               DPRINT("Running in Virtual Wire compatibility mode.\n");
+                                   }
+
+            switch (mpf->Feature1)
+            {
+               case 0:
+                  /* Non standard configuration */
+                  break;
+               case 1:
+                  DPRINT("ISA\n");
+                  break;
+               case 2:
+                  DPRINT("EISA with no IRQ8 chaining\n");
+                  break;
+               case 3:
+                  DPRINT("EISA\n");
+                  break;
+               case 4:
+                  DPRINT("MCA\n");
+                  break;
+               case 5:
+                  DPRINT("ISA and PCI\n");
+                  break;
+               case 6:
+                  DPRINT("EISA and PCI\n");
+                  break;
+               case 7:
+                  DPRINT("MCA and PCI\n");
+                  break;
+               default:
+                  DPRINT("Unknown standard configuration %d\n", mpf->Feature1);
+                  return FALSE;
+            }
+
+            CPUCount = 0;
+            IOAPICCount = 0;
+            IRQCount = 0;
+
+            if ((mpf->Feature1 == 0) && (mpf->Address)) {
+              HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)mpf->Address);
+            } else {
+              HaliConstructDefaultISAMPTable(mpf->Feature1);
+            }
+
+            return TRUE;
+         }
+      }
+      bp += 4;
+      Size -= 16;
+   }
+   return FALSE;
+}
+
+
+VOID
+HalpInitMPS(
+   VOID)
+{
+   USHORT EBDA;
+   ULONG CPU;
+
+   /* Only initialize MP system once. Once called the first time,
+      each subsequent call is part of the initialization sequence
+                       for an application processor. */
+  if (MPSInitialized) {
+    CPU = ThisCPU();
+
+    DPRINT("CPU %d says it is now booted.\n", CPU);
+
+    APICSetup();
+    APICCalibrateTimer(CPU);
+
+    /* This processor is now booted */
+    CPUMap[CPU].Flags |= CPU_ENABLED;
+    OnlineCPUs |= (1 << CPU);
+
+    return;
+  }
+
+  MPSInitialized = TRUE;
+
+  /*
+     Scan the system memory for an MP configuration table
+       1) Scan the first KB of system base memory
+       2) Scan the last KB of system base memory
+       3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh
+       4) Scan the Extended BIOS Data Area
+   */
+
+  if (!HaliScanForMPConfigTable(0x0, 0x400)) {
+    if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) {
+      if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) {
+        EBDA = *((PUSHORT)0x040E);
+        EBDA <<= 4;
+        if (!HaliScanForMPConfigTable((ULONG)EBDA, 0x400)) {
+          DbgPrint("No multiprocessor compliant system found.\n");
+          KeBugCheck(0);
+        }
+      }
+    }
+  }
+
+  /* Setup IRQ to vector translation map */
+  memset(&IRQVectorMap, sizeof(IRQVectorMap), 0);
+
+  /* Setup I/O APIC */
+  IOAPICSetup();
+
+  /* Setup busy waiting */
+  HalpCalibrateStallExecution();
+
+  /* Initialize the bootstrap processor */
+  HaliInitBSP();
+
+  NextCPU = 0;
 }
 
+#endif /* MP */
+
 /* EOF */
diff --git a/reactos/ntoskrnl/hal/x86/mps.S b/reactos/ntoskrnl/hal/x86/mps.S
new file mode 100644 (file)
index 0000000..c5a33cf
--- /dev/null
@@ -0,0 +1,76 @@
+/* $Id: mps.S,v 1.1 2001/04/13 16:12:25 chorns Exp $
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/hal/x86/mps.S
+ * PURPOSE:         Intel MultiProcessor specification support
+ * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *                  Created 12/04/2001
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <internal/i386/segment.h>
+
+/* FUNCTIONS *****************************************************************/
+
+#define BEFORE \
+  pusha; \
+  pushl %ds; \
+  pushl %es; \
+  pushl %fs; \
+  pushl %gs; \
+  movl  $(KERNEL_DS), %eax; \
+  movl  %eax, %ds; \
+  movl  %eax, %es; \
+  movl  %eax, %gs; \
+  movl  $(PCR_SELECTOR), %eax; \
+  movl  %eax, %fs;
+  
+#define AFTER \
+  popl  %gs; \
+  popl  %fs; \
+  popl  %es; \
+  popl  %ds; \
+  popa;
+
+.globl _MpsTimerInterrupt
+_MpsTimerInterrupt:
+  /* Save registers */ 
+  BEFORE
+
+  /* Call the C handler */
+  call  _MpsTimerHandler
+
+       /* Return to the caller */
+  AFTER
+  iret
+
+
+.globl _MpsErrorInterrupt
+_MpsErrorInterrupt:
+  /* Save registers */ 
+  BEFORE
+
+  /* Call the C handler */
+  call  _MpsErrorHandler
+
+       /* Return to the caller */
+  AFTER
+  iret
+
+
+.globl _MpsSpuriousInterrupt
+_MpsSpuriousInterrupt:
+  /* Save registers */ 
+  BEFORE
+
+  /* Call the C handler */
+  call  _MpsSpuriousHandler
+
+       /* Return to the caller */
+  AFTER
+  iret
+
+/* EOF */
diff --git a/reactos/ntoskrnl/hal/x86/mpsboot.asm b/reactos/ntoskrnl/hal/x86/mpsboot.asm
new file mode 100644 (file)
index 0000000..684b69a
--- /dev/null
@@ -0,0 +1,106 @@
+;
+; COPYRIGHT:       See COPYING in the top level directory
+; PROJECT:         ReactOS kernel
+; FILE:            ntoskrnl/hal/x86/mpsboot.c
+; PURPOSE:         Bootstrap code for application processors
+; PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+; UPDATE HISTORY:
+;                  Created 12/04/2001
+;
+
+;
+; Memory map at this stage is:
+;     0x2000  Location of our stack
+;     0x3000  Startup code for the APs (this code)
+;
+
+;
+; Base address of common area for BSP and APs
+;
+LOAD_BASE   equ 00200000h
+
+;
+; Magic value to be put in EAX when multiboot.S is called as part of the
+; application processor initialization process
+;
+AP_MAGIC    equ 12481020h
+
+;
+; Segment selectors
+;
+%define KERNEL_CS     (0x8)
+%define KERNEL_DS     (0x10)
+
+section .text
+
+global _APstart
+global _APend
+
+; 16 bit code
+BITS 16
+
+_APstart:
+       cli             ; Just in case
+
+  xor   ax, ax
+       mov             ds, ax
+       mov             ss, ax
+
+  mov   eax, 3000h + APgdt - _APstart
+       lgdt  [eax]
+
+  mov   eax, cr0
+  or    eax, 00010001h    ; Turn on protected mode and write protection
+  mov   cr0, eax
+
+  db    0eah
+  dw    3000h + flush - _APstart, KERNEL_CS
+
+; 32 bit code
+BITS 32
+
+flush:
+  mov   ax, KERNEL_DS
+  mov          ds, ax
+  mov          es, ax
+  mov          fs, ax
+  mov          gs, ax
+  mov          ss, ax
+
+  ; Setup a stack for the AP
+  mov   eax, 2000h
+  mov   eax, [eax]
+  mov   esp, eax
+
+  ; Jump to start of the kernel with AP magic in eax
+  mov      eax, AP_MAGIC
+  jmp      dword KERNEL_CS:(LOAD_BASE + 0x1000)
+
+  ; Never get here
+
+
+; Temporary GDT descriptor for the APs
+
+APgdt:
+; Limit
+  dw  (3*8)-1
+; Base
+  dd   3000h + gdt - _APstart
+
+gdt:
+  dw   0x0       ; Null descriptor
+  dw   0x0
+  dw   0x0
+  dw   0x0
+
+  dw   0xffff    ; Kernel code descriptor
+  dw   0x0000
+  dw   0x9a00
+  dw   0x00cf
+
+  dw   0xffff    ;  Kernel data descriptor
+  dw   0x0000
+  dw   0x9200
+  dw   0x00cf
+
+_APend:
diff --git a/reactos/ntoskrnl/hal/x86/mpsirql.c b/reactos/ntoskrnl/hal/x86/mpsirql.c
new file mode 100644 (file)
index 0000000..48c9b24
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/hal/x86/mpsirql.c
+ * PURPOSE:         Implements IRQLs for multiprocessor systems
+ * PROGRAMMERS:     David Welch (welch@cwcom.net)
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *     12/04/2001  CSH  Created
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <internal/bitops.h>
+#include <internal/ke.h>
+#include <internal/ps.h>
+#include <internal/hal/mps.h>
+
+#define NDEBUG
+#include <internal/debug.h>
+
+/* GLOBALS ******************************************************************/
+
+extern ULONG DpcQueueSize;
+
+static VOID KeSetCurrentIrql(KIRQL newlvl);
+
+/* FUNCTIONS ****************************************************************/
+
+#define IRQL2TPR(irql) (APIC_TPR_MIN + ((irql - DISPATCH_LEVEL - 1) << 4))
+
+static VOID HiSetCurrentPriority(
+  ULONG Priority)
+{
+//  DPRINT(" P(0x%X) \n", Priority);
+  APICWrite(APIC_TPR, Priority & APIC_TPR_PRI);
+}
+
+
+static VOID HiSwitchIrql(KIRQL OldIrql, ULONG Flags)
+/*
+ * FUNCTION: Switches to the current irql
+ * NOTE: Must be called with interrupt disabled
+ */
+{
+   PKTHREAD CurrentThread;
+   KIRQL CurrentIrql;
+
+   CurrentIrql = KeGetCurrentKPCR()->Irql;
+
+   if (CurrentIrql == HIGH_LEVEL)
+     {
+  /* Block all interrupts */
+  HiSetCurrentPriority(APIC_TPR_MAX);
+       return;
+     }
+
+  if (CurrentIrql == IPI_LEVEL)
+     {
+       HiSetCurrentPriority(APIC_TPR_MAX - 16);
+       popfl(Flags);
+       return;
+     }
+
+  if (CurrentIrql == CLOCK2_LEVEL)
+     {
+       HiSetCurrentPriority(APIC_TPR_MAX - 32);
+       popfl(Flags);
+       return;
+     }
+
+   if (CurrentIrql > DISPATCH_LEVEL)
+     {
+       HiSetCurrentPriority(IRQL2TPR(CurrentIrql));
+       popfl(Flags);
+       return;
+     }
+
+   /* Pass all interrupts */
+   HiSetCurrentPriority(0);
+
+   if (CurrentIrql == DISPATCH_LEVEL)
+     {
+       popfl(Flags);
+       return;
+     }
+
+   if (CurrentIrql == APC_LEVEL)
+     {
+       if (DpcQueueSize > 0 )
+         {
+            KeSetCurrentIrql(DISPATCH_LEVEL);
+            __asm__("sti\n\t");
+            KiDispatchInterrupt();
+            __asm__("cli\n\t");
+            KeSetCurrentIrql(PASSIVE_LEVEL);
+         }
+       popfl(Flags);
+       return;
+     }
+
+  CurrentThread = KeGetCurrentThread();
+
+  if (CurrentIrql == PASSIVE_LEVEL && 
+       CurrentThread != NULL && 
+       CurrentThread->ApcState.KernelApcPending)
+     {
+       KeSetCurrentIrql(APC_LEVEL);
+       __asm__("sti\n\t");
+       KiDeliverApc(0, 0, 0);
+       __asm__("cli\n\t");
+       KeSetCurrentIrql(PASSIVE_LEVEL);
+       popfl(Flags);
+     }
+   else
+     {
+       popfl(Flags);
+     }
+}
+
+
+KIRQL STDCALL KeGetCurrentIrql (VOID)
+/*
+ * PURPOSE: Returns the current irq level
+ * RETURNS: The current irq level
+ */
+{
+   return(KeGetCurrentKPCR()->Irql);
+}
+
+
+static VOID KeSetCurrentIrql(KIRQL newlvl)
+/*
+ * PURPOSE: Sets the current irq level without taking any action
+ */
+{
+//   DPRINT("KeSetCurrentIrql(newlvl %x)\n",newlvl);
+
+   KeGetCurrentKPCR()->Irql = newlvl;
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     KfLowerIrql
+ *
+ * DESCRIPTION
+ *     Restores the irq level on the current processor
+ *
+ * ARGUMENTS
+ *     NewIrql = Irql to lower to
+ *
+ * RETURN VALUE
+ *     None
+ *
+ * NOTES
+ *     Uses fastcall convention
+ */
+
+VOID FASTCALL
+KfLowerIrql (
+       KIRQL   NewIrql
+       )
+{
+  KIRQL CurrentIrql;
+  KIRQL OldIrql;
+  ULONG Flags;
+
+  //DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
+  //DbgPrint("KfLowerIrql(NewIrql %d)\n", NewIrql);
+  //KeBugCheck(0);
+
+  pushfl(Flags);
+  __asm__ ("\n\tcli\n\t");
+
+  CurrentIrql = KeGetCurrentKPCR()->Irql;
+  
+       if (NewIrql > CurrentIrql)
+       {
+               DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
+                         __FILE__, __LINE__, NewIrql, CurrentIrql);
+               KeDumpStackFrames (0, 32);
+               for(;;);
+       }
+
+       OldIrql = CurrentIrql;
+  KeGetCurrentKPCR()->Irql = NewIrql;
+       HiSwitchIrql(OldIrql, Flags);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     KeLowerIrql
+ *
+ * DESCRIPTION
+ *     Restores the irq level on the current processor
+ *
+ * ARGUMENTS
+ *     NewIrql = Irql to lower to
+ *
+ * RETURN VALUE
+ *     None
+ *
+ * NOTES
+ */
+
+VOID
+STDCALL
+KeLowerIrql (
+       KIRQL   NewIrql
+       )
+{
+       KfLowerIrql (NewIrql);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     KfRaiseIrql
+ *
+ * DESCRIPTION
+ *     Raises the hardware priority (irql)
+ *
+ * ARGUMENTS
+ *     NewIrql = Irql to raise to
+ *
+ * RETURN VALUE
+ *     previous irq level
+ *
+ * NOTES
+ *     Uses fastcall convention
+ */
+
+KIRQL
+FASTCALL
+KfRaiseIrql (
+       KIRQL   NewIrql
+       )
+{
+  KIRQL CurrentIrql;
+       KIRQL OldIrql;
+  ULONG Flags;
+
+  //DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
+  //DbgPrint("KfRaiseIrql(NewIrql %d)\n", NewIrql);
+  //KeBugCheck(0);
+
+  pushfl(Flags);
+   __asm__ ("\n\tcli\n\t");
+
+  CurrentIrql = KeGetCurrentKPCR()->Irql;
+
+       if (NewIrql < CurrentIrql)
+       {
+               DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
+                         __FILE__,__LINE__,CurrentIrql,NewIrql);
+               KeBugCheck (0);
+               for(;;);
+       }
+
+       OldIrql = CurrentIrql;
+       KeGetCurrentKPCR()->Irql = NewIrql;
+
+  //DPRINT("NewIrql %x OldIrql %x\n", NewIrql, OldIrql);
+       HiSwitchIrql(OldIrql, Flags);
+       return OldIrql;
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     KeRaiseIrql
+ *
+ * DESCRIPTION
+ *     Raises the hardware priority (irql)
+ *
+ * ARGUMENTS
+ *     NewIrql = Irql to raise to
+ *     OldIrql (OUT) = Caller supplied storage for the previous irql
+ *
+ * RETURN VALUE
+ *     None
+ *
+ * NOTES
+ *     Calls KfRaiseIrql
+ */
+
+VOID
+STDCALL
+KeRaiseIrql (
+       KIRQL   NewIrql,
+       PKIRQL  OldIrql
+       )
+{
+       *OldIrql = KfRaiseIrql (NewIrql);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     KeRaiseIrqlToDpcLevel
+ *
+ * DESCRIPTION
+ *     Raises the hardware priority (irql) to DISPATCH level
+ *
+ * ARGUMENTS
+ *     None
+ *
+ * RETURN VALUE
+ *     Previous irq level
+ *
+ * NOTES
+ *     Calls KfRaiseIrql
+ */
+
+KIRQL
+STDCALL
+KeRaiseIrqlToDpcLevel (VOID)
+{
+       return KfRaiseIrql (DISPATCH_LEVEL);
+}
+
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     KeRaiseIrqlToSynchLevel
+ *
+ * DESCRIPTION
+ *     Raises the hardware priority (irql) to CLOCK2 level
+ *
+ * ARGUMENTS
+ *     None
+ *
+ * RETURN VALUE
+ *     Previous irq level
+ *
+ * NOTES
+ *     Calls KfRaiseIrql
+ */
+
+KIRQL
+STDCALL
+KeRaiseIrqlToSynchLevel (VOID)
+{
+       return KfRaiseIrql (CLOCK2_LEVEL);
+}
+
+
+BOOLEAN STDCALL HalBeginSystemInterrupt (ULONG Vector,
+                                        KIRQL Irql,
+                                        PKIRQL OldIrql)
+{
+  DPRINT("Vector (0x%X)  Irql (0x%X)\n",
+    Vector, Irql);
+
+  if (Vector < FIRST_DEVICE_VECTOR ||
+    Vector > FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
+    DPRINT("Not a device interrupt\n");
+         return FALSE;
+  }
+
+  /*
+   * Acknowledge the interrupt
+   */
+  APICSendEOI();
+
+  *OldIrql = KeGetCurrentIrql();
+
+  KeSetCurrentIrql(Irql);
+
+  return TRUE;
+}
+
+
+VOID STDCALL HalEndSystemInterrupt (KIRQL Irql,
+                                   ULONG Unknown2)
+{
+   KeSetCurrentIrql(Irql);
+}
+
+
+BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
+                                          ULONG Unknown2)
+{
+  ULONG irq;
+
+  DPRINT("Vector (0x%X)\n", Vector);
+
+  if (Vector < FIRST_DEVICE_VECTOR ||
+    Vector > FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)  {
+    DPRINT("Not a device interrupt\n");
+         return FALSE;
+  }
+
+  irq = VECTOR2IRQ(Vector);
+
+  IOAPICMaskIrq(0, irq);
+
+  return TRUE;
+}
+
+
+BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
+                                         ULONG Unknown2,
+                                         ULONG Unknown3)
+{
+  ULONG irq;
+
+  DPRINT("Vector (0x%X)\n", Vector);
+
+  if (Vector < FIRST_DEVICE_VECTOR ||
+    Vector > FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
+    DPRINT("Not a device interrupt\n");
+         return FALSE;
+  }
+
+  irq = VECTOR2IRQ(Vector);
+
+  IOAPICUnmaskIrq(0, irq);
+
+  return TRUE;
+}
+
+/* EOF */
index 0fe87b1..ac4d14a 100644 (file)
@@ -1,4 +1,4 @@
-OBJECTS_HAL = \
+OBJECTS_HAL_COMMON = \
        hal/x86/adapter.o \
        hal/x86/beep.o \
        hal/x86/bios32.o \
@@ -9,7 +9,6 @@ OBJECTS_HAL = \
        hal/x86/fmutex.o \
        hal/x86/halinit.o \
        hal/x86/isa.o \
-       hal/x86/irql.o \
        hal/x86/kdbg.o \
        hal/x86/mbr.o \
        hal/x86/misc.o \
@@ -24,3 +23,17 @@ OBJECTS_HAL = \
        hal/x86/sysinfo.o \
        hal/x86/time.o \
        hal/x86/udelay.o
+
+OBJECTS_HAL_UP = \
+       hal/x86/irql.o
+
+OBJECTS_HAL_MP = \
+       hal/x86/mps.o \
+       hal/x86/mpsboot.o \
+       hal/x86/mpsirql.o
+
+ifeq ($(MP), 1)
+OBJECTS_HAL = $(OBJECTS_HAL_COMMON) $(OBJECTS_HAL_MP)
+else
+OBJECTS_HAL = $(OBJECTS_HAL_COMMON) $(OBJECTS_HAL_UP)
+endif
index 5a86d12..58d7949 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <ddk/ntddk.h>
 #include <string.h>
+#include <internal/hal/mps.h>
 
 #define NDEBUG
 #include <internal/debug.h>
@@ -38,13 +39,15 @@ static BYTE
 HalQueryCMOS (BYTE Reg)
 {
     BYTE Val;
+    ULONG Flags;
 
     Reg |= 0x80;
+    pushfl(Flags);
     __asm__("cli\n");  // AP unsure as to whether to do this here
     WRITE_PORT_UCHAR((PUCHAR)0x70, Reg);
     Val = READ_PORT_UCHAR((PUCHAR)0x71);
     WRITE_PORT_UCHAR((PUCHAR)0x70, 0);
-    __asm__("sti\n");  // AP unsure about this too..
+    popfl(Flags);
 
     return(Val);
 }
@@ -53,12 +56,15 @@ HalQueryCMOS (BYTE Reg)
 static VOID
 HalSetCMOS (BYTE Reg, BYTE Val)
 {
+    ULONG Flags;
+
     Reg |= 0x80;
+    pushfl(Flags);
     __asm__("cli\n");  // AP unsure as to whether to do this here
     WRITE_PORT_UCHAR((PUCHAR)0x70, Reg);
     WRITE_PORT_UCHAR((PUCHAR)0x71, Val);
     WRITE_PORT_UCHAR((PUCHAR)0x70, 0);
-    __asm__("sti\n");  // AP unsure about this too..
+    popfl(Flags);
 }
 
 
index 9d3b104..0329de7 100644 (file)
@@ -20,7 +20,7 @@
  * MA 02139, USA.  
  *
  */
-/* $Id: udelay.c,v 1.7 2001/03/16 18:11:21 dwelch Exp $
+/* $Id: udelay.c,v 1.8 2001/04/13 16:12:25 chorns Exp $
  *
  * PROJECT:        ReactOS kernel
  * FILE:           ntoskrnl/hal/x86/udelay.c
@@ -34,7 +34,7 @@
 
 #include <ddk/ntddk.h>
 
-#define NDEBUG
+//#define NDEBUG
 #include <internal/debug.h>
 
 /* GLOBALS ******************************************************************/
@@ -77,6 +77,8 @@ static unsigned int delay_count = 1;
 #define                TMR_CH1         0x4     /*    Channel 1 bit             */
 #define                TMR_CH0         0x2     /*    Channel 0 bit             */
 
+static BOOLEAN UdelayCalibrated = FALSE;
+
 /* FUNCTIONS **************************************************************/
 
 void init_pit(float h, unsigned char channel)
@@ -98,7 +100,7 @@ void init_pit(float h, unsigned char channel)
 VOID STDCALL
 __KeStallExecutionProcessor(ULONG Loops)
 {
-   unsigned int i;
+   register unsigned int i;
    for (i=0; i<Loops;i++);
 }
 
@@ -108,74 +110,107 @@ VOID STDCALL KeStallExecutionProcessor(ULONG Microseconds)
 }
 
 #define HZ (100)
-#define CLOCK_TICK_RATE (1193180)
-#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ)
+#define CLOCK_TICK_RATE (1193182)
+#define LATCH (CLOCK_TICK_RATE / HZ)
+
+static ULONG Read8254Timer(VOID)
+{
+       ULONG Count;
+
+       WRITE_PORT_UCHAR((PUCHAR)0x43, 0x00);
+       Count = READ_PORT_UCHAR((PUCHAR)0x40);
+       Count |= READ_PORT_UCHAR((PUCHAR)0x40) << 8;
+       return Count;
+}
+
+
+static VOID WaitFor8254Wraparound(VOID)
+{
+       ULONG CurCount, PrevCount = ~0;
+       LONG Delta;
+
+       CurCount = Read8254Timer();
+
+       do {
+               PrevCount = CurCount;
+               CurCount = Read8254Timer();
+               Delta = CurCount - PrevCount;
+
+       /*
+        * This limit for delta seems arbitrary, but it isn't, it's
+        * slightly above the level of error a buggy Mercury/Neptune
+        * chipset timer can cause.
+        */
+
+       } while (Delta < 300);
+}
 
 VOID HalpCalibrateStallExecution(VOID)
 {
-   unsigned int prevtick;
-   unsigned int i;
-   unsigned int calib_bit;
-   extern volatile ULONG KiRawTicks;
-   
+   ULONG i;
+   ULONG calib_bit;
+        ULONG CurCount;
+
+   if (UdelayCalibrated)
+      return;
+
+   UdelayCalibrated = TRUE;
+
    DbgPrint("Calibrating delay loop... [");
-   
+
    /* Initialise timer interrupt with MILLISECOND ms interval        */
-   //init_pit(FREQ, 0);
    WRITE_PORT_UCHAR((PUCHAR)0x43, 0x34);  /* binary, mode 2, LSB/MSB, ch 0 */
    WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH & 0xff); /* LSB */
    WRITE_PORT_UCHAR((PUCHAR)0x40, LATCH >> 8); /* MSB */
-   
+
    /* Stage 1:  Coarse calibration                                   */
-   
+
+   WaitFor8254Wraparound();
+
+   delay_count = 1;
+
    do {
-      delay_count <<= 1;          /* Next delay count to try        */
-      
-      prevtick=KiRawTicks;             /* Wait for the start of the next */
-      while(prevtick==KiRawTicks);     /* timer tick                     */
-      
-      prevtick=KiRawTicks;             /* Start measurement now          */
-      __KeStallExecutionProcessor(delay_count);       /* Do the delay                   */
-   } while(prevtick == KiRawTicks);     /* Until delay is just too big    */
-   
+      delay_count <<= 1;                  /* Next delay count to try */
+
+      WaitFor8254Wraparound();
+
+      __KeStallExecutionProcessor(delay_count);      /* Do the delay */
+
+           CurCount = Read8254Timer();
+   } while (CurCount > LATCH / 2);
+
    delay_count >>= 1;              /* Get bottom value for delay     */
-   
+
    /* Stage 2:  Fine calibration                                     */
    DbgPrint("delay_count: %d", delay_count);
-   
+
    calib_bit = delay_count;        /* Which bit are we going to test */
 
    for(i=0;i<PRECISION;i++) {
-      calib_bit >>= 1;            /* Next bit to calibrate          */
-      if(!calib_bit) break;       /* If we have done all bits, stop */
-      
-      delay_count |= calib_bit;   /* Set the bit in delay_count     */
-      
-      prevtick=KiRawTicks;             /* Wait for the start of the next */
-      while(prevtick==KiRawTicks);     /* timer tick                     */
-      
-      prevtick=KiRawTicks;             /* Start measurement now          */
-      __KeStallExecutionProcessor(delay_count);       /* Do the delay                   */
-      
-      if(prevtick != KiRawTicks)       /* If a tick has passed, turn the */
-       delay_count &= ~calib_bit;     /* calibrated bit back off */
+      calib_bit >>= 1;             /* Next bit to calibrate          */
+      if(!calib_bit) break;        /* If we have done all bits, stop */
+
+      delay_count |= calib_bit;        /* Set the bit in delay_count */
+
+      WaitFor8254Wraparound();
+
+      __KeStallExecutionProcessor(delay_count);      /* Do the delay */
+
+           CurCount = Read8254Timer();
+      if (CurCount <= LATCH / 2)   /* If a tick has passed, turn the */
+        delay_count &= ~calib_bit; /* calibrated bit back off        */
    }
-   
+
    /* We're finished:  Do the finishing touches                      */
-   
-   delay_count /= MILLISEC;       /* Calculate delay_count for 1ms   */
-   
+
+   delay_count /= (MILLISEC / 2);   /* Calculate delay_count for 1ms */
+
    DbgPrint("]\n");
    DbgPrint("delay_count: %d\n", delay_count);
-   DbgPrint("CPU speed: %d\n", delay_count/500);
+   DbgPrint("CPU speed: %d\n", delay_count/250);
 #if 0
    DbgPrint("About to start delay loop test\n");
-   for (i = 0; i < (10*1000*20); i++)
-     {
-       KeStallExecutionProcessor(50);
-     }
    DbgPrint("Waiting for five minutes...");
-   KeStallExecutionProcessor(5*60*1000*1000);
    for (i = 0; i < (5*60*1000*20); i++)
      {
        KeStallExecutionProcessor(50);
diff --git a/reactos/ntoskrnl/include/internal/hal/mps.h b/reactos/ntoskrnl/include/internal/hal/mps.h
new file mode 100644 (file)
index 0000000..265e322
--- /dev/null
@@ -0,0 +1,432 @@
+#ifndef __INCLUDE_HAL_MPS
+#define __INCLUDE_HAL_MPS
+
+#define APIC_DEFAULT_BASE     0xFEE00000    /* Default Local APIC Base Register Address */
+#define IOAPIC_DEFAULT_BASE   0xFEC00000    /* Default I/O APIC Base Register Address */
+
+/* APIC Register Address Map */
+#define APIC_ID      0x0020 /* Local APIC ID Register (R/W) */
+#define APIC_VER     0x0030 /* Local APIC Version Register (R) */
+#define APIC_TPR     0x0080 /* Task Priority Register (R/W) */
+#define APIC_APR     0x0090 /* Arbitration Priority Register (R) */
+#define APIC_PPR     0x00A0 /* Processor Priority Register (R) */
+#define APIC_EOI     0x00B0 /* EOI Register (W) */
+#define APIC_LDR     0x00D0 /* Logical Destination Register (R/W) */
+#define APIC_DFR     0x00E0 /* Destination Format Register (0-27 R, 28-31 R/W) */
+#define APIC_SIVR    0x00F0 /* Spurious Interrupt Vector Register (0-3 R, 4-9 R/W) */
+#define APIC_ISR     0x0100 /* Interrupt Service Register 0-255 (R) */
+#define APIC_TMR     0x0180 /* Trigger Mode Register 0-255 (R) */
+#define APIC_IRR     0x0200 /* Interrupt Request Register 0-255 (r) */
+#define APIC_ESR     0x0280 /* Error Status Register (R) */
+#define APIC_ICR0    0x0300 /* Interrupt Command Register 0-31 (R/W) */
+#define APIC_ICR1    0x0310 /* Interrupt Command Register 32-63 (R/W) */
+#define APIC_LVTT    0x0320 /* Local Vector Table (Timer) (R/W) */
+#define APIC_LVTPC   0x0340 /* Performance Counter LVT (R/W) */
+#define APIC_LINT0   0x0350 /* Local Vector Table (LINT0) (R/W) */
+#define APIC_LINT1   0x0360 /* Local Vector Table (LINT1) (R/W) */
+#define APIC_LVT3    0x0370 /* Local Vector Table (Error) (R/W) */
+#define APIC_ICRT    0x0380 /* Initial Count Register for Timer (R/W) */
+#define APIC_CCRT    0x0390 /* Current Count Register for Timer (R) */
+#define APIC_TDCR    0x03E0 /* Timer Divide Configuration Register (R/W) */
+
+#define APIC_ID_MASK       (0xF << 24)
+#define GET_APIC_ID(x)    (((x) & APIC_ID_MASK) >> 24)
+#define APIC_VER_MASK      0xFF00FF
+#define GET_APIC_VERSION(x)((x) & 0xFF)
+#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFF)
+
+#define APIC_TPR_PRI       0xFF
+#define APIC_TPR_INT       0xF0
+#define APIC_TPR_SUB       0xF
+#define APIC_TPR_MAX       0xFF           /* Maximum priority */
+#define APIC_TPR_MIN       0x20           /* Minimum priority */
+
+#define APIC_LDR_MASK      (0xFF << 24)
+
+#define APIC_SIVR_ENABLE   (0x1 << 8)
+#define APIC_SIVR_FOCUS    (0x1 << 9)
+
+#define APIC_ESR_MASK      (0xFE << 0)    /* Error Mask */
+
+#define APIC_ICR0_VECTOR   (0xFF << 0)    /* Vector */
+#define APIC_ICR0_DM       (0x7 << 8)     /* Delivery Mode */
+#define APIC_ICR0_DESTM    (0x1 << 11)    /* Destination Mode */
+#define APIC_ICR0_DS       (0x1 << 12)    /* Delivery Status */
+#define APIC_ICR0_LEVEL    (0x1 << 14)    /* Level */
+#define APIC_ICR0_TM       (0x1 << 15)    /* Trigger Mode */
+#define APIC_ICR0_DESTS    (0x3 << 18)    /* Destination Shorthand */
+
+/* Delivery Modes */
+#define APIC_DM_FIXED            (0x0 << 8)
+#define APIC_DM_LOWEST         (0x1 << 8)
+#define APIC_DM_SMI                (0x2 << 8)
+#define APIC_DM_REMRD            (0x3 << 8)
+#define APIC_DM_NMI                (0x4 << 8)
+#define APIC_DM_INIT      (0x5 << 8)
+#define APIC_DM_STARTUP   (0x6 << 8)
+#define APIC_DM_EXTINT   (0x7 << 8)
+#define GET_APIC_DELIVERY_MODE(x)      (((x) >> 8) & 0x7)
+#define SET_APIC_DELIVERY_MODE(x,y)    (((x) & ~0x700) | ((y) << 8))
+
+/* Destination Shorthand values */
+#define APIC_ICR0_DESTS_FIELD          (0x0 << 0)
+#define APIC_ICR0_DESTS_SELF           (0x1 << 18)
+#define APIC_ICR0_DESTS_ALL            (0x2 << 18)
+#define APIC_ICR0_DESTS_ALL_BUT_SELF   (0x3 << 18)
+
+#define APIC_ICR0_LEVEL_DEASSERT (0x0 << 14) /* Deassert level */
+#define APIC_ICR0_LEVEL_ASSERT   (0x1 << 14) /* Assert level */
+
+#define GET_APIC_DEST_FIELD(x)   (((x) >> 24) & 0xFF)
+#define SET_APIC_DEST_FIELD(x)   (((x) & 0xFF) << 24)
+
+#define GET_APIC_TIMER_BASE(x)   (((x) >> 18) & 0x3)
+#define SET_APIC_TIMER_BASE(x)   ((x) << 18)
+#define APIC_TIMER_BASE_CLKIN    0x0
+#define APIC_TIMER_BASE_TMBASE   0x1
+#define APIC_TIMER_BASE_DIV      0x2
+
+#define APIC_LVT_VECTOR                  (0xFF << 0)   /* Vector */
+#define APIC_LVT_DS                      (0x1 << 12)   /* Delivery Status */
+#define APIC_LVT_REMOTE_IRR              (0x1 << 14)           /* Remote IRR */
+#define APIC_LVT_LEVEL_TRIGGER (0x1 << 15)             /* Lvel Triggered */
+#define APIC_LVT_MASKED            (0x1 << 16)   /* Mask */
+#define APIC_LVT_PERIODIC              (0x1 << 17)   /* Timer Mode */
+
+#define APIC_LVT3_DM        (0x7 << 8)
+#define APIC_LVT3_IIPP      (0x1 << 13)
+#define APIC_LVT3_TM        (0x1 << 15)
+#define APIC_LVT3_MASKED    (0x1 << 16)
+#define APIC_LVT3_OS        (0x1 << 17)
+
+#define APIC_TDCR_TMBASE   (0x1 << 2)
+#define APIC_TDCR_MASK     0x0F
+#define APIC_TDCR_2        0x00
+#define APIC_TDCR_4        0x01
+#define APIC_TDCR_8        0x02
+#define APIC_TDCR_16       0x03
+#define APIC_TDCR_32       0x08
+#define APIC_TDCR_64       0x09
+#define APIC_TDCR_128      0x0A
+#define APIC_TDCR_1        0x0B
+
+#define APIC_TARGET_SELF         0x100
+#define APIC_TARGET_ALL          0x200
+#define APIC_TARGET_ALL_BUT_SELF 0x300
+
+#define IPI_CACHE_FLUSH    0x40
+#define IPI_INV_TLB        0x41
+#define IPI_INV_PTE        0x42
+#define IPI_INV_RESCHED    0x43
+#define IPI_STOP           0x44
+
+
+#define APIC_INTEGRATED(version) (version & 0xF0)
+
+
+/* I/O APIC Register Address Map */
+#define IOAPIC_IOREGSEL 0x0000  /* I/O Register Select (index) (R/W) */
+#define IOAPIC_IOWIN    0x0010  /* I/O window (data) (R/W) */
+
+#define IOAPIC_ID       0x0000  /* IO APIC ID (R/W) */
+#define IOAPIC_VER      0x0001  /* IO APIC Version (R) */
+#define IOAPIC_ARB      0x0002  /* IO APIC Arbitration ID (R) */
+#define IOAPIC_REDTBL   0x0010  /* Redirection Table (0-23 64-bit registers) (R/W) */
+
+#define IOAPIC_ID_MASK        (0xF << 24)
+#define GET_IOAPIC_ID(x)           (((x) & IOAPIC_ID_MASK) >> 24)
+#define SET_IOAPIC_ID(x)           ((x) << 24)
+
+#define IOAPIC_VER_MASK       (0xFF)
+#define GET_IOAPIC_VERSION(x) (((x) & IOAPIC_VER_MASK))
+#define IOAPIC_MRE_MASK       (0xFF << 16)  /* Maximum Redirection Entry */
+#define GET_IOAPIC_MRE(x)     (((x) & IOAPIC_MRE_MASK) >> 16)
+
+#define IOAPIC_ARB_MASK       (0xF << 24)
+#define GET_IOAPIC_ARB(x)          (((x) & IOAPIC_ARB_MASK) >> 24)
+
+#define IOAPIC_TBL_DELMOD   (0x7 << 10) /* Delivery Mode (see APIC_DM_*) */
+#define IOAPIC_TBL_DM       (0x1 << 11) /* Destination Mode */
+#define IOAPIC_TBL_DS       (0x1 << 12) /* Delivery Status */
+#define IOAPIC_TBL_INTPOL   (0x1 << 13) /* Interrupt Input Pin Polarity */
+#define IOAPIC_TBL_RIRR     (0x1 << 14) /* Remote IRR */
+#define IOAPIC_TBL_TM       (0x1 << 15) /* Trigger Mode */
+#define IOAPIC_TBL_IM       (0x1 << 16) /* Interrupt Mask */
+#define IOAPIC_TBL_DF0      (0xF << 56) /* Destination Field (physical mode) */
+#define IOAPIC_TBL_DF1      (0xFF<< 56) /* Destination Field (logical mode) */
+#define IOAPIC_TBL_VECTOR   (0xFF << 0) /* Vector (10h - FEh) */
+
+typedef struct _IOAPIC_ROUTE_ENTRY {
+       ULONG   vector          :  8,
+               delivery_mode   :  3,   /* 000: FIXED
+                                                      * 001: lowest priority
+                                                      * 111: ExtINT
+                                                      */
+               dest_mode       :  1,       /* 0: physical, 1: logical */
+               delivery_status :  1,
+               polarity        :  1,
+               irr             :  1,
+               trigger         :  1,       /* 0: edge, 1: level */
+               mask            :  1,         /* 0: enabled, 1: disabled */
+               __reserved_2    : 15;
+
+       union {         struct { ULONG
+                                       __reserved_1    : 24,
+                                       physical_dest   :  4,
+                                       __reserved_2    :  4;
+                       } physical;
+
+                       struct { ULONG
+                                       __reserved_1    : 24,
+                                       logical_dest    :  8;
+                       } logical;
+       } dest;
+} __attribute__ ((packed)) IOAPIC_ROUTE_ENTRY, *PIOAPIC_ROUTE_ENTRY;
+
+typedef struct _IOAPIC_INFO
+{
+   ULONG  ApicId;         /* APIC ID */
+   ULONG  ApicVersion;    /* APIC version */
+   ULONG  ApicAddress;    /* APIC address */
+   ULONG  EntryCount;     /* Number of redirection entries */
+} IOAPIC_INFO, *PIOAPIC_INFO;
+
+
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR       0xEF
+
+#define CALL_FUNCTION_VECTOR   0xFB
+#define RESCHEDULE_VECTOR                0xFC
+#define INVALIDATE_TLB_VECTOR  0xFD
+#define ERROR_VECTOR                             0xFE
+#define SPURIOUS_VECTOR                          0xFF  /* Must be 0xXF */
+
+/*
+ * First APIC vector available to drivers: (vectors 0x30-0xEE)
+ * we start at 0x31 to spread out vectors evenly between priority
+ * levels.
+ */
+#define FIRST_DEVICE_VECTOR      0x31
+#define FIRST_SYSTEM_VECTOR      0xEF
+#define NUMBER_DEVICE_VECTORS (FIRST_SYSTEM_VECTOR - FIRST_DEVICE_VECTOR)
+
+
+/* MP Floating Pointer Structure */
+#define MPF_SIGNATURE (('_' << 24) | ('P' << 16) | ('M' << 8) | '_')
+
+typedef struct __attribute__((packed)) _MP_FLOATING_POINTER
+{
+       ULONG Signature[4];     /* _MP_ */
+       ULONG Address;          /* Physical Address Pointer (0 means no configuration table exist) */
+       UCHAR Length;           /* Structure length in 16-byte paragraphs */
+       UCHAR Specification;    /* Specification revision       */
+       UCHAR Checksum;         /* Checksum */
+       UCHAR Feature1;         /* MP System Configuration Type */
+       UCHAR Feature2;         /* Bit 7 set for IMCR|PIC */
+       UCHAR Feature3;         /* Unused (0) */
+       UCHAR Feature4;         /* Unused (0) */
+       UCHAR Feature5;         /* Unused (0) */
+} MP_FLOATING_POINTER, *PMP_FLOATING_POINTER;
+
+#define FEATURE2_IMCRP  0x80
+
+/* MP Configuration Table Header */
+#define MPC_SIGNATURE (('P' << 24) | ('M' << 16) | ('C' << 8) | 'P')
+
+typedef struct __attribute__((packed)) _MP_CONFIGURATION_TABLE
+{
+       ULONG Signature[4];     /* PCMP */
+       USHORT Length;          /* Size of configuration table */
+       CHAR  Specification;    /* Specification Revision */
+       CHAR Checksum;          /* Checksum */
+       CHAR Oem[8];            /* OEM ID */
+       CHAR ProductId[12];     /* Product ID */
+       ULONG OemTable;         /* 0 if not present */
+       USHORT OemTableSize;    /* 0 if not present */
+       USHORT EntryCount;      /* Number of entries */
+       ULONG LocalAPICAddress; /* Local APIC address */
+  USHORT ExtTableLength;  /* Extended Table Length */
+  UCHAR ExtTableChecksum; /* Extended Table Checksum */
+       UCHAR Reserved;         /* Reserved */
+} MP_CONFIGURATION_TABLE, *PMP_CONFIGURATION_TABLE;
+
+/* MP Configuration Table Entries */
+#define MPCTE_PROCESSOR 0   /* One entry per processor */
+#define MPCTE_BUS       1   /* One entry per bus */
+#define MPCTE_IOAPIC    2   /* One entry per I/O APIC */
+#define MPCTE_INTSRC    3   /* One entry per bus interrupt source */
+#define MPCTE_LINTSRC   4   /* One entry per system interrupt source */
+
+
+typedef struct __attribute__((packed)) _MP_CONFIGURATION_PROCESSOR
+{
+       UCHAR Type;         /* 0 */
+       UCHAR ApicId;       /* Local APIC ID for the processor */
+       UCHAR ApicVersion;  /* Local APIC version */
+       UCHAR CpuFlags;     /* CPU flags */
+       ULONG CpuSignature; /* CPU signature */
+  ULONG FeatureFlags; /* CPUID feature value */
+       ULONG Reserved[2];  /* Reserved (0) */
+} MP_CONFIGURATION_PROCESSOR, *PMP_CONFIGURATION_PROCESSOR;
+
+#define CPU_FLAG_ENABLED         1  /* Processor is available */
+#define CPU_FLAG_BSP             2  /* Processor is the bootstrap processor */
+
+#define CPU_STEPPING_MASK  0x0F
+#define CPU_MODEL_MASK    0xF0
+#define CPU_FAMILY_MASK           0xF00
+
+
+typedef struct __attribute__((packed)) _MP_CONFIGURATION_BUS
+{
+       UCHAR Type;         /* 1 */
+       UCHAR BusId;        /* Bus ID */
+       UCHAR BusType[6];   /* Bus type */
+} MP_CONFIGURATION_BUS, *PMP_CONFIGURATION_BUS;
+
+#define MAX_BUS 32
+
+#define MP_BUS_ISA  1
+#define MP_BUS_EISA 2
+#define MP_BUS_PCI  3
+#define MP_BUS_MCA  4
+
+#define BUSTYPE_EISA     "EISA"
+#define BUSTYPE_ISA        "ISA"
+#define BUSTYPE_INTERN "INTERN"        /* Internal BUS */
+#define BUSTYPE_MCA        "MCA"
+#define BUSTYPE_VL         "VL"                  /* Local bus */
+#define BUSTYPE_PCI        "PCI"
+#define BUSTYPE_PCMCIA "PCMCIA"
+#define BUSTYPE_CBUS     "CBUS"
+#define BUSTYPE_CBUSII "CBUSII"
+#define BUSTYPE_FUTURE "FUTURE"
+#define BUSTYPE_MBI        "MBI"
+#define BUSTYPE_MBII     "MBII"
+#define BUSTYPE_MPI        "MPI"
+#define BUSTYPE_MPSA     "MPSA"
+#define BUSTYPE_NUBUS    "NUBUS"
+#define BUSTYPE_TC         "TC"
+#define BUSTYPE_VME        "VME"
+#define BUSTYPE_XPRESS "XPRESS"
+
+
+typedef struct __attribute__((packed)) _MP_CONFIGURATION_IOAPIC
+{
+       UCHAR Type;         /* 2 */
+       UCHAR ApicId;       /* I/O APIC ID */
+       UCHAR ApicVersion;  /* I/O APIC version */
+       UCHAR ApicFlags;    /* I/O APIC flags */
+       ULONG ApicAddress;  /* I/O APIC base address */
+} MP_CONFIGURATION_IOAPIC, *PMP_CONFIGURATION_IOAPIC;
+
+#define MAX_IOAPIC  2
+
+#define MP_IOAPIC_USABLE  0x01
+
+
+typedef struct __attribute__((packed)) _MP_CONFIGURATION_INTSRC
+{
+       UCHAR Type;         /* 3 */
+       UCHAR IrqType;      /* Interrupt type */
+       USHORT IrqFlag;     /* Interrupt flags */
+       UCHAR SrcBusId;     /* Source bus ID */
+       UCHAR SrcBusIrq;    /* Source bus interrupt */
+       UCHAR DstApicId;    /* Destination APIC ID */
+       UCHAR DstApicInt;   /* Destination interrupt */
+} MP_CONFIGURATION_INTSRC, *PMP_CONFIGURATION_INTSRC;
+
+#define MAX_IRQ_SOURCE  128
+
+#define INT_VECTORED    0
+#define INT_NMI         1
+#define INT_SMI         2
+#define INT_EXTINT      3
+
+#define IRQDIR_DEFAULT  0
+#define IRQDIR_HIGH     1
+#define IRQDIR_LOW      3
+
+
+typedef struct __attribute__((packed)) _MP_CONFIGURATION_INTLOCAL
+{
+       UCHAR Type;         /* 4 */
+       UCHAR IrqType;      /* Interrupt type */
+       USHORT IrqFlag;     /* Interrupt flags */
+       UCHAR SrcBusId;     /* Source bus ID */
+       UCHAR SrcBusIrq;    /* Source bus interrupt */
+       UCHAR DstApicId;    /* Destination local APIC ID */
+       UCHAR DstApicLInt;  /* Destination local APIC interrupt */
+} MP_CONFIGURATION_INTLOCAL, *PMP_CONFIGURATION_INTLOCAL;
+
+#define MP_APIC_ALL    0xFF
+
+
+static inline VOID ReadPentiumClock(PULARGE_INTEGER Count)
+{
+   register ULONG nLow;
+   register ULONG nHigh;
+  
+   __asm__ __volatile__ ("rdtsc" : "=a" (nLow), "=d" (nHigh));
+
+   Count->u.LowPart = nLow;
+   Count->u.HighPart = nHigh;
+}
+
+
+#define MAX_CPU   32
+
+
+typedef struct _CPU_INFO
+{
+   UCHAR    Flags;            /* CPU flags */
+   UCHAR    APICId;           /* Local APIC ID */
+   UCHAR    APICVersion;      /* Local APIC version */
+   UCHAR    MaxLVT;           /* Number of LVT registers */
+   ULONG    BusSpeed;         /* BUS speed */
+   ULONG    CoreSpeed;        /* Core speed */
+   UCHAR    Padding[16-12];   /* Padding to 16-byte */
+} CPU_INFO, *PCPU_INFO;
+
+/* CPU flags */
+#define CPU_USABLE   0x01  /* 1 if the CPU is usable (ie. can be used) */
+#define CPU_ENABLED  0x02  /* 1 if the CPU is enabled */
+#define CPU_BSP      0x04  /* 1 if the CPU is the bootstrap processor */
+
+
+typedef enum {
+  amPIC = 0,    /* IMCR and PIC compatibility mode */
+  amVWIRE       /* Virtual Wire compatibility mode */
+} APIC_MODE;
+
+
+#define pushfl(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
+#define popfl(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
+
+
+#define PIC_IRQS  16
+
+/* Prototypes */
+
+VOID HalpInitMPS(VOID);
+volatile ULONG IOAPICRead(ULONG Apic, ULONG Offset);
+VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value);
+VOID IOAPICMaskIrq(ULONG Apic, ULONG Irq);
+VOID IOAPICUnmaskIrq(ULONG Apic, ULONG Irq);
+volatile inline ULONG APICRead(ULONG Offset);
+inline VOID APICWrite(ULONG Offset, ULONG Value);
+inline VOID APICSendEOI(VOID);
+inline ULONG ThisCPU(VOID);
+VOID APICSendIPI(ULONG Target,
+                 ULONG DeliveryMode,
+                 ULONG IntNum,
+                 ULONG Level);
+/* For debugging */
+VOID IOAPICDump(VOID);
+VOID APICDump(VOID);
+
+#endif /* __INCLUDE_HAL_MPS */
\ No newline at end of file
index 8ecbdb1..b2fac77 100644 (file)
@@ -172,6 +172,7 @@ VOID KeInitDispatcher(VOID);
 VOID KeInitializeDispatcher(VOID);
 VOID KeInitializeTimerImpl(VOID);
 VOID KeInitializeBugCheck(VOID);
+VOID Phase1Initialization(PVOID Context);
 
 VOID KeInit1(VOID);
 VOID KeInit2(VOID);
index c2c8dce..103b084 100644 (file)
 /*
  * Defines a descriptor as it appears in the processor tables
  */
-typedef struct
+typedef struct _DESCRIPTOR
 {
-        unsigned int a;
-        unsigned int b;
-} IDT_DESCRIPTOR, GDT_DESCRIPTOR;
+  ULONG a;
+  ULONG b;
+} __attribute__ ((packed)) IDT_DESCRIPTOR, GDT_DESCRIPTOR;
 
 extern IDT_DESCRIPTOR KiIdt[256];
 //extern GDT_DESCRIPTOR KiGdt[256];
index 8902e3d..34ab838 100644 (file)
 
 #define KPROCESS_PAGE_TABLE_DIRECTORY 0x10
 
-#define KPCR_BASE                 0xFFDFF000
+#define KPCR_BASE                 0xFF000000
 
 #define KPCR_EXCEPTION_LIST       0x0
+#define KPCR_SELF                 0x18
 #define KPCR_CURRENT_THREAD       0x124        
 
 #ifndef __ASM__
 struct _KTHREAD;
 struct _KTRAPFRAME;
 
+/* FIXME: This does not work if we have more than 24 IRQs (ie. more than one I/O APIC) */
+#define VECTOR2IRQ(vector) (((vector) - 0x31) / 8)
+#define VECTOR2IRQL(vector) (4 + VECTOR2IRQ(vector))
+
 /*
  * Processor Control Region
  */
@@ -64,11 +69,29 @@ typedef struct _KPCR
    PVOID Reserved1;                   /* 10 */
    PVOID ArbitraryUserPointer;        /* 14 */
    struct _KPCR* Self;                /* 18 */
-   UCHAR Reserved2[0x108];            /* 1C */
+   UCHAR ProcessorNumber;             /* 1C */
+   KIRQL Irql;                        /* 1D */
+   UCHAR Reserved2[0x2];              /* 1E */
+   PUSHORT IDT;                       /* 20 */
+   PUSHORT GDT;                       /* 24 */
+   UCHAR Reserved3[0xFC];             /* 28 */
    struct _KTHREAD* CurrentThread;    /* 124 */
-} KPCR, *PKPCR;
+} __attribute__((packed)) KPCR, *PKPCR;
+
+static inline PKPCR KeGetCurrentKPCR(VOID)
+{
+  ULONG value;
+
+  __asm__ __volatile__ ("movl %%fs:0x18, %0\n\t"
+         : "=r" (value)
+    : /* no inputs */
+    );
+  return((PKPCR)value);
+}
+
+#define CURRENT_KPCR KeGetCurrentKPCR()
 
-#define CURRENT_KPCR ((PKPCR)KPCR_BASE)
+#define KeGetCurrentProcessorNumber (KeGetCurrentKPCR()->ProcessorNumber)
 
 extern HANDLE SystemProcessHandle;
 
index f9cd822..8e06859 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cntrller.c,v 1.6 2001/03/26 05:03:54 phreak Exp $
+/* $Id: cntrller.c,v 1.7 2001/04/13 16:12:25 chorns Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
@@ -58,9 +58,9 @@ IoAllocateController(PCONTROLLER_OBJECT ControllerObject,
 {
    PCONTROLLER_QUEUE_ENTRY entry;
    IO_ALLOCATION_ACTION Result;
-   
+
    assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
-   
+
    entry = 
      ExAllocatePoolWithTag(NonPagedPool, sizeof(CONTROLLER_QUEUE_ENTRY),
                           TAG_CQE);
index 4873277..9db2632 100644 (file)
@@ -42,7 +42,7 @@ USHORT KiGdt[11 * 4] =
  0x0, 0x0, 0xfa00, 0xcc,          /* User CS */
  0x0, 0x0, 0xf200, 0xcc,          /* User DS */
  0x0, 0x0, 0x0, 0x0,              /* TSS */
- 0x1000, 0xf000, 0x92df, 0xff00,  /* PCR */
+ 0x1000, 0x0000, 0x9200, 0xff00,  /* PCR */
  0x1000, 0x0, 0xf200, 0x0,        /* TEB */
  0x0, 0x0, 0x0, 0x0,              /* Reserved */
  0x0, 0x0, 0x0, 0x0,              /* LDT */
index de39902..9db895e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.8 2001/03/16 16:05:34 dwelch Exp $
+/* $Id: irq.c,v 1.9 2001/04/13 16:12:26 chorns Exp $
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
 /* INCLUDES ****************************************************************/
 
 #include <ddk/ntddk.h>
-
+#include <internal/config.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 +167,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 +190,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 +216,9 @@ VOID KeInitInterrupts (VOID)
                            I486_INTERRUPT_GATE;
        InitializeListHead(&isr_table[i]);
      }
+
+#endif
+
 }
 
 typedef struct _KIRQ_TRAPFRAME
@@ -125,6 +240,95 @@ typedef struct _KIRQ_TRAPFRAME
    ULONG Eflags;
 } KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
 
+#ifdef MP
+
+VOID
+KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
+/*
+ * FUNCTION: Calls the irq specific handler for an irq
+ * ARGUMENTS:
+ *         Vector    = Interrupt vector
+ *         Trapframe = CPU context
+ */
+{
+   KIRQL old_level;
+   PKINTERRUPT isr;
+   PLIST_ENTRY current;
+   ULONG irq;
+
+   DPRINT("I(%d) ", Vector);
+
+   /*
+    * Notify the rest of the kernel of the raised irq level
+    */
+   HalBeginSystemInterrupt (Vector,
+                           VECTOR2IRQL(Vector),
+                           &old_level);
+
+   irq = VECTOR2IRQ(Vector);
+
+   /*
+    * Enable interrupts
+    * NOTE: Only higher priority interrupts will get through
+    */
+   __asm__("sti\n\t");
+
+
+      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);
+      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);
+       }
+
+   /*
+    * Disable interrupts
+    */
+   __asm__("cli\n\t");
+
+   /*
+    * Unmask the related irq
+    */
+   HalEnableSystemInterrupt (Vector, 0, 0);
+
+   /*
+    * If the processor level will drop below dispatch level on return then
+    * issue a DPC queue drain interrupt
+    */
+   if (old_level < DISPATCH_LEVEL)
+     {
+
+  HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
+       __asm__("sti\n\t");
+
+       if (KeGetCurrentThread() != NULL)
+         {
+            KeGetCurrentThread()->LastEip = Trapframe->Eip;
+         }
+       KiDispatchInterrupt();
+
+       if (KeGetCurrentThread() != NULL &&
+           KeGetCurrentThread()->Alerted[1] != 0 &&
+           Trapframe->Cs != KERNEL_CS)
+         {
+           HalEndSystemInterrupt (APC_LEVEL, 0);
+           KiDeliverNormalApc();
+         }
+
+  }
+  HalEndSystemInterrupt (old_level, 0);
+}
+
+#else /* MP */
+
 VOID 
 KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
 /*
@@ -136,16 +340,14 @@ KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
    KIRQL old_level;
    PKINTERRUPT isr;
    PLIST_ENTRY current;
-   
-//   DbgPrint("{");
-   
+
    /*
     * Notify the rest of the kernel of the raised irq level
     */
    HalBeginSystemInterrupt (irq+IRQ_BASE,
                            HIGH_LEVEL-irq,
                            &old_level);
-   
+
    /*
     * Enable interrupts
     * NOTE: Only higher priority interrupts will get through
@@ -214,6 +416,7 @@ KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
    HalEndSystemInterrupt (old_level, 0);
 }
 
+#endif /* MP */
 
 static VOID 
 KeDumpIrqList(VOID)
index 6ed293d..814d758 100644 (file)
@@ -45,42 +45,31 @@ ULONG KiPcrInitDone = 0;
 VOID 
 KeInit1(VOID)
 {
+   PKPCR KPCR;
+   extern USHORT KiGdt[];
+
    KiCheckFPU();
 
    KeInitExceptions ();
    KeInitInterrupts ();
+
+   /* Initialize the initial PCR region. We can't allocate a page
+      with MmAllocPage() here because MmInit1() has not yet been
+      called, so we use a predefined page in low memory */
+   KPCR = (PKPCR)KPCR_BASE;
+   memset(KPCR, 0, PAGESIZE);
+   KPCR->Self = (PKPCR)KPCR_BASE;
+   KPCR->Irql = HIGH_LEVEL;
+   KPCR->GDT = (PUSHORT)&KiGdt;
+   KPCR->IDT = (PUSHORT)&KiIdt;
+   KiPcrInitDone = 1;
 }
 
 VOID 
 KeInit2(VOID)
 {
-   PVOID PcrPage;
-   
    KeInitDpc();
    KeInitializeBugCheck();
    KeInitializeDispatcher();
    KeInitializeTimerImpl();
-   
-   /*
-    * Initialize the PCR region. 
-    * FIXME: This should be per-processor.
-    */
-   PcrPage = MmAllocPage(0);
-   if (PcrPage == NULL)
-     {
-       DPRINT1("No memory for PCR page\n");
-       KeBugCheck(0);
-     }
-   MmCreateVirtualMapping(NULL,
-                         (PVOID)KPCR_BASE,
-                         PAGE_READWRITE,
-                         (ULONG)PcrPage);
-   memset((PVOID)KPCR_BASE, 0, 4096);
-   KiPcrInitDone = 1;
 }
-
-
-
-
-
-
index f4adb73..f19ff64 100644 (file)
@@ -1,3 +1,4 @@
+#include <internal/config.h>
 #include <internal/ntoskrnl.h>
 #include <internal/i386/segment.h>
 
@@ -8,7 +9,12 @@
 #define MULTIBOOT_HEADER_FLAGS (0x00010003)
 
 #define V2P(x) (x - 0xc0000000 + 0x200000)
-       
+
+#ifdef MP
+
+#define AP_MAGIC (0x12481020)
+
+#endif /* MP */
        
 .globl _NtProcessStartup
 .globl _start
 .globl _unmap_me
 .globl _unmap_me2
 .globl _unmap_me3
+.globl _unmap_me4
                
        /*
         * This is called by the realmode loader, with protected mode
         * enabled, paging disabled and the segment registers pointing
         * a 4Gb, 32-bit segment starting at zero.
         *
+        *    EAX = Multiboot magic or application processor magic
+        *
         *    EBX = Points to a structure in lowmem with data from the
         *    loader
         */
@@ -65,6 +74,18 @@ _multiboot_entry:
         */
        cld
 
+#ifdef MP
+
+   /*
+    * Save the multiboot or application processor magic
+    */
+   movl    %eax, %edx
+
+   cmpl    $AP_MAGIC, %edx
+   je      .m1
+
+#endif /* MP */
+
        /*
         * Zero the BSS
         */
@@ -87,6 +108,10 @@ _multiboot_entry:
        movl    $(V2P(kernel_pagetable) + 0x7), 0xC00(%esi)
        movl    $(V2P(lowmem_pagetable) + 0x7), 0xD00(%esi)
        movl    $(V2P(startup_pagedirectory) + 0x7), 0xF00(%esi) 
+#ifdef MP
+  movl $(V2P(apic_pagetable) + 0x7), 0xFEC(%esi)
+#endif /* MP */
+  movl $(V2P(kpcr_pagetable) + 0x7), 0xFF0(%esi)
 
        /*
         * Initialize the page table that maps low memory
@@ -114,6 +139,39 @@ _multiboot_entry:
        cmpl    $2048, %edi
        jl      .l4
        
+#ifdef  MP
+
+       /*
+        * Initialize the page table that maps the APIC register address space
+        */
+        
+  /* FIXME: APIC register address space can be non-standard so do the mapping later */
+
+       movl    $V2P(apic_pagetable), %esi
+       movl    $0, %edi
+       movl    $0xFEC0001B, %eax
+       movl    %eax, (%esi, %edi)
+       movl    $0x800, %edi
+       movl    $0xFEE0001B, %eax
+       movl    %eax, (%esi, %edi)
+
+#endif /* MP */
+
+       /*
+        * Initialize the page table that maps the initial KPCR (at FF000000)
+        */
+       movl    $V2P(kpcr_pagetable), %esi
+       movl    $0, %edi
+       movl    $0x1007, %eax
+       movl    %eax, (%esi, %edi)
+
+#ifdef MP
+
+.m1:
+
+#endif /* MP */
+
+
        /*
         * Set up the PDBR
         */     
@@ -138,6 +196,9 @@ _multiboot_entry:
         * Load the GDTR and IDTR with new tables located above
         * 0xc0000000
         */
+        
+  /* FIXME: Application processors should have their own GDT/IDT */
+  
        lgdt    _KiGdtDescriptor
        lidt    _KiIdtDescriptor
 
@@ -147,9 +208,37 @@ _multiboot_entry:
        movl    $KERNEL_DS, %eax
        movl    %eax, %ds
        movl    %eax, %es
-       movl    %eax, %fs
        movl    %eax, %gs
        movl    %eax, %ss
+       movl    $PCR_SELECTOR, %eax
+       movl    %eax, %fs
+
+#ifdef MP
+
+  cmpl    $AP_MAGIC, %edx
+  jne     .m2
+
+  /*
+   * This is an application processor executing
+   */
+
+       /*
+        * Initialize EFLAGS
+        */
+       pushl   $0
+       popfl
+
+       /*
+        * Call the application processor initialization code
+        */
+       pushl   $0
+       pushl   $KERNEL_CS
+       pushl   $_KiSystemStartup
+  lret
+
+.m2:
+
+#endif /* MP */
 
        /*
         * Load the initial ring0 stack
@@ -185,7 +274,15 @@ lowmem_pagetable:
 
 kernel_pagetable:
        .fill 4096, 1, 0        
-       
+
+#ifdef MP
+apic_pagetable:
+       .fill 4096, 1, 0        
+#endif /* MP */
+
+kpcr_pagetable:
+       .fill 4096, 1, 0        
+
 _unmap_me:
        .fill 4096, 1, 0
        
@@ -202,5 +299,3 @@ _trap_stack_top:
        
 _unmap_me3:    
        .fill 4096, 1, 0                        
-
-
index 5e3caae..00069ab 100644 (file)
@@ -71,11 +71,17 @@ _Ki386ContextSwitch:
        addl    $8, %esp
        popl    %ebx
 
+       /*
+        * Load the PCR selector
+        */
+       movl    $PCR_SELECTOR, %eax
+       movl    %eax, %fs
+
        /*
         * Set the current thread information in the PCR
         */
-       movl    %ebx, (KPCR_BASE + KPCR_CURRENT_THREAD)
-       
+  movl %ebx, %fs:KPCR_CURRENT_THREAD
+
        /*
         * FIXME: Save debugging state.
         */
@@ -97,7 +103,7 @@ _Ki386ContextSwitch:
         */
        movl    KTHREAD_INITIAL_STACK(%ebx), %eax
        movl    %eax, (_KiTss + KTSS_ESP0)
-       
+
        /*
         * Change the address space
         */
@@ -105,12 +111,6 @@ _Ki386ContextSwitch:
        movl    KPROCESS_PAGE_TABLE_DIRECTORY(%ebx), %eax
        movl    %eax, %cr3 
 
-       /*
-        * Load the PCR selector
-        */
-       movl    $PCR_SELECTOR, %eax
-       movl    %eax, %fs
-
        /*
         * FIXME: Restore floating point state
         */
index 58515db..ca9df7c 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: main.c,v 1.86 2001/04/10 17:48:17 dwelch Exp $
+/* $Id: main.c,v 1.87 2001/04/13 16:12:25 chorns Exp $
  *
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/ke/main.c
@@ -29,6 +29,7 @@
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
+#include <internal/config.h>
 #include <internal/ntoskrnl.h>
 #include <reactos/resource.h>
 #include <internal/mm.h>
 
 ULONG EXPORTED NtBuildNumber = KERNEL_VERSION_BUILD;
 ULONG EXPORTED NtGlobalFlag = 0;
-CHAR  EXPORTED KeNumberProcessors = 1;
+CHAR  EXPORTED KeNumberProcessors;
 LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
 static LOADER_MODULE KeLoaderModules[64];
 static UCHAR KeLoaderModuleStrings[64][256];
 static UCHAR KeLoaderCommandLine[256];
+static ULONG FirstKrnlPhysAddr;
+static ULONG LastKrnlPhysAddr;
+static ULONG LastKernelAddress;
+volatile BOOLEAN Initialized = FALSE;
 
 /* FUNCTIONS ****************************************************************/
 
@@ -378,123 +383,193 @@ InitSystemSharedUserPage (PCSZ ParameterLine)
        KeBugCheck (0x0);
      }
 }
-
+#if 0
 VOID
-_main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
-/*
- * FUNCTION: Called by the boot loader to start the kernel
- * ARGUMENTS:
- *          LoaderBlock = Pointer to boot parameters initialized by the boot 
- *                        loader
- * NOTE: The boot parameters are stored in low memory which will become
- * invalid after the memory managment is initialized so we make a local copy.
- */
+TestV86Mode(VOID)
 {
-   ULONG i;
-   ULONG last_kernel_address;
-   ULONG start;
-   PCHAR name;
-   extern ULONG _bss_end__;
-
-   /*
-    * Copy the parameters to a local buffer because lowmem will go away
-    */
-   memcpy (&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
-   memcpy (&KeLoaderModules[1], (PVOID)KeLoaderBlock.ModsAddr,
-          sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
-   KeLoaderBlock.ModsCount++;
-   KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
-   
-   /*
-    * FIXME: Preliminary hack!!!! Add boot device to beginning of command line.
-    * This should be done by the boot loader.
-    */
-   strcpy (KeLoaderCommandLine,
-          "multi(0)disk(0)rdisk(0)partition(1)\\reactos ");
-   strcat (KeLoaderCommandLine, (PUCHAR)KeLoaderBlock.CommandLine);
-   
-   KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
-   strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe");
-   KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0];
-   KeLoaderModules[0].ModStart = 0xC0000000;
-   KeLoaderModules[0].ModEnd = PAGE_ROUND_UP((ULONG)&_bss_end__);
-   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
-     {
-       strcpy(KeLoaderModuleStrings[i], (PUCHAR)KeLoaderModules[i].String);
-       KeLoaderModules[i].ModStart -= 0x200000;
-       KeLoaderModules[i].ModStart += 0xc0000000;
-       KeLoaderModules[i].ModEnd -= 0x200000;
-       KeLoaderModules[i].ModEnd += 0xc0000000;
-       KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
-     }
+  ULONG i;
+  extern UCHAR OrigIVT[1024];
+  KV86M_REGISTERS regs;
+  NTSTATUS Status;
+  struct vesa_info* vi;
+
+  for (i = 0; i < (640 / 4); i++)
+    {
+      MmCreateVirtualMapping(NULL,
+                            (PVOID)(i * 4096),
+                            PAGE_EXECUTE_READWRITE,
+                            (ULONG)MmAllocPage(0));
+    }
+  for (; i < (1024 / 4); i++)
+    {
+      MmCreateVirtualMapping(NULL,
+                            (PVOID)(i * 4096),
+                            PAGE_EXECUTE_READ,
+                            i * 4096);
+    }
+  vi = (struct vesa_info*)0x20000;
+  vi->Signature[0] = 'V';
+  vi->Signature[1] = 'B';
+  vi->Signature[2] = 'E';
+  vi->Signature[3] = '2';
+  memset(&regs, 0, sizeof(regs));
+  regs.Eax = 0x4F00;  
+  regs.Es = 0x2000;
+  regs.Edi = 0x0;
+  memcpy((PVOID)0x0, OrigIVT, 1024);
+  Status = Ke386CallBios(0x10, &regs);
+  DbgPrint("Finished (Status %x, CS:EIP %x:%x)\n", Status, regs.Cs,
+          regs.Eip);
+  DbgPrint("Eax %x\n", regs.Eax);
+  DbgPrint("Signature %.4s\n", vi->Signature);
+  DbgPrint("TotalVideoMemory %dKB\n", vi->TotalVideoMemory * 64);
+}
+#endif
 
+VOID
+ExpInitializeExecutive(VOID)
+{
    /*
     * Initialization phase 0
     */
    HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
-   KeInit1();
-   LdrInit1();
-   KeLowerIrql(DISPATCH_LEVEL);
+
+   /* Execute executive initialization code on bootstrap processor only */
+   if (!Initialized)
+   {
+      Initialized = TRUE;
+      DPRINT("Phase 0 initialization started...\n");
+
+      /*
+       * Fail at runtime if someone has changed various structures without
+       * updating the offsets used for the assembler code.
+       */
+      assert(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK);
+      assert(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB);
+      assert(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK);
+      assert(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE);
+      assert(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME);
+      assert(FIELD_OFFSET(ETHREAD, ThreadsProcess) == ETHREAD_THREADS_PROCESS);
+      assert(FIELD_OFFSET(KPROCESS, PageTableDirectory) == 
+             KPROCESS_PAGE_TABLE_DIRECTORY);
+      assert(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9);
+      assert(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
+      assert(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
+
+      assert(FIELD_OFFSET(KPCR, ExceptionList) == KPCR_EXCEPTION_LIST);
+      assert(FIELD_OFFSET(KPCR, Self) == KPCR_SELF);
+      assert(FIELD_OFFSET(KPCR, CurrentThread) == KPCR_CURRENT_THREAD);
+
+      LdrInit1();
+
+      KeLowerIrql(DISPATCH_LEVEL);
+
+      NtEarlyInitVdm();
+
+                       MmInit1(FirstKrnlPhysAddr, LastKrnlPhysAddr, LastKernelAddress);
+
+     /*
+      * Initialize the kernel debugger
+      */
+      KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
+      if (KdPollBreakIn ())
+      {
+             DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
+      }
+
+                 MmInit2();
+         KeInit2();
+
+      {
+         char tmpbuf[80];
+         sprintf(tmpbuf,"System with %d/%d MB memory\n",
+                (unsigned int)(KeLoaderBlock.MemLower)/1024,
+                (unsigned int)(KeLoaderBlock.MemHigher)/1024);
+         HalDisplayString(tmpbuf);
+      }
+
+      KeLowerIrql(PASSIVE_LEVEL);
+
+               ObInit();
+               PiInitProcessManager();
+
+      /*
+       * Allow interrupts
+       */
+     __asm__ ("sti\n\t");
+
+#ifdef MP
+   Phase1Initialization(NULL);
+#endif
+   }
+}
+
+VOID
+KiSystemStartup(VOID)
+{
+   ExpInitializeExecutive();
+
+        for (;;)
+   {
+      NtYieldExecution();
+   }
+}
+
+/* Initialization phase 1 */
+VOID Phase1Initialization(PVOID Context)
+{
+   ULONG i;
+   ULONG start;
+   PCHAR name;
+   CHAR str[50];
+
+   DPRINT("Initialization phase 1 started...\n");
 
    /*
     * Display version number and copyright/warranty message
     */
    HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build "
-                   KERNEL_VERSION_BUILD_STR")\n");
+     KERNEL_VERSION_BUILD_STR")\n");
    HalDisplayString(RES_STR_LEGAL_COPYRIGHT);
    HalDisplayString("\n\nReactOS is free software, covered by the GNU General "
-                   "Public License, and you\n");
+     "Public License, and you\n");
    HalDisplayString("are welcome to change it and/or distribute copies of it "
-                   "under certain\n"); 
+          "under certain\n"); 
    HalDisplayString("conditions. There is absolutely no warranty for ReactOS.\n");
 
-   /*
-    * Fail at runtime if someone has changed various structures without
-    * updating the offsets used for the assembler code
-    */
-   assert(FIELD_OFFSET(KTHREAD, InitialStack) == KTHREAD_INITIAL_STACK);
-   assert(FIELD_OFFSET(KTHREAD, Teb) == KTHREAD_TEB);
-   assert(FIELD_OFFSET(KTHREAD, KernelStack) == KTHREAD_KERNEL_STACK);
-   assert(FIELD_OFFSET(KTHREAD, PreviousMode) == KTHREAD_PREVIOUS_MODE);
-   assert(FIELD_OFFSET(KTHREAD, TrapFrame) == KTHREAD_TRAP_FRAME);
-   assert(FIELD_OFFSET(ETHREAD, ThreadsProcess) == ETHREAD_THREADS_PROCESS);
-   assert(FIELD_OFFSET(KPROCESS, PageTableDirectory) == 
-         KPROCESS_PAGE_TABLE_DIRECTORY);
-   assert(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9);
-   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS);
-   assert(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP);
-   
-   last_kernel_address = KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd;
-   
-   NtEarlyInitVdm();
-   MmInit1(KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000,
-          last_kernel_address - 0xc0000000 + 0x200000,
-          last_kernel_address);
+   /* Initialize all processors */
+   KeNumberProcessors = 0;
+
+   while (!HalAllProcessorsStarted())
+   {
+     HalInitializeProcessor(
+     KeNumberProcessors);
+     KeNumberProcessors++;
+   }
+
+   if (KeNumberProcessors > 1)
+   {
+      sprintf(str, "Found %d system processors.\n",
+                         KeNumberProcessors);
+   }
+   else
+   {
+      strcpy(str, "Found 1 system processor.\n");
+   }
+   HalDisplayString(str);
 
-   /*
-    * Initialize the kernel debugger
-    */
-   KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
-   if (KdPollBreakIn ())
-     {
-       DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
-     }
+#ifdef MP
 
-   /*
-    * Initialization phase 1
-    * Initalize various critical subsystems
-    */
-   HalInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
-   MmInit2();
-   KeInit2();
+        DbgPrint("BSP halted\n");
+   for (;;);
 
-   /*
-    * Allow interrupts
-    */
-   KeLowerIrql(PASSIVE_LEVEL);
+#endif /* MP */
+
+  /*
+   * Initialize various critical subsystems
+   */
+   HalInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
 
-   ObInit();
-   PiInitProcessManager();
    ExInit();
    IoInit();
    LdrInitModuleManagement();
@@ -542,25 +617,50 @@ _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
            DPRINT1("process module '%s' at %08lx\n", name, start);
            LdrProcessDriver((PVOID)start, name);
         }
+       }
+
+   DPRINT("About to try MmAllocateContiguousAlignedMemory\n");
+   do
+     {
+extern PVOID STDCALL
+MmAllocateContiguousAlignedMemory(IN ULONG NumberOfBytes,
+                                 IN PHYSICAL_ADDRESS HighestAcceptableAddress,
+                                 IN ULONG Alignment);
+       PVOID v;
+       PHYSICAL_ADDRESS p;
+       p.QuadPart = 16*1024*1024;
+       v = MmAllocateContiguousAlignedMemory(12*1024, p,
+                                            64*1024);
+       if (v != NULL)
+        {
+          DPRINT("Worked\n");
+        }
+       else
+        {
+          DPRINT("Failed\n");
+        }
      }
+   while (0);
 
    /* Create the SystemRoot symbolic link */
    DbgPrint("CommandLine: %s\n", (PUCHAR)KeLoaderBlock.CommandLine);
+
    CreateSystemRootLink ((PUCHAR)KeLoaderBlock.CommandLine);
-  
+
 #ifdef DBGPRINT_FILE_LOG
    /* On the assumption that we can now access disks start up the debug 
       logger thread */
    DebugLogInit2();
 #endif /* DBGPRINT_FILE_LOG */
+
+
    CmInitializeRegistry2();
-   
+
    /*
     * Load Auto configured drivers
     */
    LdrLoadAutoConfigDrivers();
-   
+
    /*
     * Assign drive letters
     */
@@ -580,9 +680,76 @@ _main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
     */
    LdrLoadInitialProcess();
 
-   DbgPrint("Finished main()\n");
+   DbgPrint("Finished kernel initialization.\n");
+
+        /* FIXME: Call zero page thread function */
    PsTerminateSystemThread(STATUS_SUCCESS);
 }
 
+VOID
+_main (ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock)
+/*
+ * FUNCTION: Called by the boot loader to start the kernel
+ * ARGUMENTS:
+ *          LoaderBlock = Pointer to boot parameters initialized by the boot 
+ *                        loader
+ * NOTE: The boot parameters are stored in low memory which will become
+ * invalid after the memory managment is initialized so we make a local copy.
+ */
+{
+   ULONG i;
+   ULONG last_kernel_address;
+   extern ULONG _bss_end__;
+
+   /*
+    * Copy the parameters to a local buffer because lowmem will go away
+    */
+   memcpy (&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
+   memcpy (&KeLoaderModules[1], (PVOID)KeLoaderBlock.ModsAddr,
+          sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
+   KeLoaderBlock.ModsCount++;
+   KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
+
+   /*
+    * FIXME: Preliminary hack!!!! Add boot device to beginning of command line.
+    * This should be done by the boot loader.
+    */
+   strcpy (KeLoaderCommandLine,
+          "multi(0)disk(0)rdisk(0)partition(1)\\reactos /DEBUGPORT=SCREEN");
+   strcat (KeLoaderCommandLine, (PUCHAR)KeLoaderBlock.CommandLine);
+
+   KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
+   strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe");
+   KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0];
+   KeLoaderModules[0].ModStart = 0xC0000000;
+   KeLoaderModules[0].ModEnd = PAGE_ROUND_UP((ULONG)&_bss_end__);
+   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+     {
+       strcpy(KeLoaderModuleStrings[i], (PUCHAR)KeLoaderModules[i].String);
+       KeLoaderModules[i].ModStart -= 0x200000;
+       KeLoaderModules[i].ModStart += 0xc0000000;
+       KeLoaderModules[i].ModEnd -= 0x200000;
+       KeLoaderModules[i].ModEnd += 0xc0000000;
+       KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
+     }
+
+   last_kernel_address = KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd;
+
+   FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - 0xc0000000 + 0x200000;
+   LastKrnlPhysAddr = last_kernel_address - 0xc0000000 + 0x200000;
+   LastKernelAddress = last_kernel_address;
+
+   KeInit1();
+
+#if 0
+      /*
+       * Allow interrupts
+       */
+     __asm__ ("sti\n\t");
+#endif
+
+   KiSystemStartup();
+}
+
 /* EOF */
 
index fbce048..119ad95 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: timer.c,v 1.43 2001/03/18 19:35:13 dwelch Exp $
+/* $Id: timer.c,v 1.44 2001/04/13 16:12:25 chorns Exp $
  *
  * COPYRIGHT:      See COPYING in the top level directory
  * PROJECT:        ReactOS kernel
@@ -125,7 +125,7 @@ NTSTATUS STDCALL NtDelayExecution(IN ULONG Alertable,
          Alertable, Internal, Timeout);
    
    DPRINT("Execution delay is %d/%d\n", 
-         Timeout.u.Highpart, Timeout.u.LowPart);
+         Timeout.u.HighPart, Timeout.u.LowPart);
    Status = KeDelayExecutionThread(UserMode, Alertable, &Timeout);
    return(Status);
 }
@@ -462,17 +462,12 @@ KeInitializeTimerImpl(VOID)
 {
    TIME_FIELDS TimeFields;
    LARGE_INTEGER SystemBootTime;
-   extern VOID HalpCalibrateStallExecution (VOID);
-   
+
    DPRINT("KeInitializeTimerImpl()\n");
-   
-   HalpCalibrateStallExecution ();
-   
    InitializeListHead(&TimerListHead);
    KeInitializeSpinLock(&TimerListLock);
    KeInitializeDpc(&ExpireTimerDpc, KeExpireTimers, 0);
    TimerInitDone = TRUE;
-   
    /*
     * Calculate the starting time for the system clock
     */
@@ -480,6 +475,6 @@ KeInitializeTimerImpl(VOID)
    RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
    boot_time=SystemBootTime.QuadPart;
    system_time=boot_time;
-   
+
    DPRINT("Finished KeInitializeTimerImpl()\n");
 }
index aaa2389..211a837 100644 (file)
@@ -193,7 +193,15 @@ PVOID MmInitializePageList(PVOID FirstPhysKernelAddress,
    InsertTailList(&BiosPageListHead,
                  &MmPageArray[0].ListEntry); 
 
-   i = 1;
+   /*
+    * Page one is reserved for the initial KPCR
+    */
+   MmPageArray[1].Flags = MM_PHYSICAL_PAGE_BIOS;
+   MmPageArray[1].ReferenceCount = 0;
+   InsertTailList(&BiosPageListHead,
+      &MmPageArray[1].ListEntry); 
+
+   i = 2;
    if ((ULONG)FirstPhysKernelAddress < 0xa0000)
      {
        MmStats.NrFreePages += (((ULONG)FirstPhysKernelAddress/PAGESIZE) - 1);
index 9512bde..af3eb80 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: page.c,v 1.25 2001/03/26 20:46:53 dwelch Exp $
+/* $Id: page.c,v 1.26 2001/04/13 16:12:26 chorns Exp $
  *
  * PROJECT:     ReactOS kernel
  * FILE:        ntoskrnl/mm/i386/page.c
@@ -589,10 +589,19 @@ MmCreateVirtualMappingUnsafe(PEPROCESS Process,
                             ULONG flProtect,
                             ULONG PhysicalAddress)
 {
-   PEPROCESS CurrentProcess = PsGetCurrentProcess();
-   ULONG Attributes = 0;
+   PEPROCESS CurrentProcess;
+   ULONG Attributes;
    PULONG Pte;
    NTSTATUS Status;
+
+  if (Process != NULL)
+    {
+      CurrentProcess = PsGetCurrentProcess();
+    }
+  else
+    {
+      CurrentProcess = NULL;
+    }
    
    if (Process == NULL && Address < (PVOID)KERNEL_BASE)
      {
@@ -652,11 +661,12 @@ MmCreateVirtualMapping(PEPROCESS Process,
                       ULONG flProtect,
                       ULONG PhysicalAddress)
 {
-   if (!MmIsUsablePage((PVOID)PhysicalAddress))
+        if (!MmIsUsablePage((PVOID)PhysicalAddress))
      {
-       DPRINT1("Page not usable\n");
+       DPRINT1("Page at address %x not usable\n", PhysicalAddress);
        KeBugCheck(0);
      }
+
    return(MmCreateVirtualMappingUnsafe(Process,
                                       Address,
                                       flProtect,
@@ -692,9 +702,11 @@ MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
    ULONG Attributes = 0;
    PULONG PageEntry;
    PEPROCESS CurrentProcess = PsGetCurrentProcess();
-   
-   Attributes = ProtectToPTE(flProtect);
 
+   DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
+     Process, Address, flProtect);
+
+   Attributes = ProtectToPTE(flProtect);
    if (Process != CurrentProcess)
      {
        KeAttachProcess(Process);
index dffdc1a..1c8b3c8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mminit.c,v 1.17 2001/03/28 14:24:05 dwelch Exp $
+/* $Id: mminit.c,v 1.18 2001/04/13 16:12:26 chorns Exp $
  *
  * COPYRIGHT:   See COPYING in the top directory
  * PROJECT:     ReactOS kernel 
@@ -12,6 +12,7 @@
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
+#include <internal/config.h>
 #include <internal/i386/segment.h>
 #include <internal/mm.h>
 #include <internal/ntoskrnl.h>
@@ -31,7 +32,7 @@
 #define EXTENDED_MEMORY_SIZE  (3*1024*1024)
 
 /*
- * Compiler defined symbol s
+ * Compiler defined symbols
  */
 extern unsigned int _text_start__;
 extern unsigned int _text_end__;
@@ -79,7 +80,7 @@ VOID MmInitVirtualMemory(ULONG LastKernelAddress,
    ULONG ParamLength = KernelLength;
    NTSTATUS Status;
    
-   DPRINT("MmInitVirtualMemory(%x)\n",bp);
+   DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
    
    LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
    
@@ -87,7 +88,7 @@ VOID MmInitVirtualMemory(ULONG LastKernelAddress,
 //   ExInitNonPagedPool(KERNEL_BASE + PAGE_ROUND_UP(kernel_len) + PAGESIZE);
    ExInitNonPagedPool(LastKernelAddress + PAGESIZE);
    
-   
+
    /*
     * Setup the system area descriptor list
     */
@@ -102,7 +103,6 @@ VOID MmInitVirtualMemory(ULONG LastKernelAddress,
                      0,
                      &kernel_text_desc,
                      FALSE);
-   
    Length = PAGE_ROUND_UP(((ULONG)&_bss_end__)) - 
             PAGE_ROUND_UP(((ULONG)&_text_end__));
    ParamLength = ParamLength - Length;
@@ -151,6 +151,7 @@ VOID MmInitVirtualMemory(ULONG LastKernelAddress,
                      0,
                      &kernel_shared_data_desc,
                      FALSE);
+
    MmSharedDataPagePhysicalAddress = MmAllocPage(0);
    Status = MmCreateVirtualMapping(NULL,
                                   (PVOID)KERNEL_SHARED_DATA_BASE,
@@ -176,10 +177,14 @@ VOID MmInit1(ULONG FirstKrnlPhysAddr,
 {
    ULONG i;
    ULONG kernel_len;
+ #ifndef MP
    extern unsigned int unmap_me, unmap_me2, unmap_me3;
-   
-   DPRINT("MmInit1(bp %x, LastKernelAddress %x)\n", bp, 
-         LastKernelAddress);
+#endif 
+
+   DPRINT("MmInit1(FirstKrnlPhysAddr, %x, LastKrnlPhysAddr %x, LastKernelAddress %x)\n",
+                 FirstKrnlPhysAddr,
+                 LastKrnlPhysAddr,
+                 LastKernelAddress);
    
    /*
     * FIXME: Set this based on the system command line
@@ -205,12 +210,14 @@ VOID MmInit1(ULONG FirstKrnlPhysAddr,
     * Initialize the kernel address space
     */
    MmInitializeKernelAddressSpace();
-   
+
    /*
     * Unmap low memory
     */
+#ifndef MP
+   /* FIXME: This is broken in SMP mode */
    MmDeletePageTable(NULL, 0);
-   
+#endif
    /*
     * Free all pages not used for kernel memory
     * (we assume the kernel occupies a continuous range of physical
@@ -247,30 +254,31 @@ VOID MmInit1(ULONG FirstKrnlPhysAddr,
     * segment
     */
    CHECKPOINT;
-   DPRINT("stext %x etext %x\n",(int)&stext,(int)&etext);
+   DPRINT("_text_start__ %x _text_end__ %x\n",(int)&_text_start__,(int)&_text_end__);
    for (i=PAGE_ROUND_UP(((int)&_text_start__));
        i<PAGE_ROUND_DOWN(((int)&_text_end__));i=i+PAGESIZE)
      {
        MmSetPageProtect(NULL,
                         (PVOID)i,
                         PAGE_EXECUTE_READ);
-     }
-   
+   }
+
    DPRINT("Invalidating between %x and %x\n",
          LastKernelAddress,
          KERNEL_BASE + PAGE_TABLE_SIZE);
    for (i=(LastKernelAddress); 
-       i<(KERNEL_BASE + PAGE_TABLE_SIZE); 
-       i=i+PAGESIZE)
+        i<(KERNEL_BASE + PAGE_TABLE_SIZE); 
+        i=i+PAGESIZE)
      {
-       MmDeleteVirtualMapping(NULL, (PVOID)(i), FALSE, NULL, NULL);
+        MmDeleteVirtualMapping(NULL, (PVOID)(i), FALSE, NULL, NULL);
      }
    DPRINT("Almost done MmInit()\n");
-
+#ifndef MP
+   /* FIXME: This is broken in SMP mode */
    MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me, FALSE, NULL, NULL);
    MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me2, FALSE, NULL, NULL);
    MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me3, FALSE, NULL, NULL);
-   
+#endif
    /*
     * Intialize memory areas
     */
index 37596df..859f029 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psmgr.c,v 1.7 2000/06/03 21:36:32 ekohl Exp $
+/* $Id: psmgr.c,v 1.8 2001/04/13 16:12:26 chorns Exp $
  *
  * COPYRIGHT:               See COPYING in the top level directory
  * PROJECT:                 ReactOS kernel
@@ -10,6 +10,7 @@
 /* INCLUDES **************************************************************/
 
 #include <ddk/ntddk.h>
+#include <internal/ke.h>
 #include <internal/ps.h>
 #include <reactos/version.h>
 
@@ -26,10 +27,32 @@ VOID PiShutdownProcessManager(VOID)
 
 VOID PiInitProcessManager(VOID)
 {
+#ifndef MP
+   HANDLE Phase1InitializationHandle;
+   NTSTATUS Status;
+#endif
+
    PsInitProcessManagment();
    PsInitThreadManagment();
    PsInitIdleThread();
    PiInitApcManagement();
+#ifndef MP
+   /* Create thread for Phase1Initialization */
+   Status = PsCreateSystemThread(
+      &Phase1InitializationHandle,           /* Thread handle */
+      0,                                     /* Desired access */
+      NULL,                                  /* Object attributes */
+      NULL,                                  /* Process handle */
+      NULL,                                  /* Client id */
+      (PKSTART_ROUTINE)Phase1Initialization, /* Start routine */
+      NULL);                                 /* Start context */
+   if (!NT_SUCCESS(Status)) {
+      DPRINT1("Could not create system thread (Status 0x%X)\n", Status);
+      KeBugCheck(0);
+   }
+
+   ZwClose(Phase1InitializationHandle);
+#endif
 }