2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/profile.c
5 * PURPOSE: Support for Executive Profile Objects
7 * PROGRAMMERS: Alex Ionescu
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, ExpInitializeProfileImplementation)
20 /* FIXME: NDK This structure is a *GUESS* -- Alex */
21 typedef struct _EPROFILE
{
29 KPROFILE_SOURCE ProfileSource
;
33 } EPROFILE
, *PEPROFILE
;
35 /* GLOBALS *******************************************************************/
37 POBJECT_TYPE ExProfileObjectType
= NULL
;
39 static KMUTEX ExpProfileMutex
;
41 #define PROFILE_CONTROL 1
43 static GENERIC_MAPPING ExpProfileMapping
= {
44 STANDARD_RIGHTS_READ
| PROFILE_CONTROL
,
45 STANDARD_RIGHTS_WRITE
| PROFILE_CONTROL
,
46 STANDARD_RIGHTS_EXECUTE
| PROFILE_CONTROL
,
51 ExpDeleteProfile(PVOID ObjectBody
)
55 /* Typecast the Object */
56 Profile
= (PEPROFILE
)ObjectBody
;
58 /* Check if there if the Profile was started */
59 if (Profile
->LockedBuffer
) {
61 /* Stop the Profile */
62 KeStopProfile(Profile
->KeProfile
);
64 /* Unmap the Locked Buffer */
65 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
66 MmUnlockPages(Profile
->Mdl
);
67 ExFreePool(Profile
->Mdl
);
70 /* Check if a Process is associated */
71 if (Profile
->Process
!= NULL
) {
74 ObDereferenceObject(Profile
->Process
);
75 Profile
->Process
= NULL
;
82 ExpInitializeProfileImplementation(VOID
)
84 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
87 /* Initialize the Mutex to lock the States */
88 KeInitializeMutex(&ExpProfileMutex
, 0x40);
90 DPRINT("Creating Profile Object Type\n");
92 /* Create the Event Pair Object Type */
93 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
94 RtlInitUnicodeString(&Name
, L
"Profile");
95 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
96 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KPROFILE
);
97 ObjectTypeInitializer
.GenericMapping
= ExpProfileMapping
;
98 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
99 ObjectTypeInitializer
.DeleteProcedure
= ExpDeleteProfile
;
100 ObjectTypeInitializer
.ValidAccessMask
= STANDARD_RIGHTS_ALL
;
101 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ExProfileObjectType
);
106 NtCreateProfile(OUT PHANDLE ProfileHandle
,
107 IN HANDLE Process OPTIONAL
,
113 IN KPROFILE_SOURCE ProfileSource
,
114 IN KAFFINITY Affinity
)
119 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
120 OBJECT_ATTRIBUTES ObjectAttributes
;
121 NTSTATUS Status
= STATUS_SUCCESS
;
126 if(BufferSize
== 0) return STATUS_INVALID_PARAMETER_7
;
128 /* Check the Parameters for validity */
129 if(PreviousMode
!= KernelMode
) {
133 ProbeForWriteHandle(ProfileHandle
);
135 ProbeForWrite(Buffer
,
138 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
140 Status
= _SEH_GetExceptionCode();
143 if(!NT_SUCCESS(Status
)) return Status
;
146 /* Check if a process was specified */
150 Status
= ObReferenceObjectByHandle(Process
,
151 PROCESS_QUERY_INFORMATION
,
156 if (!NT_SUCCESS(Status
)) return(Status
);
160 /* No process was specified, which means a System-Wide Profile */
163 /* For this, we need to check the Privilege */
164 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege
, PreviousMode
)) {
166 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
167 return STATUS_PRIVILEGE_NOT_HELD
;
171 /* Create the object */
172 InitializeObjectAttributes(&ObjectAttributes
,
177 Status
= ObCreateObject(KernelMode
,
186 if (!NT_SUCCESS(Status
)) return(Status
);
189 Profile
->ImageBase
= ImageBase
;
190 Profile
->ImageSize
= ImageSize
;
191 Profile
->Buffer
= Buffer
;
192 Profile
->BufferSize
= BufferSize
;
193 Profile
->BucketSize
= BucketSize
;
194 Profile
->LockedBuffer
= NULL
;
195 Profile
->Affinity
= Affinity
;
196 Profile
->Process
= pProcess
;
198 /* Insert into the Object Tree */
199 Status
= ObInsertObject ((PVOID
)Profile
,
205 ObDereferenceObject(Profile
);
207 /* Check for Success */
208 if (!NT_SUCCESS(Status
)) {
210 /* Dereference Process on failure */
211 if (pProcess
) ObDereferenceObject(pProcess
);
215 /* Copy the created handle back to the caller*/
218 *ProfileHandle
= hProfile
;
220 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
222 Status
= _SEH_GetExceptionCode();
231 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter
,
232 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
234 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
235 LARGE_INTEGER PerfFrequency
;
236 NTSTATUS Status
= STATUS_SUCCESS
;
238 /* Check the Parameters for validity */
239 if(PreviousMode
!= KernelMode
) {
243 ProbeForWriteLargeInteger(PerformanceCounter
);
245 ProbeForWriteLargeInteger(PerformanceFrequency
);
246 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
248 Status
= _SEH_GetExceptionCode();
251 if(!NT_SUCCESS(Status
)) return Status
;
256 /* Query the Kernel */
257 *PerformanceCounter
= KeQueryPerformanceCounter(&PerfFrequency
);
259 /* Return Frequency if requested */
260 if(PerformanceFrequency
) {
262 *PerformanceFrequency
= PerfFrequency
;
264 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
266 Status
= _SEH_GetExceptionCode();
275 NtStartProfile(IN HANDLE ProfileHandle
)
279 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
280 PVOID TempLockedBuffer
;
286 Status
= ObReferenceObjectByHandle(ProfileHandle
,
292 if (!NT_SUCCESS(Status
)) return(Status
);
294 /* To avoid a Race, wait on the Mutex */
295 KeWaitForSingleObject(&ExpProfileMutex
,
301 /* The Profile can still be enabled though, so handle that */
302 if (Profile
->LockedBuffer
) {
304 /* Release our lock, dereference and return */
305 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
306 ObDereferenceObject(Profile
);
307 return STATUS_PROFILING_NOT_STOPPED
;
310 /* Allocate a Kernel Profile Object. */
311 KeProfile
= ExAllocatePoolWithTag(NonPagedPool
,
313 TAG('P', 'r', 'o', 'f'));
315 /* Allocate the Mdl Structure */
316 Profile
->Mdl
= MmCreateMdl(NULL
, Profile
->Buffer
, Profile
->BufferSize
);
318 /* Probe and Lock for Write Access */
319 MmProbeAndLockPages(Profile
->Mdl
, PreviousMode
, IoWriteAccess
);
322 TempLockedBuffer
= MmMapLockedPages(Profile
->Mdl
, KernelMode
);
324 /* Initialize the Kernel Profile Object */
325 Profile
->KeProfile
= KeProfile
;
326 KeInitializeProfile(KeProfile
,
327 (PKPROCESS
)Profile
->Process
,
331 Profile
->ProfileSource
,
334 /* Start the Profiling */
335 KeStartProfile(KeProfile
, TempLockedBuffer
);
337 /* Now it's safe to save this */
338 Profile
->LockedBuffer
= TempLockedBuffer
;
340 /* Release mutex, dereference and return */
341 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
342 ObDereferenceObject(Profile
);
343 return STATUS_SUCCESS
;
348 NtStopProfile(IN HANDLE ProfileHandle
)
351 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
357 Status
= ObReferenceObjectByHandle(ProfileHandle
,
363 if (!NT_SUCCESS(Status
)) return(Status
);
366 KeWaitForSingleObject(&ExpProfileMutex
,
372 /* Make sure the Profile Object is really Started */
373 if (!Profile
->LockedBuffer
) {
375 Status
= STATUS_PROFILING_NOT_STARTED
;
379 /* Stop the Profile */
380 KeStopProfile(Profile
->KeProfile
);
382 /* Unlock the Buffer */
383 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
384 MmUnlockPages(Profile
->Mdl
);
385 ExFreePool(Profile
->KeProfile
);
387 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
388 Profile
->LockedBuffer
= NULL
;
391 /* Release Mutex, Dereference and Return */
392 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
393 ObDereferenceObject(Profile
);
399 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
402 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
403 ULONG ReturnInterval
;
404 NTSTATUS Status
= STATUS_SUCCESS
;
408 /* Check the Parameters for validity */
409 if(PreviousMode
!= KernelMode
) {
413 ProbeForWriteUlong(Interval
);
415 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
417 Status
= _SEH_GetExceptionCode();
420 if(!NT_SUCCESS(Status
)) return Status
;
423 /* Query the Interval */
424 ReturnInterval
= KeQueryIntervalProfile(ProfileSource
);
426 /* Return the data */
429 *Interval
= ReturnInterval
;
431 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
433 Status
= _SEH_GetExceptionCode();
438 return STATUS_SUCCESS
;
443 NtSetIntervalProfile(IN ULONG Interval
,
444 IN KPROFILE_SOURCE Source
)
446 /* Let the Kernel do the job */
447 KeSetIntervalProfile(Interval
, Source
);
449 /* Nothing can go wrong */
450 return STATUS_SUCCESS
;