[HAL] Implement APIC-based profiling for x64. 116/head
authorIvan Labutin <linuxrf@gmail.com>
Mon, 6 Nov 2017 18:40:21 +0000 (21:40 +0300)
committerThomas Faber <thomas.faber@reactos.org>
Thu, 15 Feb 2018 11:45:29 +0000 (12:45 +0100)
hal/halx86/apic/apic.h
hal/halx86/apic/apictimer.c
hal/halx86/apic/halinit_apic.c
hal/halx86/include/halp.h

index 5de2283..edabaa3 100644 (file)
@@ -278,5 +278,9 @@ VOID
 NTAPI
 ApicInitializeTimer(ULONG Cpu);
 
+VOID
+NTAPI
+HalInitializeProfiling(VOID);
+
 VOID __cdecl ApicSpuriousService(VOID);
 
index cc02316..5fe9305 100644 (file)
 
 extern LARGE_INTEGER HalpCpuClockFrequency;
 
+/* HAL profiling variables */
+BOOLEAN HalIsProfiling = FALSE;
+ULONGLONG HalCurProfileInterval = 10000000;
+ULONGLONG HalMinProfileInterval = 1000;
+ULONGLONG HalMaxProfileInterval = 10000000;
+
 /* TIMER FUNCTIONS ************************************************************/
 
 VOID
@@ -59,26 +65,89 @@ ApicInitializeTimer(ULONG Cpu)
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
+VOID
+NTAPI
+HalInitializeProfiling(VOID)
+{
+    KeGetPcr()->HalReserved[HAL_PROFILING_INTERVAL] = HalCurProfileInterval;
+    KeGetPcr()->HalReserved[HAL_PROFILING_MULTIPLIER] = 1; /* TODO: HACK */
+}
+
 VOID
 NTAPI
 HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
 {
-    UNIMPLEMENTED;
-    return;
+    LVT_REGISTER LvtEntry;
+
+    /* Only handle ProfileTime */
+    if (ProfileSource == ProfileTime)
+    {
+        /* OK, we are profiling now */
+        HalIsProfiling = TRUE;
+
+        /* Set interrupt interval */
+        ApicWrite(APIC_TICR, KeGetPcr()->HalReserved[HAL_PROFILING_INTERVAL]);
+
+        /* Unmask it */
+        LvtEntry.Long = 0;
+        LvtEntry.TimerMode = 1;
+        LvtEntry.Vector = APIC_PROFILE_VECTOR;
+        LvtEntry.Mask = 0;
+        ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
+    }
 }
 
 VOID
 NTAPI
 HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
 {
-    UNIMPLEMENTED;
-    return;
+    LVT_REGISTER LvtEntry;
+
+    /* Only handle ProfileTime */
+    if (ProfileSource == ProfileTime)
+    {
+        /* We are not profiling */
+        HalIsProfiling = FALSE;
+
+        /* Mask interrupt */
+        LvtEntry.Long = 0;
+        LvtEntry.TimerMode = 1;
+        LvtEntry.Vector = APIC_PROFILE_VECTOR;
+        LvtEntry.Mask = 1;
+        ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
+    }
 }
 
 ULONG_PTR
 NTAPI
 HalSetProfileInterval(IN ULONG_PTR Interval)
 {
-    UNIMPLEMENTED;
+    ULONGLONG TimerInterval;
+    ULONGLONG FixedInterval;
+
+    FixedInterval = (ULONGLONG)Interval;
+
+    /* Check bounds */
+    if (FixedInterval < HalMinProfileInterval)
+    {
+        FixedInterval = HalMinProfileInterval;
+    }
+    else if (FixedInterval > HalMaxProfileInterval)
+    {
+        FixedInterval = HalMaxProfileInterval;
+    }
+
+    /* Remember interval */
+    HalCurProfileInterval = FixedInterval;
+
+    /* Recalculate interval for APIC */
+    TimerInterval = FixedInterval * KeGetPcr()->HalReserved[HAL_PROFILING_MULTIPLIER] / HalMaxProfileInterval;
+
+    /* Remember recalculated interval in PCR */
+    KeGetPcr()->HalReserved[HAL_PROFILING_INTERVAL] = (ULONG)TimerInterval;
+
+    /* And set it */
+    ApicWrite(APIC_TICR, (ULONG)TimerInterval);
+
     return Interval;
 }
index 0ac23c5..cd5e0da 100644 (file)
@@ -32,6 +32,9 @@ HalpInitProcessor(
     /* Initialize the local APIC for this cpu */
     ApicInitializeLocalApic(ProcessorNumber);
 
+    /* Initialize profiling data (but don't start it) */
+    HalInitializeProfiling();
+
     /* Initialize the timer */
     //ApicInitializeTimer(ProcessorNumber);
 
index 315282f..079b1ad 100644 (file)
@@ -49,6 +49,10 @@ VOID
 #define HAL_APC_REQUEST         0
 #define HAL_DPC_REQUEST         1
 
+/* HAL profiling offsets in KeGetPcr()->HalReserved[] */
+#define HAL_PROFILING_INTERVAL      0
+#define HAL_PROFILING_MULTIPLIER    1
+
 /* CMOS Registers and Ports */
 #define CMOS_CONTROL_PORT       (PUCHAR)0x70
 #define CMOS_DATA_PORT          (PUCHAR)0x71