1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * PURPOSE: x64 trap handlers 5 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 6 */ 7 8 /* INCLUDES ******************************************************************/ 9 10 #include <ntoskrnl.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 VOID 16 KiRetireDpcListInDpcStack( 17 PKPRCB Prcb, 18 PVOID DpcStack); 19 20 NTSTATUS 21 KiConvertToGuiThread( 22 VOID); 23 24 _Requires_lock_not_held_(Prcb->PrcbLock) 25 VOID 26 NTAPI 27 KiDpcInterruptHandler(VOID) 28 { 29 PKPRCB Prcb = KeGetCurrentPrcb(); 30 PKTHREAD NewThread, OldThread; 31 KIRQL OldIrql; 32 33 /* Raise to DISPATCH_LEVEL */ 34 OldIrql = KfRaiseIrql(DISPATCH_LEVEL); 35 36 /* Send an EOI */ 37 KiSendEOI(); 38 39 /* Check for pending timers, pending DPCs, or pending ready threads */ 40 if ((Prcb->DpcData[0].DpcQueueDepth) || 41 (Prcb->TimerRequest) || 42 (Prcb->DeferredReadyListHead.Next)) 43 { 44 /* Retire DPCs while under the DPC stack */ 45 KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack); 46 } 47 48 /* Enable interrupts */ 49 _enable(); 50 51 /* Check for quantum end */ 52 if (Prcb->QuantumEnd) 53 { 54 /* Handle quantum end */ 55 Prcb->QuantumEnd = FALSE; 56 KiQuantumEnd(); 57 } 58 else if (Prcb->NextThread) 59 { 60 /* Acquire the PRCB lock */ 61 KiAcquirePrcbLock(Prcb); 62 63 /* Capture current thread data */ 64 OldThread = Prcb->CurrentThread; 65 NewThread = Prcb->NextThread; 66 67 /* Set new thread data */ 68 Prcb->NextThread = NULL; 69 Prcb->CurrentThread = NewThread; 70 71 /* The thread is now running */ 72 NewThread->State = Running; 73 OldThread->WaitReason = WrDispatchInt; 74 75 /* Make the old thread ready */ 76 KxQueueReadyThread(OldThread, Prcb); 77 78 /* Swap to the new thread */ 79 KiSwapContext(APC_LEVEL, OldThread); 80 } 81 82 /* Disable interrupts and go back to old irql */ 83 _disable(); 84 KeLowerIrql(OldIrql); 85 } 86 87 VOID 88 KiNmiInterruptHandler( 89 _In_ PKTRAP_FRAME TrapFrame, 90 _In_ PKEXCEPTION_FRAME ExceptionFrame) 91 { 92 BOOLEAN ManualSwapGs = FALSE; 93 94 /* Check if the NMI came from kernel mode */ 95 if ((TrapFrame->SegCs & MODE_MASK) == 0) 96 { 97 /* Check if GS base is already kernel mode. This is needed, because 98 we might be interrupted during an interrupt/exception from user-mode 99 before the swapgs instruction. */ 100 if ((LONG64)__readmsr(MSR_GS_BASE) >= 0) 101 { 102 /* Swap GS to kernel */ 103 __swapgs(); 104 ManualSwapGs = TRUE; 105 } 106 } 107 108 /* Check if this is a freeze */ 109 if (KiProcessorFreezeHandler(TrapFrame, ExceptionFrame)) 110 { 111 /* NMI was handled */ 112 goto Exit; 113 } 114 115 /* Handle the NMI */ 116 KiHandleNmi(); 117 118 Exit: 119 /* Check if we need to swap GS back */ 120 if (ManualSwapGs) 121 { 122 /* Swap GS back to user */ 123 __swapgs(); 124 } 125 } 126 127 #define MAX_SYSCALL_PARAMS 16 128 129 NTSTATUS 130 NtSyscallFailure(void) 131 { 132 /* This is the failure function */ 133 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax; 134 } 135 136 PVOID 137 KiSystemCallHandler( 138 VOID) 139 { 140 PKTRAP_FRAME TrapFrame; 141 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 142 PKTHREAD Thread; 143 PULONG64 KernelParams, UserParams; 144 ULONG ServiceNumber, TableIndex, Count; 145 ULONG64 UserRsp; 146 147 /* Get a pointer to the trap frame */ 148 TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS); 149 150 /* Increase system call count */ 151 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 152 153 /* Get the current thread */ 154 Thread = KeGetCurrentThread(); 155 156 /* Set previous mode */ 157 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 158 159 /* We don't have an exception frame yet */ 160 TrapFrame->ExceptionFrame = 0; 161 162 /* Get the user Stack pointer */ 163 UserRsp = TrapFrame->Rsp; 164 165 /* Enable interrupts */ 166 _enable(); 167 168 /* If the usermode rsp was not a usermode address, prepare an exception */ 169 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 170 171 /* Get the address of the usermode and kernelmode parameters */ 172 UserParams = (PULONG64)UserRsp + 1; 173 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 174 175 /* Get the system call number from the trap frame and decode it */ 176 ServiceNumber = (ULONG)TrapFrame->Rax; 177 TableIndex = (ServiceNumber >> TABLE_OFFSET_BITS) & ((1 << TABLE_NUMBER_BITS) - 1); 178 ServiceNumber &= SERVICE_NUMBER_MASK; 179 180 /* Check for win32k system calls */ 181 if (TableIndex == WIN32K_SERVICE_INDEX) 182 { 183 ULONG GdiBatchCount; 184 185 /* Read the GDI batch count from the TEB */ 186 _SEH2_TRY 187 { 188 GdiBatchCount = NtCurrentTeb()->GdiBatchCount; 189 } 190 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 191 { 192 GdiBatchCount = 0; 193 } 194 _SEH2_END; 195 196 /* Flush batch, if there are entries */ 197 if (GdiBatchCount != 0) 198 { 199 KeGdiFlushUserBatch(); 200 } 201 } 202 203 /* Get descriptor table */ 204 DescriptorTable = &((PKSERVICE_TABLE_DESCRIPTOR)Thread->ServiceTable)[TableIndex]; 205 206 /* Validate the system call number */ 207 if (ServiceNumber >= DescriptorTable->Limit) 208 { 209 /* Check if this is a GUI call and this is not a GUI thread yet */ 210 if ((TableIndex == WIN32K_SERVICE_INDEX) && 211 (Thread->ServiceTable == KeServiceDescriptorTable)) 212 { 213 /* Convert this thread to a GUI thread. 214 It is invalid to change the stack in the middle of a C function, 215 therefore we return KiConvertToGuiThread to the system call entry 216 point, which then calls the asm function KiConvertToGuiThread, 217 which allocates a new stack, switches to it, calls 218 PsConvertToGuiThread and resumes in the middle of 219 KiSystemCallEntry64 to restart the system call handling. 220 If converting fails, the system call returns a failure code. */ 221 return (PVOID)KiConvertToGuiThread; 222 } 223 224 /* Fail the call */ 225 TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE; 226 return (PVOID)NtSyscallFailure; 227 } 228 229 /* Get stack bytes and calculate argument count */ 230 Count = DescriptorTable->Number[ServiceNumber] / 8; 231 232 _SEH2_TRY 233 { 234 switch (Count) 235 { 236 case 16: KernelParams[15] = UserParams[15]; 237 case 15: KernelParams[14] = UserParams[14]; 238 case 14: KernelParams[13] = UserParams[13]; 239 case 13: KernelParams[12] = UserParams[12]; 240 case 12: KernelParams[11] = UserParams[11]; 241 case 11: KernelParams[10] = UserParams[10]; 242 case 10: KernelParams[9] = UserParams[9]; 243 case 9: KernelParams[8] = UserParams[8]; 244 case 8: KernelParams[7] = UserParams[7]; 245 case 7: KernelParams[6] = UserParams[6]; 246 case 6: KernelParams[5] = UserParams[5]; 247 case 5: KernelParams[4] = UserParams[4]; 248 case 4: 249 case 3: 250 case 2: 251 case 1: 252 case 0: 253 break; 254 255 default: 256 ASSERT(FALSE); 257 break; 258 } 259 } 260 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 261 { 262 TrapFrame->Rax = _SEH2_GetExceptionCode(); 263 return (PVOID)NtSyscallFailure; 264 } 265 _SEH2_END; 266 267 return (PVOID)DescriptorTable->Base[ServiceNumber]; 268 } 269 270 271 // FIXME: we need to 272 VOID 273 KiSystemService(IN PKTHREAD Thread, 274 IN PKTRAP_FRAME TrapFrame, 275 IN ULONG Instruction) 276 { 277 UNIMPLEMENTED; 278 __debugbreak(); 279 } 280 281