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 /* Initialize the Mutex to lock the States */
79 KeInitializeMutex(&ExpProfileMutex
, 0x40);
81 /* Create the Object Type */
82 ExProfileObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
83 RtlInitUnicodeString(&ExProfileObjectType
->TypeName
, L
"Profile");
84 ExProfileObjectType
->Tag
= TAG('P', 'R', 'O', 'F');
85 ExProfileObjectType
->PeakObjects
= 0;
86 ExProfileObjectType
->PeakHandles
= 0;
87 ExProfileObjectType
->TotalObjects
= 0;
88 ExProfileObjectType
->TotalHandles
= 0;
89 ExProfileObjectType
->PagedPoolCharge
= 0;
90 ExProfileObjectType
->NonpagedPoolCharge
= sizeof(EPROFILE
);
91 ExProfileObjectType
->Mapping
= &ExpProfileMapping
;
92 ExProfileObjectType
->Dump
= NULL
;
93 ExProfileObjectType
->Open
= NULL
;
94 ExProfileObjectType
->Close
= NULL
;
95 ExProfileObjectType
->Delete
= ExpDeleteProfile
;
96 ExProfileObjectType
->Parse
= NULL
;
97 ExProfileObjectType
->Security
= NULL
;
98 ExProfileObjectType
->QueryName
= NULL
;
99 ExProfileObjectType
->OkayToClose
= NULL
;
100 ExProfileObjectType
->Create
= NULL
;
101 ObpCreateTypeObject(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 ProbeForWrite(ProfileHandle
,
137 ProbeForWrite(Buffer
,
142 Status
= _SEH_GetExceptionCode();
145 if(!NT_SUCCESS(Status
)) return Status
;
148 /* Check if a process was specified */
152 Status
= ObReferenceObjectByHandle(Process
,
153 PROCESS_QUERY_INFORMATION
,
158 if (!NT_SUCCESS(Status
)) return(Status
);
162 /* No process was specified, which means a System-Wide Profile */
165 /* For this, we need to check the Privilege */
166 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege
, PreviousMode
)) {
168 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
169 return STATUS_PRIVILEGE_NOT_HELD
;
173 /* Create the object */
174 InitializeObjectAttributes(&ObjectAttributes
,
179 Status
= ObCreateObject(KernelMode
,
188 if (!NT_SUCCESS(Status
)) return(Status
);
191 Profile
->ImageBase
= ImageBase
;
192 Profile
->ImageSize
= ImageSize
;
193 Profile
->Buffer
= Buffer
;
194 Profile
->BufferSize
= BufferSize
;
195 Profile
->BucketSize
= BucketSize
;
196 Profile
->LockedBuffer
= NULL
;
197 Profile
->Affinity
= Affinity
;
198 Profile
->Process
= pProcess
;
200 /* Insert into the Object Tree */
201 Status
= ObInsertObject ((PVOID
)Profile
,
207 ObDereferenceObject(Profile
);
209 /* Check for Success */
210 if (!NT_SUCCESS(Status
)) {
212 /* Dereference Process on failure */
213 if (pProcess
) ObDereferenceObject(pProcess
);
217 /* Copy the created handle back to the caller*/
220 *ProfileHandle
= hProfile
;
224 Status
= _SEH_GetExceptionCode();
233 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter
,
234 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
236 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
237 LARGE_INTEGER PerfFrequency
;
238 NTSTATUS Status
= STATUS_SUCCESS
;
240 /* Check the Parameters for validity */
241 if(PreviousMode
!= KernelMode
) {
245 ProbeForWrite(PerformanceCounter
,
246 sizeof(LARGE_INTEGER
),
249 ProbeForWrite(PerformanceFrequency
,
250 sizeof(LARGE_INTEGER
),
254 Status
= _SEH_GetExceptionCode();
257 if(!NT_SUCCESS(Status
)) return Status
;
262 /* Query the Kernel */
263 *PerformanceCounter
= KeQueryPerformanceCounter(&PerfFrequency
);
265 /* Return Frequency if requested */
266 if(PerformanceFrequency
) {
268 *PerformanceFrequency
= PerfFrequency
;
272 Status
= _SEH_GetExceptionCode();
281 NtStartProfile(IN HANDLE ProfileHandle
)
285 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
286 PVOID TempLockedBuffer
;
292 Status
= ObReferenceObjectByHandle(ProfileHandle
,
298 if (!NT_SUCCESS(Status
)) return(Status
);
300 /* To avoid a Race, wait on the Mutex */
301 KeWaitForSingleObject(&ExpProfileMutex
,
307 /* The Profile can still be enabled though, so handle that */
308 if (Profile
->LockedBuffer
) {
310 /* Release our lock, dereference and return */
311 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
312 ObDereferenceObject(Profile
);
313 return STATUS_PROFILING_NOT_STOPPED
;
316 /* Allocate a Kernel Profile Object. */
317 KeProfile
= ExAllocatePoolWithTag(NonPagedPool
,
319 TAG('P', 'r', 'o', 'f'));
321 /* Allocate the Mdl Structure */
322 Profile
->Mdl
= MmCreateMdl(NULL
, Profile
->Buffer
, Profile
->BufferSize
);
324 /* Probe and Lock for Write Access */
325 MmProbeAndLockPages(Profile
->Mdl
, PreviousMode
, IoWriteAccess
);
328 TempLockedBuffer
= MmMapLockedPages(Profile
->Mdl
, KernelMode
);
330 /* Initialize the Kernel Profile Object */
331 Profile
->KeProfile
= KeProfile
;
332 KeInitializeProfile(KeProfile
,
333 (PKPROCESS
)Profile
->Process
,
337 Profile
->ProfileSource
,
340 /* Start the Profiling */
341 KeStartProfile(KeProfile
, TempLockedBuffer
);
343 /* Now it's safe to save this */
344 Profile
->LockedBuffer
= TempLockedBuffer
;
346 /* Release mutex, dereference and return */
347 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
348 ObDereferenceObject(Profile
);
349 return STATUS_SUCCESS
;
354 NtStopProfile(IN HANDLE ProfileHandle
)
357 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
363 Status
= ObReferenceObjectByHandle(ProfileHandle
,
369 if (!NT_SUCCESS(Status
)) return(Status
);
372 KeWaitForSingleObject(&ExpProfileMutex
,
378 /* Make sure the Profile Object is really Started */
379 if (!Profile
->LockedBuffer
) {
381 Status
= STATUS_PROFILING_NOT_STARTED
;
385 /* Stop the Profile */
386 KeStopProfile(Profile
->KeProfile
);
388 /* Unlock the Buffer */
389 MmUnmapLockedPages(Profile
->LockedBuffer
, Profile
->Mdl
);
390 MmUnlockPages(Profile
->Mdl
);
391 ExFreePool(Profile
->KeProfile
);
393 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
394 Profile
->LockedBuffer
= NULL
;
397 /* Release Mutex, Dereference and Return */
398 KeReleaseMutex(&ExpProfileMutex
, FALSE
);
399 ObDereferenceObject(Profile
);
405 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
408 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
409 ULONG ReturnInterval
;
410 NTSTATUS Status
= STATUS_SUCCESS
;
414 /* Check the Parameters for validity */
415 if(PreviousMode
!= KernelMode
) {
419 ProbeForWrite(Interval
,
425 Status
= _SEH_GetExceptionCode();
428 if(!NT_SUCCESS(Status
)) return Status
;
431 /* Query the Interval */
432 ReturnInterval
= KeQueryIntervalProfile(ProfileSource
);
434 /* Return the data */
437 *Interval
= ReturnInterval
;
441 Status
= _SEH_GetExceptionCode();
446 return STATUS_SUCCESS
;
451 NtSetIntervalProfile(IN ULONG Interval
,
452 IN KPROFILE_SOURCE Source
)
454 /* Let the Kernel do the job */
455 KeSetIntervalProfile(Interval
, Source
);
457 /* Nothing can go wrong */
458 return STATUS_SUCCESS
;