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 81 /* Set up a trap frame from the context. */ 82 KeContextToTrapFrame(Context, 83 NULL, 84 TrapFrame, 85 CONTEXT_AMD64 | ContextFlags, 86 UserMode); 87 88 /* Set SS, DS, ES's RPL Mask properly */ 89 TrapFrame->SegSs |= RPL_MASK; 90 TrapFrame->SegDs |= RPL_MASK; 91 TrapFrame->SegEs |= RPL_MASK; 92 TrapFrame->Dr7 = 0; 93 94 /* Set the previous mode as user */ 95 TrapFrame->PreviousMode = UserMode; 96 97 /* Terminate the Exception Handler List */ 98 TrapFrame->ExceptionFrame = 0; 99 100 /* We return to ... */ 101 StartFrame->Return = (ULONG64)KiServiceExit2; 102 } 103 else 104 { 105 PKKINIT_FRAME InitFrame; 106 107 /* Set up the Initial Frame for the system thread */ 108 InitFrame = ((PKKINIT_FRAME)Thread->InitialStack) - 1; 109 StartFrame = &InitFrame->StartFrame; 110 CtxSwitchFrame = &InitFrame->CtxSwitchFrame; 111 112 /* Save back the new value of the kernel stack. */ 113 Thread->KernelStack = (PVOID)InitFrame; 114 115 /* Tell the thread it will run in Kernel Mode */ 116 Thread->PreviousMode = KernelMode; 117 118 // FIXME Setup the Fx Area 119 120 /* No NPX State */ 121 Thread->NpxState = 0xA; 122 123 /* We have no return address! */ 124 StartFrame->Return = 0; 125 } 126 127 /* Set up the Context Switch Frame */ 128 CtxSwitchFrame->Return = (ULONG64)KiThreadStartup; 129 CtxSwitchFrame->ApcBypass = FALSE; 130 131 StartFrame->P1Home = (ULONG64)StartRoutine; 132 StartFrame->P2Home = (ULONG64)StartContext; 133 StartFrame->P3Home = 0; 134 StartFrame->P4Home = (ULONG64)SystemRoutine; 135 StartFrame->Reserved = 0; 136 } 137 138 BOOLEAN 139 KiSwapContextResume( 140 IN PKTHREAD NewThread, 141 IN PKTHREAD OldThread, 142 IN BOOLEAN ApcBypass) 143 { 144 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 145 PKPROCESS OldProcess, NewProcess; 146 147 /* Setup ring 0 stack pointer */ 148 Pcr->TssBase->Rsp0 = (ULONG64)NewThread->InitialStack; // FIXME: NPX save area? 149 Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; 150 151 /* Now we are the new thread. Check if it's in a new process */ 152 OldProcess = OldThread->ApcState.Process; 153 NewProcess = NewThread->ApcState.Process; 154 if (OldProcess != NewProcess) 155 { 156 /* Switch address space and flush TLB */ 157 __writecr3(NewProcess->DirectoryTableBase[0]); 158 159 /* Set new TSS fields */ 160 //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; 161 } 162 163 /* Set TEB pointer and GS base */ 164 Pcr->NtTib.Self = (PVOID)NewThread->Teb; 165 if (NewThread->Teb) 166 { 167 /* This will switch the usermode gs */ 168 __writemsr(MSR_GS_SWAP, (ULONG64)NewThread->Teb); 169 } 170 171 /* Increase context switch count */ 172 Pcr->ContextSwitches++; 173 NewThread->ContextSwitches++; 174 175 /* DPCs shouldn't be active */ 176 if (Pcr->Prcb.DpcRoutineActive) 177 { 178 /* Crash the machine */ 179 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC, 180 (ULONG_PTR)OldThread, 181 (ULONG_PTR)NewThread, 182 (ULONG_PTR)OldThread->InitialStack, 183 0); 184 } 185 186 /* Kernel APCs may be pending */ 187 if (NewThread->ApcState.KernelApcPending) 188 { 189 /* Are APCs enabled? */ 190 if (!NewThread->SpecialApcDisable) 191 { 192 /* Request APC delivery */ 193 if (!ApcBypass) 194 HalRequestSoftwareInterrupt(APC_LEVEL); 195 else 196 return TRUE; 197 } 198 } 199 200 /* Return stating that no kernel APCs are pending*/ 201 return FALSE; 202 } 203 204 /* EOF */ 205 206 207