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 *****************************************************************/
13 #include <internal/debug.h>
15 /* This structure is a *GUESS* -- Alex */
16 typedef struct _EPROFILE
{
24 KPROFILE_SOURCE ProfileSource
;
28 } EPROFILE
, *PEPROFILE
;
30 /* GLOBALS *******************************************************************/
32 POBJECT_TYPE EXPORTED ExProfileObjectType
= NULL
;
34 static KMUTEX ExpProfileMutex
;
36 #define PROFILE_CONTROL 1
38 static GENERIC_MAPPING ExpProfileMapping
= {
39 STANDARD_RIGHTS_READ
| PROFILE_CONTROL
,
40 STANDARD_RIGHTS_WRITE
| PROFILE_CONTROL
,
41 STANDARD_RIGHTS_EXECUTE
| PROFILE_CONTROL
,
46 ExpDeleteProfile(PVOID ObjectBody
)
50 /* Typecast the Object */
51 Profile
= (PEPROFILE
)ObjectBody
;
53 /* Check if there if the Profile was started */
54 if (Profile
->LockedBuffer
) {
56 /* Stop the Profile */
57 KeStopProfile(Profile
->KeProfile
);
59 /* Unmap the Locked Buffer */
60 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
61 MmUnlockPages(Profile
->Mdl
);
62 ExFreePool(Profile
->Mdl
);
65 /* Check if a Process is associated */
66 if (Profile
->Process
!= NULL
) {
69 ObDereferenceObject(Profile
->Process
);
70 Profile
->Process
= NULL
;
76 ExpInitializeProfileImplementation(VOID
)
78 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
81 /* Initialize the Mutex to lock the States */
82 KeInitializeMutex(&ExpProfileMutex
, 0x40);
84 DPRINT1("Creating Profile Object Type\n");
86 /* Create the Event Pair Object Type */
87 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
88 RtlInitUnicodeString(&Name
, L
"Profile");
89 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
90 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KPROFILE
);
91 ObjectTypeInitializer
.GenericMapping
= ExpProfileMapping
;
92 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
93 ObjectTypeInitializer
.DeleteProcedure
= ExpDeleteProfile
;
94 ObjectTypeInitializer
.ValidAccessMask
= STANDARD_RIGHTS_ALL
;
95 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
96 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ExProfileObjectType
);
101 NtCreateProfile(OUT PHANDLE ProfileHandle
,
102 IN HANDLE Process OPTIONAL
,
108 IN KPROFILE_SOURCE ProfileSource
,
109 IN KAFFINITY Affinity
)
114 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
115 OBJECT_ATTRIBUTES ObjectAttributes
;
116 NTSTATUS Status
= STATUS_SUCCESS
;
121 if(BufferSize
== 0) return STATUS_INVALID_PARAMETER_7
;
123 /* Check the Parameters for validity */
124 if(PreviousMode
!= KernelMode
) {
128 ProbeForWrite(ProfileHandle
,
132 ProbeForWrite(Buffer
,
135 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
137 Status
= _SEH_GetExceptionCode();
140 if(!NT_SUCCESS(Status
)) return Status
;
143 /* Check if a process was specified */
147 Status
= ObReferenceObjectByHandle(Process
,
148 PROCESS_QUERY_INFORMATION
,
153 if (!NT_SUCCESS(Status
)) return(Status
);
157 /* No process was specified, which means a System-Wide Profile */
160 /* For this, we need to check the Privilege */
161 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege
, PreviousMode
)) {
163 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
164 return STATUS_PRIVILEGE_NOT_HELD
;
168 /* Create the object */
169 InitializeObjectAttributes(&ObjectAttributes
,
174 Status
= ObCreateObject(KernelMode
,
183 if (!NT_SUCCESS(Status
)) return(Status
);
186 Profile
->ImageBase
= ImageBase
;
187 Profile
->ImageSize
= ImageSize
;
188 Profile
->Buffer
= Buffer
;
189 Profile
->BufferSize
= BufferSize
;
190 Profile
->BucketSize
= BucketSize
;
191 Profile
->LockedBuffer
= NULL
;
192 Profile
->Affinity
= Affinity
;
193 Profile
->Process
= pProcess
;
195 /* Insert into the Object Tree */
196 Status
= ObInsertObject ((PVOID
)Profile
,
202 ObDereferenceObject(Profile
);
204 /* Check for Success */
205 if (!NT_SUCCESS(Status
)) {
207 /* Dereference Process on failure */
208 if (pProcess
) ObDereferenceObject(pProcess
);
212 /* Copy the created handle back to the caller*/
215 *ProfileHandle
= hProfile
;
217 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
219 Status
= _SEH_GetExceptionCode();
228 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter
,
229 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
231 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
232 LARGE_INTEGER PerfFrequency
;
233 NTSTATUS Status
= STATUS_SUCCESS
;
235 /* Check the Parameters for validity */
236 if(PreviousMode
!= KernelMode
) {
240 ProbeForWrite(PerformanceCounter
,
241 sizeof(LARGE_INTEGER
),
244 ProbeForWrite(PerformanceFrequency
,
245 sizeof(LARGE_INTEGER
),
247 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
249 Status
= _SEH_GetExceptionCode();
252 if(!NT_SUCCESS(Status
)) return Status
;
257 /* Query the Kernel */
258 *PerformanceCounter
= KeQueryPerformanceCounter(&PerfFrequency
);
260 /* Return Frequency if requested */
261 if(PerformanceFrequency
) {
263 *PerformanceFrequency
= PerfFrequency
;
265 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
267 Status
= _SEH_GetExceptionCode();
276 NtStartProfile(IN HANDLE ProfileHandle
)
280 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
281 PVOID TempLockedBuffer
;
287 Status
= ObReferenceObjectByHandle(ProfileHandle
,
293 if (!NT_SUCCESS(Status
)) return(Status
);
295 /* To avoid a Race, wait on the Mutex */
296 KeWaitForSingleObject(&ExpProfileMutex
,
302 /* The Profile can still be enabled though, so handle that */
303 if (Profile
->LockedBuffer
) {
305 /* Release our lock, dereference and return */
306 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
307 ObDereferenceObject(Profile
);
308 return STATUS_PROFILING_NOT_STOPPED
;
311 /* Allocate a Kernel Profile Object. */
312 KeProfile
= ExAllocatePoolWithTag(NonPagedPool
,
314 TAG('P', 'r', 'o', 'f'));
316 /* Allocate the Mdl Structure */
317 Profile
->Mdl
= MmCreateMdl(NULL
, Profile
->Buffer
, Profile
->BufferSize
);
319 /* Probe and Lock for Write Access */
320 MmProbeAndLockPages(Profile
->Mdl
, PreviousMode
, IoWriteAccess
);
323 TempLockedBuffer
= MmMapLockedPages(Profile
->Mdl
, KernelMode
);
325 /* Initialize the Kernel Profile Object */
326 Profile
->KeProfile
= KeProfile
;
327 KeInitializeProfile(KeProfile
,
328 (PKPROCESS
)Profile
->Process
,
332 Profile
->ProfileSource
,
335 /* Start the Profiling */
336 KeStartProfile(KeProfile
, TempLockedBuffer
);
338 /* Now it's safe to save this */
339 Profile
->LockedBuffer
= TempLockedBuffer
;
341 /* Release mutex, dereference and return */
342 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
343 ObDereferenceObject(Profile
);
344 return STATUS_SUCCESS
;
349 NtStopProfile(IN HANDLE ProfileHandle
)
352 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
358 Status
= ObReferenceObjectByHandle(ProfileHandle
,
364 if (!NT_SUCCESS(Status
)) return(Status
);
367 KeWaitForSingleObject(&ExpProfileMutex
,
373 /* Make sure the Profile Object is really Started */
374 if (!Profile
->LockedBuffer
) {
376 Status
= STATUS_PROFILING_NOT_STARTED
;
380 /* Stop the Profile */
381 KeStopProfile(Profile
->KeProfile
);
383 /* Unlock the Buffer */
384 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
385 MmUnlockPages(Profile
->Mdl
);
386 ExFreePool(Profile
->KeProfile
);
388 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
389 Profile
->LockedBuffer
= NULL
;
392 /* Release Mutex, Dereference and Return */
393 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
394 ObDereferenceObject(Profile
);
400 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
403 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
404 ULONG ReturnInterval
;
405 NTSTATUS Status
= STATUS_SUCCESS
;
409 /* Check the Parameters for validity */
410 if(PreviousMode
!= KernelMode
) {
414 ProbeForWrite(Interval
,
418 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
420 Status
= _SEH_GetExceptionCode();
423 if(!NT_SUCCESS(Status
)) return Status
;
426 /* Query the Interval */
427 ReturnInterval
= KeQueryIntervalProfile(ProfileSource
);
429 /* Return the data */
432 *Interval
= ReturnInterval
;
434 } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter
) {
436 Status
= _SEH_GetExceptionCode();
441 return STATUS_SUCCESS
;
446 NtSetIntervalProfile(IN ULONG Interval
,
447 IN KPROFILE_SOURCE Source
)
449 /* Let the Kernel do the job */
450 KeSetIntervalProfile(Interval
, Source
);
452 /* Nothing can go wrong */
453 return STATUS_SUCCESS
;