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 #define MAX_SYSCALL_PARAMS 16 88 89 NTSTATUS 90 NtSyscallFailure(void) 91 { 92 /* This is the failure function */ 93 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax; 94 } 95 96 PVOID 97 KiSystemCallHandler( 98 VOID) 99 { 100 PKTRAP_FRAME TrapFrame; 101 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 102 PKTHREAD Thread; 103 PULONG64 KernelParams, UserParams; 104 ULONG ServiceNumber, Offset, Count; 105 ULONG64 UserRsp; 106 107 /* Get a pointer to the trap frame */ 108 TrapFrame = (PKTRAP_FRAME)((PULONG64)_AddressOfReturnAddress() + 1 + MAX_SYSCALL_PARAMS); 109 110 /* Increase system call count */ 111 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); 112 113 /* Get the current thread */ 114 Thread = KeGetCurrentThread(); 115 116 /* Set previous mode */ 117 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; 118 119 /* Save the old trap frame and set the new */ 120 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; 121 Thread->TrapFrame = TrapFrame; 122 123 /* We don't have an exception frame yet */ 124 TrapFrame->ExceptionFrame = 0; 125 126 /* Before enabling interrupts get the user rsp from the KPCR */ 127 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); 128 TrapFrame->Rsp = UserRsp; 129 130 /* Enable interrupts */ 131 _enable(); 132 133 /* If the usermode rsp was not a usermode address, prepare an exception */ 134 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; 135 136 /* Get the address of the usermode and kernelmode parameters */ 137 UserParams = (PULONG64)UserRsp + 1; 138 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; 139 140 /* Get the system call number from the trap frame and decode it */ 141 ServiceNumber = (ULONG)TrapFrame->Rax; 142 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 143 ServiceNumber &= SERVICE_NUMBER_MASK; 144 145 /* Check for win32k system calls */ 146 if (Offset & SERVICE_TABLE_TEST) 147 { 148 ULONG GdiBatchCount; 149 150 /* Read the GDI batch count from the TEB */ 151 _SEH2_TRY 152 { 153 GdiBatchCount = NtCurrentTeb()->GdiBatchCount; 154 } 155 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 156 { 157 GdiBatchCount = 0; 158 } 159 _SEH2_END; 160 161 /* Flush batch, if there are entries */ 162 if (GdiBatchCount != 0) 163 { 164 KeGdiFlushUserBatch(); 165 } 166 } 167 168 /* Get descriptor table */ 169 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 170 171 /* Validate the system call number */ 172 if (ServiceNumber >= DescriptorTable->Limit) 173 { 174 /* Check if this is a GUI call */ 175 if (!(Offset & SERVICE_TABLE_TEST)) 176 { 177 /* Fail the call */ 178 TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE; 179 return (PVOID)NtSyscallFailure; 180 } 181 182 /* Convert us to a GUI thread 183 To be entirely correct. we return KiConvertToGuiThread, 184 which allocates a new stack, switches to it, calls 185 PsConvertToGuiThread and resumes in the middle of 186 KiSystemCallEntry64 to restart the system call handling. */ 187 return (PVOID)KiConvertToGuiThread; 188 } 189 190 /* Get stack bytes and calculate argument count */ 191 Count = DescriptorTable->Number[ServiceNumber] / 8; 192 193 _SEH2_TRY 194 { 195 switch (Count) 196 { 197 case 16: KernelParams[15] = UserParams[15]; 198 case 15: KernelParams[14] = UserParams[14]; 199 case 14: KernelParams[13] = UserParams[13]; 200 case 13: KernelParams[12] = UserParams[12]; 201 case 12: KernelParams[11] = UserParams[11]; 202 case 11: KernelParams[10] = UserParams[10]; 203 case 10: KernelParams[9] = UserParams[9]; 204 case 9: KernelParams[8] = UserParams[8]; 205 case 8: KernelParams[7] = UserParams[7]; 206 case 7: KernelParams[6] = UserParams[6]; 207 case 6: KernelParams[5] = UserParams[5]; 208 case 5: KernelParams[4] = UserParams[4]; 209 case 4: 210 case 3: 211 case 2: 212 case 1: 213 case 0: 214 break; 215 216 default: 217 ASSERT(FALSE); 218 break; 219 } 220 } 221 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 222 { 223 TrapFrame->Rax = _SEH2_GetExceptionCode(); 224 return (PVOID)NtSyscallFailure; 225 } 226 _SEH2_END; 227 228 return (PVOID)DescriptorTable->Base[ServiceNumber]; 229 } 230 231 232 // FIXME: we need to 233 VOID 234 KiSystemService(IN PKTHREAD Thread, 235 IN PKTRAP_FRAME TrapFrame, 236 IN ULONG Instruction) 237 { 238 UNIMPLEMENTED; 239 __debugbreak(); 240 } 241 242