Move some profile stuff to NDK and fix some bugs in the executive implementation, as well as support segmented profile objects Modified: trunk/reactos/include/ndk/extypes.h Modified: trunk/reactos/ntoskrnl/ex/profile.c Modified: trunk/reactos/ntoskrnl/include/internal/ke.h _____
Modified: trunk/reactos/include/ndk/extypes.h --- trunk/reactos/include/ndk/extypes.h 2005-12-29 15:14:50 UTC (rev 20425) +++ trunk/reactos/include/ndk/extypes.h 2005-12-29 17:55:31 UTC (rev 20426) @@ -55,46 +55,58 @@
// // Invalid Handle Value Constant // -#define INVALID_HANDLE_VALUE (HANDLE)-1 +#define INVALID_HANDLE_VALUE (HANDLE)-1
#endif
// // Increments // -#define MUTANT_INCREMENT 1 +#define MUTANT_INCREMENT 1
// // Callback Object Access Mask // -#define CALLBACK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x0001) -#define CALLBACK_EXECUTE (STANDARD_RIGHTS_EXECUTE|SYNCHRONIZE|0x0001) -#define CALLBACK_WRITE (STANDARD_RIGHTS_WRITE|SYNCHRONIZE|0x0001) -#define CALLBACK_READ (STANDARD_RIGHTS_READ|SYNCHRONIZE|0x0001) +#define CALLBACK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x0001) +#define CALLBACK_EXECUTE (STANDARD_RIGHTS_EXECUTE|SYNCHRONIZE|0x0001) +#define CALLBACK_WRITE (STANDARD_RIGHTS_WRITE|SYNCHRONIZE|0x0001) +#define CALLBACK_READ (STANDARD_RIGHTS_READ|SYNCHRONIZE|0x0001)
// // Event Object Access Masks // #ifdef NTOS_MODE_USER -#define EVENT_QUERY_STATE 0x0001 +#define EVENT_QUERY_STATE 0x0001
// // Semaphore Object Acess Masks // -#define SEMAPHORE_QUERY_STATE 0x0001 +#define SEMAPHORE_QUERY_STATE 0x0001 #endif
// // Event Pair Access Masks // -#define EVENT_PAIR_ALL_ACCESS 0x1F0000L +#define EVENT_PAIR_ALL_ACCESS 0x1F0000L
// +// Profile Object Access Masks +// +#define PROFILE_CONTROL 0x0001 +#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL) + +// // Maximum Parameters for NtRaiseHardError // -#define MAXIMUM_HARDERROR_PARAMETERS 4 +#define MAXIMUM_HARDERROR_PARAMETERS 4
// +// Pushlock Wait Block Flags +// +#define EX_PUSH_LOCK_FLAGS_EXCLUSIVE 1 +#define EX_PUSH_LOCK_FLAGS_WAIT 2 + +// // Shutdown types for NtShutdownSystem // typedef enum _SHUTDOWN_ACTION @@ -271,8 +283,21 @@ } EX_FAST_REF, *PEX_FAST_REF;
// -// Executive Fast Reference Wait Block +// Executive Cache-Aware Rundown Reference Descriptor // +typedef struct _EX_RUNDOWN_REF_CACHE_AWARE +{ + union + { + ULONG_PTR Count; + PVOID Ptr; + }; + PVOID PoolToFree; +} EX_RUNDOWN_REF_CACHE_AWARE, *PEX_RUNDOWN_REF_CACHE_AWARE; + +// +// Executive Rundown Wait Block +// typedef struct _EX_RUNDOWN_WAIT_BLOCK { ULONG_PTR Count; @@ -280,6 +305,32 @@ } EX_RUNDOWN_WAIT_BLOCK, *PEX_RUNDOWN_WAIT_BLOCK;
// +// Executive Pushlock Wait Block +// +#ifndef __GNUC__ // WARNING! PUSHLOCKS WILL NOT WORK IN GCC FOR NOW!!! +__declspec(align(16)) +#endif +typedef struct _EX_PUSH_LOCK_WAIT_BLOCK +{ + union + { + KGATE WakeGate; + KEVENT WakeEvent; + }; + struct _EX_PUSH_LOCK_WAIT_BLOCK *Next; + struct _EX_PUSH_LOCK_WAIT_BLOCK *Last; + struct _EX_PUSH_LOCK_WAIT_BLOCK *Previous; + LONG ShareCount; + LONG Flags; +#if DBG + BOOL Signaled; + EX_PUSH_LOCK NewValue; + EX_PUSH_LOCK OldValue; + PEX_PUSH_LOCK PushLock; +#endif +} EX_PUSH_LOCK_WAIT_BLOCK, *PEX_PUSH_LOCK_WAIT_BLOCK; + +// // Callback Object // typedef struct _CALLBACK_OBJECT @@ -291,6 +342,25 @@ } CALLBACK_OBJECT , *PCALLBACK_OBJECT;
// +// Profile OBject +// +typedef struct _EPROFILE +{ + PEPROCESS Process; + PVOID ImageBase; + SIZE_T ImageSize; + PVOID Buffer; + ULONG BufferSize; + ULONG BucketSize; + PKPROFILE KeProfile; + PVOID LockedBuffer; + PMDL Mdl; + ULONG Segment; + KPROFILE_SOURCE ProfileSource; + KAFFINITY Affinity; +} EPROFILE, *PEPROFILE; + +// // Handle Table Structures // typedef struct _HANDLE_TABLE_ENTRY_INFO _____
Modified: trunk/reactos/ntoskrnl/ex/profile.c --- trunk/reactos/ntoskrnl/ex/profile.c 2005-12-29 15:14:50 UTC (rev 20425) +++ trunk/reactos/ntoskrnl/ex/profile.c 2005-12-29 17:55:31 UTC (rev 20426) @@ -1,65 +1,55 @@
/* * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel + * PROJECT: ReactOS Kernel * FILE: ntoskrnl/ex/profile.c * PURPOSE: Support for Executive Profile Objects - * - * PROGRAMMERS: Alex Ionescu + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * Thomas Weidenmueller */
/* INCLUDES *****************************************************************/
+#include <ntoskrnl.h> #define NDEBUG -#include <ntoskrnl.h> #include <internal/debug.h>
#if defined (ALLOC_PRAGMA) #pragma alloc_text(INIT, ExpInitializeProfileImplementation) #endif
-/* FIXME: NDK This structure is a *GUESS* -- Alex */ -typedef struct _EPROFILE { - PEPROCESS Process; - PVOID ImageBase; - ULONG ImageSize; - ULONG BucketSize; - PVOID Buffer; - ULONG BufferSize; - PKPROFILE KeProfile; - KPROFILE_SOURCE ProfileSource; - KAFFINITY Affinity; - PMDL Mdl; - PVOID LockedBuffer; -} EPROFILE, *PEPROFILE; +#define TAG_PROFILE TAG('P', 'r', 'o', 'f')
/* GLOBALS *******************************************************************/
POBJECT_TYPE ExProfileObjectType = NULL; +KMUTEX ExpProfileMutex;
-static KMUTEX ExpProfileMutex; - -#define PROFILE_CONTROL 1 - -static GENERIC_MAPPING ExpProfileMapping = { +GENERIC_MAPPING ExpProfileMapping = +{ STANDARD_RIGHTS_READ | PROFILE_CONTROL, STANDARD_RIGHTS_WRITE | PROFILE_CONTROL, STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL, - STANDARD_RIGHTS_ALL}; + PROFILE_ALL_ACCESS +};
+/* FUNCTIONS *****************************************************************/ + VOID -STDCALL +NTAPI ExpDeleteProfile(PVOID ObjectBody) { PEPROFILE Profile; + ULONG State;
/* Typecast the Object */ Profile = (PEPROFILE)ObjectBody;
/* Check if there if the Profile was started */ - if (Profile->LockedBuffer) { - + if (Profile->LockedBuffer) + { /* Stop the Profile */ - KeStopProfile(Profile->KeProfile); + State = KeStopProfile(Profile->KeProfile); + ASSERT(State != FALSE);
/* Unmap the Locked Buffer */ MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl); @@ -67,28 +57,22 @@ ExFreePool(Profile->Mdl); }
- /* Check if a Process is associated */ - if (Profile->Process != NULL) { - - /* Dereference it */ - ObDereferenceObject(Profile->Process); - Profile->Process = NULL; - } + /* Check if a Process is associated and reference it */ + if (Profile->Process) ObDereferenceObject(Profile->Process); }
VOID INIT_FUNCTION -STDCALL +NTAPI ExpInitializeProfileImplementation(VOID) { OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - + DPRINT("Creating Profile Object Type\n"); + /* Initialize the Mutex to lock the States */ - KeInitializeMutex(&ExpProfileMutex, 0x40); + KeInitializeMutex(&ExpProfileMutex, 64);
- DPRINT("Creating Profile Object Type\n"); - /* Create the Event Pair Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Profile"); @@ -97,12 +81,12 @@ ObjectTypeInitializer.GenericMapping = ExpProfileMapping; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile; - ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL; + ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS; ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType); }
NTSTATUS -STDCALL +NTAPI NtCreateProfile(OUT PHANDLE ProfileHandle, IN HANDLE Process OPTIONAL, IN PVOID ImageBase, @@ -119,33 +103,79 @@ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status = STATUS_SUCCESS; - + ULONG Segment = 0, Log2 = 0; PAGED_CODE();
/* Easy way out */ - if(BufferSize == 0) return STATUS_INVALID_PARAMETER_7; + if(!BufferSize) return STATUS_INVALID_PARAMETER_7;
- /* Check the Parameters for validity */ - if(PreviousMode != KernelMode) { + /* Check if this is a low-memory profile */ + if ((!BucketSize) && (ImageBase < (PVOID)(0x10000))) + { + /* Validate size */ + if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7;
- _SEH_TRY { + /* This will become a segmented profile object */ + Segment = (ULONG)ImageBase; + ImageBase = 0;
+ /* Recalculate the bucket size */ + BucketSize = ImageSize / (BufferSize / sizeof(ULONG)); + + /* Convert it to log2 */ + BucketSize--; + while (BucketSize >>= 1) Log2++; + BucketSize += Log2 + 1; + } + + /* Validate bucket size */ + if ((BucketSize > 31) || (BucketSize < 2)) + { + DPRINT1("Bucket size invalid\n"); + return STATUS_INVALID_PARAMETER; + } + + /* Make sure that the buckets can map the range */ + if ((ImageSize >> (BucketSize - 2)) > BufferSize) + { + DPRINT1("Bucket size too small\n"); + return STATUS_BUFFER_TOO_SMALL; + } + + /* Make sure that the range isn't too gigantic */ + if (((ULONG_PTR)ImageBase + ImageSize) < ImageSize) + { + DPRINT1("Range too big\n"); + return STATUS_BUFFER_OVERFLOW; + } + + /* Check if we were called from user-mode */ + if(PreviousMode != KernelMode) + { + /* Entry SEH */ + _SEH_TRY + { + /* Make sure that the handle pointer is valid */ ProbeForWriteHandle(ProfileHandle);
+ /* Check if the buffer is valid */ ProbeForWrite(Buffer, BufferSize, sizeof(ULONG)); - } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) { - + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { Status = _SEH_GetExceptionCode(); - } _SEH_END; + } + _SEH_END;
+ /* Bail out if we failed */ if(!NT_SUCCESS(Status)) return Status; }
/* Check if a process was specified */ - if (Process) { - + if (Process) + { /* Reference it */ Status = ObReferenceObjectByHandle(Process, PROCESS_QUERY_INFORMATION, @@ -154,15 +184,18 @@ (PVOID*)&pProcess, NULL); if (!NT_SUCCESS(Status)) return(Status); + } + else + { + /* Segmented profile objects cannot be used system-wide */ + if (Segment) return STATUS_INVALID_PARAMETER;
- } else { - /* No process was specified, which means a System-Wide Profile */ pProcess = NULL;
/* For this, we need to check the Privilege */ - if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode)) { - + if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode)) + { DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n"); return STATUS_PRIVILEGE_NOT_HELD; } @@ -181,7 +214,7 @@ NULL, sizeof(EPROFILE), 0, - 0, + sizeof(EPROFILE) + sizeof(KPROFILE), (PVOID*)&Profile); if (!NT_SUCCESS(Status)) return(Status);
@@ -192,6 +225,8 @@ Profile->BufferSize = BufferSize; Profile->BucketSize = BucketSize; Profile->LockedBuffer = NULL; + Profile->Segment = Segment; + Profile->ProfileSource = ProfileSource; Profile->Affinity = Affinity; Profile->Process = pProcess;
@@ -205,29 +240,31 @@ ObDereferenceObject(Profile);
/* Check for Success */ - if (!NT_SUCCESS(Status)) { - + if (!NT_SUCCESS(Status)) + { /* Dereference Process on failure */ if (pProcess) ObDereferenceObject(pProcess); return Status; }
- /* Copy the created handle back to the caller*/ - _SEH_TRY { - + /* Enter SEH */ + _SEH_TRY + { + /* Copy the created handle back to the caller*/ *ProfileHandle = hProfile; - - } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) { - + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { Status = _SEH_GetExceptionCode(); - } _SEH_END; + } + _SEH_END;
/* Return Status */ return Status; }
NTSTATUS -STDCALL +NTAPI NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL) { @@ -235,43 +272,50 @@ LARGE_INTEGER PerfFrequency; NTSTATUS Status = STATUS_SUCCESS;
- /* Check the Parameters for validity */ - if(PreviousMode != KernelMode) { - - _SEH_TRY { - + /* Check if we were called from user-mode */ + if(PreviousMode != KernelMode) + { + /* Entry SEH Block */ + _SEH_TRY + { + /* Make sure the counter and frequency are valid */ ProbeForWriteLargeInteger(PerformanceCounter); - - ProbeForWriteLargeInteger(PerformanceFrequency); - } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) { - + if (PerformanceFrequency) + { + ProbeForWriteLargeInteger(PerformanceFrequency); + } + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { Status = _SEH_GetExceptionCode(); - } _SEH_END; + } + _SEH_END;
+ /* If the pointers are invalid, bail out */ if(!NT_SUCCESS(Status)) return Status; }
- _SEH_TRY { - + /* Enter a new SEH Block */ + _SEH_TRY + { /* Query the Kernel */ *PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
/* Return Frequency if requested */ - if(PerformanceFrequency) { - - *PerformanceFrequency = PerfFrequency; - } - } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) { - + if(PerformanceFrequency) *PerformanceFrequency = PerfFrequency; + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { Status = _SEH_GetExceptionCode(); + } + _SEH_END;
- } _SEH_END; - + /* Return status to caller */ return Status; }
NTSTATUS -STDCALL +NTAPI NtStartProfile(IN HANDLE ProfileHandle) { PEPROFILE Profile; @@ -279,7 +323,6 @@ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PVOID TempLockedBuffer; NTSTATUS Status; - PAGED_CODE();
/* Get the Object */ @@ -299,8 +342,8 @@ NULL);
/* The Profile can still be enabled though, so handle that */ - if (Profile->LockedBuffer) { - + if (Profile->LockedBuffer) + { /* Release our lock, dereference and return */ KeReleaseMutex(&ExpProfileMutex, FALSE); ObDereferenceObject(Profile); @@ -310,7 +353,7 @@ /* Allocate a Kernel Profile Object. */ KeProfile = ExAllocatePoolWithTag(NonPagedPool, sizeof(EPROFILE), - TAG('P', 'r', 'o', 'f')); + TAG_PROFILE);
/* Allocate the Mdl Structure */ Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer, Profile->BufferSize); @@ -344,13 +387,12 @@ }
NTSTATUS -STDCALL +NTAPI NtStopProfile(IN HANDLE ProfileHandle) { PEPROFILE Profile; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; - PAGED_CODE();
/* Get the Object */ @@ -370,8 +412,8 @@ NULL);
/* Make sure the Profile Object is really Started */ - if (!Profile->LockedBuffer) { - + if (!Profile->LockedBuffer) + { Status = STATUS_PROFILING_NOT_STARTED; goto Exit; } @@ -395,51 +437,55 @@ }
NTSTATUS -STDCALL -NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource, +NTAPI +NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource, OUT PULONG Interval) { KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); ULONG ReturnInterval; NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE();
- /* Check the Parameters for validity */ - if(PreviousMode != KernelMode) { - - _SEH_TRY { - + /* Check if we were called from user-mode */ + if(PreviousMode != KernelMode) + { + /* Enter SEH Block */ + _SEH_TRY + { + /* Validate interval */ ProbeForWriteUlong(Interval); - - } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) { - + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { Status = _SEH_GetExceptionCode(); - } _SEH_END; + } + _SEH_END;
+ /* If pointer was invalid, bail out */ if(!NT_SUCCESS(Status)) return Status; }
/* Query the Interval */ ReturnInterval = KeQueryIntervalProfile(ProfileSource);
- /* Return the data */ - _SEH_TRY { - + /* Enter SEH block for return */ + _SEH_TRY + { + /* Return the data */ *Interval = ReturnInterval; - - } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) { - + } + _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) + { Status = _SEH_GetExceptionCode(); + } + _SEH_END;
- } _SEH_END; - /* Return Success */ return STATUS_SUCCESS; }
NTSTATUS -STDCALL +NTAPI NtSetIntervalProfile(IN ULONG Interval, IN KPROFILE_SOURCE Source) { _____
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h --- trunk/reactos/ntoskrnl/include/internal/ke.h 2005-12-29 15:14:50 UTC (rev 20425) +++ trunk/reactos/ntoskrnl/include/internal/ke.h 2005-12-29 17:55:31 UTC (rev 20426) @@ -188,7 +188,7 @@
PVOID Buffer );
-VOID +BOOLEAN STDCALL KeStopProfile(struct _KPROFILE* Profile);