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