2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/hal/x86/thread.c
5 * PURPOSE: HAL multitasking functions
6 * PROGRAMMER: David Welch (welch@mcmail.com)
11 /* INCLUDES ****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ntoskrnl.h>
16 #include <internal/ps.h>
17 #include <internal/string.h>
18 #include <internal/hal.h>
19 #include <internal/i386/segment.h>
20 #include <internal/mmhal.h>
23 #include <internal/debug.h>
25 /* GLOBALS ***************************************************************/
27 #define FIRST_TSS_SELECTOR (KERNEL_DS + 0x8)
28 #define FIRST_TSS_OFFSET (FIRST_TSS_SELECTOR / 8)
30 static char null_ldt
[8]={0,};
31 static unsigned int null_ldt_sel
=0;
32 static PETHREAD FirstThread
=NULL
;
34 /* FUNCTIONS **************************************************************/
36 void HalTaskSwitch(PKTHREAD thread
)
38 * FUNCTION: Switch tasks
40 * thread = Thread to switch to
41 * NOTE: This function will not return until the current thread is scheduled
45 DPRINT("Scheduling thread %x\n",thread
);
46 DPRINT("Scheduling thread %x\n",thread
->Context
.nr
);
47 DPRINT("previous task %x reserved1 %x esp0 %x ss0 %x\n",
48 thread
->Context
.previous_task
,thread
->Context
.reserved1
,
49 thread
->Context
.esp0
,thread
->Context
.ss0
);
50 DPRINT("reserved2 %x esp1 %x ss1 %x reserved3 %x esp2 %x ss2 %x\n",
51 thread
->Context
.reserved2
,thread
->Context
.esp1
,thread
->Context
.ss1
,
52 thread
->Context
.reserved3
,thread
->Context
.esp2
,thread
->Context
.ss2
);
53 DPRINT("reserved4 %x cr3 %x eip %x eflags %x eax %x\n",
54 thread
->Context
.reserved4
,thread
->Context
.cr3
,thread
->Context
.eip
,
55 thread
->Context
.eflags
,thread
->Context
.eax
);
56 DPRINT("ecx %x edx %x ebx %x esp %x ebp %x esi %x\n",
57 thread
->Context
.ecx
,thread
->Context
.edx
,thread
->Context
.ebx
,
58 thread
->Context
.esp
,thread
->Context
.ebp
,thread
->Context
.esi
);
59 DPRINT("edi %x es %x reserved5 %x cs %x reserved6 %x\n",
60 thread
->Context
.edi
,thread
->Context
.es
,thread
->Context
.reserved5
,
61 thread
->Context
.cs
,thread
->Context
.reserved6
);
62 DPRINT("ss %x reserved7 %x ds %x reserved8 %x fs %x\n",
63 thread
->Context
.ss
,thread
->Context
.reserved7
,thread
->Context
.ds
,
64 thread
->Context
.reserved8
,thread
->Context
.fs
);
65 DPRINT("reserved9 %x gs %x reserved10 %x ldt %x reserved11 %x\n",
66 thread
->Context
.reserved9
,thread
->Context
.gs
,
67 thread
->Context
.reserved10
,thread
->Context
.ldt
,
68 thread
->Context
.reserved11
);
69 DPRINT("trap %x iomap_base %x nr %x io_bitmap[0] %x\n",
70 thread
->Context
.trap
,thread
->Context
.iomap_base
,
71 thread
->Context
.nr
,thread
->Context
.io_bitmap
[0]);
77 : "m" (*(((unsigned char *)(&(thread
->Context
.nr
)))-4) )
81 static unsigned int allocate_tss_descriptor(void)
83 * FUNCTION: Allocates a slot within the GDT to describe a TSS
84 * RETURNS: The offset within the GDT of the slot allocated on succcess
91 if (gdt
[FIRST_TSS_OFFSET
+ i
].a
==0 &&
92 gdt
[FIRST_TSS_OFFSET
+ i
].b
==0)
94 return(FIRST_TSS_OFFSET
+ i
);
100 static void begin_thread(PKSTART_ROUTINE fn
, PVOID start_context
)
102 * FUNCTION: This function is the start point for all new threads
104 * fn = Actual start point of the thread
105 * start_context = Parameter to pass to the start routine
110 // DPRINT("begin_thread %x %x\n",fn,start_context);
111 KeLowerIrql(PASSIVE_LEVEL
);
112 ret
= fn(start_context
);
113 PsTerminateSystemThread(ret
);
117 #define FLAG_NT (1<<14)
118 #define FLAG_VM (1<<17)
119 #define FLAG_IF (1<<9)
120 #define FLAG_IOPL ((1<<12)+(1<<13))
122 NTSTATUS
KeValidateUserContext(PCONTEXT Context
)
124 * FUNCTION: Validates a processor context
126 * Context = Context to validate
128 * NOTE: This only validates the context as not violating system security, it
129 * doesn't guararantee the thread won't crash at some point
130 * NOTE2: This relies on there only being two selectors which can access
134 if (Context
->Eip
>= KERNEL_BASE
)
136 return(STATUS_UNSUCCESSFUL
);
138 if (Context
->SegCs
== KERNEL_CS
)
140 return(STATUS_UNSUCCESSFUL
);
142 if (Context
->SegDs
== KERNEL_DS
)
144 return(STATUS_UNSUCCESSFUL
);
146 if (Context
->SegEs
== KERNEL_DS
)
148 return(STATUS_UNSUCCESSFUL
);
150 if (Context
->SegFs
== KERNEL_DS
)
152 return(STATUS_UNSUCCESSFUL
);
154 if (Context
->SegGs
== KERNEL_DS
)
156 return(STATUS_UNSUCCESSFUL
);
158 if ((Context
->EFlags
& FLAG_IOPL
) != 0 ||
159 (Context
->EFlags
& FLAG_NT
) ||
160 (Context
->EFlags
& FLAG_VM
) ||
161 (!(Context
->EFlags
& FLAG_IF
)))
163 return(STATUS_SUCCESS
);
165 return(STATUS_SUCCESS
);
168 NTSTATUS
HalInitTaskWithContext(PETHREAD Thread
, PCONTEXT Context
)
170 * FUNCTION: Initialize a task with a user mode context
172 * Thread = Thread to initialize
173 * Context = Processor context to initialize it with
180 unsigned int* kernel_stack
;
183 DPRINT("HalInitTaskWithContext(Thread %x, Context %x)\n",
186 assert(sizeof(hal_thread_state
)>=0x68);
188 if ((Status
=KeValidateUserContext(Context
))!=STATUS_SUCCESS
)
193 desc
= allocate_tss_descriptor();
194 length
= sizeof(hal_thread_state
) - 1;
195 base
= (unsigned int)(&(Thread
->Tcb
.Context
));
196 kernel_stack
= ExAllocatePool(NonPagedPool
,PAGESIZE
);
199 * Setup a TSS descriptor
201 gdt
[desc
].a
= (length
& 0xffff) | ((base
& 0xffff) << 16);
202 gdt
[desc
].b
= ((base
& 0xff0000)>>16) | 0x8900 | (length
& 0xf0000)
203 | (base
& 0xff000000);
206 * Initialize the thread context
208 memset(&Thread
->Tcb
.Context
,0,sizeof(hal_thread_state
));
209 Thread
->Tcb
.Context
.ldt
= null_ldt_sel
;
210 Thread
->Tcb
.Context
.eflags
= Context
->EFlags
;
211 Thread
->Tcb
.Context
.iomap_base
= FIELD_OFFSET(hal_thread_state
,io_bitmap
);
212 Thread
->Tcb
.Context
.esp0
= (ULONG
)&kernel_stack
[1021];
213 Thread
->Tcb
.Context
.ss0
= KERNEL_DS
;
214 Thread
->Tcb
.Context
.esp
= Context
->Esp
;
215 Thread
->Tcb
.Context
.ss
= Context
->SegSs
;
216 Thread
->Tcb
.Context
.cs
= Context
->SegCs
;
217 Thread
->Tcb
.Context
.eip
= Context
->Eip
;
218 Thread
->Tcb
.Context
.io_bitmap
[0] = 0xff;
219 Thread
->Tcb
.Context
.cr3
=
220 linear_to_physical(Thread
->ThreadsProcess
->Pcb
.PageTableDirectory
);
221 Thread
->Tcb
.Context
.ds
= Context
->SegDs
;
222 Thread
->Tcb
.Context
.es
= Context
->SegEs
;
223 Thread
->Tcb
.Context
.fs
= Context
->SegFs
;
224 Thread
->Tcb
.Context
.gs
= Context
->SegGs
;
225 Thread
->Tcb
.Context
.eax
= Context
->Eax
;
226 Thread
->Tcb
.Context
.ebx
= Context
->Ebx
;
227 Thread
->Tcb
.Context
.ecx
= Context
->Ecx
;
228 Thread
->Tcb
.Context
.edx
= Context
->Edx
;
229 Thread
->Tcb
.Context
.edi
= Context
->Edi
;
230 Thread
->Tcb
.Context
.esi
= Context
->Esi
;
231 Thread
->Tcb
.Context
.ebp
= Context
->Ebp
;
233 Thread
->Tcb
.Context
.nr
= desc
* 8;
234 DPRINT("Allocated %x\n",desc
*8);
236 return(STATUS_SUCCESS
);
239 BOOLEAN
HalInitTask(PETHREAD thread
, PKSTART_ROUTINE fn
, PVOID StartContext
)
241 * FUNCTION: Initializes the HAL portion of a thread object
243 * thread = Object describes the thread
244 * fn = Entrypoint for the thread
245 * StartContext = parameter to pass to the thread entrypoint
246 * RETURNS: True if the function succeeded
249 unsigned int desc
= allocate_tss_descriptor();
250 unsigned int length
= sizeof(hal_thread_state
) - 1;
251 unsigned int base
= (unsigned int)(&(thread
->Tcb
.Context
));
252 unsigned int* kernel_stack
= ExAllocatePool(NonPagedPool
,4096);
254 DPRINT("HalInitTask(Thread %x, fn %x, StartContext %x)\n",
255 thread
,fn
,StartContext
);
256 DPRINT("thread->ThreadsProcess %x\n",thread
->ThreadsProcess
);
261 assert(sizeof(hal_thread_state
)>=0x68);
264 * Setup a TSS descriptor
266 gdt
[desc
].a
= (length
& 0xffff) | ((base
& 0xffff) << 16);
267 gdt
[desc
].b
= ((base
& 0xff0000)>>16) | 0x8900 | (length
& 0xf0000)
268 | (base
& 0xff000000);
271 * Initialize the stack for the thread (including the two arguments to
272 * the general start routine).
274 kernel_stack
[1023] = (unsigned int)StartContext
;
275 kernel_stack
[1022] = (unsigned int)fn
;
276 kernel_stack
[1021] = NULL
;
279 * Initialize the thread context
281 memset(&thread
->Tcb
.Context
,0,sizeof(hal_thread_state
));
282 thread
->Tcb
.Context
.ldt
= null_ldt_sel
;
283 thread
->Tcb
.Context
.eflags
= (1<<1)+(1<<9);
284 thread
->Tcb
.Context
.iomap_base
= FIELD_OFFSET(hal_thread_state
,io_bitmap
);
285 thread
->Tcb
.Context
.esp0
= &kernel_stack
[1021];
286 thread
->Tcb
.Context
.ss0
= KERNEL_DS
;
287 thread
->Tcb
.Context
.esp
= &kernel_stack
[1021];
288 thread
->Tcb
.Context
.ss
= KERNEL_DS
;
289 thread
->Tcb
.Context
.cs
= KERNEL_CS
;
290 thread
->Tcb
.Context
.eip
= (unsigned long)begin_thread
;
291 thread
->Tcb
.Context
.io_bitmap
[0] = 0xff;
292 thread
->Tcb
.Context
.cr3
=
293 linear_to_physical(thread
->ThreadsProcess
->Pcb
.PageTableDirectory
);
294 thread
->Tcb
.Context
.ds
= KERNEL_DS
;
295 thread
->Tcb
.Context
.es
= KERNEL_DS
;
296 thread
->Tcb
.Context
.fs
= KERNEL_DS
;
297 thread
->Tcb
.Context
.gs
= KERNEL_DS
;
298 thread
->Tcb
.Context
.nr
= desc
* 8;
299 DPRINT("Allocated %x\n",desc
*8);
305 void HalInitFirstTask(PETHREAD thread
)
307 * FUNCTION: Called to setup the HAL portion of a thread object for the
315 memset(null_ldt
,0,sizeof(null_ldt
));
316 desc
= allocate_tss_descriptor();
317 base
= (unsigned int)&null_ldt
;
318 length
= sizeof(null_ldt
) - 1;
319 gdt
[desc
].a
= (length
& 0xffff) | ((base
& 0xffff) << 16);
320 gdt
[desc
].b
= ((base
& 0xff0000)>>16) | 0x8200 | (length
& 0xf0000)
321 | (base
& 0xff000000);
322 null_ldt_sel
= desc
*8;
325 * Initialize the thread context
327 HalInitTask(thread
,NULL
,NULL
);
330 * Load the task register
334 : "a" (thread
->Tcb
.Context
.nr
));
335 FirstThread
= thread
;