diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index 4ac5c2e5dc9..2a925982e02 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -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 diff --git a/reactos/ntoskrnl/Makefile.i386 b/reactos/ntoskrnl/Makefile.i386 index 1c00d8ff558..bee30e9cf8a 100644 --- a/reactos/ntoskrnl/Makefile.i386 +++ b/reactos/ntoskrnl/Makefile.i386 @@ -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 \ diff --git a/reactos/ntoskrnl/hal/x86/halinit.c b/reactos/ntoskrnl/hal/x86/halinit.c index a521276af07..cca0f785cff 100644 --- a/reactos/ntoskrnl/hal/x86/halinit.c +++ b/reactos/ntoskrnl/hal/x86/halinit.c @@ -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 @@ -12,27 +12,45 @@ /* INCLUDES *****************************************************************/ #include +#include #include #include +#ifdef MP +#include +#endif /* MP */ + #define NDEBUG #include + /* 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; diff --git a/reactos/ntoskrnl/hal/x86/mp.c b/reactos/ntoskrnl/hal/x86/mp.c index 5bf58133ff9..bc7f2855cb0 100644 --- a/reactos/ntoskrnl/hal/x86/mp.c +++ b/reactos/ntoskrnl/hal/x86/mp.c @@ -1,29 +1,1740 @@ -/* $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 +#include +#define NDEBUG #include +#ifdef MP + +#include +#include +#include +#include +#include +#include + +/* + 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< 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 index 00000000000..c5a33cf2351 --- /dev/null +++ b/reactos/ntoskrnl/hal/x86/mps.S @@ -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 + +/* 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 index 00000000000..684b69ab823 --- /dev/null +++ b/reactos/ntoskrnl/hal/x86/mpsboot.asm @@ -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 index 00000000000..48c9b24b58f --- /dev/null +++ b/reactos/ntoskrnl/hal/x86/mpsirql.c @@ -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 +#include +#include +#include +#include + +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/hal/x86/sources b/reactos/ntoskrnl/hal/x86/sources index 0fe87b13a7c..ac4d14a4ebe 100644 --- a/reactos/ntoskrnl/hal/x86/sources +++ b/reactos/ntoskrnl/hal/x86/sources @@ -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 diff --git a/reactos/ntoskrnl/hal/x86/time.c b/reactos/ntoskrnl/hal/x86/time.c index 5a86d12eea9..58d7949a6ba 100644 --- a/reactos/ntoskrnl/hal/x86/time.c +++ b/reactos/ntoskrnl/hal/x86/time.c @@ -10,6 +10,7 @@ #include #include +#include #define NDEBUG #include @@ -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); } diff --git a/reactos/ntoskrnl/hal/x86/udelay.c b/reactos/ntoskrnl/hal/x86/udelay.c index 9d3b104dbad..0329de7baf5 100644 --- a/reactos/ntoskrnl/hal/x86/udelay.c +++ b/reactos/ntoskrnl/hal/x86/udelay.c @@ -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 -#define NDEBUG +//#define NDEBUG #include /* 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> 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>= 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 index 00000000000..265e322734d --- /dev/null +++ b/reactos/ntoskrnl/include/internal/hal/mps.h @@ -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 diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 8ecbdb16b38..b2fac772743 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -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); diff --git a/reactos/ntoskrnl/include/internal/ntoskrnl.h b/reactos/ntoskrnl/include/internal/ntoskrnl.h index c2c8dce01ea..103b0848e98 100644 --- a/reactos/ntoskrnl/include/internal/ntoskrnl.h +++ b/reactos/ntoskrnl/include/internal/ntoskrnl.h @@ -27,11 +27,11 @@ /* * 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]; diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 8902e3dffb4..34ab838071d 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -40,9 +40,10 @@ #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__ @@ -52,6 +53,10 @@ 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; -#define CURRENT_KPCR ((PKPCR)KPCR_BASE) +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 KeGetCurrentProcessorNumber (KeGetCurrentKPCR()->ProcessorNumber) extern HANDLE SystemProcessHandle; diff --git a/reactos/ntoskrnl/io/cntrller.c b/reactos/ntoskrnl/io/cntrller.c index f9cd822be89..8e06859c510 100644 --- a/reactos/ntoskrnl/io/cntrller.c +++ b/reactos/ntoskrnl/io/cntrller.c @@ -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); diff --git a/reactos/ntoskrnl/ke/i386/gdt.c b/reactos/ntoskrnl/ke/i386/gdt.c index 4873277f6c4..9db26323d9a 100644 --- a/reactos/ntoskrnl/ke/i386/gdt.c +++ b/reactos/ntoskrnl/ke/i386/gdt.c @@ -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 */ diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index de39902afb7..9db895e85df 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -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 @@ -19,17 +19,114 @@ /* INCLUDES ****************************************************************/ #include - +#include #include #include #include #include +#ifdef MP +#include +#endif /* MP */ + #define NDEBUG #include /* 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;iServiceRoutine(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) diff --git a/reactos/ntoskrnl/ke/i386/kernel.c b/reactos/ntoskrnl/ke/i386/kernel.c index 6ed293d7324..814d758e128 100644 --- a/reactos/ntoskrnl/ke/i386/kernel.c +++ b/reactos/ntoskrnl/ke/i386/kernel.c @@ -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; } - - - - - - diff --git a/reactos/ntoskrnl/ke/i386/multiboot.S b/reactos/ntoskrnl/ke/i386/multiboot.S index f4adb73e7e2..f19ff64594e 100644 --- a/reactos/ntoskrnl/ke/i386/multiboot.S +++ b/reactos/ntoskrnl/ke/i386/multiboot.S @@ -1,3 +1,4 @@ +#include #include #include @@ -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 @@ -19,12 +25,15 @@ .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 - - diff --git a/reactos/ntoskrnl/ke/i386/tskswitch.S b/reactos/ntoskrnl/ke/i386/tskswitch.S index 5e3caae34db..00069abfc31 100644 --- a/reactos/ntoskrnl/ke/i386/tskswitch.S +++ b/reactos/ntoskrnl/ke/i386/tskswitch.S @@ -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 */ diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index 58515db12b0..ca9df7cf8c4 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -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 +#include #include #include #include @@ -52,11 +53,15 @@ 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 +TestV86Mode(VOID) +{ + 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(®s, 0, sizeof(regs)); + regs.Eax = 0x4F00; + regs.Es = 0x2000; + regs.Edi = 0x0; + memcpy((PVOID)0x0, OrigIVT, 1024); + Status = Ke386CallBios(0x10, ®s); + 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 -_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. - */ +ExpInitializeExecutive(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]; - } - /* * 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; - /* - * Initialize the kernel debugger - */ - KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - if (KdPollBreakIn ()) - { - DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C); - } + while (!HalAllProcessorsStarted()) + { + HalInitializeProcessor( + KeNumberProcessors); + KeNumberProcessors++; + } - /* - * Initialization phase 1 - * Initalize various critical subsystems - */ + if (KeNumberProcessors > 1) + { + sprintf(str, "Found %d system processors.\n", + KeNumberProcessors); + } + else + { + strcpy(str, "Found 1 system processor.\n"); + } + HalDisplayString(str); + +#ifdef MP + + DbgPrint("BSP halted\n"); + for (;;); + +#endif /* MP */ + + /* + * Initialize various critical subsystems + */ HalInitSystem (1, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); - MmInit2(); - KeInit2(); - /* - * Allow interrupts - */ - KeLowerIrql(PASSIVE_LEVEL); - - 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 */ diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index fbce048e9f2..119ad952d78 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -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"); } diff --git a/reactos/ntoskrnl/mm/freelist.c b/reactos/ntoskrnl/mm/freelist.c index aaa2389979b..211a8370b0e 100644 --- a/reactos/ntoskrnl/mm/freelist.c +++ b/reactos/ntoskrnl/mm/freelist.c @@ -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); diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index 9512bdeb056..af3eb80b8ba 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -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); diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index dffdc1aecfb..1c8b3c814ea 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -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 +#include #include #include #include @@ -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 +#include #include #include @@ -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 }