Copy makefile
[reactos.git] / reactos / ntoskrnl / ex / profile.c
1 /* $Id:$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/nt/profile.c
6 * PURPOSE: Support for profiling
7 *
8 * PROGRAMMERS: No programmer listed.
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #include <internal/debug.h>
15
16 /* TYPES ********************************************************************/
17
18 /* GLOBALS *******************************************************************/
19
20 POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
21
22 static GENERIC_MAPPING ExpProfileMapping = {
23 STANDARD_RIGHTS_READ,
24 STANDARD_RIGHTS_WRITE,
25 STANDARD_RIGHTS_EXECUTE,
26 STANDARD_RIGHTS_ALL};
27
28 /*
29 * Size of the profile hash table.
30 */
31 #define PROFILE_HASH_TABLE_SIZE (32)
32
33 /*
34 * Table of lists of per-process profiling data structures hashed by PID.
35 */
36 LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
37
38 /*
39 * Head of the list of profile data structures for the kernel.
40 */
41 LIST_ENTRY SystemProfileList;
42
43 /*
44 * Lock that protects the profiling data structures.
45 */
46 KSPIN_LOCK ProfileListLock;
47
48 /*
49 * Timer interrupts happen before we have initialized the profiling
50 * data structures so just ignore them before that.
51 */
52 BOOLEAN ProfileInitDone = FALSE;
53
54 VOID INIT_FUNCTION
55 ExpInitializeProfileImplementation(VOID)
56 {
57 ULONG i;
58
59 InitializeListHead(&SystemProfileList);
60
61 for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
62 {
63 InitializeListHead(&ProcessProfileListHashTable[i]);
64 }
65
66 KeInitializeSpinLock(&ProfileListLock);
67 ProfileInitDone = TRUE;
68
69 ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
70
71 RtlpCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile", NonPagedPool);
72
73 ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
74 ExProfileObjectType->PeakObjects = 0;
75 ExProfileObjectType->PeakHandles = 0;
76 ExProfileObjectType->TotalObjects = 0;
77 ExProfileObjectType->TotalHandles = 0;
78 ExProfileObjectType->PagedPoolCharge = 0;
79 ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
80 ExProfileObjectType->Mapping = &ExpProfileMapping;
81 ExProfileObjectType->Dump = NULL;
82 ExProfileObjectType->Open = NULL;
83 ExProfileObjectType->Close = NULL;
84 ExProfileObjectType->Delete = KiDeleteProfile;
85 ExProfileObjectType->Parse = NULL;
86 ExProfileObjectType->Security = NULL;
87 ExProfileObjectType->QueryName = NULL;
88 ExProfileObjectType->OkayToClose = NULL;
89 ExProfileObjectType->Create = NULL;
90
91 ObpCreateTypeObject(ExProfileObjectType);
92 }
93
94 NTSTATUS STDCALL
95 NtCreateProfile(OUT PHANDLE ProfileHandle,
96 IN HANDLE Process OPTIONAL,
97 IN PVOID ImageBase,
98 IN ULONG ImageSize,
99 IN ULONG BucketSize,
100 IN PVOID Buffer,
101 IN ULONG BufferSize,
102 IN KPROFILE_SOURCE ProfileSource,
103 IN KAFFINITY Affinity)
104 {
105 HANDLE hProfile;
106 PKPROFILE Profile;
107 PEPROCESS pProcess;
108 KPROCESSOR_MODE PreviousMode;
109 OBJECT_ATTRIBUTES ObjectAttributes;
110 NTSTATUS Status = STATUS_SUCCESS;
111
112 PAGED_CODE();
113
114 PreviousMode = ExGetPreviousMode();
115
116 if(BufferSize == 0)
117 {
118 return STATUS_INVALID_PARAMETER_7;
119 }
120
121 if(PreviousMode != KernelMode)
122 {
123 _SEH_TRY
124 {
125 ProbeForWrite(ProfileHandle,
126 sizeof(HANDLE),
127 sizeof(ULONG));
128 ProbeForWrite(Buffer,
129 BufferSize,
130 sizeof(ULONG));
131 }
132 _SEH_HANDLE
133 {
134 Status = _SEH_GetExceptionCode();
135 }
136 _SEH_END;
137
138 if(!NT_SUCCESS(Status))
139 {
140 return Status;
141 }
142 }
143
144 /*
145 * Reference the associated process
146 */
147 if (Process != NULL)
148 {
149 Status = ObReferenceObjectByHandle(Process,
150 PROCESS_QUERY_INFORMATION,
151 PsProcessType,
152 PreviousMode,
153 (PVOID*)&pProcess,
154 NULL);
155 if (!NT_SUCCESS(Status))
156 {
157 return(Status);
158 }
159 }
160 else
161 {
162 pProcess = NULL;
163 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
164 PreviousMode))
165 {
166 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
167 return STATUS_PRIVILEGE_NOT_HELD;
168 }
169 }
170
171 /*
172 * Check the parameters
173 */
174 if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
175 (pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
176 {
177 return(STATUS_INVALID_PARAMETER_3);
178 }
179 if (((ImageSize >> BucketSize) * 4) >= BufferSize)
180 {
181 return(STATUS_BUFFER_TOO_SMALL);
182 }
183 if (ProfileSource != ProfileTime)
184 {
185 return(STATUS_INVALID_PARAMETER_9);
186 }
187 if (Affinity != 0)
188 {
189 return(STATUS_INVALID_PARAMETER_10);
190 }
191
192 /*
193 * Create the object
194 */
195 InitializeObjectAttributes(&ObjectAttributes,
196 NULL,
197 0,
198 NULL,
199 NULL);
200
201 Status = ObCreateObject(KernelMode,
202 ExProfileObjectType,
203 &ObjectAttributes,
204 PreviousMode,
205 NULL,
206 sizeof(KPROFILE),
207 0,
208 0,
209 (PVOID*)&Profile);
210 if (!NT_SUCCESS(Status))
211 {
212 return(Status);
213 }
214
215 /*
216 * Initialize it
217 */
218 Profile->Base = ImageBase;
219 Profile->Size = ImageSize;
220 Profile->BucketShift = BucketSize;
221 Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
222 if(Profile->BufferMdl == NULL) {
223 DPRINT("MmCreateMdl: Out of memory!");
224 ObDereferenceObject (Profile);
225 return(STATUS_NO_MEMORY);
226 }
227 MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
228 Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
229 Profile->BufferSize = BufferSize;
230 Profile->ProcessorMask = Affinity;
231 Profile->Started = FALSE;
232 Profile->Process = pProcess;
233
234 /*
235 * Insert the profile into the profile list data structures
236 */
237 KiInsertProfile(Profile);
238
239 Status = ObInsertObject ((PVOID)Profile,
240 NULL,
241 STANDARD_RIGHTS_ALL,
242 0,
243 NULL,
244 &hProfile);
245 if (!NT_SUCCESS(Status))
246 {
247 ObDereferenceObject (Profile);
248 return Status;
249 }
250
251 /*
252 * Copy the created handle back to the caller
253 */
254 _SEH_TRY
255 {
256 *ProfileHandle = hProfile;
257 }
258 _SEH_HANDLE
259 {
260 Status = _SEH_GetExceptionCode();
261 }
262 _SEH_END;
263
264 ObDereferenceObject(Profile);
265
266 return Status;
267 }
268
269 NTSTATUS STDCALL
270 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
271 OUT PULONG Interval)
272 {
273 KPROCESSOR_MODE PreviousMode;
274 NTSTATUS Status = STATUS_SUCCESS;
275
276 PAGED_CODE();
277
278 PreviousMode = ExGetPreviousMode();
279
280 if(PreviousMode != KernelMode)
281 {
282 _SEH_TRY
283 {
284 ProbeForWrite(Interval,
285 sizeof(ULONG),
286 sizeof(ULONG));
287 }
288 _SEH_HANDLE
289 {
290 Status = _SEH_GetExceptionCode();
291 }
292 _SEH_END;
293
294 if(!NT_SUCCESS(Status))
295 {
296 return Status;
297 }
298 }
299
300 if (ProfileSource == ProfileTime)
301 {
302 ULONG ReturnInterval;
303
304 /* FIXME: What units does this use, for now nanoseconds */
305 ReturnInterval = 100;
306
307 _SEH_TRY
308 {
309 *Interval = ReturnInterval;
310 }
311 _SEH_HANDLE
312 {
313 Status = _SEH_GetExceptionCode();
314 }
315 _SEH_END;
316
317 return Status;
318 }
319 return STATUS_INVALID_PARAMETER_2;
320 }
321
322 NTSTATUS STDCALL
323 NtSetIntervalProfile(IN ULONG Interval,
324 IN KPROFILE_SOURCE Source)
325 {
326 return(STATUS_NOT_IMPLEMENTED);
327 }
328
329 NTSTATUS STDCALL
330 NtStartProfile(IN HANDLE ProfileHandle)
331 {
332 PKPROFILE Profile;
333 KPROCESSOR_MODE PreviousMode;
334 NTSTATUS Status;
335
336 PAGED_CODE();
337
338 PreviousMode = ExGetPreviousMode();
339
340 Status = ObReferenceObjectByHandle(ProfileHandle,
341 STANDARD_RIGHTS_ALL,
342 ExProfileObjectType,
343 PreviousMode,
344 (PVOID*)&Profile,
345 NULL);
346 if (!NT_SUCCESS(Status))
347 {
348 return(Status);
349 }
350 Profile->Started = TRUE;
351 ObDereferenceObject(Profile);
352 return(STATUS_SUCCESS);
353 }
354
355 NTSTATUS STDCALL
356 NtStopProfile(IN HANDLE ProfileHandle)
357 {
358 PKPROFILE Profile;
359 KPROCESSOR_MODE PreviousMode;
360 NTSTATUS Status;
361
362 PAGED_CODE();
363
364 PreviousMode = ExGetPreviousMode();
365
366 Status = ObReferenceObjectByHandle(ProfileHandle,
367 STANDARD_RIGHTS_ALL,
368 ExProfileObjectType,
369 PreviousMode,
370 (PVOID*)&Profile,
371 NULL);
372 if (!NT_SUCCESS(Status))
373 {
374 return(Status);
375 }
376 Profile->Started = FALSE;
377 ObDereferenceObject(Profile);
378 return(STATUS_SUCCESS);
379 }
380
381