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 ProbeForWrite(ProfileHandle
,
133 ProbeForWrite(Buffer
,
136 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
138 Status
= _SEH_GetExceptionCode();
141 if(!NT_SUCCESS(Status
)) return Status
;
144 /* Check if a process was specified */
148 Status
= ObReferenceObjectByHandle(Process
,
149 PROCESS_QUERY_INFORMATION
,
154 if (!NT_SUCCESS(Status
)) return(Status
);
158 /* No process was specified, which means a System-Wide Profile */
161 /* For this, we need to check the Privilege */
162 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege
, PreviousMode
)) {
164 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
165 return STATUS_PRIVILEGE_NOT_HELD
;
169 /* Create the object */
170 InitializeObjectAttributes(&ObjectAttributes
,
175 Status
= ObCreateObject(KernelMode
,
184 if (!NT_SUCCESS(Status
)) return(Status
);
187 Profile
->ImageBase
= ImageBase
;
188 Profile
->ImageSize
= ImageSize
;
189 Profile
->Buffer
= Buffer
;
190 Profile
->BufferSize
= BufferSize
;
191 Profile
->BucketSize
= BucketSize
;
192 Profile
->LockedBuffer
= NULL
;
193 Profile
->Affinity
= Affinity
;
194 Profile
->Process
= pProcess
;
196 /* Insert into the Object Tree */
197 Status
= ObInsertObject ((PVOID
)Profile
,
203 ObDereferenceObject(Profile
);
205 /* Check for Success */
206 if (!NT_SUCCESS(Status
)) {
208 /* Dereference Process on failure */
209 if (pProcess
) ObDereferenceObject(pProcess
);
213 /* Copy the created handle back to the caller*/
216 *ProfileHandle
= hProfile
;
218 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
220 Status
= _SEH_GetExceptionCode();
229 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter
,
230 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
232 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
233 LARGE_INTEGER PerfFrequency
;
234 NTSTATUS Status
= STATUS_SUCCESS
;
236 /* Check the Parameters for validity */
237 if(PreviousMode
!= KernelMode
) {
241 ProbeForWrite(PerformanceCounter
,
242 sizeof(LARGE_INTEGER
),
245 ProbeForWrite(PerformanceFrequency
,
246 sizeof(LARGE_INTEGER
),
248 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
250 Status
= _SEH_GetExceptionCode();
253 if(!NT_SUCCESS(Status
)) return Status
;
258 /* Query the Kernel */
259 *PerformanceCounter
= KeQueryPerformanceCounter(&PerfFrequency
);
261 /* Return Frequency if requested */
262 if(PerformanceFrequency
) {
264 *PerformanceFrequency
= PerfFrequency
;
266 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
268 Status
= _SEH_GetExceptionCode();
277 NtStartProfile(IN HANDLE ProfileHandle
)
281 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
282 PVOID TempLockedBuffer
;
288 Status
= ObReferenceObjectByHandle(ProfileHandle
,
294 if (!NT_SUCCESS(Status
)) return(Status
);
296 /* To avoid a Race, wait on the Mutex */
297 KeWaitForSingleObject(&ExpProfileMutex
,
303 /* The Profile can still be enabled though, so handle that */
304 if (Profile
->LockedBuffer
) {
306 /* Release our lock, dereference and return */
307 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
308 ObDereferenceObject(Profile
);
309 return STATUS_PROFILING_NOT_STOPPED
;
312 /* Allocate a Kernel Profile Object. */
313 KeProfile
= ExAllocatePoolWithTag(NonPagedPool
,
315 TAG('P', 'r', 'o', 'f'));
317 /* Allocate the Mdl Structure */
318 Profile
->Mdl
= MmCreateMdl(NULL
, Profile
->Buffer
, Profile
->BufferSize
);
320 /* Probe and Lock for Write Access */
321 MmProbeAndLockPages(Profile
->Mdl
, PreviousMode
, IoWriteAccess
);
324 TempLockedBuffer
= MmMapLockedPages(Profile
->Mdl
, KernelMode
);
326 /* Initialize the Kernel Profile Object */
327 Profile
->KeProfile
= KeProfile
;
328 KeInitializeProfile(KeProfile
,
329 (PKPROCESS
)Profile
->Process
,
333 Profile
->ProfileSource
,
336 /* Start the Profiling */
337 KeStartProfile(KeProfile
, TempLockedBuffer
);
339 /* Now it's safe to save this */
340 Profile
->LockedBuffer
= TempLockedBuffer
;
342 /* Release mutex, dereference and return */
343 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
344 ObDereferenceObject(Profile
);
345 return STATUS_SUCCESS
;
350 NtStopProfile(IN HANDLE ProfileHandle
)
353 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
359 Status
= ObReferenceObjectByHandle(ProfileHandle
,
365 if (!NT_SUCCESS(Status
)) return(Status
);
368 KeWaitForSingleObject(&ExpProfileMutex
,
374 /* Make sure the Profile Object is really Started */
375 if (!Profile
->LockedBuffer
) {
377 Status
= STATUS_PROFILING_NOT_STARTED
;
381 /* Stop the Profile */
382 KeStopProfile(Profile
->KeProfile
);
384 /* Unlock the Buffer */
385 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
386 MmUnlockPages(Profile
->Mdl
);
387 ExFreePool(Profile
->KeProfile
);
389 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
390 Profile
->LockedBuffer
= NULL
;
393 /* Release Mutex, Dereference and Return */
394 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
395 ObDereferenceObject(Profile
);
401 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
404 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
405 ULONG ReturnInterval
;
406 NTSTATUS Status
= STATUS_SUCCESS
;
410 /* Check the Parameters for validity */
411 if(PreviousMode
!= KernelMode
) {
415 ProbeForWrite(Interval
,
419 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
421 Status
= _SEH_GetExceptionCode();
424 if(!NT_SUCCESS(Status
)) return Status
;
427 /* Query the Interval */
428 ReturnInterval
= KeQueryIntervalProfile(ProfileSource
);
430 /* Return the data */
433 *Interval
= ReturnInterval
;
435 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
437 Status
= _SEH_GetExceptionCode();
442 return STATUS_SUCCESS
;
447 NtSetIntervalProfile(IN ULONG Interval
,
448 IN KPROFILE_SOURCE Source
)
450 /* Let the Kernel do the job */
451 KeSetIntervalProfile(Interval
, Source
);
453 /* Nothing can go wrong */
454 return STATUS_SUCCESS
;