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
)((char*)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 ((char*)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
= (USHORT
)Context
->SegGs
;
143 TrapFrame
->Es
= (USHORT
)Context
->SegEs
;
144 TrapFrame
->Ds
= (USHORT
)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
= (USHORT
)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
)((char*)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
);