Author: tkreuzer
Date: Tue Sep 6 21:01:49 2011
New Revision: 53611
URL:
http://svn.reactos.org/svn/reactos?rev=53611&view=rev
Log:
[HAL]
Start implementing APIC support, which is needed for both SMP and x64. It will use the
local APIC + I/O APIC for interrupt control, the RTC instead of the PIT for the timer
interrupt (PIT doesn't always work with I/O APIC), the APIC timer for profiling and
finally the TSC for the performance counter and KeStallExecutionProcessor.
The code is incomplete and doesn't work yet
Added:
trunk/reactos/hal/halx86/apic/ (with props)
trunk/reactos/hal/halx86/apic/apic.c (with props)
trunk/reactos/hal/halx86/apic/apic.h (with props)
trunk/reactos/hal/halx86/apic/apictimer.c (with props)
trunk/reactos/hal/halx86/apic/apictrap.S (with props)
trunk/reactos/hal/halx86/apic/rtctimer.c (with props)
trunk/reactos/hal/halx86/apic/tsc.c (with props)
trunk/reactos/hal/halx86/apic/tsc.h (with props)
trunk/reactos/hal/halx86/apic/tsccal.S (with props)
Propchange: trunk/reactos/hal/halx86/apic/
------------------------------------------------------------------------------
--- bugtraq:logregex (added)
+++ bugtraq:logregex Tue Sep 6 21:01:49 2011
@@ -1,0 +1,2 @@
+([Ii]ssue|[Bb]ug)s? #?(\d+)(,? ?#?(\d+))*(,? ?(and |or )?#?(\d+))?
+(\d+)
Propchange: trunk/reactos/hal/halx86/apic/
------------------------------------------------------------------------------
bugtraq:message = See issue #%BUGID% for more details.
Propchange: trunk/reactos/hal/halx86/apic/
------------------------------------------------------------------------------
bugtraq:url =
http://www.reactos.org/bugzilla/show_bug.cgi?id=%BUGID%
Propchange: trunk/reactos/hal/halx86/apic/
------------------------------------------------------------------------------
tsvn:logminsize = 10
Added: trunk/reactos/hal/halx86/apic/apic.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/apic.c?rev…
==============================================================================
--- trunk/reactos/hal/halx86/apic/apic.c (added)
+++ trunk/reactos/hal/halx86/apic/apic.c [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,693 @@
+/*
+ * PROJECT: ReactOS HAL
+ * LICENSE: GNU GPL - See COPYING in the top level directory
+ * FILE: hal/halx86/generic/apic.c
+ * PURPOSE: HAL APIC Management and Control Code
+ * PROGRAMMERS: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ * REFERENCES:
http://www.joseflores.com/docs/ExploringIrql.html
+ *
http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx
+ *
http://bbs.unixmap.net/thread-2022-1-1.html
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <hal.h>
+#define NDEBUG
+#include <debug.h>
+
+#include "apic.h"
+
+/* GLOBALS ********************************************************************/
+
+UCHAR HalpVectorToIndex[256];
+
+#ifndef _M_AMD64
+static const UCHAR
+HalpIRQLtoTPR[32] =
+{
+ 0x00, /* 0 PASSIVE_LEVEL */
+ 0x3d, /* 1 APC_LEVEL */
+ 0x41, /* 2 DISPATCH_LEVEL */
+ 0x41, /* 3 \ */
+ 0x51, /* 4 \ */
+ 0x61, /* 5 | */
+ 0x71, /* 6 | */
+ 0x81, /* 7 | */
+ 0x91, /* 8 | */
+ 0xa1, /* 9 | */
+ 0xb1, /* 10 | */
+ 0xb1, /* 11 | */
+ 0xb1, /* 12 | */
+ 0xb1, /* 13 | */
+ 0xb1, /* 14 | */
+ 0xb1, /* 15 DEVICE IRQL */
+ 0xb1, /* 16 | */
+ 0xb1, /* 17 | */
+ 0xb1, /* 18 | */
+ 0xb1, /* 19 | */
+ 0xb1, /* 20 | */
+ 0xb1, /* 21 | */
+ 0xb1, /* 22 | */
+ 0xb1, /* 23 | */
+ 0xb1, /* 24 | */
+ 0xb1, /* 25 / */
+ 0xb1, /* 26 / */
+ 0xc1, /* 27 PROFILE_LEVEL */
+ 0xd1, /* 28 CLOCK2_LEVEL */
+ 0xe1, /* 29 IPI_LEVEL */
+ 0xef, /* 30 POWER_LEVEL */
+ 0xff, /* 31 HIGH_LEVEL */
+};
+
+static const KIRQL
+HalVectorToIRQL[16] =
+{
+ 0, /* 00 PASSIVE_LEVEL */
+ 0xff, /* 10 */
+ 0xff, /* 20 */
+ 1, /* 3D APC_LEVEL */
+ 2, /* 41 DISPATCH_LEVEL */
+ 4, /* 50 \ */
+ 5, /* 60 \ */
+ 6, /* 70 | */
+ 7, /* 80 DEVICE IRQL */
+ 8, /* 90 | */
+ 9, /* A0 / */
+ 10, /* B0 / */
+ 27, /* C1 PROFILE_LEVEL */
+ 28, /* D1 CLOCK2_LEVEL */
+ 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */
+ 31, /* FF HIGH_LEVEL */
+};
+#endif
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+ULONG
+FORCEINLINE
+IOApicRead(UCHAR Register)
+{
+ /* Select the register, then do the read */
+ *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register;
+ return *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN);
+}
+
+VOID
+FORCEINLINE
+IOApicWrite(UCHAR Register, ULONG Value)
+{
+ /* Select the register, then do the write */
+ *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register;
+ *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN) = Value;
+}
+
+KIRQL
+FORCEINLINE
+ApicGetProcessorIrql(VOID)
+{
+ /* Read the TPR and convert it to an IRQL */
+ return TprToIrql(ApicRead(APIC_PPR));
+}
+
+KIRQL
+FORCEINLINE
+ApicGetCurrentIrql(VOID)
+{
+ /* Read the TPR and convert it to an IRQL */
+ return TprToIrql(ApicRead(APIC_TPR));
+}
+
+VOID
+FORCEINLINE
+ApicSetCurrentIrql(KIRQL Irql)
+{
+ /* Convert IRQL and write the TPR */
+ ApicWrite(APIC_TPR, IrqlToTpr(Irql));
+}
+
+UCHAR
+FASTCALL
+HalpIrqToVector(UCHAR Irq)
+{
+ IOAPIC_REDIRECTION_REGISTER ReDirReg;
+
+ /* Read low dword of the redirection entry */
+ ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq);
+
+ /* Return the vector */
+ return (UCHAR)ReDirReg.Vector;
+}
+
+KIRQL
+FASTCALL
+HalpVectorToIrql(UCHAR Vector)
+{
+ return TprToIrql(Vector >> 2);
+}
+
+UCHAR
+FASTCALL
+HalpVectorToIrq(UCHAR Vector)
+{
+ return HalpVectorToIndex[Vector];
+}
+
+VOID
+NTAPI
+HalpInitializeLegacyPIC(VOID)
+{
+ I8259_ICW1 Icw1;
+ I8259_ICW2 Icw2;
+ I8259_ICW3 Icw3;
+ I8259_ICW4 Icw4;
+
+ /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
+ Icw1.NeedIcw4 = TRUE;
+ Icw1.OperatingMode = Cascade;
+ Icw1.Interval = Interval8;
+ Icw1.InterruptMode = EdgeTriggered;
+ Icw1.Init = TRUE;
+ Icw1.InterruptVectorAddress = 0;
+ __outbyte(PIC1_CONTROL_PORT, Icw1.Bits);
+
+ /* ICW2 - interrupt vector offset */
+ Icw2.Bits = PRIMARY_VECTOR_BASE;
+ __outbyte(PIC1_DATA_PORT, Icw2.Bits);
+
+ /* Connect slave to IRQ 2 */
+ Icw3.Bits = 0;
+ Icw3.SlaveIrq2 = TRUE;
+ __outbyte(PIC1_DATA_PORT, Icw3.Bits);
+
+ /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested
mode */
+ Icw4.SystemMode = New8086Mode;
+ Icw4.EoiMode = NormalEoi;
+ Icw4.BufferedMode = NonBuffered;
+ Icw4.SpecialFullyNestedMode = FALSE;
+ Icw4.Reserved = 0;
+ __outbyte(PIC1_DATA_PORT, Icw4.Bits);
+
+ /* Mask all interrupts */
+ __outbyte(PIC1_DATA_PORT, 0xFF);
+
+ /* Initialize ICW1 for slave, interval 8, edge-triggered mode with ICW4 */
+ Icw1.NeedIcw4 = TRUE;
+ Icw1.InterruptMode = EdgeTriggered;
+ Icw1.OperatingMode = Cascade;
+ Icw1.Interval = Interval8;
+ Icw1.Init = TRUE;
+ Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */
+ __outbyte(PIC2_CONTROL_PORT, Icw1.Bits);
+
+ /* Set interrupt vector base */
+ Icw2.Bits = PRIMARY_VECTOR_BASE + 8;
+ __outbyte(PIC2_DATA_PORT, Icw2.Bits);
+
+ /* Slave ID */
+ Icw3.Bits = 0;
+ Icw3.SlaveId = 2;
+ __outbyte(PIC2_DATA_PORT, Icw3.Bits);
+
+ /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested
mode */
+ Icw4.SystemMode = New8086Mode;
+ Icw4.EoiMode = NormalEoi;
+ Icw4.BufferedMode = NonBuffered;
+ Icw4.SpecialFullyNestedMode = FALSE;
+ Icw4.Reserved = 0;
+ __outbyte(PIC2_DATA_PORT, Icw4.Bits);
+
+ /* Mask all interrupts */
+ __outbyte(PIC2_DATA_PORT, 0xFF);
+}
+
+
+VOID
+ApicInitializeLocalApic(ULONG Cpu)
+{
+ APIC_BASE_ADRESS_REGISTER BaseRegister;
+ APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister;
+ LVT_REGISTER LvtEntry;
+
+ /* Enable the APIC if it wasn't yet */
+ BaseRegister.Long = __readmsr(MSR_APIC_BASE);
+ BaseRegister.Enable = 1;
+ BaseRegister.BootStrapCPUCore = (Cpu == 0);
+ __writemsr(MSR_APIC_BASE, BaseRegister.Long);
+
+ DPRINT1("ApicBase for Cpu %u PhysicalAddress = %p\n", Cpu,
BaseRegister.BaseAddress);
+ DPRINT1("ApicVersion = 0x%lx\n", ApicRead(0x30));
+
+ /* Set spurious vector and SoftwareEnable to 1 */
+ SpIntRegister.Long = ApicRead(APIC_SIVR);
+ SpIntRegister.Vector = APIC_SPURIOUS_VECTOR;
+ SpIntRegister.SoftwareEnable = 1;
+ SpIntRegister.FocusCPUCoreChecking = 0;
+ ApicWrite(APIC_SIVR, SpIntRegister.Long);
+
+ /* Set the spurious ISR */
+ KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService);
+
+ /* Create a template LVT */
+ LvtEntry.Long = 0;
+ LvtEntry.Vector = 0xFF;
+ LvtEntry.MessageType = APIC_MT_Fixed;
+ LvtEntry.DeliveryStatus = 0;
+ LvtEntry.RemoteIRR = 0;
+ LvtEntry.TriggerMode = APIC_TGM_Edge;
+ LvtEntry.Mask = 1;
+ LvtEntry.TimerMode = 0;
+
+ /* Initalize and mask LVTs */
+ ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
+ ApicWrite(APIC_THRMLVTR, LvtEntry.Long);
+ ApicWrite(APIC_PCLVTR, LvtEntry.Long);
+ ApicWrite(APIC_EXT0LVTR, LvtEntry.Long);
+ ApicWrite(APIC_EXT1LVTR, LvtEntry.Long);
+ ApicWrite(APIC_EXT2LVTR, LvtEntry.Long);
+ ApicWrite(APIC_EXT3LVTR, LvtEntry.Long);
+
+ /* LINT0 */
+ LvtEntry.Vector = APIC_SPURIOUS_VECTOR;
+ LvtEntry.MessageType = APIC_MT_ExtInt;
+ ApicWrite(APIC_LINT0, LvtEntry.Long);
+
+ /* Enable LINT1 (NMI) */
+ LvtEntry.Mask = 0;
+ LvtEntry.Vector = APIC_NMI_VECTOR;
+ LvtEntry.MessageType = APIC_MT_NMI;
+ LvtEntry.TriggerMode = APIC_TGM_Level;
+ ApicWrite(APIC_LINT1, LvtEntry.Long);
+
+ /* Enable error LVTR */
+ LvtEntry.Vector = APIC_ERROR_VECTOR;
+ LvtEntry.MessageType = APIC_MT_Fixed;
+ ApicWrite(APIC_ERRLVTR, LvtEntry.Long);
+
+ DPRINT1("Error code = 0x%lx\n", ApicRead(0x280));
+}
+
+VOID
+NTAPI
+ApicInitializeProcessor(
+ IN ULONG ProcessorNumber,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+ DPRINT1("ApicInitializeProcessor(%ld)\n", ProcessorNumber);
+
+ /* Initialize the local APIC for this cpu */
+ ApicInitializeLocalApic(ProcessorNumber);
+
+ /* Initialize the timer */
+ ApicInitializeTimer(ProcessorNumber);
+
+}
+
+VOID
+FORCEINLINE
+ApicWriteIORedirectionEntry(
+ UCHAR Index,
+ IOAPIC_REDIRECTION_REGISTER ReDirReg)
+{
+ IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
+ IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
+}
+
+IOAPIC_REDIRECTION_REGISTER
+FORCEINLINE
+ApicReadIORedirectionEntry(
+ UCHAR Index)
+{
+ IOAPIC_REDIRECTION_REGISTER ReDirReg;
+
+ ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
+ ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1);
+
+ return ReDirReg;
+}
+
+UCHAR
+NTAPI
+HalpAllocateSystemInterrupt(
+ IN UCHAR Irq,
+ IN KIRQL Irql)
+{
+ IOAPIC_REDIRECTION_REGISTER ReDirReg;
+ IN UCHAR Vector;
+
+ /* Start with low vector */
+ Vector = IrqlToTpr(Irql);
+
+ /* Find an empty vector */
+ while (HalpVectorToIndex[Vector] != 0xFF)
+ {
+ Vector++;
+
+ /* Check if we went over the edge */
+ if (TprToIrql(Vector) > Irql)
+ {
+ /* Nothing free, return failure */
+ return 0;
+ }
+ }
+
+ /* Save irq in the table */
+ HalpVectorToIndex[Vector] = Irq;
+
+ /* Setup a redirection entry */
+ ReDirReg.Vector = Vector;
+ ReDirReg.DeliveryMode = APIC_MT_LowestPriority;
+ ReDirReg.DestinationMode = APIC_DM_Logical;
+ ReDirReg.DeliveryStatus = 0;
+ ReDirReg.Polarity = 0;
+ ReDirReg.RemoteIRR = 0;
+ ReDirReg.TriggerMode = APIC_TGM_Edge;
+ ReDirReg.Mask = 1;
+ ReDirReg.Reserved = 0;
+ ReDirReg.Destination = 0;
+
+ /* Initialize entry */
+ IOApicWrite(IOAPIC_REDTBL + 2 * Irq, ReDirReg.Long0);
+ IOApicWrite(IOAPIC_REDTBL + 2 * Irq + 1, ReDirReg.Long1);
+
+ return Vector;
+}
+
+VOID
+NTAPI
+ApicInitializeIOApic(VOID)
+{
+ PHARDWARE_PTE Pte;
+ IOAPIC_REDIRECTION_REGISTER ReDirReg;
+ UCHAR Index;
+ ULONG Vector;
+
+ /* Map the I/O Apic page */
+ Pte = HalAddressToPte(IOAPIC_BASE);
+ Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE;
+ Pte->Valid = 1;
+ Pte->Write = 1;
+ Pte->Owner = 1;
+ Pte->CacheDisable = 1;
+ Pte->Global = 1;
+ _ReadWriteBarrier();
+
+ /* Setup a redirection entry */
+ ReDirReg.Vector = 0xFF;
+ ReDirReg.DeliveryMode = APIC_MT_Fixed;
+ ReDirReg.DestinationMode = APIC_DM_Physical;
+ ReDirReg.DeliveryStatus = 0;
+ ReDirReg.Polarity = 0;
+ ReDirReg.RemoteIRR = 0;
+ ReDirReg.TriggerMode = APIC_TGM_Edge;
+ ReDirReg.Mask = 1;
+ ReDirReg.Reserved = 0;
+ ReDirReg.Destination = 0;
+
+ /* Loop all table entries */
+ for (Index = 0; Index < 24; Index++)
+ {
+ /* Initialize entry */
+ IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
+ IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
+ }
+
+ /* Init the vactor to index table */
+ for (Vector = 0; Vector <= 255; Vector++)
+ {
+ HalpVectorToIndex[Vector] = 0xFF;
+ }
+
+ // HACK: Allocate all IRQs, should rather do that on demand
+ for (Index = 0; Index <= 15; Index++)
+ {
+ /* Map the IRQs to IRQLs like with the PIC */
+ HalpAllocateSystemInterrupt(Index, 27 - Index);
+ }
+
+ /* Enable the timer interrupt */
+ ReDirReg.Vector = APIC_CLOCK_VECTOR;
+ ReDirReg.DestinationMode = APIC_DM_Logical;
+ ReDirReg.TriggerMode = APIC_TGM_Edge;
+ ReDirReg.Mask = 0;
+ IOApicWrite(IOAPIC_REDTBL + 2 * APIC_CLOCK_INDEX, ReDirReg.Long0);
+
+}
+
+VOID
+NTAPI
+HalpInitializePICs(IN BOOLEAN EnableInterrupts)
+{
+ ULONG_PTR EFlags;
+
+ /* Save EFlags and disable interrupts */
+ EFlags = __readeflags();
+ _disable();
+
+ /* Initialize the local APIC for this cpu */
+ ApicInitializeLocalApic(0);
+
+ /* Initialize and mask the PIC */
+ HalpInitializeLegacyPIC();
+
+ /* Initialize the I/O APIC */
+ ApicInitializeIOApic();
+ ApicWrite(APIC_EOI, 0);
+
+ /* Register interrupt handlers */
+ KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt);
+ KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt);
+ KeRegisterInterruptHandler(DPC_VECTOR, HalpDispatchInterrupt);
+
+ // HACK, since we messed with the value, should init the local apic in
+ // HalInitializeProcessor instead
+ ApicSetCurrentIrql(APC_LEVEL);
+ ASSERT(ApicGetProcessorIrql() <= APC_LEVEL);
+
+__debugbreak();
+
+HalpInitializeClock();
+//HalpCalibrateStallExecution();
+_enable();
+for (;;);
+
+
+ /* Restore interrupt state */
+ if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
+ __writeeflags(EFlags);
+}
+
+VOID
+DECLSPEC_NORETURN
+FASTCALL
+HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
+{
+ ASSERT(ApicGetCurrentIrql() < APC_LEVEL);
+ ASSERT(ApicGetProcessorIrql() == APC_LEVEL);
+
+ UNIMPLEMENTED;
+ ASSERT(FALSE);
+}
+
+VOID
+DECLSPEC_NORETURN
+FASTCALL
+HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)
+{
+ KIRQL OldIrql = ApicGetCurrentIrql();
+__debugbreak();
+ ASSERT(OldIrql < DISPATCH_LEVEL);
+ ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL);
+
+ ApicSetCurrentIrql(DISPATCH_LEVEL);
+
+ /* Enable interrupts and call the kernel's DPC interrupt handler */
+ _enable();
+ KiDispatchInterrupt();
+ _disable();
+
+ ApicSetCurrentIrql(OldIrql);
+
+ ApicWrite(APIC_EOI, 0);
+
+ /* Exit the interrupt */
+ KiEoiHelper(TrapFrame);
+}
+
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID
+FASTCALL
+HalRequestSoftwareInterrupt(IN KIRQL Irql)
+{
+ APIC_COMMAND_REGISTER CommandRegister;
+
+ /* Setup the command register */
+ CommandRegister.Long0 = 0;
+ CommandRegister.Vector = IrqlToTpr(Irql);
+ CommandRegister.MessageType = APIC_MT_Fixed;
+ CommandRegister.TriggerMode = APIC_TGM_Edge;
+ CommandRegister.DestinationShortHand = APIC_DSH_Self;
+
+ /* Write the low dword to send the interrupt */
+ ApicWrite(APIC_ICR0, CommandRegister.Long0);
+}
+
+VOID
+FASTCALL
+HalClearSoftwareInterrupt(
+ IN KIRQL Irql)
+{
+ /* Nothing to do */
+}
+
+BOOLEAN
+NTAPI
+HalEnableSystemInterrupt(
+ IN UCHAR Vector,
+ IN KIRQL Irql,
+ IN KINTERRUPT_MODE InterruptMode)
+{
+ IOAPIC_REDIRECTION_REGISTER ReDirReg;
+ UCHAR Index;
+ ASSERT(Irql <= HIGH_LEVEL);
+ ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0));
+
+ Index = HalpVectorToIndex[Vector];
+
+ /* Read lower dword of redirection entry */
+ ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
+
+ ReDirReg.Vector = Vector;
+ ReDirReg.DeliveryMode = APIC_MT_LowestPriority;
+ ReDirReg.DestinationMode = APIC_DM_Logical;
+ ReDirReg.TriggerMode = 1 - InterruptMode;
+ ReDirReg.Mask = FALSE;
+
+ /* Write back lower dword */
+ IOApicWrite(IOAPIC_REDTBL + 2 * Irql, ReDirReg.Long0);
+
+ return TRUE;
+}
+
+VOID
+NTAPI
+HalDisableSystemInterrupt(
+ IN UCHAR Vector,
+ IN KIRQL Irql)
+{
+ IOAPIC_REDIRECTION_REGISTER ReDirReg;
+ UCHAR Index;
+ ASSERT(Irql <= HIGH_LEVEL);
+
+ Index = HalpVectorToIndex[Vector];
+
+ /* Read lower dword of redirection entry */
+ ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
+
+ /* Mask it */
+ ReDirReg.Mask = 1;
+
+ /* Write back lower dword */
+ IOApicWrite(IOAPIC_REDTBL + 2 * Irql, ReDirReg.Long0);
+}
+
+BOOLEAN
+NTAPI
+HalBeginSystemInterrupt(
+ IN KIRQL Irql,
+ IN UCHAR Vector,
+ OUT PKIRQL OldIrql)
+{
+ /* Get the current IRQL */
+ *OldIrql = ApicGetCurrentIrql();
+
+ /* Set the new IRQL */
+ ApicSetCurrentIrql(Irql);
+
+ /* Turn on interrupts */
+ _enable();
+
+ /* Success */
+ return TRUE;
+}
+
+VOID
+NTAPI
+HalEndSystemInterrupt(
+ IN KIRQL OldIrql,
+ IN PKTRAP_FRAME TrapFrame)
+{
+ /* Restore the old IRQL */
+ ApicSetCurrentIrql(OldIrql);
+
+ /* Write 0 to the EndOfInterruptRegister for level triggered ints */
+ ApicWrite(APIC_EOI, 0);
+}
+
+#ifndef _M_AMD64
+
+KIRQL
+NTAPI
+KeGetCurrentIrql(VOID)
+{
+ /* Read the current TPR and convert it to an IRQL */
+ return ApicGetCurrentIrql();
+}
+
+VOID
+FASTCALL
+KfLowerIrql(
+ IN KIRQL OldIrql)
+{
+#if DBG
+ /* Validate correct lower */
+ if (OldIrql > ApicGetCurrentIrql())
+ {
+ /* Crash system */
+ KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
+ }
+#endif
+ /* Convert the new IRQL to a TPR value and write the register */
+ ApicSetCurrentIrql(OldIrql);
+}
+
+KIRQL
+FASTCALL
+KfRaiseIrql(
+ IN KIRQL NewIrql)
+{
+ KIRQL OldIrql;
+
+ /* Read the current TPR and convert it to an IRQL */
+ OldIrql = ApicGetCurrentIrql();
+#if DBG
+ /* Validate correct raise */
+ if (OldIrql > NewIrql)
+ {
+ /* Crash system */
+ KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
+ }
+#endif
+ /* Convert the new IRQL to a TPR value and write the register */
+ ApicSetCurrentIrql(NewIrql);
+
+ return OldIrql;
+}
+
+KIRQL
+NTAPI
+KeRaiseIrqlToDpcLevel(VOID)
+{
+ return KfRaiseIrql(DISPATCH_LEVEL);
+}
+
+KIRQL
+NTAPI
+KeRaiseIrqlToSynchLevel(VOID)
+{
+ return KfRaiseIrql(SYNCH_LEVEL);
+}
+
+#endif /* !_M_AMD64 */
+
Propchange: trunk/reactos/hal/halx86/apic/apic.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/apic.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/apic.h?rev…
==============================================================================
--- trunk/reactos/hal/halx86/apic/apic.h (added)
+++ trunk/reactos/hal/halx86/apic/apic.h [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,271 @@
+
+#ifdef _M_AMD64
+#define APIC_BASE 0xfffffffffee00000ULL;
+#define ZERO_VECTOR 0x00 // IRQL 00
+#define APC_VECTOR 0x3D // IRQL 01
+#define APIC_SPURIOUS_VECTOR 0x3f
+#define DPC_VECTOR 0x41 // IRQL 02
+#define APIC_GENERIC_VECTOR 0xC1 // IRQL 27
+#define APIC_CLOCK_VECTOR 0xD1 // IRQL 28
+#define APIC_SYNCH_VECTOR 0xD1 // IRQL 28
+#define APIC_IPI_VECTOR 0xE1 // IRQL 29
+#define APIC_ERROR_VECTOR 0xE3
+#define POWERFAIL_VECTOR 0xEF // IRQL 30
+#define APIC_PROFILE_VECTOR 0xFD // IRQL 31
+#define APIC_NMI_VECTOR 0xFF
+#define IrqlToTpr(Irql) (Irql << 4)
+#define TprToIrql(Tpr) (Tpr >> 4)
+#else
+#define APIC_BASE 0xFFFE0000
+#define IOAPIC_BASE 0xFFFE1000 // checkme
+#define IOAPIC_PHYS_BASE 0xFEC00000
+#define ZERO_VECTOR 0x00 // IRQL 00
+#define APIC_SPURIOUS_VECTOR 0x1f
+#define APC_VECTOR 0x3D // IRQL 01
+#define DPC_VECTOR 0x41 // IRQL 02
+#define APIC_GENERIC_VECTOR 0xC1 // IRQL 27
+#define APIC_CLOCK_VECTOR 0xD1 // IRQL 28
+#define APIC_SYNCH_VECTOR 0xD1 // IRQL 28
+#define APIC_IPI_VECTOR 0xE1 // IRQL 29
+#define APIC_ERROR_VECTOR 0xE3
+#define POWERFAIL_VECTOR 0xEF // IRQL 30
+#define APIC_PROFILE_VECTOR 0xFD // IRQL 31
+#define APIC_NMI_VECTOR 0xFF
+#define IrqlToTpr(Irql) (HalpIRQLtoTPR[Irql])
+#define TprToIrql(Tpr) (HalVectorToIRQL[Tpr >> 4])
+#endif
+
+#define MSR_APIC_BASE 0x0000001B
+#define APIC_CLOCK_INDEX 8
+
+
+/* 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_RRR 0x00C0 /* Remote Read Register () */
+#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_TMRLVTR 0x0320 /* Timer Local Vector Table (R/W) */
+#define APIC_THRMLVTR 0x0330 /* Thermal Local Vector Table */
+#define APIC_PCLVTR 0x0340 /* Performance Counter Local Vector Table (R/W) */
+#define APIC_LINT0 0x0350 /* LINT0 Local Vector Table (R/W) */
+#define APIC_LINT1 0x0360 /* LINT1 Local Vector Table (R/W) */
+#define APIC_ERRLVTR 0x0370 /* Error Local Vector Table (R/W) */
+#define APIC_TICR 0x0380 /* Initial Count Register for Timer (R/W) */
+#define APIC_TCCR 0x0390 /* Current Count Register for Timer (R) */
+#define APIC_TDCR 0x03E0 /* Timer Divide Configuration Register (R/W) */
+#define APIC_EAFR 0x0400 /* extended APIC Feature register (R/W) */
+#define APIC_EACR 0x0410 /* Extended APIC Control Register (R/W) */
+#define APIC_SEOI 0x0420 /* Specific End Of Interrupt Register (W) */
+#define APIC_EXT0LVTR 0x0500 /* Extended Interrupt 0 Local Vector Table */
+#define APIC_EXT1LVTR 0x0510 /* Extended Interrupt 1 Local Vector Table */
+#define APIC_EXT2LVTR 0x0520 /* Extended Interrupt 2 Local Vector Table */
+#define APIC_EXT3LVTR 0x0530 /* Extended Interrupt 3 Local Vector Table */
+
+enum
+{
+ APIC_MT_Fixed = 0,
+ APIC_MT_LowestPriority = 1,
+ APIC_MT_SMI = 2,
+ APIC_MT_RemoteRead = 3,
+ APIC_MT_NMI = 4,
+ APIC_MT_INIT = 5,
+ APIC_MT_Startup = 6,
+ APIC_MT_ExtInt = 7,
+};
+
+enum
+{
+ APIC_TGM_Edge,
+ APIC_TGM_Level
+};
+
+enum
+{
+ APIC_DM_Physical,
+ APIC_DM_Logical
+};
+
+enum
+{
+ APIC_DSH_Destination,
+ APIC_DSH_Self,
+ APIC_DSH_AllIncludingSelf,
+ APIC_DSH_AllExclusingSelf
+};
+
+enum
+{
+ TIMER_DV_DivideBy2 = 0,
+ TIMER_DV_DivideBy4 = 1,
+ TIMER_DV_DivideBy8 = 2,
+ TIMER_DV_DivideBy16 = 3,
+ TIMER_DV_DivideBy32 = 8,
+ TIMER_DV_DivideBy64 = 9,
+ TIMER_DV_DivideBy128 = 10,
+ TIMER_DV_DivideBy1 = 11,
+};
+
+
+typedef union _APIC_BASE_ADRESS_REGISTER
+{
+ ULONG64 Long;
+ struct
+ {
+ ULONG64 Reserved1:8;
+ ULONG64 BootStrapCPUCore:1;
+ ULONG64 Reserved2:2;
+ ULONG64 Enable:1;
+ ULONG64 BaseAddress:40;
+ ULONG64 ReservedMBZ:12;
+ };
+} APIC_BASE_ADRESS_REGISTER;
+
+typedef union _APIC_SPURIOUS_INERRUPT_REGISTER
+{
+ ULONG Long;
+ struct
+ {
+ ULONG Vector:8;
+ ULONG SoftwareEnable:1;
+ ULONG FocusCPUCoreChecking:1;
+ ULONG ReservedMBZ:22;
+ };
+} APIC_SPURIOUS_INERRUPT_REGISTER;
+
+typedef union
+{
+ ULONG Long;
+ struct
+ {
+ ULONG Version:8;
+ ULONG ReservedMBZ:8;
+ ULONG MaxLVT:8;
+ ULONG ReservedMBZ1:7;
+ ULONG ExtRegSpacePresent:1;
+ };
+} APIC_VERSION_REGISTER;
+
+typedef union
+{
+ ULONG Long;
+ struct
+ {
+ ULONG Version:1;
+ ULONG SEOIEnable:1;
+ ULONG ExtApicIdEnable:1;
+ ULONG ReservedMBZ:29;
+ };
+} APIC_EXTENDED_CONTROL_REGISTER;
+
+typedef union _APIC_COMMAND_REGISTER
+{
+ ULONGLONG LongLong;
+ struct
+ {
+ ULONG Long0;
+ ULONG Long1;
+ };
+ struct
+ {
+ ULONGLONG Vector:8;
+ ULONGLONG MessageType:3;
+ ULONGLONG DestinationMode:1;
+ ULONGLONG DeliveryStatus:1;
+ ULONGLONG ReservedMBZ:1;
+ ULONGLONG Level:1;
+ ULONGLONG TriggerMode:1;
+ ULONGLONG RemoteReadStatus:2;
+ ULONGLONG DestinationShortHand:2;
+ ULONGLONG Reserved2MBZ:36;
+ ULONGLONG Destination:8;
+ };
+} APIC_COMMAND_REGISTER;
+
+typedef union
+{
+ ULONG Long;
+ struct
+ {
+ ULONG Vector:8;
+ ULONG MessageType:3;
+ ULONG ReservedMBZ:1;
+ ULONG DeliveryStatus:1;
+ ULONG Reserved1MBZ:1;
+ ULONG RemoteIRR:1;
+ ULONG TriggerMode:1;
+ ULONG Mask:1;
+ ULONG TimerMode:1;
+ ULONG Reserved2MBZ:13;
+ };
+} LVT_REGISTER;
+
+
+enum
+{
+ IOAPIC_IOREGSEL = 0x00,
+ IOAPIC_IOWIN = 0x10
+};
+
+enum
+{
+ IOAPIC_ID = 0x00,
+ IOAPIC_VER = 0x01,
+ IOAPIC_ARB = 0x02,
+ IOAPIC_REDTBL = 0x28
+};
+
+typedef union _IOAPIC_REDIRECTION_REGISTER
+{
+ ULONGLONG LongLong;
+ struct
+ {
+ ULONG Long0;
+ ULONG Long1;
+ };
+ struct
+ {
+ ULONGLONG Vector:8;
+ ULONGLONG DeliveryMode:3;
+ ULONGLONG DestinationMode:1;
+ ULONGLONG DeliveryStatus:1;
+ ULONGLONG Polarity:1;
+ ULONGLONG RemoteIRR:1;
+ ULONGLONG TriggerMode:1;
+ ULONGLONG Mask:1;
+ ULONGLONG Reserved:39;
+ ULONGLONG Destination:8;
+ };
+} IOAPIC_REDIRECTION_REGISTER;
+
+ULONG
+FORCEINLINE
+ApicRead(ULONG Offset)
+{
+ return *(volatile ULONG *)(APIC_BASE + Offset);
+}
+
+VOID
+FORCEINLINE
+ApicWrite(ULONG Offset, ULONG Value)
+{
+ *(volatile ULONG *)(APIC_BASE + Offset) = Value;
+}
+
+VOID
+NTAPI
+ApicInitializeTimer(ULONG Cpu);
+
+VOID ApicSpuriousService(VOID);
+
Propchange: trunk/reactos/hal/halx86/apic/apic.h
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/apictimer.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/apictimer.…
==============================================================================
--- trunk/reactos/hal/halx86/apic/apictimer.c (added)
+++ trunk/reactos/hal/halx86/apic/apictimer.c [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,84 @@
+/*
+ * PROJECT: ReactOS HAL
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: hal/halx86/apic/apictimer.c
+ * PURPOSE: System Profiling
+ * PROGRAMMERS: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <hal.h>
+#define NDEBUG
+#include <debug.h>
+
+#include "apic.h"
+
+extern LARGE_INTEGER HalpCpuClockFrequency;
+
+/* TIMER FUNCTIONS ************************************************************/
+
+VOID
+NTAPI
+ApicSetTimerInterval(ULONG MicroSeconds)
+{
+ LVT_REGISTER LvtEntry;
+ ULONGLONG TimerInterval;
+
+ /* Calculate the Timer interval */
+ TimerInterval = HalpCpuClockFrequency.QuadPart * MicroSeconds / 1000000;
+
+ /* Set the count interval */
+ ApicWrite(APIC_TICR, (ULONG)TimerInterval);
+
+ /* Set to periodic */
+ LvtEntry.Long = 0;
+ LvtEntry.TimerMode = 1;
+ LvtEntry.Vector = APIC_PROFILE_VECTOR;
+ LvtEntry.Mask = 0;
+ ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
+
+}
+
+VOID
+NTAPI
+ApicInitializeTimer(ULONG Cpu)
+{
+
+ /* Initialize the TSC */
+ //HalpInitializeTsc();
+
+ /* Set clock multiplier to 1 */
+ ApicWrite(APIC_TDCR, TIMER_DV_DivideBy1);
+
+ ApicSetTimerInterval(1000);
+
+// KeSetTimeIncrement
+}
+
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID
+NTAPI
+HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
+{
+ UNIMPLEMENTED;
+ return;
+}
+
+VOID
+NTAPI
+HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
+{
+ UNIMPLEMENTED;
+ return;
+}
+
+ULONG_PTR
+NTAPI
+HalSetProfileInterval(IN ULONG_PTR Interval)
+{
+ UNIMPLEMENTED;
+ return Interval;
+}
Propchange: trunk/reactos/hal/halx86/apic/apictimer.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/apictrap.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/apictrap.S…
==============================================================================
--- trunk/reactos/hal/halx86/apic/apictrap.S (added)
+++ trunk/reactos/hal/halx86/apic/apictrap.S [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,36 @@
+/*
+ * FILE: hal/halx86/apic/apictrap.S
+ * COPYRIGHT: See COPYING in the top level directory
+ * PURPOSE: System Traps, Entrypoints and Exitpoints
+ * PROGRAMMER: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ * NOTE: See asmmacro.S for the shared entry/exit code.
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <asm.inc>
+#include <internal/i386/asmmacro.S>
+
+#ifdef _M_AMD64
+#include <ksamd64.inc>
+PUBLIC ApicSpuriousService
+#else
+#include <ks386.inc>
+PUBLIC _ApicSpuriousService
+#endif
+
+.code
+
+TRAP_ENTRY HalpTrap0D, 0
+TRAP_ENTRY HalpApcInterrupt, KI_SOFTWARE_TRAP
+TRAP_ENTRY HalpDispatchInterrupt, KI_PUSH_FAKE_ERROR_CODE
+TRAP_ENTRY HalpClockInterrupt, KI_PUSH_FAKE_ERROR_CODE
+TRAP_ENTRY HalpProfileInterrupt, KI_PUSH_FAKE_ERROR_CODE
+
+FUNC ApicSpuriousService
+ int 3
+ iret
+ENDFUNC ApicSpuriousService
+
+
+END
Propchange: trunk/reactos/hal/halx86/apic/apictrap.S
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/rtctimer.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/rtctimer.c…
==============================================================================
--- trunk/reactos/hal/halx86/apic/rtctimer.c (added)
+++ trunk/reactos/hal/halx86/apic/rtctimer.c [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,144 @@
+/*
+ * PROJECT: ReactOS HAL
+ * LICENSE: GNU GPL - See COPYING in the top level directory
+ * FILE: hal/halx86/generic/apic.c
+ * PURPOSE: HAL APIC Management and Control Code
+ * PROGRAMMERS: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ * REFERENCES:
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <hal.h>
+#define NDEBUG
+#include <debug.h>
+
+
+/* GLOBALS ********************************************************************/
+
+const UCHAR HalpClockVector = 0xD1;
+BOOLEAN HalpClockSetMSRate;
+UCHAR HalpNextMSRate;
+UCHAR HalpCurrentRate = 9;
+ULONG HalpCurrentTimeIncrement;
+static UCHAR RtcLargestClockRate = 10;
+
+
+ULONG
+FORCEINLINE
+RtcClockRateToIncrement(UCHAR Rate)
+{
+ ULONG Freqency = ((32768 << 1) >> Rate);
+ return (1000000 + (Freqency/2)) / Freqency;
+}
+
+VOID
+RtcSetClockRate(UCHAR ClockRate)
+{
+ ULONG_PTR EFlags;
+ UCHAR RegisterA;
+
+ /* Disable interrupts */
+ EFlags = __readeflags();
+ _disable();
+
+ // TODO: disable NMI
+
+ /* Read value of register A */
+ RegisterA = HalpReadCmos(RTC_REGISTER_A);
+
+ /* Change lower 4 bits to new rate */
+ RegisterA &= 0xF0;
+ RegisterA |= ClockRate;
+
+ /* Write the new value */
+ HalpWriteCmos(RTC_REGISTER_A, RegisterA);
+
+ /* Restore interrupts if they were previously enabled */
+ __writeeflags(EFlags);
+}
+
+
+VOID
+NTAPI
+INIT_FUNCTION
+HalpInitializeClock(VOID)
+{
+ UCHAR RegisterB;
+ // TODO: disable NMI
+
+ /* Enable the periodic interrupt in the CMOS */
+ RegisterB = HalpReadCmos(RTC_REGISTER_B);
+ HalpWriteCmos(RTC_REGISTER_B, RegisterB | RTC_REG_B_PI);
+
+ // RtcSetClockRate(HalpCurrentRate);
+}
+
+VOID
+FASTCALL
+HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
+{
+ ULONG LastIncrement;
+ KIRQL Irql;
+
+ /* Enter trap */
+ KiEnterInterruptTrap(TrapFrame);
+__debugbreak();
+ /* Start the interrupt */
+ if (HalBeginSystemInterrupt(CLOCK2_LEVEL, PRIMARY_VECTOR_BASE, &Irql))
+ {
+ /* Read register C, so that the next interrupt can happen */
+ HalpReadCmos(RTC_REGISTER_C);;
+
+ /* Save increment */
+ LastIncrement = HalpCurrentTimeIncrement;
+
+ /* Check if someone changed the time rate */
+ if (HalpClockSetMSRate)
+ {
+ /* Update the global values */
+ HalpCurrentRate = HalpNextMSRate;
+ HalpCurrentTimeIncrement = RtcClockRateToIncrement(HalpCurrentRate);
+
+ /* Set new clock rate */
+ RtcSetClockRate(HalpCurrentRate);
+
+ /* We're done */
+ HalpClockSetMSRate = FALSE;
+ }
+
+ /* Update the system time -- the kernel will exit this trap */
+ KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
+ }
+
+ /* Spurious, just end the interrupt */
+ KiEoiHelper(TrapFrame);
+}
+
+VOID
+FASTCALL
+HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame)
+{
+ __debugbreak();
+}
+
+ULONG
+NTAPI
+HalSetTimeIncrement(IN ULONG Increment)
+{
+ UCHAR Rate;
+
+ /* Lookup largest value below given Increment */
+ for (Rate = 2; Rate < RtcLargestClockRate; Rate++)
+ {
+ /* Check if this is the largest rate possible */
+ if (RtcClockRateToIncrement(Rate + 1) > Increment) break;
+ }
+
+ /* Set the rate and tell HAL we want to change it */
+ HalpNextMSRate = Rate;
+ HalpClockSetMSRate = TRUE;
+
+ /* Return the real increment */
+ return RtcClockRateToIncrement(Rate);
+}
Propchange: trunk/reactos/hal/halx86/apic/rtctimer.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/tsc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/tsc.c?rev=…
==============================================================================
--- trunk/reactos/hal/halx86/apic/tsc.c (added)
+++ trunk/reactos/hal/halx86/apic/tsc.c [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,140 @@
+/*
+ * PROJECT: ReactOS HAL
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: hal/halamd64/generic/tsc.c
+ * PURPOSE: HAL Routines for TSC handling
+ * PROGRAMMERS: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <hal.h>
+#define NDEBUG
+#include <debug.h>
+
+#include "tsc.h"
+
+LARGE_INTEGER HalpCpuClockFrequency = {INITIAL_STALL_COUNT * 1000000};
+
+UCHAR TscCalibrationPhase;
+LARGE_INTEGER TscCalibrationArray[NUM_SAMPLES];
+extern const UCHAR HalpClockVector;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+HalpInitializeTsc()
+{
+ ULONG_PTR Flags;
+ KIDTENTRY OldIdtEntry, *IdtPointer;
+ PKPCR Pcr = KeGetPcr();
+
+ /* Check if the CPU supports RDTSC */
+ if (!(KeGetCurrentPrcb()->FeatureBits & KF_RDTSC))
+ {
+ KeBugCheck(HAL_INITIALIZATION_FAILED);
+ }
+
+ /* Save flags and disable interrupts */
+ Flags = __readeflags();
+ _disable();
+
+__debugbreak();
+
+ /* Initialze the PIT */
+ //HalpInitializePIT();
+
+ /* Save old IDT entry */
+ IdtPointer = KiGetIdtEntry(Pcr, HalpClockVector);
+ OldIdtEntry = *IdtPointer;
+
+ /* Set the calibration ISR */
+ KeRegisterInterruptHandler(HalpClockVector, TscCalibrationISR);
+
+ /* Reset TSC value to 0 */
+ __writemsr(MSR_RDTSC, 0);
+
+ /* Enable the timer interupt */
+ HalEnableSystemInterrupt(HalpClockVector, CLOCK_LEVEL, Latched);
+
+ /* Wait for completion */
+ _enable();
+ while (TscCalibrationPhase < NUM_SAMPLES) _ReadWriteBarrier();
+ _disable();
+
+ /* Disable the timer interupt */
+ HalDisableSystemInterrupt(HalpClockVector, CLOCK_LEVEL);
+
+ /* Restore old IDT entry */
+ *IdtPointer = OldIdtEntry;
+
+ // do linear regression
+
+
+ /* Restore flags */
+ __writeeflags(Flags);
+
+}
+
+VOID
+NTAPI
+HalpCalibrateStallExecution(VOID)
+{
+ // Timer interrupt is now active
+
+ HalpInitializeTsc();
+
+ KeGetPcr()->StallScaleFactor = (ULONG)(HalpCpuClockFrequency.QuadPart / 1000000);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+LARGE_INTEGER
+NTAPI
+KeQueryPerformanceCounter(
+ OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
+{
+ LARGE_INTEGER Result;
+
+ /* Make sure it's calibrated */
+ ASSERT(HalpCpuClockFrequency.QuadPart != 0);
+
+ /* Does the caller want the frequency? */
+ if (PerformanceFrequency)
+ {
+ /* Return tsc frequency */
+ *PerformanceFrequency = HalpCpuClockFrequency;
+ }
+
+ /* Return the current value */
+ Result.QuadPart = __rdtsc();
+ return Result;
+}
+
+VOID
+NTAPI
+KeStallExecutionProcessor(ULONG MicroSeconds)
+{
+ ULONG64 StartTime, EndTime;
+
+ /* Get the initial time */
+ StartTime = __rdtsc();
+
+ /* Calculate the ending time */
+ EndTime = StartTime + HalpCpuClockFrequency.QuadPart * MicroSeconds;
+
+ /* Loop until time is elapsed */
+ while (__rdtsc() < EndTime);
+}
+
+VOID
+NTAPI
+HalCalibratePerformanceCounter(
+ IN volatile PLONG Count,
+ IN ULONGLONG NewCount)
+{
+ UNIMPLEMENTED;
+ ASSERT(FALSE);
+}
+
Propchange: trunk/reactos/hal/halx86/apic/tsc.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/tsc.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/tsc.h?rev=…
==============================================================================
--- trunk/reactos/hal/halx86/apic/tsc.h (added)
+++ trunk/reactos/hal/halx86/apic/tsc.h [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,15 @@
+
+
+#define NUM_SAMPLES 4
+#define MSR_RDTSC 0x10
+
+#ifndef __ASM__
+
+void TscCalibrationISR(void);
+extern LARGE_INTEGER HalpCpuClockFrequency;
+VOID NTAPI HalpInitializeTsc();
+
+
+#define KiGetIdtEntry(Pcr, Vector) &((Pcr)->IDT[Vector])
+
+#endif
Propchange: trunk/reactos/hal/halx86/apic/tsc.h
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/hal/halx86/apic/tsccal.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/apic/tsccal.S?r…
==============================================================================
--- trunk/reactos/hal/halx86/apic/tsccal.S (added)
+++ trunk/reactos/hal/halx86/apic/tsccal.S [iso-8859-1] Tue Sep 6 21:01:49 2011
@@ -1,0 +1,39 @@
+
+#include <asm.inc>
+#include "tsc.h"
+
+.code
+
+EXTERN _TscCalibrationPhase:BYTE
+EXTERN _TscCalibrationArray:QWORD
+
+PUBLIC _TscCalibrationISR
+_TscCalibrationISR:
+ push eax
+ push ecx
+ push edx
+
+ /* The first thing we do is read the current TSC value */
+ rdtsc
+
+ /* Read the current phase */
+ movzx ecx, byte ptr ds:[_TscCalibrationPhase]
+
+ /* Check if we're already done */
+ cmp cl, NUM_SAMPLES
+ jnb _CalibrationISR_Exit
+
+ /* Store the current value */
+ mov dword ptr _TscCalibrationArray[ecx * 2], eax
+ mov dword ptr _TscCalibrationArray[ecx * 2 + 4], edx
+
+ /* Advance phase */
+ inc byte ptr ds:[_TscCalibrationPhase]
+
+_CalibrationISR_Exit:
+ pop edx
+ pop ecx
+ pop eax
+ iretd
+
+END
Propchange: trunk/reactos/hal/halx86/apic/tsccal.S
------------------------------------------------------------------------------
svn:eol-style = native