1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/ke/amd64/thrdini.c 5 * PURPOSE: amd64 Thread Context Creation 6 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) 7 * Alex Ionescu (alex@relsoft.net) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 extern void KiInvalidSystemThreadStartupExit(void); 17 extern void KiUserThreadStartupExit(void); 18 extern void KiServiceExit3(void); 19 20 typedef struct _KUINIT_FRAME 21 { 22 KSWITCH_FRAME CtxSwitchFrame; 23 KSTART_FRAME StartFrame; 24 KEXCEPTION_FRAME ExceptionFrame; 25 KTRAP_FRAME TrapFrame; 26 //FX_SAVE_AREA FxSaveArea; 27 } KUINIT_FRAME, *PKUINIT_FRAME; 28 29 typedef struct _KKINIT_FRAME 30 { 31 KSWITCH_FRAME CtxSwitchFrame; 32 KSTART_FRAME StartFrame; 33 //FX_SAVE_AREA FxSaveArea; 34 } KKINIT_FRAME, *PKKINIT_FRAME; 35 36 /* FUNCTIONS *****************************************************************/ 37 38 VOID 39 NTAPI 40 KiInitializeContextThread(IN PKTHREAD Thread, 41 IN PKSYSTEM_ROUTINE SystemRoutine, 42 IN PKSTART_ROUTINE StartRoutine, 43 IN PVOID StartContext, 44 IN PCONTEXT Context) 45 { 46 //PFX_SAVE_AREA FxSaveArea; 47 //PFXSAVE_FORMAT FxSaveFormat; 48 PKSTART_FRAME StartFrame; 49 PKSWITCH_FRAME CtxSwitchFrame; 50 PKTRAP_FRAME TrapFrame; 51 ULONG ContextFlags; 52 53 /* Check if this is a With-Context Thread */ 54 if (Context) 55 { 56 PKUINIT_FRAME InitFrame; 57 58 /* Set up the Initial Frame */ 59 InitFrame = ((PKUINIT_FRAME)Thread->InitialStack) - 1; 60 StartFrame = &InitFrame->StartFrame; 61 CtxSwitchFrame = &InitFrame->CtxSwitchFrame; 62 63 /* Save back the new value of the kernel stack. */ 64 Thread->KernelStack = (PVOID)InitFrame; 65 66 /* Tell the thread it will run in User Mode */ 67 Thread->PreviousMode = UserMode; 68 69 // FIXME Setup the Fx Area 70 71 /* Set the Thread's NPX State */ 72 Thread->NpxState = 0xA; 73 Thread->Header.NpxIrql = PASSIVE_LEVEL; 74 75 /* Make sure, we have control registers, disable debug registers */ 76 ASSERT((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL); 77 ContextFlags = Context->ContextFlags & ~CONTEXT_DEBUG_REGISTERS; 78 79 /* Setup the Trap Frame */ 80 TrapFrame = &InitFrame->TrapFrame; 81 82 /* Zero out the trap frame */ 83 RtlZeroMemory(TrapFrame, sizeof(KTRAP_FRAME)); 84 RtlZeroMemory(&InitFrame->ExceptionFrame, sizeof(KEXCEPTION_FRAME)); 85 86 /* Set up a trap frame from the context. */ 87 KeContextToTrapFrame(Context, 88 &InitFrame->ExceptionFrame, 89 TrapFrame, 90 CONTEXT_AMD64 | ContextFlags, 91 UserMode); 92 93 /* Set SS, DS, ES's RPL Mask properly */ 94 TrapFrame->SegSs |= RPL_MASK; 95 TrapFrame->SegDs |= RPL_MASK; 96 TrapFrame->SegEs |= RPL_MASK; 97 TrapFrame->Dr7 = 0; 98 99 /* Set the previous mode as user */ 100 TrapFrame->PreviousMode = UserMode; 101 102 /* Terminate the Exception Handler List */ 103 TrapFrame->ExceptionFrame = 0; 104 105 /* KiThreadStartup returns to KiUserThreadStartupExit */ 106 StartFrame->Return = (ULONG64)KiUserThreadStartupExit; 107 108 /* KiUserThreadStartupExit returns to KiServiceExit3 */ 109 InitFrame->ExceptionFrame.Return = (ULONG64)KiServiceExit3; 110 } 111 else 112 { 113 PKKINIT_FRAME InitFrame; 114 115 /* Set up the Initial Frame for the system thread */ 116 InitFrame = ((PKKINIT_FRAME)Thread->InitialStack) - 1; 117 StartFrame = &InitFrame->StartFrame; 118 CtxSwitchFrame = &InitFrame->CtxSwitchFrame; 119 120 /* Save back the new value of the kernel stack. */ 121 Thread->KernelStack = (PVOID)InitFrame; 122 123 /* Tell the thread it will run in Kernel Mode */ 124 Thread->PreviousMode = KernelMode; 125 126 // FIXME Setup the Fx Area 127 128 /* No NPX State */ 129 Thread->NpxState = 0xA; 130 131 /* This must never return! */ 132 StartFrame->Return = (ULONG64)KiInvalidSystemThreadStartupExit; 133 } 134 135 /* Set up the Context Switch Frame */ 136 CtxSwitchFrame->Return = (ULONG64)KiThreadStartup; 137 CtxSwitchFrame->ApcBypass = TRUE; 138 139 StartFrame->P1Home = (ULONG64)StartRoutine; 140 StartFrame->P2Home = (ULONG64)StartContext; 141 StartFrame->P3Home = 0; 142 StartFrame->P4Home = (ULONG64)SystemRoutine; 143 StartFrame->Reserved = 0; 144 } 145 146 BOOLEAN 147 KiSwapContextResume( 148 _In_ BOOLEAN ApcBypass, 149 _In_ PKTHREAD OldThread, 150 _In_ PKTHREAD NewThread) 151 { 152 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 153 PKPROCESS OldProcess, NewProcess; 154 155 /* Setup ring 0 stack pointer */ 156 Pcr->TssBase->Rsp0 = (ULONG64)NewThread->InitialStack; // FIXME: NPX save area? 157 Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; 158 159 /* Now we are the new thread. Check if it's in a new process */ 160 OldProcess = OldThread->ApcState.Process; 161 NewProcess = NewThread->ApcState.Process; 162 if (OldProcess != NewProcess) 163 { 164 /* Switch address space and flush TLB */ 165 __writecr3(NewProcess->DirectoryTableBase[0]); 166 167 /* Set new TSS fields */ 168 //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; 169 } 170 171 /* Set TEB pointer and GS base */ 172 Pcr->NtTib.Self = (PVOID)NewThread->Teb; 173 if (NewThread->Teb) 174 { 175 /* This will switch the usermode gs */ 176 __writemsr(MSR_GS_SWAP, (ULONG64)NewThread->Teb); 177 } 178 179 /* Increase context switch count */ 180 Pcr->ContextSwitches++; 181 NewThread->ContextSwitches++; 182 183 /* DPCs shouldn't be active */ 184 if (Pcr->Prcb.DpcRoutineActive) 185 { 186 /* Crash the machine */ 187 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC, 188 (ULONG_PTR)OldThread, 189 (ULONG_PTR)NewThread, 190 (ULONG_PTR)OldThread->InitialStack, 191 0); 192 } 193 194 /* Old thread os no longer busy */ 195 OldThread->SwapBusy = FALSE; 196 197 /* Kernel APCs may be pending */ 198 if (NewThread->ApcState.KernelApcPending) 199 { 200 /* Are APCs enabled? */ 201 if ((NewThread->SpecialApcDisable == 0) && 202 (ApcBypass == 0)) 203 { 204 /* Return TRUE to indicate that we want APCs to be delivered */ 205 return TRUE; 206 } 207 208 /* Request an APC interrupt to be delivered later */ 209 HalRequestSoftwareInterrupt(APC_LEVEL); 210 } 211 212 /* Return stating that no kernel APCs are pending*/ 213 return FALSE; 214 } 215 216 /* EOF */ 217 218 219