My Project
Loading...
Searching...
No Matches
thread.c
Go to the documentation of this file.
1#include "../../includes/ps.h"
2#include "../../assert.h"
3#include "../../includes/mg.h"
4#include "../../includes/ob.h"
5
6#define MIN_TID 3u
7#define MAX_TID 0xFFFFFFFCu
8#define ALIGN_DELTA 3u
9#define MAX_FREE_POOL 1024u
10
11#define THREAD_STACK_SIZE (1024*24) // 24 KiB
12#define THREAD_ALIGNMENT 16
13
14// Clean exit for a thread—never returns!
15static void ThreadExit(void) {
16#ifdef DEBUG
17 gop_printf(COLOR_RED, "Reached ThreadExit, dereferencing object.\n");
18#endif
19 // Terminate the thread.
20 assert(&PsGetCurrentThread()->InternalThread == MeGetCurrentThread());
22}
23
24static void ThreadWrapperEx(ThreadEntry thread_entry, THREAD_PARAMETER parameter) {
25 // thread_entry(parameters) -> void func(void*)
26 thread_entry(parameter); // If thread entry takes no parameters, passing NULL is still fine.
28 ThreadExit();
29}
30
32
35 HANDLE ProcessHandle,
36 PHANDLE ThreadHandle,
37 ThreadEntry EntryPoint,
38 THREAD_PARAMETER ThreadParameter,
39 TimeSliceTicks TimeSlice
40)
41
42{
43 // Checks.
44 if (!ProcessHandle || !EntryPoint || !TimeSlice) return MT_INVALID_PARAM;
45 MTSTATUS Status;
46 PEPROCESS ParentProcess;
47
48 Status = ObReferenceObjectByHandle(ProcessHandle, MT_PROCESS_CREATE_THREAD, PsProcessType, (void**)&ParentProcess, NULL);
49 if (MT_FAILURE(Status)) return Status;
50
51 // Acquire process rundown protection.
52 if (!MsAcquireRundownProtection(&ParentProcess->ProcessRundown)) {
53 // Process is, being terminated?
55 }
56
57 // Create a new thread.
58 PETHREAD Thread;
59 Status = ObCreateObject(PsThreadType, sizeof(ETHREAD), (void**) & Thread);
60 if (MT_FAILURE(Status)) goto Cleanup;
61
62 // Initialize list head.
64
65 // Create a TID for the thread.
66 Thread->TID = PsAllocateThreadId(Thread);
67
68 // Create a new stack for the thread's kernel environment.
70 if (!Thread->InternalThread.KernelStack) goto CleanupWithRef;
71
72 // Create user mode stack. (FIXME User mode stack creation like in ntdll, but how does it create the first user mode thread stack, helluva i know.)
73 void* BaseAddress = (void*)(USER_VA_END - 4096);
74 Status = MmAllocateVirtualMemory(ParentProcess, &BaseAddress, 4096, VAD_FLAG_WRITE | VAD_FLAG_READ);
75 if (MT_FAILURE(Status)) goto CleanupWithRef;
76 Thread->InternalThread.StackBase = (void*)(USER_VA_END); // Stack grows downward.
77
78 // Setup timeslice.
79 Thread->InternalThread.TimeSlice = TimeSlice;
80 Thread->InternalThread.TimeSliceAllocated = TimeSlice;
81
82 // Set registers
83 TRAP_FRAME ContextFrame;
84 kmemset(&ContextFrame, 0, sizeof(TRAP_FRAME));
85
86 ContextFrame.rsp = (uint64_t)Thread->InternalThread.StackBase;
87 ContextFrame.rip = (uint64_t)EntryPoint;
88 ContextFrame.rdi = (uint64_t)ThreadParameter;
89 ContextFrame.rflags = USER_RFLAGS;
90 ContextFrame.cs = USER_CS;
91 ContextFrame.ss = USER_SS;
92 Thread->InternalThread.TrapRegisters = ContextFrame;
93
94 // Set state
96 Thread->InternalThread.ApcState.SavedApcProcess = ParentProcess;
97
98 // Set process's thread properties.
99 if (!ParentProcess->MainThread) {
100 ParentProcess->MainThread = Thread;
101 }
102
103 Thread->ParentProcess = ParentProcess;
104
105 // Create a handle for the thread (and place it in the process's handle table).
106 Status = ObCreateHandleForObjectEx(Thread, MT_THREAD_ALL_ACCESS, ThreadHandle, ParentProcess->ObjectTable);
107 if (MT_FAILURE(Status)) goto CleanupWithRef;
108
109 // Add to list of all threads in the parent process.
110 InsertTailList(&ParentProcess->AllThreads, &Thread->ThreadListEntry);
111 InterlockedIncrementU32((volatile uint32_t*)&ParentProcess->NumThreads);
112 Status = MT_SUCCESS;
113CleanupWithRef:
114 // If all went smoothly, this should cancel out the reference made by ObCreateHandleForObject. (so we only have 1 reference left by ObCreateObject)
115 // If not, it would reach reference 0, and PspDeleteThread would execute.
116 ObDereferenceObject(Thread);
117Cleanup:
119 return Status;
120}
121
123 if (!PsInitialSystemProcess.PID) return MT_NOT_FOUND; // The system process, somehow, hasn't been setupped yet.
124 if (!entry || !TIMESLICE) return MT_INVALID_PARAM;
125
126 // First, allocate a new thread. (using our shiny and glossy new object manager!!!)
127 MTSTATUS Status;
128 PETHREAD thread;
129 Status = ObCreateObject(PsThreadType, sizeof(ETHREAD), (void*) & thread);
130 if (MT_FAILURE(Status)) {
131 return Status;
132 }
133
135
136 // Zero it.
137 kmemset((void*)thread, 0, sizeof(ETHREAD));
138 bool LargeStack = false;
139 void* stackStart = MiCreateKernelStack(LargeStack);
140
141 if (!stackStart) {
142 // free thread
143 ObDereferenceObject(thread);
144 return MT_NO_MEMORY;
145 }
146
147 uintptr_t StackTop = (uintptr_t)stackStart;
148
149 StackTop &= ~0xF; // Align to 16 bytes (clear lower 4 bits)
150 StackTop -= 8; // Decrement by 8 to keep 16-byte alignment. (after pushes)
151
152 thread->InternalThread.StackBase = stackStart; // The stackbase must be the one gotten from MiCreateKernelStack, as freeing with StackTop will result in incorrect arithmetic, and so assertion failure.
153 thread->InternalThread.IsLargeStack = LargeStack;
154 thread->InternalThread.KernelStack = stackStart;
155
157 kmemset(cfm, 0, sizeof * cfm);
158
159 // Set our timeslice.
160 thread->InternalThread.TimeSlice = TIMESLICE;
161 thread->InternalThread.TimeSliceAllocated = TIMESLICE;
162
163 // saved rsp must point to the top (aligned), not sp-8
164 cfm->rsp = (uint64_t)StackTop;
165 cfm->rip = (uint64_t)ThreadWrapperEx;
166 cfm->rdi = (uint64_t)entry; // first argument to ThreadWrapperEx (the entry point)
167 cfm->rsi = (uint64_t)parameter; // second arugment to ThreadWrapperEx (the parameter pointer)
168
169 cfm->ss = KERNEL_SS;
170 cfm->cs = KERNEL_CS;
171
172 // Create it's RFLAGS with IF bit set to 1.
173 cfm->rflags |= (1 << 9ULL);
174
175 // Set it's registers and others.
176 thread->InternalThread.TrapRegisters = *cfm;
178 thread->TID = PsAllocateThreadId(thread);
179 thread->CurrentEvent = NULL;
181
182 // Process stuffz
183 thread->ParentProcess = &PsInitialSystemProcess; // The parent process for the system thread, is the system process.
184 MeEnqueueThreadWithLock(&MeGetCurrentProcessor()->readyQueue, thread);
185
186
187 return MT_SUCCESS;
188}
189
192 return CONTAINING_RECORD(MeGetCurrentThread(), ETHREAD, InternalThread);
193}
194
195void
197 IN PETHREAD Thread,
198 IN MTSTATUS ExitStatus
199)
200
201{
202 // On thread terminations, we only unlink them from global list, delete stacks, and other
203 // BUT WE DO NOT - Delete the ETHREAD, since thats up to the object manager to do so, we do not interfere
204 // with its work.
205 Thread->InternalThread.ThreadState = THREAD_TERMINATING;
206 Thread->ExitStatus = ExitStatus;
207
208 // Signal all events that the thread is waiting on to execute immediately.
209 // Todo parse waitblock.
210
211 // Since this is marked as TERMINATING, the scheduler will dereference the thread in Ob, and from that if
212 // the references have reached 0, the Ob will call PsDeleteThread.
213 // The scheduler WILL NOT schedule this thread anymore due to its TERMINATION flag.
214
215 // Schedule away!
216 Schedule();
217}
218
219void
221 IN void* Object
222)
223
224{
225 // This function is called when the reference count for this thread has reached 0 (e.g, it is no longer in use)
226 // (No need to call PsTerminateThread, it is the one that initiated the final dereference, since it set to terminated, and scheduler called dereference)
227 // We free everything that the thread uses.
228 // All though, before, we should wait for rundown release (so nobody is changing the fields to avoid UAF)
229 PETHREAD Thread = (PETHREAD)Object;
231
232 bool IsKernelThread = PsIsKernelThread(Thread);
233
234 // Free TID.
235 PsFreeCid(Thread->TID);
236
237 // Free its stack.
238 if (IsKernelThread) {
240 }
241 else {
242 assert(false, "User mode threads are not supported yet.");
243 }
244
245 // When we reach here, the function returns, and the ETHREAD is deleted.
246}
#define IN
Definition annotations.h:7
#define assert(...)
Definition assert.h:57
FORCEINLINE uint32_t InterlockedIncrementU32(volatile uint32_t *target)
Definition atomic.h:115
HANDLE PsAllocateThreadId(IN PETHREAD Thread)
Definition cid.c:88
void PsFreeCid(IN HANDLE Cid)
Definition cid.c:163
struct _EPROCESS EPROCESS
Definition core.h:49
struct _TRAP_FRAME TRAP_FRAME
Definition core.h:53
EPROCESS * PEPROCESS
Definition core.h:50
struct _ETHREAD ETHREAD
Definition core.h:41
ETHREAD * PETHREAD
Definition core.h:42
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
int32_t * PHANDLE
Definition ht.h:59
int32_t HANDLE
Definition ht.h:59
#define CONTAINING_RECORD(ptr, type, member)
Definition macros.h:11
#define KERNEL_SS
Definition me.h:240
#define USER_CS
Definition me.h:241
#define USER_RFLAGS
Definition me.h:245
FORCEINLINE PITHREAD MeGetCurrentThread(void)
Definition me.h:431
#define KERNEL_CS
Definition me.h:238
#define USER_SS
Definition me.h:243
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
enum _TimeSliceTicks TimeSliceTicks
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:29
@ VAD_FLAG_READ
Definition mm.h:259
@ VAD_FLAG_WRITE
Definition mm.h:260
FORCEINLINE void * kmemset(void *dest, int64_t val, uint64_t len)
Definition mm.h:540
#define USER_VA_END
Definition mm.h:160
void * MiCreateKernelStack(IN bool LargeStack)
Definition mmproc.c:25
FORCEINLINE void InitializeListHead(PDOUBLY_LINKED_LIST Head)
Definition ms.h:166
FORCEINLINE void InsertTailList(PDOUBLY_LINKED_LIST Head, PDOUBLY_LINKED_LIST Entry)
Definition ms.h:179
#define MT_NO_MEMORY
Definition mtstatus.h:42
#define MT_SUCCESS
Definition mtstatus.h:22
#define MT_PROCESS_IS_TERMINATING
Definition mtstatus.h:123
#define MT_FAILURE(Status)
Definition mtstatus.h:16
#define MT_INVALID_PARAM
Definition mtstatus.h:24
int32_t MTSTATUS
Definition mtstatus.h:12
#define MT_NOT_FOUND
Definition mtstatus.h:30
MTSTATUS ObReferenceObjectByHandle(IN HANDLE Handle, IN uint32_t DesiredAccess, IN POBJECT_TYPE DesiredType, OUT void **Object, _Out_Opt PHANDLE_TABLE_ENTRY HandleInformation)
Definition ob.c:247
MTSTATUS ObCreateHandleForObjectEx(IN void *Object, IN ACCESS_MASK DesiredAccess, OUT PHANDLE ReturnedHandle, IN PHANDLE_TABLE ObjectTable)
Definition ob.c:363
void ObDereferenceObject(IN void *Object)
Definition ob.c:446
MTSTATUS ObCreateObject(IN POBJECT_TYPE ObjectType, IN uint32_t ObjectSize, OUT void **ObjectCreated)
Definition ob.c:116
FORCEINLINE void MeEnqueueThreadWithLock(Queue *queue, PETHREAD thread)
Definition ps.h:306
void(* ThreadEntry)(THREAD_PARAMETER)
Definition ps.h:147
#define MT_THREAD_ALL_ACCESS
Definition ps.h:72
#define MT_PROCESS_CREATE_THREAD
Definition ps.h:79
@ THREAD_TERMINATING
Definition ps.h:41
@ THREAD_READY
Definition ps.h:39
FORCEINLINE bool PsIsKernelThread(IN PETHREAD Thread)
Definition ps.h:259
void * THREAD_PARAMETER
Definition ps.h:146
POBJECT_TYPE PsThreadType
Definition psmgr.c:31
POBJECT_TYPE PsProcessType
Definition psmgr.c:30
void PsDeferKernelStackDeletion(void *StackBase, bool IsLarge)
Definition pswork.c:65
bool MsAcquireRundownProtection(IN PRUNDOWN_REF rundown)
Definition rundown.c:7
void MsReleaseRundownProtection(IN PRUNDOWN_REF rundown)
Definition rundown.c:40
void MsWaitForRundownProtectionRelease(IN PRUNDOWN_REF rundown)
Definition rundown.c:63
NORETURN void Schedule(void)
Definition scheduler.c:105
EPROCESS PsInitialSystemProcess
Definition kernel.c:162
PEPROCESS SavedApcProcess
Definition me.h:249
uint32_t NumThreads
Definition ps.h:110
struct _RUNDOWN_REF ProcessRundown
Definition ps.h:105
PHANDLE_TABLE ObjectTable
Definition ps.h:114
struct _ETHREAD * MainThread
Definition ps.h:108
DOUBLY_LINKED_LIST AllThreads
Definition ps.h:109
struct _RUNDOWN_REF ThreadRundown
Definition ps.h:129
struct _EPROCESS * ParentProcess
Definition ps.h:127
struct _ITHREAD InternalThread
Definition ps.h:122
HANDLE TID
Definition ps.h:125
struct _EVENT * CurrentEvent
Definition ps.h:126
struct _DOUBLY_LINKED_LIST ThreadListEntry
Definition ps.h:128
uint32_t ThreadState
Definition me.h:263
void * StackBase
Definition me.h:264
bool IsLargeStack
Definition me.h:265
enum _TimeSliceTicks TimeSlice
Definition me.h:267
void * KernelStack
Definition me.h:266
struct _TRAP_FRAME TrapRegisters
Definition me.h:262
enum _TimeSliceTicks TimeSliceAllocated
Definition me.h:268
struct _APC_STATE ApcState
Definition me.h:270
uint64_t ss
Definition me.h:161
uint64_t rdi
Definition me.h:154
uint64_t rsp
Definition me.h:160
uint64_t rip
Definition me.h:157
uint64_t rflags
Definition me.h:159
uint64_t rsi
Definition me.h:154
uint64_t cs
Definition me.h:158
MTSTATUS PsCreateSystemThread(ThreadEntry entry, THREAD_PARAMETER parameter, TimeSliceTicks TIMESLICE)
Definition thread.c:122
void PsTerminateThread(IN PETHREAD Thread, IN MTSTATUS ExitStatus)
Definition thread.c:196
PETHREAD PsGetCurrentThread(void)
Definition thread.c:191
MTSTATUS PsCreateThread(HANDLE ProcessHandle, PHANDLE ThreadHandle, ThreadEntry EntryPoint, THREAD_PARAMETER ThreadParameter, TimeSliceTicks TimeSlice)
Definition thread.c:34
void PsDeleteThread(IN void *Object)
Definition thread.c:220
MTSTATUS MmAllocateVirtualMemory(IN PEPROCESS Process, _In_Opt _Out_Opt void **BaseAddress, IN size_t NumberOfBytes, IN VAD_FLAGS VadFlags)
Definition vad.c:723