Move some profile stuff to NDK and fix some bugs in the executive implementation...
[reactos.git] / reactos / ntoskrnl / ex / profile.c
index 863add8..142d177 100644 (file)
-/* $Id:$
- * 
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            ntoskrnl/nt/profile.c
- * PURPOSE:         Support for profiling
- * 
- * PROGRAMMERS:     No programmer listed.
+ * PROJECT:         ReactOS Kernel
+ * FILE:            ntoskrnl/ex/profile.c
+ * PURPOSE:         Support for Executive Profile Objects
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  Thomas Weidenmueller
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
-/* TYPES ********************************************************************/
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, ExpInitializeProfileImplementation)
+#endif
+
+#define TAG_PROFILE TAG('P', 'r', 'o', 'f')
 
 /* GLOBALS *******************************************************************/
 
-POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
+POBJECT_TYPE ExProfileObjectType = NULL;
+KMUTEX ExpProfileMutex;
 
-static GENERIC_MAPPING ExpProfileMapping = {
-       STANDARD_RIGHTS_READ,
-       STANDARD_RIGHTS_WRITE,
-       STANDARD_RIGHTS_EXECUTE,
-       STANDARD_RIGHTS_ALL};
+GENERIC_MAPPING ExpProfileMapping =
+{
+    STANDARD_RIGHTS_READ    | PROFILE_CONTROL,
+    STANDARD_RIGHTS_WRITE   | PROFILE_CONTROL,
+    STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
+    PROFILE_ALL_ACCESS
+};
 
-/*
- * Size of the profile hash table.
- */
-#define PROFILE_HASH_TABLE_SIZE      (32)
+/* FUNCTIONS *****************************************************************/
 
-/*
- * Table of lists of per-process profiling data structures hashed by PID.
- */
-LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
+VOID
+NTAPI
+ExpDeleteProfile(PVOID ObjectBody)
+{
+    PEPROFILE Profile;
+    ULONG State;
 
-/*
- * Head of the list of profile data structures for the kernel.
- */
-LIST_ENTRY SystemProfileList;
+    /* Typecast the Object */
+    Profile = (PEPROFILE)ObjectBody;
 
-/*
- * Lock that protects the profiling data structures.
- */
-KSPIN_LOCK ProfileListLock;
+    /* Check if there if the Profile was started */
+    if (Profile->LockedBuffer)
+    {
+        /* Stop the Profile */
+        State = KeStopProfile(Profile->KeProfile);
+        ASSERT(State != FALSE);
+
+        /* Unmap the Locked Buffer */
+        MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
+        MmUnlockPages(Profile->Mdl);
+        ExFreePool(Profile->Mdl);
+    }
 
-/*
- * Timer interrupts happen before we have initialized the profiling
- * data structures so just ignore them before that.
- */
-BOOLEAN ProfileInitDone = FALSE;
+    /* Check if a Process is associated and reference it */
+    if (Profile->Process) ObDereferenceObject(Profile->Process);
+}
 
-VOID INIT_FUNCTION
+VOID
+INIT_FUNCTION
+NTAPI
 ExpInitializeProfileImplementation(VOID)
 {
-  ULONG i;
-
-  InitializeListHead(&SystemProfileList);
-  
-  for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
-    {
-      InitializeListHead(&ProcessProfileListHashTable[i]);
-    }
-
-  KeInitializeSpinLock(&ProfileListLock);
-  ProfileInitDone = TRUE;
-
-  ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
-  
-  RtlpCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile", NonPagedPool);
-  
-  ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
-  ExProfileObjectType->PeakObjects = 0;
-  ExProfileObjectType->PeakHandles = 0;
-  ExProfileObjectType->TotalObjects = 0;
-  ExProfileObjectType->TotalHandles = 0;
-  ExProfileObjectType->PagedPoolCharge = 0;
-  ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
-  ExProfileObjectType->Mapping = &ExpProfileMapping;
-  ExProfileObjectType->Dump = NULL;
-  ExProfileObjectType->Open = NULL;
-  ExProfileObjectType->Close = NULL;
-  ExProfileObjectType->Delete = KiDeleteProfile;
-  ExProfileObjectType->Parse = NULL;
-  ExProfileObjectType->Security = NULL;
-  ExProfileObjectType->QueryName = NULL;
-  ExProfileObjectType->OkayToClose = NULL;
-  ExProfileObjectType->Create = NULL;
-
-  ObpCreateTypeObject(ExProfileObjectType);
+    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+    UNICODE_STRING Name;
+    DPRINT("Creating Profile Object Type\n");
+
+    /* Initialize the Mutex to lock the States */
+    KeInitializeMutex(&ExpProfileMutex, 64);
+
+    /* Create the Event Pair Object Type */
+    RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+    RtlInitUnicodeString(&Name, L"Profile");
+    ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+    ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KPROFILE);
+    ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
+    ObjectTypeInitializer.PoolType = NonPagedPool;
+    ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
+    ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
+    ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType);
 }
 
-NTSTATUS STDCALL 
+NTSTATUS
+NTAPI
 NtCreateProfile(OUT PHANDLE ProfileHandle,
-               IN HANDLE Process  OPTIONAL,
-               IN PVOID ImageBase, 
-               IN ULONG ImageSize, 
-               IN ULONG BucketSize,
-               IN PVOID Buffer,
-               IN ULONG BufferSize,
-               IN KPROFILE_SOURCE ProfileSource,
-               IN KAFFINITY Affinity)
+                IN HANDLE Process OPTIONAL,
+                IN PVOID ImageBase,
+                IN ULONG ImageSize,
+                IN ULONG BucketSize,
+                IN PVOID Buffer,
+                IN ULONG BufferSize,
+                IN KPROFILE_SOURCE ProfileSource,
+                IN KAFFINITY Affinity)
 {
-  HANDLE hProfile;
-  PKPROFILE Profile;
-  PEPROCESS pProcess;
-  KPROCESSOR_MODE PreviousMode;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  NTSTATUS Status = STATUS_SUCCESS;
-  
-  PAGED_CODE();
-  
-  PreviousMode = ExGetPreviousMode();
-  
-  if(BufferSize == 0)
-  {
-    return STATUS_INVALID_PARAMETER_7;
-  }
-  
-  if(PreviousMode != KernelMode)
-  {
-    _SEH_TRY
-    {
-      ProbeForWrite(ProfileHandle,
-                    sizeof(HANDLE),
-                    sizeof(ULONG));
-      ProbeForWrite(Buffer,
-                    BufferSize,
-                    sizeof(ULONG));
-    }
-    _SEH_HANDLE
-    {
-      Status = _SEH_GetExceptionCode();
-    }
-    _SEH_END;
-    
-    if(!NT_SUCCESS(Status))
+    HANDLE hProfile;
+    PEPROFILE Profile;
+    PEPROCESS pProcess;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Segment = 0, Log2 = 0;
+    PAGED_CODE();
+
+    /* Easy way out */
+    if(!BufferSize) return STATUS_INVALID_PARAMETER_7;
+
+    /* Check if this is a low-memory profile */
+    if ((!BucketSize) && (ImageBase < (PVOID)(0x10000)))
     {
-      return Status;
+        /* Validate size */
+        if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7;
+
+        /* This will become a segmented profile object */
+        Segment = (ULONG)ImageBase;
+        ImageBase = 0;
+
+        /* Recalculate the bucket size */
+        BucketSize = ImageSize / (BufferSize / sizeof(ULONG));
+
+        /* Convert it to log2 */
+        BucketSize--;
+        while (BucketSize >>= 1) Log2++;
+        BucketSize += Log2 + 1;
     }
-  }
 
-  /*
-   * Reference the associated process
-   */
-  if (Process != NULL)
+    /* Validate bucket size */
+    if ((BucketSize > 31) || (BucketSize < 2))
     {
-      Status = ObReferenceObjectByHandle(Process,
-                                        PROCESS_QUERY_INFORMATION,
-                                        PsProcessType,
-                                        PreviousMode,
-                                        (PVOID*)&pProcess,
-                                        NULL);
-      if (!NT_SUCCESS(Status))
-       {
-         return(Status);
-       }
+        DPRINT1("Bucket size invalid\n");
+        return STATUS_INVALID_PARAMETER;
     }
-  else
+
+    /* Make sure that the buckets can map the range */
+    if ((ImageSize >> (BucketSize - 2)) > BufferSize)
     {
-      pProcess = NULL;
-      if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
-                                 PreviousMode))
-      {
-        DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
-        return STATUS_PRIVILEGE_NOT_HELD;
-      }
+        DPRINT1("Bucket size too small\n");
+        return STATUS_BUFFER_TOO_SMALL;
     }
 
-  /*
-   * Check the parameters
-   */
-  if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
-      (pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
+    /* Make sure that the range isn't too gigantic */
+    if (((ULONG_PTR)ImageBase + ImageSize) < ImageSize)
     {
-      return(STATUS_INVALID_PARAMETER_3);
+        DPRINT1("Range too big\n");
+        return STATUS_BUFFER_OVERFLOW;
     }
-  if (((ImageSize >> BucketSize) * 4) >= BufferSize)
+
+    /* Check if we were called from user-mode */
+    if(PreviousMode != KernelMode)
     {
-      return(STATUS_BUFFER_TOO_SMALL);
+        /* Entry SEH */
+        _SEH_TRY
+        {
+            /* Make sure that the handle pointer is valid */
+            ProbeForWriteHandle(ProfileHandle);
+
+            /* Check if the buffer is valid */
+            ProbeForWrite(Buffer,
+                          BufferSize,
+                          sizeof(ULONG));
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        /* Bail out if we failed */
+        if(!NT_SUCCESS(Status)) return Status;
     }
-  if (ProfileSource != ProfileTime)
+
+    /* Check if a process was specified */
+    if (Process)
     {
-      return(STATUS_INVALID_PARAMETER_9);
+        /* Reference it */
+        Status = ObReferenceObjectByHandle(Process,
+                                           PROCESS_QUERY_INFORMATION,
+                                           PsProcessType,
+                                           PreviousMode,
+                                           (PVOID*)&pProcess,
+                                           NULL);
+        if (!NT_SUCCESS(Status)) return(Status);
     }
-  if (Affinity != 0)
+    else
     {
-      return(STATUS_INVALID_PARAMETER_10);
+        /* Segmented profile objects cannot be used system-wide */
+        if (Segment) return STATUS_INVALID_PARAMETER;
+
+        /* No process was specified, which means a System-Wide Profile */
+        pProcess = NULL;
+
+        /* For this, we need to check the Privilege */
+        if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode))
+        {
+            DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
     }
 
-  /*
-   * Create the object
-   */
-  InitializeObjectAttributes(&ObjectAttributes,
+    /* Create the object */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               NULL,
+                               0,
+                               NULL,
+                               NULL);
+    Status = ObCreateObject(KernelMode,
+                            ExProfileObjectType,
+                            &ObjectAttributes,
+                            PreviousMode,
+                            NULL,
+                            sizeof(EPROFILE),
+                            0,
+                            sizeof(EPROFILE) + sizeof(KPROFILE),
+                            (PVOID*)&Profile);
+    if (!NT_SUCCESS(Status)) return(Status);
+
+    /* Initialize it */
+    Profile->ImageBase = ImageBase;
+    Profile->ImageSize = ImageSize;
+    Profile->Buffer = Buffer;
+    Profile->BufferSize = BufferSize;
+    Profile->BucketSize = BucketSize;
+    Profile->LockedBuffer = NULL;
+    Profile->Segment = Segment;
+    Profile->ProfileSource = ProfileSource;
+    Profile->Affinity = Affinity;
+    Profile->Process = pProcess;
+
+    /* Insert into the Object Tree */
+    Status = ObInsertObject ((PVOID)Profile,
                              NULL,
+                             PROFILE_CONTROL,
                              0,
                              NULL,
-                             NULL);
-
-  Status = ObCreateObject(KernelMode,
-                         ExProfileObjectType,
-                         &ObjectAttributes,
-                         PreviousMode,
-                         NULL,
-                         sizeof(KPROFILE),
-                         0,
-                         0,
-                         (PVOID*)&Profile);
-  if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-
-  /*
-   * Initialize it
-   */
-  Profile->Base = ImageBase;
-  Profile->Size = ImageSize;
-  Profile->BucketShift = BucketSize;
-  Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
-  if(Profile->BufferMdl == NULL) {
-       DPRINT("MmCreateMdl: Out of memory!");
-       ObDereferenceObject (Profile);
-       return(STATUS_NO_MEMORY);
-  }  
-  MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
-  Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
-  Profile->BufferSize = BufferSize;
-  Profile->ProcessorMask = Affinity;
-  Profile->Started = FALSE;
-  Profile->Process = pProcess;
-
-  /*
-   * Insert the profile into the profile list data structures
-   */
-  KiInsertProfile(Profile);
-
-  Status = ObInsertObject ((PVOID)Profile,
-                          NULL,
-                          STANDARD_RIGHTS_ALL,
-                          0,
-                          NULL,
-                          &hProfile);
-  if (!NT_SUCCESS(Status))
+                             &hProfile);
+    ObDereferenceObject(Profile);
+
+    /* Check for Success */
+    if (!NT_SUCCESS(Status))
     {
-      ObDereferenceObject (Profile);
-      return Status;
+        /* Dereference Process on failure */
+        if (pProcess) ObDereferenceObject(pProcess);
+        return Status;
     }
 
-  /*
-   * Copy the created handle back to the caller
-   */
-  _SEH_TRY
-  {
-    *ProfileHandle = hProfile;
-  }
-  _SEH_HANDLE
-  {
-    Status = _SEH_GetExceptionCode();
-  }
-  _SEH_END;
-
-  ObDereferenceObject(Profile);
-
-  return Status;
-}
-
-NTSTATUS STDCALL 
-NtQueryIntervalProfile(IN  KPROFILE_SOURCE ProfileSource,
-                      OUT PULONG Interval)
-{
-  KPROCESSOR_MODE PreviousMode;
-  NTSTATUS Status = STATUS_SUCCESS;
-  
-  PAGED_CODE();
-  
-  PreviousMode = ExGetPreviousMode();
-  
-  if(PreviousMode != KernelMode)
-  {
+    /* Enter SEH */
     _SEH_TRY
     {
-      ProbeForWrite(Interval,
-                    sizeof(ULONG),
-                    sizeof(ULONG));
+        /* Copy the created handle back to the caller*/
+        *ProfileHandle = hProfile;
     }
-    _SEH_HANDLE
+    _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
     {
-      Status = _SEH_GetExceptionCode();
+        Status = _SEH_GetExceptionCode();
     }
     _SEH_END;
-    
-    if(!NT_SUCCESS(Status))
+
+    /* Return Status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
+                          OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    LARGE_INTEGER PerfFrequency;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Check if we were called from user-mode */
+    if(PreviousMode != KernelMode)
     {
-      return Status;
+        /* Entry SEH Block */
+        _SEH_TRY
+        {
+            /* Make sure the counter and frequency are valid */
+            ProbeForWriteLargeInteger(PerformanceCounter);
+            if (PerformanceFrequency)
+            {
+                ProbeForWriteLargeInteger(PerformanceFrequency);
+            }
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        /* If the pointers are invalid, bail out */
+        if(!NT_SUCCESS(Status)) return Status;
     }
-  }
 
-  if (ProfileSource == ProfileTime)
+    /* Enter a new SEH Block */
+    _SEH_TRY
     {
-      ULONG ReturnInterval;
-
-      /* FIXME: What units does this use, for now nanoseconds */
-      ReturnInterval = 100;
+        /* Query the Kernel */
+        *PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
 
-      _SEH_TRY
-      {
-        *Interval = ReturnInterval;
-      }
-      _SEH_HANDLE
-      {
+        /* Return Frequency if requested */
+        if(PerformanceFrequency) *PerformanceFrequency = PerfFrequency;
+    }
+    _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+    {
         Status = _SEH_GetExceptionCode();
-      }
-      _SEH_END;
-      
-      return Status;
     }
-  return STATUS_INVALID_PARAMETER_2;
-}
+    _SEH_END;
 
-NTSTATUS STDCALL 
-NtSetIntervalProfile(IN ULONG Interval,
-                    IN KPROFILE_SOURCE Source)
-{
-  return(STATUS_NOT_IMPLEMENTED);
+    /* Return status to caller */
+    return Status;
 }
 
-NTSTATUS STDCALL 
+NTSTATUS
+NTAPI
 NtStartProfile(IN HANDLE ProfileHandle)
 {
-  PKPROFILE Profile;
-  KPROCESSOR_MODE PreviousMode;
-  NTSTATUS Status;
-  
-  PAGED_CODE();
-  
-  PreviousMode = ExGetPreviousMode();
-
-  Status = ObReferenceObjectByHandle(ProfileHandle,
-                                    STANDARD_RIGHTS_ALL,
-                                    ExProfileObjectType,
-                                    PreviousMode,
-                                    (PVOID*)&Profile,
-                                    NULL);
-  if (!NT_SUCCESS(Status))
+    PEPROFILE Profile;
+    PKPROFILE KeProfile;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PVOID TempLockedBuffer;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Get the Object */
+    Status = ObReferenceObjectByHandle(ProfileHandle,
+                                       PROFILE_CONTROL,
+                                       ExProfileObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Profile,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return(Status);
+
+    /* To avoid a Race, wait on the Mutex */
+    KeWaitForSingleObject(&ExpProfileMutex,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    /* The Profile can still be enabled though, so handle that */
+    if (Profile->LockedBuffer)
     {
-      return(Status);
+        /* Release our lock, dereference and return */
+        KeReleaseMutex(&ExpProfileMutex, FALSE);
+        ObDereferenceObject(Profile);
+        return STATUS_PROFILING_NOT_STOPPED;
     }
-  Profile->Started = TRUE;
-  ObDereferenceObject(Profile);
-  return(STATUS_SUCCESS);
+
+    /* Allocate a Kernel Profile Object. */
+    KeProfile = ExAllocatePoolWithTag(NonPagedPool,
+                                      sizeof(EPROFILE),
+                                      TAG_PROFILE);
+
+    /* Allocate the Mdl Structure */
+    Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer, Profile->BufferSize);
+
+    /* Probe and Lock for Write Access */
+    MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
+
+    /* Map the pages */
+    TempLockedBuffer = MmMapLockedPages(Profile->Mdl, KernelMode);
+
+    /* Initialize the Kernel Profile Object */
+    Profile->KeProfile = KeProfile;
+    KeInitializeProfile(KeProfile,
+                        (PKPROCESS)Profile->Process,
+                        Profile->ImageBase,
+                        Profile->ImageSize,
+                        Profile->BucketSize,
+                        Profile->ProfileSource,
+                        Profile->Affinity);
+
+    /* Start the Profiling */
+    KeStartProfile(KeProfile, TempLockedBuffer);
+
+    /* Now it's safe to save this */
+    Profile->LockedBuffer = TempLockedBuffer;
+
+    /* Release mutex, dereference and return */
+    KeReleaseMutex(&ExpProfileMutex, FALSE);
+    ObDereferenceObject(Profile);
+    return STATUS_SUCCESS;
 }
 
-NTSTATUS STDCALL 
+NTSTATUS
+NTAPI
 NtStopProfile(IN HANDLE ProfileHandle)
 {
-  PKPROFILE Profile;
-  KPROCESSOR_MODE PreviousMode;
-  NTSTATUS Status;
-  
-  PAGED_CODE();
-  
-  PreviousMode = ExGetPreviousMode();
-
-  Status = ObReferenceObjectByHandle(ProfileHandle,
-                                    STANDARD_RIGHTS_ALL,
-                                    ExProfileObjectType,
-                                    PreviousMode,
-                                    (PVOID*)&Profile,
-                                    NULL);
-  if (!NT_SUCCESS(Status))
+    PEPROFILE Profile;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Get the Object */
+    Status = ObReferenceObjectByHandle(ProfileHandle,
+                                       PROFILE_CONTROL,
+                                       ExProfileObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Profile,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return(Status);
+
+    /* Get the Mutex */
+    KeWaitForSingleObject(&ExpProfileMutex,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    /* Make sure the Profile Object is really Started */
+    if (!Profile->LockedBuffer)
+    {
+        Status = STATUS_PROFILING_NOT_STARTED;
+        goto Exit;
+    }
+
+    /* Stop the Profile */
+    KeStopProfile(Profile->KeProfile);
+
+    /* Unlock the Buffer */
+    MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
+    MmUnlockPages(Profile->Mdl);
+    ExFreePool(Profile->KeProfile);
+
+    /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
+    Profile->LockedBuffer = NULL;
+
+Exit:
+    /* Release Mutex, Dereference and Return */
+    KeReleaseMutex(&ExpProfileMutex, FALSE);
+    ObDereferenceObject(Profile);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
+                       OUT PULONG Interval)
+{
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    ULONG ReturnInterval;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+
+    /* Check if we were called from user-mode */
+    if(PreviousMode != KernelMode)
     {
-      return(Status);
+        /* Enter SEH Block */
+        _SEH_TRY
+        {
+            /* Validate interval */
+            ProbeForWriteUlong(Interval);
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        /* If pointer was invalid, bail out */
+        if(!NT_SUCCESS(Status)) return Status;
     }
-  Profile->Started = FALSE;
-  ObDereferenceObject(Profile);
-  return(STATUS_SUCCESS);
+
+    /* Query the Interval */
+    ReturnInterval = KeQueryIntervalProfile(ProfileSource);
+
+    /* Enter SEH block for return */
+    _SEH_TRY
+    {
+        /* Return the data */
+        *Interval = ReturnInterval;
+    }
+    _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+    {
+        Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
+
+    /* Return Success */
+    return STATUS_SUCCESS;
 }
 
+NTSTATUS
+NTAPI
+NtSetIntervalProfile(IN ULONG Interval,
+                     IN KPROFILE_SOURCE Source)
+{
+    /* Let the Kernel do the job */
+    KeSetIntervalProfile(Interval, Source);
 
+    /* Nothing can go wrong */
+    return STATUS_SUCCESS;
+}