:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / ke / i386 / thread.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * PROJECT:              ReactOS kernel
21  * FILE:                 ntoskrnl/ke/i386/thread.c
22  * PURPOSE:              Architecture multitasking functions
23  * PROGRAMMER:           David Welch (welch@cwcom.net)
24  * REVISION HISTORY:
25  *             27/06/98: Created
26  */
27
28 /* INCLUDES ****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <internal/ntoskrnl.h>
32 #include <internal/ps.h>
33 #include <internal/i386/segment.h>
34 #include <internal/i386/mm.h>
35 #include <internal/ke.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* GLOBALS *******************************************************************/
41
42 #define FLAG_NT (1<<14)
43 #define FLAG_VM (1<<17)
44 #define FLAG_IF (1<<9)
45 #define FLAG_IOPL ((1<<12)+(1<<13))
46
47 /* FUNCTIONS *****************************************************************/
48
49 NTSTATUS 
50 Ki386ValidateUserContext(PCONTEXT Context)
51 /*
52  * FUNCTION: Validates a processor context
53  * ARGUMENTS:
54  *        Context = Context to validate
55  * RETURNS: Status
56  * NOTE: This only validates the context as not violating system security, it
57  * doesn't guararantee the thread won't crash at some point
58  * NOTE2: This relies on there only being two selectors which can access 
59  * system space
60  */
61 {
62    if (Context->Eip >= KERNEL_BASE)
63      {
64         return(STATUS_UNSUCCESSFUL);
65      }
66    if (Context->SegCs == KERNEL_CS)
67      {
68         return(STATUS_UNSUCCESSFUL);
69      }
70    if (Context->SegDs == KERNEL_DS)
71      {
72         return(STATUS_UNSUCCESSFUL);
73      }
74    if (Context->SegEs == KERNEL_DS)
75      {
76         return(STATUS_UNSUCCESSFUL);
77      }
78    if (Context->SegFs == KERNEL_DS)
79      {
80         return(STATUS_UNSUCCESSFUL);
81      }
82    if (Context->SegGs == KERNEL_DS)
83      {
84         return(STATUS_UNSUCCESSFUL);
85      }
86    if ((Context->EFlags & FLAG_IOPL) != 0 ||
87        (Context->EFlags & FLAG_NT) ||
88        (Context->EFlags & FLAG_VM) ||
89        (!(Context->EFlags & FLAG_IF)))
90      {
91         return(STATUS_UNSUCCESSFUL);
92      }
93    return(STATUS_SUCCESS);
94 }
95
96 NTSTATUS
97 Ke386InitThreadWithContext(PKTHREAD Thread, PCONTEXT Context)
98 {
99   PULONG KernelStack;
100   ULONG InitSize;
101   PKTRAP_FRAME TrapFrame;
102
103   /*
104    * Setup a stack frame for exit from the task switching routine
105    */
106   
107   InitSize = 5 * sizeof(DWORD) + sizeof(DWORD) + 6 * sizeof(DWORD) + 
108     sizeof(FLOATING_SAVE_AREA) + sizeof(KTRAP_FRAME);
109   KernelStack = (PULONG)(Thread->KernelStack - InitSize);
110
111   /* Set up the initial frame for the return from the dispatcher. */
112   KernelStack[0] = 0;      /* EDI */
113   KernelStack[1] = 0;      /* ESI */
114   KernelStack[2] = 0;      /* EBX */
115   KernelStack[3] = 0;      /* EBP */
116   KernelStack[4] = (ULONG)PsBeginThreadWithContextInternal;   /* EIP */
117
118   /* Save the context flags. */
119   KernelStack[5] = Context->ContextFlags;
120
121   /* Set up the initial values of the debugging registers. */
122   KernelStack[6] = Context->Dr0;
123   KernelStack[7] = Context->Dr1;
124   KernelStack[8] = Context->Dr2;
125   KernelStack[9] = Context->Dr3;
126   KernelStack[10] = Context->Dr6;
127   KernelStack[11] = Context->Dr7;
128
129   /* Set up the initial floating point state. */
130   memcpy((PVOID)&KernelStack[12], (PVOID)&Context->FloatSave,
131          sizeof(FLOATING_SAVE_AREA));
132
133   /* Set up a trap frame from the context. */
134   TrapFrame = (PKTRAP_FRAME)
135     ((PVOID)KernelStack + 12 * sizeof(DWORD) + sizeof(FLOATING_SAVE_AREA));
136   TrapFrame->DebugEbp = (PVOID)Context->Ebp;
137   TrapFrame->DebugEip = (PVOID)Context->Eip;
138   TrapFrame->DebugArgMark = 0;
139   TrapFrame->DebugPointer = 0;
140   TrapFrame->TempCs = 0;
141   TrapFrame->TempEip = 0;
142   TrapFrame->Gs = Context->SegGs;
143   TrapFrame->Es = Context->SegEs;
144   TrapFrame->Ds = Context->SegDs;
145   TrapFrame->Edx = Context->Edx;
146   TrapFrame->Ecx = Context->Ecx;
147   TrapFrame->Eax = Context->Eax;
148   TrapFrame->PreviousMode = UserMode;
149   TrapFrame->ExceptionList = (PVOID)0xFFFFFFFF;
150   TrapFrame->Fs = TEB_SELECTOR;
151   TrapFrame->Edi = Context->Edi;
152   TrapFrame->Esi = Context->Esi;
153   TrapFrame->Ebx = Context->Ebx;
154   TrapFrame->Ebp = Context->Ebp;
155   TrapFrame->ErrorCode = 0;
156   TrapFrame->Cs = Context->SegCs;
157   TrapFrame->Eip = Context->Eip;
158   TrapFrame->Eflags = Context->EFlags | FLAG_IF;
159   TrapFrame->Eflags &= ~(FLAG_VM | FLAG_NT | FLAG_IOPL);
160   TrapFrame->Esp = Context->Esp;
161   TrapFrame->Ss = Context->SegSs;
162   /* FIXME: Should check for a v86 mode context here. */
163
164   /* Save back the new value of the kernel stack. */
165   Thread->KernelStack = (PVOID)KernelStack;
166
167   return(STATUS_SUCCESS);
168 }
169
170 NTSTATUS
171 Ke386InitThread(PKTHREAD Thread, 
172                 PKSTART_ROUTINE StartRoutine, 
173                 PVOID StartContext)
174      /*
175       * Initialize a thread
176       */
177 {
178   PULONG KernelStack;
179
180   /*
181    * Setup a stack frame for exit from the task switching routine
182    */
183   
184   KernelStack = (PULONG)(Thread->KernelStack - (8*4));
185   KernelStack[0] = 0;      /* EDI */
186   KernelStack[1] = 0;      /* ESI */
187   KernelStack[2] = 0;      /* EBX */
188   KernelStack[3] = 0;      /* EBP */
189   KernelStack[4] = (ULONG)PsBeginThread;   /* EIP */
190   KernelStack[5] = 0;     /* Return EIP */
191   KernelStack[6] = (ULONG)StartRoutine; /* First argument to PsBeginThread */
192   KernelStack[7] = (ULONG)StartContext; /* Second argument to PsBeginThread */
193   Thread->KernelStack = (VOID*)KernelStack;
194
195   return(STATUS_SUCCESS);
196 }
197
198 /* EOF */