This commit was generated by cvs2svn to compensate for changes in r52,
[reactos.git] / reactos / ntoskrnl / hal / x86 / thread.c
1 /*
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)
7 * REVISION HISTORY:
8 * 27/06/98: Created
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <windows.h>
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>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* GLOBALS ***************************************************************/
26
27 #define FIRST_TSS_SELECTOR (KERNEL_DS + 0x8)
28 #define FIRST_TSS_OFFSET (FIRST_TSS_SELECTOR / 8)
29
30 static char null_ldt[8]={0,};
31 static unsigned int null_ldt_sel=0;
32 static PETHREAD FirstThread=NULL;
33
34 /* FUNCTIONS **************************************************************/
35
36 void HalTaskSwitch(PKTHREAD thread)
37 /*
38 * FUNCTION: Switch tasks
39 * ARGUMENTS:
40 * thread = Thread to switch to
41 * NOTE: This function will not return until the current thread is scheduled
42 * again
43 */
44 {
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]);
72 __asm__("pushfl\n\t"
73 "cli\n\t"
74 "ljmp %0\n\t"
75 "popfl\n\t"
76 : /* No outputs */
77 : "m" (*(((unsigned char *)(&(thread->Context.nr)))-4) )
78 : "ax","dx");
79 }
80
81 static unsigned int allocate_tss_descriptor(void)
82 /*
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
85 * Zero on failure
86 */
87 {
88 unsigned int i;
89 for (i=0;i<16;i++)
90 {
91 if (gdt[FIRST_TSS_OFFSET + i].a==0 &&
92 gdt[FIRST_TSS_OFFSET + i].b==0)
93 {
94 return(FIRST_TSS_OFFSET + i);
95 }
96 }
97 return(0);
98 }
99
100 static void begin_thread(PKSTART_ROUTINE fn, PVOID start_context)
101 /*
102 * FUNCTION: This function is the start point for all new threads
103 * ARGUMENTS:
104 * fn = Actual start point of the thread
105 * start_context = Parameter to pass to the start routine
106 * RETURNS: Can't
107 */
108 {
109 NTSTATUS ret;
110 // DPRINT("begin_thread %x %x\n",fn,start_context);
111 KeLowerIrql(PASSIVE_LEVEL);
112 ret = fn(start_context);
113 PsTerminateSystemThread(ret);
114 for(;;);
115 }
116
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))
121
122 NTSTATUS KeValidateUserContext(PCONTEXT Context)
123 /*
124 * FUNCTION: Validates a processor context
125 * ARGUMENTS:
126 * Context = Context to validate
127 * RETURNS: Status
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
131 * system space
132 */
133 {
134 if (Context->Eip >= KERNEL_BASE)
135 {
136 return(STATUS_UNSUCCESSFUL);
137 }
138 if (Context->SegCs == KERNEL_CS)
139 {
140 return(STATUS_UNSUCCESSFUL);
141 }
142 if (Context->SegDs == KERNEL_DS)
143 {
144 return(STATUS_UNSUCCESSFUL);
145 }
146 if (Context->SegEs == KERNEL_DS)
147 {
148 return(STATUS_UNSUCCESSFUL);
149 }
150 if (Context->SegFs == KERNEL_DS)
151 {
152 return(STATUS_UNSUCCESSFUL);
153 }
154 if (Context->SegGs == KERNEL_DS)
155 {
156 return(STATUS_UNSUCCESSFUL);
157 }
158 if ((Context->EFlags & FLAG_IOPL) != 0 ||
159 (Context->EFlags & FLAG_NT) ||
160 (Context->EFlags & FLAG_VM) ||
161 (!(Context->EFlags & FLAG_IF)))
162 {
163 return(STATUS_SUCCESS);
164 }
165 return(STATUS_SUCCESS);
166 }
167
168 NTSTATUS HalInitTaskWithContext(PETHREAD Thread, PCONTEXT Context)
169 /*
170 * FUNCTION: Initialize a task with a user mode context
171 * ARGUMENTS:
172 * Thread = Thread to initialize
173 * Context = Processor context to initialize it with
174 * RETURNS: Status
175 */
176 {
177 unsigned int desc;
178 unsigned int length;
179 unsigned int base;
180 unsigned int* kernel_stack;
181 NTSTATUS Status;
182
183 DPRINT("HalInitTaskWithContext(Thread %x, Context %x)\n",
184 Thread,Context);
185
186 assert(sizeof(hal_thread_state)>=0x68);
187
188 if ((Status=KeValidateUserContext(Context))!=STATUS_SUCCESS)
189 {
190 return(Status);
191 }
192
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);
197
198 /*
199 * Setup a TSS descriptor
200 */
201 gdt[desc].a = (length & 0xffff) | ((base & 0xffff) << 16);
202 gdt[desc].b = ((base & 0xff0000)>>16) | 0x8900 | (length & 0xf0000)
203 | (base & 0xff000000);
204
205 /*
206 * Initialize the thread context
207 */
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;
232
233 Thread->Tcb.Context.nr = desc * 8;
234 DPRINT("Allocated %x\n",desc*8);
235
236 return(STATUS_SUCCESS);
237 }
238
239 BOOLEAN HalInitTask(PETHREAD thread, PKSTART_ROUTINE fn, PVOID StartContext)
240 /*
241 * FUNCTION: Initializes the HAL portion of a thread object
242 * ARGUMENTS:
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
247 */
248 {
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);
253
254 DPRINT("HalInitTask(Thread %x, fn %x, StartContext %x)\n",
255 thread,fn,StartContext);
256 DPRINT("thread->ThreadsProcess %x\n",thread->ThreadsProcess);
257
258 /*
259 * Make sure
260 */
261 assert(sizeof(hal_thread_state)>=0x68);
262
263 /*
264 * Setup a TSS descriptor
265 */
266 gdt[desc].a = (length & 0xffff) | ((base & 0xffff) << 16);
267 gdt[desc].b = ((base & 0xff0000)>>16) | 0x8900 | (length & 0xf0000)
268 | (base & 0xff000000);
269
270 /*
271 * Initialize the stack for the thread (including the two arguments to
272 * the general start routine).
273 */
274 kernel_stack[1023] = (unsigned int)StartContext;
275 kernel_stack[1022] = (unsigned int)fn;
276 kernel_stack[1021] = NULL;
277
278 /*
279 * Initialize the thread context
280 */
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);
300
301
302 return(TRUE);
303 }
304
305 void HalInitFirstTask(PETHREAD thread)
306 /*
307 * FUNCTION: Called to setup the HAL portion of a thread object for the
308 * initial thread
309 */
310 {
311 unsigned int base;
312 unsigned int length;
313 unsigned int desc;
314
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;
323
324 /*
325 * Initialize the thread context
326 */
327 HalInitTask(thread,NULL,NULL);
328
329 /*
330 * Load the task register
331 */
332 __asm__("ltr %%ax"
333 : /* no output */
334 : "a" (thread->Tcb.Context.nr));
335 FirstThread = thread;
336 }