/*
* COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+ * PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ex/profile.c
* PURPOSE: Support for Executive Profile Objects
- *
- * PROGRAMMERS: Alex Ionescu
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ * Thomas Weidenmueller
*/
/* INCLUDES *****************************************************************/
-#define NDEBUG
#include <ntoskrnl.h>
-#include <internal/debug.h>
-
-/* This structure is a *GUESS* -- Alex */
-typedef struct _EPROFILE {
- PEPROCESS Process;
- PVOID ImageBase;
- ULONG ImageSize;
- ULONG BucketSize;
- PVOID Buffer;
- ULONG BufferSize;
- PKPROFILE KeProfile;
- KPROFILE_SOURCE ProfileSource;
- KAFFINITY Affinity;
- PMDL Mdl;
- PVOID LockedBuffer;
-} EPROFILE, *PEPROFILE;
+#define NDEBUG
+#include <debug.h>
-/* GLOBALS *******************************************************************/
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, ExpInitializeProfileImplementation)
+#endif
-POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
+#define TAG_PROFILE 'forP'
-static KMUTEX ExpProfileMutex;
+/* GLOBALS *******************************************************************/
-#define PROFILE_CONTROL 1
+POBJECT_TYPE ExProfileObjectType = NULL;
+KMUTEX ExpProfileMutex;
-static GENERIC_MAPPING ExpProfileMapping = {
+GENERIC_MAPPING ExpProfileMapping =
+{
STANDARD_RIGHTS_READ | PROFILE_CONTROL,
STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
- STANDARD_RIGHTS_ALL};
+ PROFILE_ALL_ACCESS
+};
+
+/* FUNCTIONS *****************************************************************/
VOID
-STDCALL
+NTAPI
ExpDeleteProfile(PVOID ObjectBody)
{
PEPROFILE Profile;
+ ULONG State;
/* Typecast the Object */
Profile = (PEPROFILE)ObjectBody;
/* Check if there if the Profile was started */
- if (Profile->LockedBuffer) {
-
+ if (Profile->LockedBufferAddress)
+ {
/* Stop the Profile */
- KeStopProfile(Profile->KeProfile);
+ State = KeStopProfile(Profile->ProfileObject);
+ ASSERT(State != FALSE);
/* Unmap the Locked Buffer */
- MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
+ MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
MmUnlockPages(Profile->Mdl);
ExFreePool(Profile->Mdl);
}
- /* Check if a Process is associated */
- if (Profile->Process != NULL) {
-
- /* Dereference it */
- ObDereferenceObject(Profile->Process);
- Profile->Process = NULL;
- }
+ /* Check if a Process is associated and reference it */
+ if (Profile->Process) ObDereferenceObject(Profile->Process);
}
VOID
INIT_FUNCTION
-STDCALL
+NTAPI
ExpInitializeProfileImplementation(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
-
+ DPRINT("Creating Profile Object Type\n");
+
/* Initialize the Mutex to lock the States */
- KeInitializeMutex(&ExpProfileMutex, 0x40);
+ KeInitializeMutex(&ExpProfileMutex, 64);
- DPRINT("Creating Profile Object Type\n");
-
/* Create the Event Pair Object Type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Profile");
ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
- ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL;
- ObjectTypeInitializer.UseDefaultObject = TRUE;
- ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType);
+ ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
+ ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExProfileObjectType);
}
NTSTATUS
-STDCALL
+NTAPI
NtCreateProfile(OUT PHANDLE ProfileHandle,
IN HANDLE Process OPTIONAL,
- IN PVOID ImageBase,
- IN ULONG ImageSize,
+ IN PVOID RangeBase,
+ IN ULONG RangeSize,
IN ULONG BucketSize,
IN PVOID Buffer,
IN ULONG BufferSize,
PEPROCESS pProcess;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status = STATUS_SUCCESS;
-
+ NTSTATUS Status;
+ ULONG Log2 = 0;
+ ULONG_PTR Segment = 0;
PAGED_CODE();
/* Easy way out */
- if(BufferSize == 0) return STATUS_INVALID_PARAMETER_7;
+ if(!BufferSize) return STATUS_INVALID_PARAMETER_7;
- /* Check the Parameters for validity */
- if(PreviousMode != KernelMode) {
+ /* Check if this is a low-memory profile */
+ if ((!BucketSize) && (RangeBase < (PVOID)(0x10000)))
+ {
+ /* Validate size */
+ if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7;
- _SEH_TRY {
+ /* This will become a segmented profile object */
+ Segment = (ULONG_PTR)RangeBase;
+ RangeBase = 0;
- ProbeForWrite(ProfileHandle,
- sizeof(HANDLE),
- sizeof(ULONG));
+ /* Recalculate the bucket size */
+ BucketSize = RangeSize / (BufferSize / sizeof(ULONG));
+
+ /* Convert it to log2 */
+ BucketSize--;
+ while (BucketSize >>= 1) Log2++;
+ BucketSize += Log2 + 1;
+ }
+ /* Validate bucket size */
+ if ((BucketSize > 31) || (BucketSize < 2))
+ {
+ DPRINT1("Bucket size invalid\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Make sure that the buckets can map the range */
+ if ((RangeSize >> (BucketSize - 2)) > BufferSize)
+ {
+ DPRINT1("Bucket size too small\n");
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Make sure that the range isn't too gigantic */
+ if (((ULONG_PTR)RangeBase + RangeSize) < RangeSize)
+ {
+ DPRINT1("Range too big\n");
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ /* Check if we were called from user-mode */
+ if(PreviousMode != KernelMode)
+ {
+ /* Entry SEH */
+ _SEH2_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;
-
- if(!NT_SUCCESS(Status)) return Status;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
/* Check if a process was specified */
- if (Process) {
-
+ if (Process)
+ {
/* Reference it */
Status = ObReferenceObjectByHandle(Process,
PROCESS_QUERY_INFORMATION,
(PVOID*)&pProcess,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
-
- } else {
+ }
+ else
+ {
+ /* 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)) {
-
+ if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode))
+ {
DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
NULL,
sizeof(EPROFILE),
0,
- 0,
+ sizeof(EPROFILE) + sizeof(KPROFILE),
(PVOID*)&Profile);
- if (!NT_SUCCESS(Status)) return(Status);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Dereference the process object if it was specified */
+ if (pProcess) ObDereferenceObject(pProcess);
+
+ /* Return Status */
+ return Status;
+ }
/* Initialize it */
- Profile->ImageBase = ImageBase;
- Profile->ImageSize = ImageSize;
+ Profile->RangeBase = RangeBase;
+ Profile->RangeSize = RangeSize;
Profile->Buffer = Buffer;
Profile->BufferSize = BufferSize;
Profile->BucketSize = BucketSize;
- Profile->LockedBuffer = NULL;
+ Profile->LockedBufferAddress = NULL;
+ Profile->Segment = Segment;
+ Profile->ProfileSource = ProfileSource;
Profile->Affinity = Affinity;
Profile->Process = pProcess;
ObDereferenceObject(Profile);
/* Check for Success */
- if (!NT_SUCCESS(Status)) {
-
+ if (!NT_SUCCESS(Status))
+ {
/* Dereference Process on failure */
if (pProcess) ObDereferenceObject(pProcess);
return Status;
}
- /* Copy the created handle back to the caller*/
- _SEH_TRY {
-
+ /* Enter SEH */
+ _SEH2_TRY
+ {
+ /* Copy the created handle back to the caller*/
*ProfileHandle = hProfile;
-
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
- Status = _SEH_GetExceptionCode();
- } _SEH_END;
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
/* Return Status */
return Status;
}
NTSTATUS
-STDCALL
+NTAPI
NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
{
LARGE_INTEGER PerfFrequency;
NTSTATUS Status = STATUS_SUCCESS;
- /* Check the Parameters for validity */
- if(PreviousMode != KernelMode) {
-
- _SEH_TRY {
-
- ProbeForWrite(PerformanceCounter,
- sizeof(LARGE_INTEGER),
- sizeof(ULONG));
-
- ProbeForWrite(PerformanceFrequency,
- sizeof(LARGE_INTEGER),
- sizeof(ULONG));
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
- Status = _SEH_GetExceptionCode();
- } _SEH_END;
-
- if(!NT_SUCCESS(Status)) return Status;
+ /* Check if we were called from user-mode */
+ if (PreviousMode != KernelMode)
+ {
+ /* Entry SEH Block */
+ _SEH2_TRY
+ {
+ /* Make sure the counter and frequency are valid */
+ ProbeForWriteLargeInteger(PerformanceCounter);
+ if (PerformanceFrequency)
+ {
+ ProbeForWriteLargeInteger(PerformanceFrequency);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
- _SEH_TRY {
-
+ /* Enter a new SEH Block */
+ _SEH2_TRY
+ {
/* Query the Kernel */
*PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
/* Return Frequency if requested */
- if(PerformanceFrequency) {
-
- *PerformanceFrequency = PerfFrequency;
- }
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
- Status = _SEH_GetExceptionCode();
-
- } _SEH_END;
+ if (PerformanceFrequency) *PerformanceFrequency = PerfFrequency;
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ /* Return status to caller */
return Status;
}
NTSTATUS
-STDCALL
+NTAPI
NtStartProfile(IN HANDLE ProfileHandle)
{
PEPROFILE Profile;
- PKPROFILE KeProfile;
+ PKPROFILE ProfileObject;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- PVOID TempLockedBuffer;
+ PVOID TempLockedBufferAddress;
NTSTATUS Status;
-
PAGED_CODE();
/* Get the Object */
NULL);
/* The Profile can still be enabled though, so handle that */
- if (Profile->LockedBuffer) {
-
+ if (Profile->LockedBufferAddress)
+ {
/* Release our lock, dereference and return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
ObDereferenceObject(Profile);
}
/* Allocate a Kernel Profile Object. */
- KeProfile = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(EPROFILE),
- TAG('P', 'r', 'o', 'f'));
+ ProfileObject = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(EPROFILE),
+ TAG_PROFILE);
+ if (!ProfileObject)
+ {
+ /* Out of memory, fail */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
/* Allocate the Mdl Structure */
Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer, Profile->BufferSize);
- /* Probe and Lock for Write Access */
- MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
+ /* Protect this in SEH as we might raise an exception */
+ _SEH2_TRY
+ {
+ /* Probe and Lock for Write Access */
+ MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ /* Release our lock, free the buffer, dereference and return */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ ExFreePool(ProfileObject);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
/* Map the pages */
- TempLockedBuffer = MmMapLockedPages(Profile->Mdl, KernelMode);
+ TempLockedBufferAddress = MmMapLockedPages(Profile->Mdl, KernelMode);
/* Initialize the Kernel Profile Object */
- Profile->KeProfile = KeProfile;
- KeInitializeProfile(KeProfile,
+ Profile->ProfileObject = ProfileObject;
+ KeInitializeProfile(ProfileObject,
(PKPROCESS)Profile->Process,
- Profile->ImageBase,
- Profile->ImageSize,
+ Profile->RangeBase,
+ Profile->RangeSize,
Profile->BucketSize,
Profile->ProfileSource,
Profile->Affinity);
/* Start the Profiling */
- KeStartProfile(KeProfile, TempLockedBuffer);
+ KeStartProfile(ProfileObject, TempLockedBufferAddress);
/* Now it's safe to save this */
- Profile->LockedBuffer = TempLockedBuffer;
+ Profile->LockedBufferAddress = TempLockedBufferAddress;
/* Release mutex, dereference and return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
}
NTSTATUS
-STDCALL
+NTAPI
NtStopProfile(IN HANDLE ProfileHandle)
{
PEPROFILE Profile;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
-
PAGED_CODE();
/* Get the Object */
NULL);
/* Make sure the Profile Object is really Started */
- if (!Profile->LockedBuffer) {
-
+ if (!Profile->LockedBufferAddress)
+ {
Status = STATUS_PROFILING_NOT_STARTED;
goto Exit;
}
/* Stop the Profile */
- KeStopProfile(Profile->KeProfile);
+ KeStopProfile(Profile->ProfileObject);
/* Unlock the Buffer */
- MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
+ MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
MmUnlockPages(Profile->Mdl);
- ExFreePool(Profile->KeProfile);
+ ExFreePool(Profile->ProfileObject);
/* Clear the Locked Buffer pointer, meaning the Object is Stopped */
- Profile->LockedBuffer = NULL;
+ Profile->LockedBufferAddress = NULL;
Exit:
/* Release Mutex, Dereference and Return */
}
NTSTATUS
-STDCALL
-NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
+NTAPI
+NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
OUT PULONG Interval)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
ULONG ReturnInterval;
NTSTATUS Status = STATUS_SUCCESS;
-
PAGED_CODE();
- /* Check the Parameters for validity */
- if(PreviousMode != KernelMode) {
-
- _SEH_TRY {
-
- ProbeForWrite(Interval,
- sizeof(ULONG),
- sizeof(ULONG));
-
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
- Status = _SEH_GetExceptionCode();
- } _SEH_END;
-
- if(!NT_SUCCESS(Status)) return Status;
+ /* Check if we were called from user-mode */
+ if (PreviousMode != KernelMode)
+ {
+ /* Enter SEH Block */
+ _SEH2_TRY
+ {
+ /* Validate interval */
+ ProbeForWriteUlong(Interval);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
/* Query the Interval */
ReturnInterval = KeQueryIntervalProfile(ProfileSource);
- /* Return the data */
- _SEH_TRY {
-
+ /* Enter SEH block for return */
+ _SEH2_TRY
+ {
+ /* Return the data */
*Interval = ReturnInterval;
-
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
- Status = _SEH_GetExceptionCode();
-
- } _SEH_END;
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
/* Return Success */
- return STATUS_SUCCESS;
+ return Status;
}
NTSTATUS
-STDCALL
+NTAPI
NtSetIntervalProfile(IN ULONG Interval,
IN KPROFILE_SOURCE Source)
{