Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenprofile.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS Kernel 00004 * FILE: ntoskrnl/ex/profile.c 00005 * PURPOSE: Support for Executive Profile Objects 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 * Thomas Weidenmueller 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #if defined (ALLOC_PRAGMA) 00017 #pragma alloc_text(INIT, ExpInitializeProfileImplementation) 00018 #endif 00019 00020 #define TAG_PROFILE 'forP' 00021 00022 /* GLOBALS *******************************************************************/ 00023 00024 POBJECT_TYPE ExProfileObjectType = NULL; 00025 KMUTEX ExpProfileMutex; 00026 00027 GENERIC_MAPPING ExpProfileMapping = 00028 { 00029 STANDARD_RIGHTS_READ | PROFILE_CONTROL, 00030 STANDARD_RIGHTS_WRITE | PROFILE_CONTROL, 00031 STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL, 00032 PROFILE_ALL_ACCESS 00033 }; 00034 00035 /* FUNCTIONS *****************************************************************/ 00036 00037 VOID 00038 NTAPI 00039 ExpDeleteProfile(PVOID ObjectBody) 00040 { 00041 PEPROFILE Profile; 00042 ULONG State; 00043 00044 /* Typecast the Object */ 00045 Profile = (PEPROFILE)ObjectBody; 00046 00047 /* Check if there if the Profile was started */ 00048 if (Profile->LockedBufferAddress) 00049 { 00050 /* Stop the Profile */ 00051 State = KeStopProfile(Profile->ProfileObject); 00052 ASSERT(State != FALSE); 00053 00054 /* Unmap the Locked Buffer */ 00055 MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl); 00056 MmUnlockPages(Profile->Mdl); 00057 IoFreeMdl(Profile->Mdl); 00058 } 00059 00060 /* Check if a Process is associated and reference it */ 00061 if (Profile->Process) ObDereferenceObject(Profile->Process); 00062 } 00063 00064 VOID 00065 INIT_FUNCTION 00066 NTAPI 00067 ExpInitializeProfileImplementation(VOID) 00068 { 00069 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 00070 UNICODE_STRING Name; 00071 DPRINT("Creating Profile Object Type\n"); 00072 00073 /* Initialize the Mutex to lock the States */ 00074 KeInitializeMutex(&ExpProfileMutex, 64); 00075 00076 /* Create the Event Pair Object Type */ 00077 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 00078 RtlInitUnicodeString(&Name, L"Profile"); 00079 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 00080 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KPROFILE); 00081 ObjectTypeInitializer.GenericMapping = ExpProfileMapping; 00082 ObjectTypeInitializer.PoolType = NonPagedPool; 00083 ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile; 00084 ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS; 00085 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExProfileObjectType); 00086 } 00087 00088 NTSTATUS 00089 NTAPI 00090 NtCreateProfile(OUT PHANDLE ProfileHandle, 00091 IN HANDLE Process OPTIONAL, 00092 IN PVOID RangeBase, 00093 IN ULONG RangeSize, 00094 IN ULONG BucketSize, 00095 IN PVOID Buffer, 00096 IN ULONG BufferSize, 00097 IN KPROFILE_SOURCE ProfileSource, 00098 IN KAFFINITY Affinity) 00099 { 00100 HANDLE hProfile; 00101 PEPROFILE Profile; 00102 PEPROCESS pProcess; 00103 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00104 OBJECT_ATTRIBUTES ObjectAttributes; 00105 NTSTATUS Status; 00106 ULONG Log2 = 0; 00107 ULONG_PTR Segment = 0; 00108 PAGED_CODE(); 00109 00110 /* Easy way out */ 00111 if(!BufferSize) return STATUS_INVALID_PARAMETER_7; 00112 00113 /* Check if this is a low-memory profile */ 00114 if ((!BucketSize) && (RangeBase < (PVOID)(0x10000))) 00115 { 00116 /* Validate size */ 00117 if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7; 00118 00119 /* This will become a segmented profile object */ 00120 Segment = (ULONG_PTR)RangeBase; 00121 RangeBase = 0; 00122 00123 /* Recalculate the bucket size */ 00124 BucketSize = RangeSize / (BufferSize / sizeof(ULONG)); 00125 00126 /* Convert it to log2 */ 00127 BucketSize--; 00128 while (BucketSize >>= 1) Log2++; 00129 BucketSize += Log2 + 1; 00130 } 00131 00132 /* Validate bucket size */ 00133 if ((BucketSize > 31) || (BucketSize < 2)) 00134 { 00135 DPRINT1("Bucket size invalid\n"); 00136 return STATUS_INVALID_PARAMETER; 00137 } 00138 00139 /* Make sure that the buckets can map the range */ 00140 if ((RangeSize >> (BucketSize - 2)) > BufferSize) 00141 { 00142 DPRINT1("Bucket size too small\n"); 00143 return STATUS_BUFFER_TOO_SMALL; 00144 } 00145 00146 /* Make sure that the range isn't too gigantic */ 00147 if (((ULONG_PTR)RangeBase + RangeSize) < RangeSize) 00148 { 00149 DPRINT1("Range too big\n"); 00150 return STATUS_BUFFER_OVERFLOW; 00151 } 00152 00153 /* Check if we were called from user-mode */ 00154 if(PreviousMode != KernelMode) 00155 { 00156 /* Entry SEH */ 00157 _SEH2_TRY 00158 { 00159 /* Make sure that the handle pointer is valid */ 00160 ProbeForWriteHandle(ProfileHandle); 00161 00162 /* Check if the buffer is valid */ 00163 ProbeForWrite(Buffer, 00164 BufferSize, 00165 sizeof(ULONG)); 00166 } 00167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00168 { 00169 /* Return the exception code */ 00170 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00171 } 00172 _SEH2_END; 00173 } 00174 00175 /* Check if a process was specified */ 00176 if (Process) 00177 { 00178 /* Reference it */ 00179 Status = ObReferenceObjectByHandle(Process, 00180 PROCESS_QUERY_INFORMATION, 00181 PsProcessType, 00182 PreviousMode, 00183 (PVOID*)&pProcess, 00184 NULL); 00185 if (!NT_SUCCESS(Status)) return(Status); 00186 } 00187 else 00188 { 00189 /* Segmented profile objects cannot be used system-wide */ 00190 if (Segment) return STATUS_INVALID_PARAMETER; 00191 00192 /* No process was specified, which means a System-Wide Profile */ 00193 pProcess = NULL; 00194 00195 /* For this, we need to check the Privilege */ 00196 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode)) 00197 { 00198 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n"); 00199 return STATUS_PRIVILEGE_NOT_HELD; 00200 } 00201 } 00202 00203 /* Create the object */ 00204 InitializeObjectAttributes(&ObjectAttributes, 00205 NULL, 00206 0, 00207 NULL, 00208 NULL); 00209 Status = ObCreateObject(KernelMode, 00210 ExProfileObjectType, 00211 &ObjectAttributes, 00212 PreviousMode, 00213 NULL, 00214 sizeof(EPROFILE), 00215 0, 00216 sizeof(EPROFILE) + sizeof(KPROFILE), 00217 (PVOID*)&Profile); 00218 if (!NT_SUCCESS(Status)) 00219 { 00220 /* Dereference the process object if it was specified */ 00221 if (pProcess) ObDereferenceObject(pProcess); 00222 00223 /* Return Status */ 00224 return Status; 00225 } 00226 00227 /* Initialize it */ 00228 Profile->RangeBase = RangeBase; 00229 Profile->RangeSize = RangeSize; 00230 Profile->Buffer = Buffer; 00231 Profile->BufferSize = BufferSize; 00232 Profile->BucketSize = BucketSize; 00233 Profile->LockedBufferAddress = NULL; 00234 Profile->Segment = Segment; 00235 Profile->ProfileSource = ProfileSource; 00236 Profile->Affinity = Affinity; 00237 Profile->Process = pProcess; 00238 00239 /* Insert into the Object Tree */ 00240 Status = ObInsertObject ((PVOID)Profile, 00241 NULL, 00242 PROFILE_CONTROL, 00243 0, 00244 NULL, 00245 &hProfile); 00246 ObDereferenceObject(Profile); 00247 00248 /* Check for Success */ 00249 if (!NT_SUCCESS(Status)) 00250 { 00251 /* Dereference Process on failure */ 00252 if (pProcess) ObDereferenceObject(pProcess); 00253 return Status; 00254 } 00255 00256 /* Enter SEH */ 00257 _SEH2_TRY 00258 { 00259 /* Copy the created handle back to the caller*/ 00260 *ProfileHandle = hProfile; 00261 } 00262 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00263 { 00264 Status = _SEH2_GetExceptionCode(); 00265 } 00266 _SEH2_END; 00267 00268 /* Return Status */ 00269 return Status; 00270 } 00271 00272 NTSTATUS 00273 NTAPI 00274 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, 00275 OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL) 00276 { 00277 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00278 LARGE_INTEGER PerfFrequency; 00279 NTSTATUS Status = STATUS_SUCCESS; 00280 00281 /* Check if we were called from user-mode */ 00282 if (PreviousMode != KernelMode) 00283 { 00284 /* Entry SEH Block */ 00285 _SEH2_TRY 00286 { 00287 /* Make sure the counter and frequency are valid */ 00288 ProbeForWriteLargeInteger(PerformanceCounter); 00289 if (PerformanceFrequency) 00290 { 00291 ProbeForWriteLargeInteger(PerformanceFrequency); 00292 } 00293 } 00294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00295 { 00296 /* Return the exception code */ 00297 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00298 } 00299 _SEH2_END; 00300 } 00301 00302 /* Enter a new SEH Block */ 00303 _SEH2_TRY 00304 { 00305 /* Query the Kernel */ 00306 *PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency); 00307 00308 /* Return Frequency if requested */ 00309 if (PerformanceFrequency) *PerformanceFrequency = PerfFrequency; 00310 } 00311 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00312 { 00313 /* Get the exception code */ 00314 Status = _SEH2_GetExceptionCode(); 00315 } 00316 _SEH2_END; 00317 00318 /* Return status to caller */ 00319 return Status; 00320 } 00321 00322 NTSTATUS 00323 NTAPI 00324 NtStartProfile(IN HANDLE ProfileHandle) 00325 { 00326 PEPROFILE Profile; 00327 PKPROFILE ProfileObject; 00328 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00329 PVOID TempLockedBufferAddress; 00330 NTSTATUS Status; 00331 PAGED_CODE(); 00332 00333 /* Get the Object */ 00334 Status = ObReferenceObjectByHandle(ProfileHandle, 00335 PROFILE_CONTROL, 00336 ExProfileObjectType, 00337 PreviousMode, 00338 (PVOID*)&Profile, 00339 NULL); 00340 if (!NT_SUCCESS(Status)) return(Status); 00341 00342 /* To avoid a Race, wait on the Mutex */ 00343 KeWaitForSingleObject(&ExpProfileMutex, 00344 Executive, 00345 KernelMode, 00346 FALSE, 00347 NULL); 00348 00349 /* The Profile can still be enabled though, so handle that */ 00350 if (Profile->LockedBufferAddress) 00351 { 00352 /* Release our lock, dereference and return */ 00353 KeReleaseMutex(&ExpProfileMutex, FALSE); 00354 ObDereferenceObject(Profile); 00355 return STATUS_PROFILING_NOT_STOPPED; 00356 } 00357 00358 /* Allocate a Kernel Profile Object. */ 00359 ProfileObject = ExAllocatePoolWithTag(NonPagedPool, 00360 sizeof(EPROFILE), 00361 TAG_PROFILE); 00362 if (!ProfileObject) 00363 { 00364 /* Out of memory, fail */ 00365 KeReleaseMutex(&ExpProfileMutex, FALSE); 00366 ObDereferenceObject(Profile); 00367 return STATUS_INSUFFICIENT_RESOURCES; 00368 } 00369 00370 /* Allocate the Mdl Structure */ 00371 Profile->Mdl = IoAllocateMdl(Profile->Buffer, Profile->BufferSize, FALSE, FALSE, NULL); 00372 00373 /* Protect this in SEH as we might raise an exception */ 00374 _SEH2_TRY 00375 { 00376 /* Probe and Lock for Write Access */ 00377 MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess); 00378 } 00379 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00380 { 00381 /* Release our lock, free the buffer, dereference and return */ 00382 KeReleaseMutex(&ExpProfileMutex, FALSE); 00383 ObDereferenceObject(Profile); 00384 ExFreePoolWithTag(ProfileObject, TAG_PROFILE); 00385 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00386 } 00387 _SEH2_END; 00388 00389 /* Map the pages */ 00390 TempLockedBufferAddress = MmMapLockedPages(Profile->Mdl, KernelMode); 00391 00392 /* Initialize the Kernel Profile Object */ 00393 Profile->ProfileObject = ProfileObject; 00394 KeInitializeProfile(ProfileObject, 00395 (PKPROCESS)Profile->Process, 00396 Profile->RangeBase, 00397 Profile->RangeSize, 00398 Profile->BucketSize, 00399 Profile->ProfileSource, 00400 Profile->Affinity); 00401 00402 /* Start the Profiling */ 00403 KeStartProfile(ProfileObject, TempLockedBufferAddress); 00404 00405 /* Now it's safe to save this */ 00406 Profile->LockedBufferAddress = TempLockedBufferAddress; 00407 00408 /* Release mutex, dereference and return */ 00409 KeReleaseMutex(&ExpProfileMutex, FALSE); 00410 ObDereferenceObject(Profile); 00411 return STATUS_SUCCESS; 00412 } 00413 00414 NTSTATUS 00415 NTAPI 00416 NtStopProfile(IN HANDLE ProfileHandle) 00417 { 00418 PEPROFILE Profile; 00419 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00420 NTSTATUS Status; 00421 PAGED_CODE(); 00422 00423 /* Get the Object */ 00424 Status = ObReferenceObjectByHandle(ProfileHandle, 00425 PROFILE_CONTROL, 00426 ExProfileObjectType, 00427 PreviousMode, 00428 (PVOID*)&Profile, 00429 NULL); 00430 if (!NT_SUCCESS(Status)) return(Status); 00431 00432 /* Get the Mutex */ 00433 KeWaitForSingleObject(&ExpProfileMutex, 00434 Executive, 00435 KernelMode, 00436 FALSE, 00437 NULL); 00438 00439 /* Make sure the Profile Object is really Started */ 00440 if (!Profile->LockedBufferAddress) 00441 { 00442 Status = STATUS_PROFILING_NOT_STARTED; 00443 goto Exit; 00444 } 00445 00446 /* Stop the Profile */ 00447 KeStopProfile(Profile->ProfileObject); 00448 00449 /* Unlock the Buffer */ 00450 MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl); 00451 MmUnlockPages(Profile->Mdl); 00452 ExFreePoolWithTag(Profile->ProfileObject, TAG_PROFILE); 00453 00454 /* Clear the Locked Buffer pointer, meaning the Object is Stopped */ 00455 Profile->LockedBufferAddress = NULL; 00456 00457 Exit: 00458 /* Release Mutex, Dereference and Return */ 00459 KeReleaseMutex(&ExpProfileMutex, FALSE); 00460 ObDereferenceObject(Profile); 00461 return Status; 00462 } 00463 00464 NTSTATUS 00465 NTAPI 00466 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource, 00467 OUT PULONG Interval) 00468 { 00469 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00470 ULONG ReturnInterval; 00471 NTSTATUS Status = STATUS_SUCCESS; 00472 PAGED_CODE(); 00473 00474 /* Check if we were called from user-mode */ 00475 if (PreviousMode != KernelMode) 00476 { 00477 /* Enter SEH Block */ 00478 _SEH2_TRY 00479 { 00480 /* Validate interval */ 00481 ProbeForWriteUlong(Interval); 00482 } 00483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00484 { 00485 /* Return the exception code */ 00486 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00487 } 00488 _SEH2_END; 00489 } 00490 00491 /* Query the Interval */ 00492 ReturnInterval = (ULONG)KeQueryIntervalProfile(ProfileSource); 00493 00494 /* Enter SEH block for return */ 00495 _SEH2_TRY 00496 { 00497 /* Return the data */ 00498 *Interval = ReturnInterval; 00499 } 00500 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00501 { 00502 /* Get the exception code */ 00503 Status = _SEH2_GetExceptionCode(); 00504 } 00505 _SEH2_END; 00506 00507 /* Return Success */ 00508 return Status; 00509 } 00510 00511 NTSTATUS 00512 NTAPI 00513 NtSetIntervalProfile(IN ULONG Interval, 00514 IN KPROFILE_SOURCE Source) 00515 { 00516 /* Let the Kernel do the job */ 00517 KeSetIntervalProfile(Interval, Source); 00518 00519 /* Nothing can go wrong */ 00520 return STATUS_SUCCESS; 00521 } Generated on Thu May 24 2012 04:24:25 for ReactOS by
1.7.6.1
|