7082ca5572468b232532dd05c1bc0c244b941857
[reactos.git] / reactos / ntoskrnl / ps / create.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/create.c
6 * PURPOSE: Thread managment
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Phillip Susi
10 * Skywing
11 */
12
13 /*
14 * NOTE:
15 *
16 * All of the routines that manipulate the thread queue synchronize on
17 * a single spinlock
18 *
19 */
20
21 /* INCLUDES ****************************************************************/
22
23 #include <ntoskrnl.h>
24 #define NDEBUG
25 #include <internal/debug.h>
26
27 /* GLOBAL *******************************************************************/
28
29 #define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
30
31 static ULONG PiThreadNotifyRoutineCount = 0;
32 static PCREATE_THREAD_NOTIFY_ROUTINE
33 PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
34
35 /* FUNCTIONS ***************************************************************/
36
37 /*
38 * @implemented
39 */
40 NTSTATUS STDCALL
41 PsAssignImpersonationToken(PETHREAD Thread,
42 HANDLE TokenHandle)
43 {
44 PACCESS_TOKEN Token;
45 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
46 NTSTATUS Status;
47
48 if (TokenHandle != NULL)
49 {
50 Status = ObReferenceObjectByHandle(TokenHandle,
51 TOKEN_IMPERSONATE,
52 SepTokenObjectType,
53 KeGetPreviousMode(),
54 (PVOID*)&Token,
55 NULL);
56 if (!NT_SUCCESS(Status))
57 {
58 return(Status);
59 }
60 ImpersonationLevel = SeTokenImpersonationLevel(Token);
61 }
62 else
63 {
64 Token = NULL;
65 ImpersonationLevel = 0;
66 }
67
68 PsImpersonateClient(Thread,
69 Token,
70 FALSE,
71 FALSE,
72 ImpersonationLevel);
73 if (Token != NULL)
74 {
75 ObDereferenceObject(Token);
76 }
77
78 return(STATUS_SUCCESS);
79 }
80
81
82 /*
83 * @implemented
84 */
85 VOID STDCALL
86 PsRevertToSelf (VOID)
87 {
88 PsRevertThreadToSelf(PsGetCurrentThread());
89 }
90
91 /*
92 * @implemented
93 */
94 VOID
95 STDCALL
96 PsRevertThreadToSelf(
97 IN PETHREAD Thread
98 )
99 {
100 if (Thread->ActiveImpersonationInfo == TRUE)
101 {
102 ObDereferenceObject (Thread->ImpersonationInfo->Token);
103 Thread->ActiveImpersonationInfo = FALSE;
104 }
105 }
106
107 /*
108 * @implemented
109 */
110 VOID STDCALL
111 PsImpersonateClient (IN PETHREAD Thread,
112 IN PACCESS_TOKEN Token,
113 IN BOOLEAN CopyOnOpen,
114 IN BOOLEAN EffectiveOnly,
115 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
116 {
117 if (Token == NULL)
118 {
119 if (Thread->ActiveImpersonationInfo == TRUE)
120 {
121 Thread->ActiveImpersonationInfo = FALSE;
122 if (Thread->ImpersonationInfo->Token != NULL)
123 {
124 ObDereferenceObject (Thread->ImpersonationInfo->Token);
125 }
126 }
127 return;
128 }
129
130 if (Thread->ImpersonationInfo == NULL)
131 {
132 Thread->ImpersonationInfo = ExAllocatePool (NonPagedPool,
133 sizeof(PS_IMPERSONATION_INFORMATION));
134 }
135
136 Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel;
137 Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen;
138 Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly;
139 Thread->ImpersonationInfo->Token = Token;
140 ObReferenceObjectByPointer (Token,
141 0,
142 SepTokenObjectType,
143 KernelMode);
144 Thread->ActiveImpersonationInfo = TRUE;
145 }
146
147
148 PACCESS_TOKEN
149 PsReferenceEffectiveToken(PETHREAD Thread,
150 PTOKEN_TYPE TokenType,
151 PBOOLEAN EffectiveOnly,
152 PSECURITY_IMPERSONATION_LEVEL Level)
153 {
154 PEPROCESS Process;
155 PACCESS_TOKEN Token;
156
157 if (Thread->ActiveImpersonationInfo == FALSE)
158 {
159 Process = Thread->ThreadsProcess;
160 *TokenType = TokenPrimary;
161 *EffectiveOnly = FALSE;
162 Token = Process->Token;
163 }
164 else
165 {
166 Token = Thread->ImpersonationInfo->Token;
167 *TokenType = TokenImpersonation;
168 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
169 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
170 }
171 return(Token);
172 }
173
174
175 NTSTATUS STDCALL
176 NtImpersonateThread(IN HANDLE ThreadHandle,
177 IN HANDLE ThreadToImpersonateHandle,
178 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
179 {
180 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
181 SECURITY_CLIENT_CONTEXT ClientContext;
182 PETHREAD Thread;
183 PETHREAD ThreadToImpersonate;
184 KPROCESSOR_MODE PreviousMode;
185 NTSTATUS Status = STATUS_SUCCESS;
186
187 PAGED_CODE();
188
189 PreviousMode = ExGetPreviousMode();
190
191 if(PreviousMode != KernelMode)
192 {
193 _SEH_TRY
194 {
195 ProbeForRead(SecurityQualityOfService,
196 sizeof(SECURITY_QUALITY_OF_SERVICE),
197 sizeof(ULONG));
198 SafeServiceQoS = *SecurityQualityOfService;
199 SecurityQualityOfService = &SafeServiceQoS;
200 }
201 _SEH_HANDLE
202 {
203 Status = _SEH_GetExceptionCode();
204 }
205 _SEH_END;
206
207 if(!NT_SUCCESS(Status))
208 {
209 return Status;
210 }
211 }
212
213 Status = ObReferenceObjectByHandle(ThreadHandle,
214 THREAD_IMPERSONATE,
215 PsThreadType,
216 PreviousMode,
217 (PVOID*)&Thread,
218 NULL);
219 if(NT_SUCCESS(Status))
220 {
221 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
222 THREAD_DIRECT_IMPERSONATION,
223 PsThreadType,
224 PreviousMode,
225 (PVOID*)&ThreadToImpersonate,
226 NULL);
227 if(NT_SUCCESS(Status))
228 {
229 Status = SeCreateClientSecurity(ThreadToImpersonate,
230 SecurityQualityOfService,
231 0,
232 &ClientContext);
233 if(NT_SUCCESS(Status))
234 {
235 SeImpersonateClient(&ClientContext,
236 Thread);
237 if(ClientContext.ClientToken != NULL)
238 {
239 ObDereferenceObject (ClientContext.ClientToken);
240 }
241 }
242
243 ObDereferenceObject(ThreadToImpersonate);
244 }
245 ObDereferenceObject(Thread);
246 }
247
248 return Status;
249 }
250
251 /*
252 * @implemented
253 */
254 PACCESS_TOKEN STDCALL
255 PsReferenceImpersonationToken(IN PETHREAD Thread,
256 OUT PBOOLEAN CopyOnOpen,
257 OUT PBOOLEAN EffectiveOnly,
258 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
259 {
260 if (Thread->ActiveImpersonationInfo == FALSE)
261 {
262 return NULL;
263 }
264
265 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
266 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
267 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
268 ObReferenceObjectByPointer (Thread->ImpersonationInfo->Token,
269 TOKEN_ALL_ACCESS,
270 SepTokenObjectType,
271 KernelMode);
272
273 return Thread->ImpersonationInfo->Token;
274 }
275
276 #ifdef PsDereferencePrimaryToken
277 #undef PsDereferenceImpersonationToken
278 #endif
279 /*
280 * @implemented
281 */
282 VOID
283 STDCALL
284 PsDereferenceImpersonationToken(
285 IN PACCESS_TOKEN ImpersonationToken
286 )
287 {
288 if (ImpersonationToken) {
289 ObDereferenceObject(ImpersonationToken);
290 }
291 }
292
293 #ifdef PsDereferencePrimaryToken
294 #undef PsDereferencePrimaryToken
295 #endif
296 /*
297 * @implemented
298 */
299 VOID
300 STDCALL
301 PsDereferencePrimaryToken(
302 IN PACCESS_TOKEN PrimaryToken
303 )
304 {
305 ObDereferenceObject(PrimaryToken);
306 }
307
308 /*
309 * @implemented
310 */
311 BOOLEAN
312 STDCALL
313 PsDisableImpersonation(
314 IN PETHREAD Thread,
315 IN PSE_IMPERSONATION_STATE ImpersonationState
316 )
317 {
318 if (Thread->ActiveImpersonationInfo == FALSE)
319 {
320 ImpersonationState->Token = NULL;
321 ImpersonationState->CopyOnOpen = FALSE;
322 ImpersonationState->EffectiveOnly = FALSE;
323 ImpersonationState->Level = 0;
324 return TRUE;
325 }
326
327 /* FIXME */
328 /* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */
329
330 Thread->ActiveImpersonationInfo = FALSE;
331 ImpersonationState->Token = Thread->ImpersonationInfo->Token;
332 ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
333 ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
334 ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel;
335
336 /* FIXME */
337 /* ExfReleasePushLock(&Thread->ThreadLock); */
338
339 return TRUE;
340 }
341
342 /*
343 * @implemented
344 */
345 VOID
346 STDCALL
347 PsRestoreImpersonation(
348 IN PETHREAD Thread,
349 IN PSE_IMPERSONATION_STATE ImpersonationState
350 )
351 {
352 PsImpersonateClient(Thread, ImpersonationState->Token,
353 ImpersonationState->CopyOnOpen,
354 ImpersonationState->EffectiveOnly,
355 ImpersonationState->Level);
356 ObfDereferenceObject(ImpersonationState->Token);
357 }
358
359 VOID
360 PiBeforeBeginThread(CONTEXT c)
361 {
362 KeLowerIrql(PASSIVE_LEVEL);
363 }
364
365
366 VOID STDCALL
367 PiDeleteThread(PVOID ObjectBody)
368 {
369 PETHREAD Thread;
370 PEPROCESS Process;
371
372 Thread = (PETHREAD)ObjectBody;
373
374 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
375
376 Process = Thread->ThreadsProcess;
377 Thread->ThreadsProcess = NULL;
378
379 if(Thread->Cid.UniqueThread != NULL)
380 {
381 PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
382 }
383
384 if(Thread->Tcb.Win32Thread != NULL)
385 {
386 /* Free the W32THREAD structure if present */
387 ExFreePool (Thread->Tcb.Win32Thread);
388 }
389
390 KeReleaseThread(ETHREAD_TO_KTHREAD(Thread));
391
392 ObDereferenceObject(Process);
393
394 DPRINT("PiDeleteThread() finished\n");
395 }
396
397
398 NTSTATUS
399 PsInitializeThread(PEPROCESS Process,
400 PETHREAD* ThreadPtr,
401 POBJECT_ATTRIBUTES ObjectAttributes,
402 KPROCESSOR_MODE AccessMode,
403 BOOLEAN First)
404 {
405 PETHREAD Thread;
406 NTSTATUS Status;
407 KIRQL oldIrql;
408
409 PAGED_CODE();
410
411 if (Process == NULL)
412 {
413 Process = PsInitialSystemProcess;
414 }
415
416 /*
417 * Create and initialize thread
418 */
419 Status = ObCreateObject(AccessMode,
420 PsThreadType,
421 ObjectAttributes,
422 KernelMode,
423 NULL,
424 sizeof(ETHREAD),
425 0,
426 0,
427 (PVOID*)&Thread);
428 if (!NT_SUCCESS(Status))
429 {
430 return(Status);
431 }
432
433 /*
434 * Reference process
435 */
436 ObReferenceObjectByPointer(Process,
437 PROCESS_CREATE_THREAD,
438 PsProcessType,
439 KernelMode);
440
441 Thread->ThreadsProcess = Process;
442 Thread->Cid.UniqueThread = NULL;
443 Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
444
445 DPRINT("Thread = %x\n",Thread);
446
447 KeInitializeThread(&Process->Pcb, &Thread->Tcb, First);
448 InitializeListHead(&Thread->TerminationPortList);
449 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
450 InitializeListHead(&Thread->IrpList);
451 Thread->DeadThread = FALSE;
452 Thread->HasTerminated = FALSE;
453 Thread->Tcb.Win32Thread = NULL;
454 DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
455
456
457 Thread->Tcb.BasePriority = (CHAR)Process->Pcb.BasePriority;
458 Thread->Tcb.Priority = Thread->Tcb.BasePriority;
459
460 /*
461 * Local Procedure Call facility (LPC)
462 */
463 KeInitializeSemaphore (& Thread->LpcReplySemaphore, 0, LONG_MAX);
464 Thread->LpcReplyMessage = NULL;
465 Thread->LpcReplyMessageId = 0; /* not valid */
466 /* Thread->LpcReceiveMessageId = 0; */
467 Thread->LpcExitThreadCalled = FALSE;
468 Thread->LpcReceivedMsgIdValid = FALSE;
469
470 oldIrql = KeAcquireDispatcherDatabaseLock();
471 InsertTailList(&Process->ThreadListHead,
472 &Thread->ThreadListEntry);
473 KeReleaseDispatcherDatabaseLock(oldIrql);
474
475 *ThreadPtr = Thread;
476
477 return STATUS_SUCCESS;
478 }
479
480
481 static NTSTATUS
482 PsCreateTeb(HANDLE ProcessHandle,
483 PTEB *TebPtr,
484 PETHREAD Thread,
485 PINITIAL_TEB InitialTeb)
486 {
487 PEPROCESS Process;
488 NTSTATUS Status;
489 ULONG ByteCount;
490 ULONG RegionSize;
491 ULONG TebSize;
492 PVOID TebBase;
493 TEB Teb;
494
495 PAGED_CODE();
496
497 TebSize = PAGE_SIZE;
498
499 if (NULL == Thread->ThreadsProcess)
500 {
501 /* We'll be allocating a 64k block here and only use 4k of it, but this
502 path should almost never be taken. Actually, I never saw it was taken,
503 so maybe we should just ASSERT(NULL != Thread->ThreadsProcess) and
504 move on */
505 TebBase = NULL;
506 Status = ZwAllocateVirtualMemory(ProcessHandle,
507 &TebBase,
508 0,
509 &TebSize,
510 MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
511 PAGE_READWRITE);
512 if (! NT_SUCCESS(Status))
513 {
514 DPRINT1("Failed to allocate virtual memory for TEB\n");
515 return Status;
516 }
517 }
518 else
519 {
520 Process = Thread->ThreadsProcess;
521 ExAcquireFastMutex(&Process->TebLock);
522 if (NULL == Process->TebBlock ||
523 Process->TebBlock == Process->TebLastAllocated)
524 {
525 Process->TebBlock = NULL;
526 RegionSize = MM_VIRTMEM_GRANULARITY;
527 Status = ZwAllocateVirtualMemory(ProcessHandle,
528 &Process->TebBlock,
529 0,
530 &RegionSize,
531 MEM_RESERVE | MEM_TOP_DOWN,
532 PAGE_READWRITE);
533 if (! NT_SUCCESS(Status))
534 {
535 ExReleaseFastMutex(&Process->TebLock);
536 DPRINT1("Failed to reserve virtual memory for TEB\n");
537 return Status;
538 }
539 Process->TebLastAllocated = (PVOID) ((char *) Process->TebBlock + RegionSize);
540 }
541 TebBase = (PVOID) ((char *) Process->TebLastAllocated - PAGE_SIZE);
542 Status = ZwAllocateVirtualMemory(ProcessHandle,
543 &TebBase,
544 0,
545 &TebSize,
546 MEM_COMMIT,
547 PAGE_READWRITE);
548 if (! NT_SUCCESS(Status))
549 {
550 DPRINT1("Failed to commit virtual memory for TEB\n");
551 return Status;
552 }
553 Process->TebLastAllocated = TebBase;
554 ExReleaseFastMutex(&Process->TebLock);
555 }
556
557 DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
558 ASSERT(NULL != TebBase && PAGE_SIZE <= TebSize);
559
560 RtlZeroMemory(&Teb, sizeof(TEB));
561 /* set all pointers to and from the TEB */
562 Teb.Tib.Self = TebBase;
563 if (Thread->ThreadsProcess)
564 {
565 Teb.Peb = Thread->ThreadsProcess->Peb; /* No PEB yet!! */
566 }
567 DPRINT("Teb.Peb %x\n", Teb.Peb);
568
569 /* store stack information from InitialTeb */
570 if(InitialTeb != NULL)
571 {
572 /* fixed-size stack */
573 if(InitialTeb->StackBase && InitialTeb->StackLimit)
574 {
575 Teb.Tib.StackBase = InitialTeb->StackBase;
576 Teb.Tib.StackLimit = InitialTeb->StackLimit;
577 Teb.DeallocationStack = InitialTeb->StackLimit;
578 }
579 /* expandable stack */
580 else
581 {
582 Teb.Tib.StackBase = InitialTeb->StackCommit;
583 Teb.Tib.StackLimit = InitialTeb->StackCommitMax;
584 Teb.DeallocationStack = InitialTeb->StackReserved;
585 }
586 }
587
588 /* more initialization */
589 Teb.Cid.UniqueThread = Thread->Cid.UniqueThread;
590 Teb.Cid.UniqueProcess = Thread->Cid.UniqueProcess;
591 Teb.CurrentLocale = PsDefaultThreadLocaleId;
592
593 /* Terminate the exception handler list */
594 Teb.Tib.ExceptionList = (PVOID)-1;
595
596 DPRINT("sizeof(TEB) %x\n", sizeof(TEB));
597
598 /* write TEB data into teb page */
599 Status = NtWriteVirtualMemory(ProcessHandle,
600 TebBase,
601 &Teb,
602 sizeof(TEB),
603 &ByteCount);
604
605 if (!NT_SUCCESS(Status))
606 {
607 /* free TEB */
608 DPRINT1 ("Writing TEB failed!\n");
609
610 RegionSize = 0;
611 NtFreeVirtualMemory(ProcessHandle,
612 TebBase,
613 &RegionSize,
614 MEM_RELEASE);
615
616 return Status;
617 }
618
619 if (TebPtr != NULL)
620 {
621 *TebPtr = (PTEB)TebBase;
622 }
623
624 DPRINT("TEB allocated at %p\n", TebBase);
625
626 return Status;
627 }
628
629
630 VOID STDCALL
631 LdrInitApcRundownRoutine(PKAPC Apc)
632 {
633 ExFreePool(Apc);
634 }
635
636
637 VOID STDCALL
638 LdrInitApcKernelRoutine(PKAPC Apc,
639 PKNORMAL_ROUTINE* NormalRoutine,
640 PVOID* NormalContext,
641 PVOID* SystemArgument1,
642 PVOID* SystemArgument2)
643 {
644 ExFreePool(Apc);
645 }
646
647
648 NTSTATUS STDCALL
649 NtCreateThread(OUT PHANDLE ThreadHandle,
650 IN ACCESS_MASK DesiredAccess,
651 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
652 IN HANDLE ProcessHandle,
653 OUT PCLIENT_ID ClientId,
654 IN PCONTEXT ThreadContext,
655 IN PINITIAL_TEB InitialTeb,
656 IN BOOLEAN CreateSuspended)
657 {
658 HANDLE hThread;
659 CONTEXT SafeContext;
660 INITIAL_TEB SafeInitialTeb;
661 PEPROCESS Process;
662 PETHREAD Thread;
663 PTEB TebBase;
664 PKAPC LdrInitApc;
665 KIRQL oldIrql;
666 KPROCESSOR_MODE PreviousMode;
667 NTSTATUS Status = STATUS_SUCCESS;
668
669 PAGED_CODE();
670
671 if(ThreadContext == NULL)
672 {
673 return STATUS_INVALID_PARAMETER;
674 }
675
676 PreviousMode = ExGetPreviousMode();
677
678 if(PreviousMode != KernelMode)
679 {
680 _SEH_TRY
681 {
682 ProbeForWrite(ThreadHandle,
683 sizeof(HANDLE),
684 sizeof(ULONG));
685 if(ClientId != NULL)
686 {
687 ProbeForWrite(ClientId,
688 sizeof(CLIENT_ID),
689 sizeof(ULONG));
690 }
691 ProbeForRead(ThreadContext,
692 sizeof(CONTEXT),
693 sizeof(ULONG));
694 SafeContext = *ThreadContext;
695 ThreadContext = &SafeContext;
696 ProbeForRead(InitialTeb,
697 sizeof(INITIAL_TEB),
698 sizeof(ULONG));
699 SafeInitialTeb = *InitialTeb;
700 InitialTeb = &SafeInitialTeb;
701 }
702 _SEH_HANDLE
703 {
704 Status = _SEH_GetExceptionCode();
705 }
706 _SEH_END;
707
708 if(!NT_SUCCESS(Status))
709 {
710 return Status;
711 }
712 }
713
714 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
715 ThreadHandle,ThreadContext);
716
717 Status = ObReferenceObjectByHandle(ProcessHandle,
718 PROCESS_CREATE_THREAD,
719 PsProcessType,
720 PreviousMode,
721 (PVOID*)&Process,
722 NULL);
723 if(!NT_SUCCESS(Status))
724 {
725 return(Status);
726 }
727
728 Status = PsInitializeThread(Process,
729 &Thread,
730 ObjectAttributes,
731 PreviousMode,
732 FALSE);
733
734 ObDereferenceObject(Process);
735
736 if (!NT_SUCCESS(Status))
737 {
738 return(Status);
739 }
740
741 /* create a client id handle */
742 Status = PsCreateCidHandle(Thread, PsThreadType, &Thread->Cid.UniqueThread);
743 if (!NT_SUCCESS(Status))
744 {
745 ObDereferenceObject(Thread);
746 return Status;
747 }
748
749 Status = KiArchInitThreadWithContext(&Thread->Tcb, ThreadContext);
750 if (!NT_SUCCESS(Status))
751 {
752 PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
753 ObDereferenceObject(Thread);
754 return(Status);
755 }
756
757 Status = PsCreateTeb(ProcessHandle,
758 &TebBase,
759 Thread,
760 InitialTeb);
761 if (!NT_SUCCESS(Status))
762 {
763 PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
764 ObDereferenceObject(Thread);
765 return(Status);
766 }
767 Thread->Tcb.Teb = TebBase;
768
769 Thread->StartAddress = NULL;
770
771 /*
772 * Maybe send a message to the process's debugger
773 */
774 DbgkCreateThread((PVOID)ThreadContext->Eip);
775
776 /*
777 * First, force the thread to be non-alertable for user-mode alerts.
778 */
779 Thread->Tcb.Alertable = FALSE;
780
781 /*
782 * If the thread is to be created suspended then queue an APC to
783 * do the suspend before we run any userspace code.
784 */
785 if (CreateSuspended)
786 {
787 PsSuspendThread(Thread, NULL);
788 }
789
790 /*
791 * Queue an APC to the thread that will execute the ntdll startup
792 * routine.
793 */
794 LdrInitApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
795 KeInitializeApc(LdrInitApc, &Thread->Tcb, OriginalApcEnvironment, LdrInitApcKernelRoutine,
796 LdrInitApcRundownRoutine, LdrpGetSystemDllEntryPoint(),
797 UserMode, NULL);
798 KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);
799
800 /*
801 * The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE.
802 * We must do this manually. Do NOT attempt to set the Thread to Alertable before the call,
803 * doing so is a blatant and erronous hack.
804 */
805 Thread->Tcb.ApcState.UserApcPending = TRUE;
806 Thread->Tcb.Alerted[KernelMode] = TRUE;
807
808 oldIrql = KeAcquireDispatcherDatabaseLock ();
809 PsUnblockThread(Thread, NULL, 0);
810 KeReleaseDispatcherDatabaseLock(oldIrql);
811
812 Status = ObInsertObject((PVOID)Thread,
813 NULL,
814 DesiredAccess,
815 0,
816 NULL,
817 &hThread);
818 if(NT_SUCCESS(Status))
819 {
820 _SEH_TRY
821 {
822 if(ClientId != NULL)
823 {
824 *ClientId = Thread->Cid;
825 }
826 *ThreadHandle = hThread;
827 }
828 _SEH_HANDLE
829 {
830 Status = _SEH_GetExceptionCode();
831 }
832 _SEH_END;
833 }
834
835 return Status;
836 }
837
838
839 /*
840 * @implemented
841 */
842 NTSTATUS STDCALL
843 PsCreateSystemThread(PHANDLE ThreadHandle,
844 ACCESS_MASK DesiredAccess,
845 POBJECT_ATTRIBUTES ObjectAttributes,
846 HANDLE ProcessHandle,
847 PCLIENT_ID ClientId,
848 PKSTART_ROUTINE StartRoutine,
849 PVOID StartContext)
850 /*
851 * FUNCTION: Creates a thread which executes in kernel mode
852 * ARGUMENTS:
853 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
854 * handle
855 * DesiredAccess = Requested access to the thread
856 * ObjectAttributes = Object attributes (optional)
857 * ProcessHandle = Handle of process thread will run in
858 * NULL to use system process
859 * ClientId (OUT) = Caller supplied storage for the returned client id
860 * of the thread (optional)
861 * StartRoutine = Entry point for the thread
862 * StartContext = Argument supplied to the thread when it begins
863 * execution
864 * RETURNS: Success or failure status
865 */
866 {
867 PETHREAD Thread;
868 NTSTATUS Status;
869 KIRQL oldIrql;
870
871 PAGED_CODE();
872
873 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
874 ThreadHandle,ProcessHandle);
875
876 Status = PsInitializeThread(NULL,
877 &Thread,
878 ObjectAttributes,
879 KernelMode,
880 FALSE);
881 if (!NT_SUCCESS(Status))
882 {
883 return(Status);
884 }
885
886 Status = PsCreateCidHandle(Thread,
887 PsThreadType,
888 &Thread->Cid.UniqueThread);
889 if(!NT_SUCCESS(Status))
890 {
891 ObDereferenceObject(Thread);
892 return Status;
893 }
894
895 Thread->StartAddress = StartRoutine;
896 Status = KiArchInitThread(&Thread->Tcb, StartRoutine, StartContext);
897 if (!NT_SUCCESS(Status))
898 {
899 ObDereferenceObject(Thread);
900 return(Status);
901 }
902
903 if (ClientId != NULL)
904 {
905 *ClientId=Thread->Cid;
906 }
907
908 oldIrql = KeAcquireDispatcherDatabaseLock ();
909 PsUnblockThread(Thread, NULL, 0);
910 KeReleaseDispatcherDatabaseLock(oldIrql);
911
912 Status = ObInsertObject((PVOID)Thread,
913 NULL,
914 DesiredAccess,
915 0,
916 NULL,
917 ThreadHandle);
918
919 /* don't dereference the thread, the initial reference serves as the keep-alive
920 reference which will be removed by the thread reaper */
921
922 return Status;
923 }
924
925
926 VOID STDCALL
927 PspRunCreateThreadNotifyRoutines(PETHREAD CurrentThread,
928 BOOLEAN Create)
929 {
930 ULONG i;
931 CLIENT_ID Cid = CurrentThread->Cid;
932
933 for (i = 0; i < PiThreadNotifyRoutineCount; i++)
934 {
935 PiThreadNotifyRoutine[i](Cid.UniqueProcess, Cid.UniqueThread, Create);
936 }
937 }
938
939
940 /*
941 * @implemented
942 */
943 NTSTATUS STDCALL
944 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
945 {
946 if (PiThreadNotifyRoutineCount >= MAX_THREAD_NOTIFY_ROUTINE_COUNT)
947 {
948 return(STATUS_INSUFFICIENT_RESOURCES);
949 }
950
951 PiThreadNotifyRoutine[PiThreadNotifyRoutineCount] = NotifyRoutine;
952 PiThreadNotifyRoutineCount++;
953
954 return(STATUS_SUCCESS);
955 }
956
957 /* EOF */