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 /* This structure is a *GUESS* -- Alex */
17 typedef struct _EPROFILE
{
25 KPROFILE_SOURCE ProfileSource
;
29 } EPROFILE
, *PEPROFILE
;
31 /* GLOBALS *******************************************************************/
33 POBJECT_TYPE EXPORTED ExProfileObjectType
= NULL
;
35 static KMUTEX ExpProfileMutex
;
37 #define PROFILE_CONTROL 1
39 static GENERIC_MAPPING ExpProfileMapping
= {
40 STANDARD_RIGHTS_READ
| PROFILE_CONTROL
,
41 STANDARD_RIGHTS_WRITE
| PROFILE_CONTROL
,
42 STANDARD_RIGHTS_EXECUTE
| PROFILE_CONTROL
,
47 ExpDeleteProfile(PVOID ObjectBody
)
51 /* Typecast the Object */
52 Profile
= (PEPROFILE
)ObjectBody
;
54 /* Check if there if the Profile was started */
55 if (Profile
->LockedBuffer
) {
57 /* Stop the Profile */
58 KeStopProfile(Profile
->KeProfile
);
60 /* Unmap the Locked Buffer */
61 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
62 MmUnlockPages(Profile
->Mdl
);
63 ExFreePool(Profile
->Mdl
);
66 /* Check if a Process is associated */
67 if (Profile
->Process
!= NULL
) {
70 ObDereferenceObject(Profile
->Process
);
71 Profile
->Process
= NULL
;
78 ExpInitializeProfileImplementation(VOID
)
80 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
83 /* Initialize the Mutex to lock the States */
84 KeInitializeMutex(&ExpProfileMutex
, 0x40);
86 DPRINT("Creating Profile Object Type\n");
88 /* Create the Event Pair Object Type */
89 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
90 RtlInitUnicodeString(&Name
, L
"Profile");
91 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
92 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KPROFILE
);
93 ObjectTypeInitializer
.GenericMapping
= ExpProfileMapping
;
94 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
95 ObjectTypeInitializer
.DeleteProcedure
= ExpDeleteProfile
;
96 ObjectTypeInitializer
.ValidAccessMask
= STANDARD_RIGHTS_ALL
;
97 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ExProfileObjectType
);
102 NtCreateProfile(OUT PHANDLE ProfileHandle
,
103 IN HANDLE Process OPTIONAL
,
109 IN KPROFILE_SOURCE ProfileSource
,
110 IN KAFFINITY Affinity
)
115 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
116 OBJECT_ATTRIBUTES ObjectAttributes
;
117 NTSTATUS Status
= STATUS_SUCCESS
;
122 if(BufferSize
== 0) return STATUS_INVALID_PARAMETER_7
;
124 /* Check the Parameters for validity */
125 if(PreviousMode
!= KernelMode
) {
129 ProbeForWriteHandle(ProfileHandle
);
131 ProbeForWrite(Buffer
,
134 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
136 Status
= _SEH_GetExceptionCode();
139 if(!NT_SUCCESS(Status
)) return Status
;
142 /* Check if a process was specified */
146 Status
= ObReferenceObjectByHandle(Process
,
147 PROCESS_QUERY_INFORMATION
,
152 if (!NT_SUCCESS(Status
)) return(Status
);
156 /* No process was specified, which means a System-Wide Profile */
159 /* For this, we need to check the Privilege */
160 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege
, PreviousMode
)) {
162 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
163 return STATUS_PRIVILEGE_NOT_HELD
;
167 /* Create the object */
168 InitializeObjectAttributes(&ObjectAttributes
,
173 Status
= ObCreateObject(KernelMode
,
182 if (!NT_SUCCESS(Status
)) return(Status
);
185 Profile
->ImageBase
= ImageBase
;
186 Profile
->ImageSize
= ImageSize
;
187 Profile
->Buffer
= Buffer
;
188 Profile
->BufferSize
= BufferSize
;
189 Profile
->BucketSize
= BucketSize
;
190 Profile
->LockedBuffer
= NULL
;
191 Profile
->Affinity
= Affinity
;
192 Profile
->Process
= pProcess
;
194 /* Insert into the Object Tree */
195 Status
= ObInsertObject ((PVOID
)Profile
,
201 ObDereferenceObject(Profile
);
203 /* Check for Success */
204 if (!NT_SUCCESS(Status
)) {
206 /* Dereference Process on failure */
207 if (pProcess
) ObDereferenceObject(pProcess
);
211 /* Copy the created handle back to the caller*/
214 *ProfileHandle
= hProfile
;
216 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
218 Status
= _SEH_GetExceptionCode();
227 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter
,
228 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
230 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
231 LARGE_INTEGER PerfFrequency
;
232 NTSTATUS Status
= STATUS_SUCCESS
;
234 /* Check the Parameters for validity */
235 if(PreviousMode
!= KernelMode
) {
239 ProbeForWriteLargeInteger(PerformanceCounter
);
241 ProbeForWriteLargeInteger(PerformanceFrequency
);
242 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
244 Status
= _SEH_GetExceptionCode();
247 if(!NT_SUCCESS(Status
)) return Status
;
252 /* Query the Kernel */
253 *PerformanceCounter
= KeQueryPerformanceCounter(&PerfFrequency
);
255 /* Return Frequency if requested */
256 if(PerformanceFrequency
) {
258 *PerformanceFrequency
= PerfFrequency
;
260 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
262 Status
= _SEH_GetExceptionCode();
271 NtStartProfile(IN HANDLE ProfileHandle
)
275 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
276 PVOID TempLockedBuffer
;
282 Status
= ObReferenceObjectByHandle(ProfileHandle
,
288 if (!NT_SUCCESS(Status
)) return(Status
);
290 /* To avoid a Race, wait on the Mutex */
291 KeWaitForSingleObject(&ExpProfileMutex
,
297 /* The Profile can still be enabled though, so handle that */
298 if (Profile
->LockedBuffer
) {
300 /* Release our lock, dereference and return */
301 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
302 ObDereferenceObject(Profile
);
303 return STATUS_PROFILING_NOT_STOPPED
;
306 /* Allocate a Kernel Profile Object. */
307 KeProfile
= ExAllocatePoolWithTag(NonPagedPool
,
309 TAG('P', 'r', 'o', 'f'));
311 /* Allocate the Mdl Structure */
312 Profile
->Mdl
= MmCreateMdl(NULL
, Profile
->Buffer
, Profile
->BufferSize
);
314 /* Probe and Lock for Write Access */
315 MmProbeAndLockPages(Profile
->Mdl
, PreviousMode
, IoWriteAccess
);
318 TempLockedBuffer
= MmMapLockedPages(Profile
->Mdl
, KernelMode
);
320 /* Initialize the Kernel Profile Object */
321 Profile
->KeProfile
= KeProfile
;
322 KeInitializeProfile(KeProfile
,
323 (PKPROCESS
)Profile
->Process
,
327 Profile
->ProfileSource
,
330 /* Start the Profiling */
331 KeStartProfile(KeProfile
, TempLockedBuffer
);
333 /* Now it's safe to save this */
334 Profile
->LockedBuffer
= TempLockedBuffer
;
336 /* Release mutex, dereference and return */
337 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
338 ObDereferenceObject(Profile
);
339 return STATUS_SUCCESS
;
344 NtStopProfile(IN HANDLE ProfileHandle
)
347 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
353 Status
= ObReferenceObjectByHandle(ProfileHandle
,
359 if (!NT_SUCCESS(Status
)) return(Status
);
362 KeWaitForSingleObject(&ExpProfileMutex
,
368 /* Make sure the Profile Object is really Started */
369 if (!Profile
->LockedBuffer
) {
371 Status
= STATUS_PROFILING_NOT_STARTED
;
375 /* Stop the Profile */
376 KeStopProfile(Profile
->KeProfile
);
378 /* Unlock the Buffer */
379 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
380 MmUnlockPages(Profile
->Mdl
);
381 ExFreePool(Profile
->KeProfile
);
383 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
384 Profile
->LockedBuffer
= NULL
;
387 /* Release Mutex, Dereference and Return */
388 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
389 ObDereferenceObject(Profile
);
395 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
398 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
399 ULONG ReturnInterval
;
400 NTSTATUS Status
= STATUS_SUCCESS
;
404 /* Check the Parameters for validity */
405 if(PreviousMode
!= KernelMode
) {
409 ProbeForWriteUlong(Interval
);
411 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
413 Status
= _SEH_GetExceptionCode();
416 if(!NT_SUCCESS(Status
)) return Status
;
419 /* Query the Interval */
420 ReturnInterval
= KeQueryIntervalProfile(ProfileSource
);
422 /* Return the data */
425 *Interval
= ReturnInterval
;
427 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
429 Status
= _SEH_GetExceptionCode();
434 return STATUS_SUCCESS
;
439 NtSetIntervalProfile(IN ULONG Interval
,
440 IN KPROFILE_SOURCE Source
)
442 /* Let the Kernel do the job */
443 KeSetIntervalProfile(Interval
, Source
);
445 /* Nothing can go wrong */
446 return STATUS_SUCCESS
;