- some ULONG / SIZE_T fixes
[reactos.git] / reactos / ntoskrnl / ps / thread.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/thread.c
5 * PURPOSE: Process Manager: Thread Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* GLOBALS ******************************************************************/
17
18 extern BOOLEAN CcPfEnablePrefetcher;
19 extern ULONG MmReadClusterSize;
20 POBJECT_TYPE PsThreadType = NULL;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 VOID
25 NTAPI
26 PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
27 IN PVOID StartContext)
28 {
29 PETHREAD Thread;
30 PTEB Teb;
31 BOOLEAN DeadThread = FALSE;
32 KIRQL OldIrql;
33 PAGED_CODE();
34 PSTRACE(PS_THREAD_DEBUG,
35 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
36
37 /* Go to Passive Level */
38 KeLowerIrql(PASSIVE_LEVEL);
39 Thread = PsGetCurrentThread();
40
41 /* Check if the thread is dead */
42 if (Thread->DeadThread)
43 {
44 /* Remember that we're dead */
45 DeadThread = TRUE;
46 }
47 else
48 {
49 /* Get the Locale ID and save Preferred Proc */
50 Teb = NtCurrentTeb();
51 Teb->CurrentLocale = MmGetSessionLocaleId();
52 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
53 }
54
55 /* Check if this is a dead thread, or if we're hiding */
56 if (!(Thread->DeadThread) && !(Thread->HideFromDebugger))
57 {
58 /* We're not, so notify the debugger */
59 DbgkCreateThread(StartContext);
60 }
61
62 /* Make sure we're not already dead */
63 if (!DeadThread)
64 {
65 /* Check if the Prefetcher is enabled */
66 if (CcPfEnablePrefetcher)
67 {
68 /* FIXME: Prepare to prefetch this process */
69 }
70
71 /* Raise to APC */
72 KeRaiseIrql(APC_LEVEL, &OldIrql);
73
74 /* Queue the User APC */
75 KiInitializeUserApc(NULL,
76 (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
77 sizeof(KTRAP_FRAME) -
78 SIZEOF_FX_SAVE_AREA),
79 PspSystemDllEntryPoint,
80 NULL,
81 PspSystemDllBase,
82 NULL);
83
84 /* Lower it back to passive */
85 KeLowerIrql(PASSIVE_LEVEL);
86 }
87 else
88 {
89 /* We're dead, kill us now */
90 PspTerminateThreadByPointer(Thread,
91 STATUS_THREAD_IS_TERMINATING,
92 TRUE);
93 }
94
95 /* Do we have a cookie set yet? */
96 if (!SharedUserData->Cookie)
97 {
98 LARGE_INTEGER SystemTime;
99 ULONG NewCookie;
100 PKPRCB Prcb;
101
102 /* Generate a new cookie */
103 KeQuerySystemTime(&SystemTime);
104 Prcb = KeGetCurrentPrcb();
105 NewCookie = Prcb->MmPageFaultCount ^ Prcb->InterruptTime ^
106 SystemTime.u.LowPart ^ SystemTime.u.HighPart ^
107 (ULONG_PTR)&SystemTime;
108
109 /* Set the new cookie*/
110 InterlockedCompareExchange((LONG*)&SharedUserData->Cookie,
111 NewCookie,
112 0);
113 }
114 }
115
116 _SEH_FILTER(PspUnhandledExceptionInSystemThread)
117 {
118 PEXCEPTION_POINTERS ExceptionPointers= _SEH_GetExceptionPointers();
119
120 /* Print debugging information */
121 DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
122 ExceptionPointers);
123 DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
124 ExceptionPointers->ExceptionRecord->ExceptionCode,
125 ExceptionPointers->ExceptionRecord->ExceptionAddress,
126 ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
127 ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
128 ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
129 ExceptionPointers->ExceptionRecord->ExceptionInformation[3]);
130
131 /* Bugcheck the system */
132 KeBugCheckEx(0x7E,
133 ExceptionPointers->ExceptionRecord->ExceptionCode,
134 (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
135 (ULONG_PTR)ExceptionPointers->ExceptionRecord,
136 (ULONG_PTR)ExceptionPointers->ContextRecord);
137 return 0;
138 }
139
140 VOID
141 NTAPI
142 PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
143 IN PVOID StartContext)
144 {
145 PETHREAD Thread;
146 PSTRACE(PS_THREAD_DEBUG,
147 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
148
149 /* Unlock the dispatcher Database */
150 KeLowerIrql(PASSIVE_LEVEL);
151 Thread = PsGetCurrentThread();
152
153 /* Make sure the thread isn't gone */
154 _SEH_TRY
155 {
156 if (!(Thread->Terminated) && !(Thread->DeadThread))
157 {
158 /* Call it the Start Routine */
159 StartRoutine(StartContext);
160 }
161 }
162 _SEH_EXCEPT(PspUnhandledExceptionInSystemThread)
163 {
164 /* Bugcheck if we got here */
165 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
166 }
167 _SEH_END;
168
169 /* Exit the thread */
170 PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);
171 }
172
173 NTSTATUS
174 NTAPI
175 PspCreateThread(OUT PHANDLE ThreadHandle,
176 IN ACCESS_MASK DesiredAccess,
177 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
178 IN HANDLE ProcessHandle,
179 IN PEPROCESS TargetProcess,
180 OUT PCLIENT_ID ClientId,
181 IN PCONTEXT ThreadContext,
182 IN PINITIAL_TEB InitialTeb,
183 IN BOOLEAN CreateSuspended,
184 IN PKSTART_ROUTINE StartRoutine OPTIONAL,
185 IN PVOID StartContext OPTIONAL)
186 {
187 HANDLE hThread;
188 PEPROCESS Process;
189 PETHREAD Thread;
190 PTEB TebBase = NULL;
191 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
192 NTSTATUS Status, AccessStatus;
193 HANDLE_TABLE_ENTRY CidEntry;
194 ACCESS_STATE LocalAccessState;
195 PACCESS_STATE AccessState = &LocalAccessState;
196 AUX_ACCESS_DATA AuxData;
197 BOOLEAN Result, SdAllocated;
198 PSECURITY_DESCRIPTOR SecurityDescriptor;
199 SECURITY_SUBJECT_CONTEXT SubjectContext;
200 PAGED_CODE();
201 PSTRACE(PS_THREAD_DEBUG,
202 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
203 ThreadContext, TargetProcess, ProcessHandle);
204
205 /* If we were called from PsCreateSystemThread, then we're kernel mode */
206 if (StartRoutine) PreviousMode = KernelMode;
207
208 /* Reference the Process by handle or pointer, depending on what we got */
209 if (ProcessHandle)
210 {
211 /* Normal thread or System Thread */
212 Status = ObReferenceObjectByHandle(ProcessHandle,
213 PROCESS_CREATE_THREAD,
214 PsProcessType,
215 PreviousMode,
216 (PVOID*)&Process,
217 NULL);
218 PSREFTRACE(Process);
219 }
220 else
221 {
222 /* System thread inside System Process, or Normal Thread with a bug */
223 if (StartRoutine)
224 {
225 /* Reference the Process by Pointer */
226 ObReferenceObject(TargetProcess);
227 Process = TargetProcess;
228 Status = STATUS_SUCCESS;
229 }
230 else
231 {
232 /* Fake ObReference returning this */
233 Status = STATUS_INVALID_HANDLE;
234 }
235 }
236
237 /* Check for success */
238 if (!NT_SUCCESS(Status)) return Status;
239
240 /* Also make sure that User-Mode isn't trying to create a system thread */
241 if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
242 {
243 /* Fail */
244 ObDereferenceObject(Process);
245 return STATUS_INVALID_HANDLE;
246 }
247
248 /* Create Thread Object */
249 Status = ObCreateObject(PreviousMode,
250 PsThreadType,
251 ObjectAttributes,
252 PreviousMode,
253 NULL,
254 sizeof(ETHREAD),
255 0,
256 0,
257 (PVOID*)&Thread);
258 if (!NT_SUCCESS(Status))
259 {
260 /* We failed; dereference the process and exit */
261 ObDereferenceObject(Process);
262 return Status;
263 }
264
265 /* Zero the Object entirely */
266 RtlZeroMemory(Thread, sizeof(ETHREAD));
267
268 /* Initialize rundown protection */
269 ExInitializeRundownProtection(&Thread->RundownProtect);
270
271 /* Initialize exit code */
272 Thread->ExitStatus = STATUS_PENDING;
273
274 /* Set the Process CID */
275 Thread->ThreadsProcess = Process;
276 Thread->Cid.UniqueProcess = Process->UniqueProcessId;
277
278 /* Create Cid Handle */
279 CidEntry.Object = Thread;
280 CidEntry.GrantedAccess = 0;
281 Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
282 if (!Thread->Cid.UniqueThread)
283 {
284 /* We couldn't create the CID, dereference the thread and fail */
285 ObDereferenceObject(Thread);
286 return STATUS_INSUFFICIENT_RESOURCES;
287 }
288
289 /* Save the read cluster size */
290 Thread->ReadClusterSize = MmReadClusterSize;
291
292 /* Initialize the LPC Reply Semaphore */
293 KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
294
295 /* Initialize the list heads and locks */
296 InitializeListHead(&Thread->LpcReplyChain);
297 InitializeListHead(&Thread->IrpList);
298 InitializeListHead(&Thread->PostBlockList);
299 InitializeListHead(&Thread->ActiveTimerListHead);
300 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
301
302 /* Acquire rundown protection */
303 if (!ExAcquireRundownProtection (&Process->RundownProtect))
304 {
305 /* Fail */
306 ObDereferenceObject(Thread);
307 return STATUS_PROCESS_IS_TERMINATING;
308 }
309
310 /* Now let the kernel initialize the context */
311 if (ThreadContext)
312 {
313 /* User-mode Thread, create Teb */
314 TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
315 if (!TebBase)
316 {
317 /* Failed to create the TEB. Release rundown and dereference */
318 ExReleaseRundownProtection(&Process->RundownProtect);
319 ObDereferenceObject(Thread);
320 return STATUS_INSUFFICIENT_RESOURCES;
321 }
322
323 /* Set the Start Addresses */
324 #if defined(_M_IX86)
325 Thread->StartAddress = (PVOID)ThreadContext->Eip;
326 Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
327 #elif defined(_M_PPC)
328 Thread->StartAddress = (PVOID)ThreadContext->Dr0;
329 Thread->Win32StartAddress = (PVOID)ThreadContext->Gpr3;
330 #elif defined(_M_MIPS)
331 Thread->StartAddress = (PVOID)ThreadContext->Psr;
332 Thread->Win32StartAddress = (PVOID)ThreadContext->IntA0;
333 #elif defined(_M_ARM)
334 Thread->StartAddress = (PVOID)ThreadContext->Pc;
335 Thread->Win32StartAddress = (PVOID)ThreadContext->R0;
336 #elif defined(_M_AMD64)
337 Thread->StartAddress = (PVOID)ThreadContext->Rip;
338 Thread->Win32StartAddress = (PVOID)ThreadContext->Rax;
339 #else
340 #error Unknown architecture
341 #endif
342
343 /* Let the kernel intialize the Thread */
344 Status = KeInitThread(&Thread->Tcb,
345 NULL,
346 PspUserThreadStartup,
347 NULL,
348 Thread->StartAddress,
349 ThreadContext,
350 TebBase,
351 &Process->Pcb);
352 }
353 else
354 {
355 /* System Thread */
356 Thread->StartAddress = StartRoutine;
357 PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
358
359 /* Let the kernel intialize the Thread */
360 Status = KeInitThread(&Thread->Tcb,
361 NULL,
362 PspSystemThreadStartup,
363 StartRoutine,
364 StartContext,
365 NULL,
366 NULL,
367 &Process->Pcb);
368 }
369
370 /* Check if we failed */
371 if (!NT_SUCCESS(Status))
372 {
373 /* Delete the TEB if we had done */
374 if (TebBase) MmDeleteTeb(Process, TebBase);
375
376 /* Release rundown and dereference */
377 ExReleaseRundownProtection(&Process->RundownProtect);
378 ObDereferenceObject(Thread);
379 return Status;
380 }
381
382 /* Lock the process */
383 KeEnterCriticalRegion();
384 ExAcquirePushLockExclusive(&Process->ProcessLock);
385
386 /* Make sure the proces didn't just die on us */
387 if (Process->ProcessDelete) goto Quickie;
388
389 /* Check if the thread was ours, terminated and it was user mode */
390 if ((Thread->Terminated) &&
391 (ThreadContext) &&
392 (Thread->ThreadsProcess == Process))
393 {
394 /* Cleanup, we don't want to start it up and context switch */
395 goto Quickie;
396 }
397
398 /*
399 * Insert the Thread into the Process's Thread List
400 * Note, this is the ETHREAD Thread List. It is removed in
401 * ps/kill.c!PspExitThread.
402 */
403 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
404 Process->ActiveThreads++;
405
406 /* Start the thread */
407 KeStartThread(&Thread->Tcb);
408
409 /* Release the process lock */
410 ExReleasePushLockExclusive(&Process->ProcessLock);
411 KeLeaveCriticalRegion();
412
413 /* Release rundown */
414 ExReleaseRundownProtection(&Process->RundownProtect);
415
416 /* Notify WMI */
417 //WmiTraceProcess(Process, TRUE);
418 //WmiTraceThread(Thread, InitialTeb, TRUE);
419
420 /* Notify Thread Creation */
421 PspRunCreateThreadNotifyRoutines(Thread, TRUE);
422
423 /* Reference ourselves as a keep-alive */
424 ObReferenceObjectEx(Thread, 2);
425
426 /* Suspend the Thread if we have to */
427 if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
428
429 /* Check if we were already terminated */
430 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
431
432 /* Create an access state */
433 Status = SeCreateAccessStateEx(NULL,
434 ThreadContext ?
435 PsGetCurrentProcess() : Process,
436 &LocalAccessState,
437 &AuxData,
438 DesiredAccess,
439 &PsThreadType->TypeInfo.GenericMapping);
440 if (!NT_SUCCESS(Status))
441 {
442 /* Access state failed, thread is dead */
443 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
444
445 /* If we were suspended, wake it up */
446 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
447
448 /* Dispatch thread */
449 KeReadyThread(&Thread->Tcb);
450
451 /* Dereference completely to kill it */
452 ObDereferenceObjectEx(Thread, 2);
453 return Status;
454 }
455
456 /* Insert the Thread into the Object Manager */
457 Status = ObInsertObject(Thread,
458 AccessState,
459 DesiredAccess,
460 0,
461 NULL,
462 &hThread);
463
464 /* Delete the access state if we had one */
465 if (AccessState) SeDeleteAccessState(AccessState);
466
467 /* Check for success */
468 if (NT_SUCCESS(Status))
469 {
470 /* Wrap in SEH to protect against bad user-mode pointers */
471 _SEH_TRY
472 {
473 /* Return Cid and Handle */
474 if (ClientId) *ClientId = Thread->Cid;
475 *ThreadHandle = hThread;
476 }
477 _SEH_HANDLE
478 {
479 /* Get the exception code */
480 Status = _SEH_GetExceptionCode();
481
482 /* Thread insertion failed, thread is dead */
483 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
484
485 /* If we were suspended, wake it up */
486 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
487
488 /* Dispatch thread */
489 KeReadyThread(&Thread->Tcb);
490
491 /* Dereference it, leaving only the keep-alive */
492 ObDereferenceObject(Thread);
493
494 /* Close its handle, killing it */
495 ObCloseHandle(ThreadHandle, PreviousMode);
496 }
497 _SEH_END;
498 if (!NT_SUCCESS(Status)) return Status;
499 }
500 else
501 {
502 /* Thread insertion failed, thread is dead */
503 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
504
505 /* If we were suspended, wake it up */
506 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
507 }
508
509 /* Get the create time */
510 KeQuerySystemTime(&Thread->CreateTime);
511 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
512
513 /* Make sure the thread isn't dead */
514 if (!Thread->DeadThread)
515 {
516 /* Get the thread's SD */
517 Status = ObGetObjectSecurity(Thread,
518 &SecurityDescriptor,
519 &SdAllocated);
520 if (!NT_SUCCESS(Status))
521 {
522 /* Thread insertion failed, thread is dead */
523 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
524
525 /* If we were suspended, wake it up */
526 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
527
528 /* Dispatch thread */
529 KeReadyThread(&Thread->Tcb);
530
531 /* Dereference it, leaving only the keep-alive */
532 ObDereferenceObject(Thread);
533
534 /* Close its handle, killing it */
535 ObCloseHandle(ThreadHandle, PreviousMode);
536 return Status;
537 }
538
539 /* Create the subject context */
540 SubjectContext.ProcessAuditId = Process;
541 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
542 SubjectContext.ClientToken = NULL;
543
544 /* Do the access check */
545 Result = SeAccessCheck(SecurityDescriptor,
546 &SubjectContext,
547 FALSE,
548 MAXIMUM_ALLOWED,
549 0,
550 NULL,
551 &PsThreadType->TypeInfo.GenericMapping,
552 PreviousMode,
553 &Thread->GrantedAccess,
554 &AccessStatus);
555
556 /* Dereference the token and let go the SD */
557 ObFastDereferenceObject(&Process->Token,
558 SubjectContext.PrimaryToken);
559 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
560
561 /* Remove access if it failed */
562 if (!Result) Process->GrantedAccess = 0;
563
564 /* Set least some minimum access */
565 Thread->GrantedAccess |= (THREAD_TERMINATE |
566 THREAD_SET_INFORMATION |
567 THREAD_QUERY_INFORMATION);
568 }
569 else
570 {
571 /* Set the thread access mask to maximum */
572 Thread->GrantedAccess = THREAD_ALL_ACCESS;
573 }
574
575 /* Dispatch thread */
576 KeReadyThread(&Thread->Tcb);
577
578 /* Dereference it, leaving only the keep-alive */
579 ObDereferenceObject(Thread);
580
581 /* Return */
582 return Status;
583
584 /* Most annoying failure case ever, where we undo almost all manually */
585 Quickie:
586 /* When we get here, the process is locked, unlock it */
587 ExReleasePushLockExclusive(&Process->ProcessLock);
588 KeLeaveCriticalRegion();
589
590 /* Uninitailize it */
591 KeUninitThread(&Thread->Tcb);
592
593 /* If we had a TEB, delete it */
594 if (TebBase) MmDeleteTeb(Process, TebBase);
595
596 /* Release rundown protection, which we also hold */
597 ExReleaseRundownProtection(&Process->RundownProtect);
598
599 /* Dereference the thread and return failure */
600 ObDereferenceObject(Thread);
601 return STATUS_PROCESS_IS_TERMINATING;
602 }
603
604 /* PUBLIC FUNCTIONS **********************************************************/
605
606 /*
607 * @implemented
608 */
609 NTSTATUS
610 NTAPI
611 PsCreateSystemThread(OUT PHANDLE ThreadHandle,
612 IN ACCESS_MASK DesiredAccess,
613 IN POBJECT_ATTRIBUTES ObjectAttributes,
614 IN HANDLE ProcessHandle,
615 IN PCLIENT_ID ClientId,
616 IN PKSTART_ROUTINE StartRoutine,
617 IN PVOID StartContext)
618 {
619 PEPROCESS TargetProcess = NULL;
620 HANDLE Handle = ProcessHandle;
621 PAGED_CODE();
622 PSTRACE(PS_THREAD_DEBUG,
623 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n",
624 ProcessHandle, StartRoutine, StartContext);
625
626 /* Check if we have a handle. If not, use the System Process */
627 if (!ProcessHandle)
628 {
629 Handle = NULL;
630 TargetProcess = PsInitialSystemProcess;
631 }
632
633 /* Call the shared function */
634 return PspCreateThread(ThreadHandle,
635 DesiredAccess,
636 ObjectAttributes,
637 Handle,
638 TargetProcess,
639 ClientId,
640 NULL,
641 NULL,
642 FALSE,
643 StartRoutine,
644 StartContext);
645 }
646
647 /*
648 * @implemented
649 */
650 NTSTATUS
651 NTAPI
652 PsLookupThreadByThreadId(IN HANDLE ThreadId,
653 OUT PETHREAD *Thread)
654 {
655 PHANDLE_TABLE_ENTRY CidEntry;
656 PETHREAD FoundThread;
657 NTSTATUS Status = STATUS_INVALID_PARAMETER;
658 PAGED_CODE();
659 PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId);
660 KeEnterCriticalRegion();
661
662 /* Get the CID Handle Entry */
663 CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
664 if (CidEntry)
665 {
666 /* Get the Process */
667 FoundThread = CidEntry->Object;
668
669 /* Make sure it's really a process */
670 if (FoundThread->Tcb.DispatcherHeader.Type == ThreadObject)
671 {
672 /* Safe Reference and return it */
673 if (ObReferenceObjectSafe(FoundThread))
674 {
675 *Thread = FoundThread;
676 Status = STATUS_SUCCESS;
677 }
678 }
679
680 /* Unlock the Entry */
681 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
682 }
683
684 /* Return to caller */
685 KeLeaveCriticalRegion();
686 return Status;
687 }
688
689 /*
690 * @implemented
691 */
692 HANDLE
693 NTAPI
694 PsGetCurrentThreadId(VOID)
695 {
696 return PsGetCurrentThread()->Cid.UniqueThread;
697 }
698
699 /*
700 * @implemented
701 */
702 ULONG
703 NTAPI
704 PsGetThreadFreezeCount(IN PETHREAD Thread)
705 {
706 return Thread->Tcb.FreezeCount;
707 }
708
709 /*
710 * @implemented
711 */
712 BOOLEAN
713 NTAPI
714 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread)
715 {
716 return Thread->HardErrorsAreDisabled ? TRUE : FALSE;
717 }
718
719 /*
720 * @implemented
721 */
722 HANDLE
723 NTAPI
724 PsGetThreadId(IN PETHREAD Thread)
725 {
726 return Thread->Cid.UniqueThread;
727 }
728
729 /*
730 * @implemented
731 */
732 PEPROCESS
733 NTAPI
734 PsGetThreadProcess(IN PETHREAD Thread)
735 {
736 return Thread->ThreadsProcess;
737 }
738
739 /*
740 * @implemented
741 */
742 HANDLE
743 NTAPI
744 PsGetThreadProcessId(IN PETHREAD Thread)
745 {
746 return Thread->Cid.UniqueProcess;
747 }
748
749 /*
750 * @implemented
751 */
752 HANDLE
753 NTAPI
754 PsGetThreadSessionId(IN PETHREAD Thread)
755 {
756 return (HANDLE)Thread->ThreadsProcess->Session;
757 }
758
759 /*
760 * @implemented
761 */
762 PTEB
763 NTAPI
764 PsGetThreadTeb(IN PETHREAD Thread)
765 {
766 return Thread->Tcb.Teb;
767 }
768
769 /*
770 * @implemented
771 */
772 PVOID
773 NTAPI
774 PsGetThreadWin32Thread(IN PETHREAD Thread)
775 {
776 return Thread->Tcb.Win32Thread;
777 }
778
779 /*
780 * @implemented
781 */
782 KPROCESSOR_MODE
783 NTAPI
784 PsGetCurrentThreadPreviousMode(VOID)
785 {
786 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
787 }
788
789 /*
790 * @implemented
791 */
792 PVOID
793 NTAPI
794 PsGetCurrentThreadStackBase(VOID)
795 {
796 return PsGetCurrentThread()->Tcb.StackBase;
797 }
798
799 /*
800 * @implemented
801 */
802 PVOID
803 NTAPI
804 PsGetCurrentThreadStackLimit(VOID)
805 {
806 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
807 }
808
809 /*
810 * @implemented
811 */
812 BOOLEAN
813 NTAPI
814 PsIsThreadTerminating(IN PETHREAD Thread)
815 {
816 return Thread->Terminated ? TRUE : FALSE;
817 }
818
819 /*
820 * @implemented
821 */
822 BOOLEAN
823 NTAPI
824 PsIsSystemThread(IN PETHREAD Thread)
825 {
826 return Thread->SystemThread ? TRUE: FALSE;
827 }
828
829 /*
830 * @implemented
831 */
832 BOOLEAN
833 NTAPI
834 PsIsThreadImpersonating(IN PETHREAD Thread)
835 {
836 return Thread->ActiveImpersonationInfo ? TRUE : FALSE;
837 }
838
839 /*
840 * @implemented
841 */
842 VOID
843 NTAPI
844 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread,
845 IN BOOLEAN HardErrorsAreDisabled)
846 {
847 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
848 }
849
850 /*
851 * @implemented
852 */
853 struct _W32THREAD*
854 NTAPI
855 PsGetCurrentThreadWin32Thread(VOID)
856 {
857 return PsGetCurrentThread()->Tcb.Win32Thread;
858 }
859
860 /*
861 * @implemented
862 */
863 VOID
864 NTAPI
865 PsSetThreadWin32Thread(IN PETHREAD Thread,
866 IN PVOID Win32Thread)
867 {
868 Thread->Tcb.Win32Thread = Win32Thread;
869 }
870
871 NTSTATUS
872 NTAPI
873 NtCreateThread(OUT PHANDLE ThreadHandle,
874 IN ACCESS_MASK DesiredAccess,
875 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
876 IN HANDLE ProcessHandle,
877 OUT PCLIENT_ID ClientId,
878 IN PCONTEXT ThreadContext,
879 IN PINITIAL_TEB InitialTeb,
880 IN BOOLEAN CreateSuspended)
881 {
882 INITIAL_TEB SafeInitialTeb;
883 NTSTATUS Status = STATUS_SUCCESS;
884 PAGED_CODE();
885 PSTRACE(PS_THREAD_DEBUG,
886 "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
887
888 /* Check if this was from user-mode */
889 if (KeGetPreviousMode() != KernelMode)
890 {
891 /* Make sure that we got a context */
892 if (!ThreadContext) return STATUS_INVALID_PARAMETER;
893
894 /* Protect checks */
895 _SEH_TRY
896 {
897 /* Make sure the handle pointer we got is valid */
898 ProbeForWriteHandle(ThreadHandle);
899
900 /* Check if the caller wants a client id */
901 if(ClientId)
902 {
903 /* Make sure we can write to it */
904 ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
905 }
906
907 /* Make sure that the entire context is readable */
908 ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
909
910 /* Check the Initial TEB */
911 ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
912 SafeInitialTeb = *InitialTeb;
913 }
914 _SEH_HANDLE
915 {
916 Status = _SEH_GetExceptionCode();
917 }
918 _SEH_END;
919 if (!NT_SUCCESS(Status)) return Status;
920 }
921 else
922 {
923 /* Use the Initial TEB as is */
924 SafeInitialTeb = *InitialTeb;
925 }
926
927 /* Call the shared function */
928 return PspCreateThread(ThreadHandle,
929 DesiredAccess,
930 ObjectAttributes,
931 ProcessHandle,
932 NULL,
933 ClientId,
934 ThreadContext,
935 &SafeInitialTeb,
936 CreateSuspended,
937 NULL,
938 NULL);
939 }
940
941 /*
942 * @implemented
943 */
944 NTSTATUS
945 NTAPI
946 NtOpenThread(OUT PHANDLE ThreadHandle,
947 IN ACCESS_MASK DesiredAccess,
948 IN POBJECT_ATTRIBUTES ObjectAttributes,
949 IN PCLIENT_ID ClientId OPTIONAL)
950 {
951 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
952 CLIENT_ID SafeClientId;
953 ULONG Attributes = 0;
954 HANDLE hThread = NULL;
955 NTSTATUS Status = STATUS_SUCCESS;
956 PETHREAD Thread;
957 BOOLEAN HasObjectName = FALSE;
958 ACCESS_STATE AccessState;
959 AUX_ACCESS_DATA AuxData;
960 PAGED_CODE();
961 PSTRACE(PS_THREAD_DEBUG,
962 "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
963
964 /* Check if we were called from user mode */
965 if (PreviousMode != KernelMode)
966 {
967 /* Enter SEH for probing */
968 _SEH_TRY
969 {
970 /* Probe the thread handle */
971 ProbeForWriteHandle(ThreadHandle);
972
973 /* Check for a CID structure */
974 if (ClientId)
975 {
976 /* Probe and capture it */
977 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
978 SafeClientId = *ClientId;
979 ClientId = &SafeClientId;
980 }
981
982 /*
983 * Just probe the object attributes structure, don't capture it
984 * completely. This is done later if necessary
985 */
986 ProbeForRead(ObjectAttributes,
987 sizeof(OBJECT_ATTRIBUTES),
988 sizeof(ULONG));
989 HasObjectName = (ObjectAttributes->ObjectName != NULL);
990 Attributes = ObjectAttributes->Attributes;
991 }
992 _SEH_HANDLE
993 {
994 /* Get the exception code */
995 Status = _SEH_GetExceptionCode();
996 }
997 _SEH_END;
998 if (!NT_SUCCESS(Status)) return Status;
999 }
1000 else
1001 {
1002 /* Otherwise just get the data directly */
1003 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1004 Attributes = ObjectAttributes->Attributes;
1005 }
1006
1007 /* Can't pass both, fail */
1008 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1009
1010 /* Create an access state */
1011 Status = SeCreateAccessState(&AccessState,
1012 &AuxData,
1013 DesiredAccess,
1014 &PsProcessType->TypeInfo.GenericMapping);
1015 if (!NT_SUCCESS(Status)) return Status;
1016
1017 /* Check if this is a debugger */
1018 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1019 {
1020 /* Did he want full access? */
1021 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1022 {
1023 /* Give it to him */
1024 AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS;
1025 }
1026 else
1027 {
1028 /* Otherwise just give every other access he could want */
1029 AccessState.PreviouslyGrantedAccess |=
1030 AccessState.RemainingDesiredAccess;
1031 }
1032
1033 /* The caller desires nothing else now */
1034 AccessState.RemainingDesiredAccess = 0;
1035 }
1036
1037 /* Open by name if one was given */
1038 if (HasObjectName)
1039 {
1040 /* Open it */
1041 Status = ObOpenObjectByName(ObjectAttributes,
1042 PsThreadType,
1043 PreviousMode,
1044 &AccessState,
1045 0,
1046 NULL,
1047 &hThread);
1048
1049 /* Get rid of the access state */
1050 SeDeleteAccessState(&AccessState);
1051 }
1052 else if (ClientId)
1053 {
1054 /* Open by Thread ID */
1055 if (ClientId->UniqueProcess)
1056 {
1057 /* Get the Process */
1058 Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread);
1059 }
1060 else
1061 {
1062 /* Get the Process */
1063 Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread);
1064 }
1065
1066 /* Check if we didn't find anything */
1067 if (!NT_SUCCESS(Status))
1068 {
1069 /* Get rid of the access state and return */
1070 SeDeleteAccessState(&AccessState);
1071 return Status;
1072 }
1073
1074 /* Open the Thread Object */
1075 Status = ObOpenObjectByPointer(Thread,
1076 Attributes,
1077 &AccessState,
1078 0,
1079 PsThreadType,
1080 PreviousMode,
1081 &hThread);
1082
1083 /* Delete the access state and dereference the thread */
1084 SeDeleteAccessState(&AccessState);
1085 ObDereferenceObject(Thread);
1086 }
1087 else
1088 {
1089 /* Neither an object name nor a client id was passed */
1090 return STATUS_INVALID_PARAMETER_MIX;
1091 }
1092
1093 /* Check for success */
1094 if (NT_SUCCESS(Status))
1095 {
1096 /* Protect against bad user-mode pointers */
1097 _SEH_TRY
1098 {
1099 /* Write back the handle */
1100 *ThreadHandle = hThread;
1101 }
1102 _SEH_HANDLE
1103 {
1104 /* Get the exception code */
1105 Status = _SEH_GetExceptionCode();
1106 }
1107 _SEH_END;
1108 }
1109
1110 /* Return status */
1111 return Status;
1112 }
1113
1114 /* EOF */