3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/thread.c
22 * PURPOSE: Architecture multitasking functions
23 * PROGRAMMER: David Welch (welch@cwcom.net)
28 /* INCLUDES ****************************************************************/
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>
38 #include <internal/debug.h>
40 /* GLOBALS *******************************************************************/
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))
47 /* FUNCTIONS *****************************************************************/
50 Ki386ValidateUserContext(PCONTEXT Context)
52 * FUNCTION: Validates a processor context
54 * Context = Context to validate
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
62 if (Context->Eip >= KERNEL_BASE)
64 return(STATUS_UNSUCCESSFUL);
66 if (Context->SegCs == KERNEL_CS)
68 return(STATUS_UNSUCCESSFUL);
70 if (Context->SegDs == KERNEL_DS)
72 return(STATUS_UNSUCCESSFUL);
74 if (Context->SegEs == KERNEL_DS)
76 return(STATUS_UNSUCCESSFUL);
78 if (Context->SegFs == KERNEL_DS)
80 return(STATUS_UNSUCCESSFUL);
82 if (Context->SegGs == KERNEL_DS)
84 return(STATUS_UNSUCCESSFUL);
86 if ((Context->EFlags & FLAG_IOPL) != 0 ||
87 (Context->EFlags & FLAG_NT) ||
88 (Context->EFlags & FLAG_VM) ||
89 (!(Context->EFlags & FLAG_IF)))
91 return(STATUS_UNSUCCESSFUL);
93 return(STATUS_SUCCESS);
97 Ke386InitThreadWithContext(PKTHREAD Thread, PCONTEXT Context)
101 PKTRAP_FRAME TrapFrame;
104 * Setup a stack frame for exit from the task switching routine
107 InitSize = 5 * sizeof(DWORD) + sizeof(DWORD) + 6 * sizeof(DWORD) +
108 sizeof(FLOATING_SAVE_AREA) + sizeof(KTRAP_FRAME);
109 KernelStack = (PULONG)(Thread->KernelStack - InitSize);
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 */
118 /* Save the context flags. */
119 KernelStack[5] = Context->ContextFlags;
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;
129 /* Set up the initial floating point state. */
130 memcpy((PVOID)&KernelStack[12], (PVOID)&Context->FloatSave,
131 sizeof(FLOATING_SAVE_AREA));
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. */
164 /* Save back the new value of the kernel stack. */
165 Thread->KernelStack = (PVOID)KernelStack;
167 return(STATUS_SUCCESS);
171 Ke386InitThread(PKTHREAD Thread,
172 PKSTART_ROUTINE StartRoutine,
175 * Initialize a thread
181 * Setup a stack frame for exit from the task switching routine
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;
195 return(STATUS_SUCCESS);