ReactOS 0.4.15-dev-7961-gdcf9eb0
traphandler.c
Go to the documentation of this file.
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
15VOID
17 PKPRCB Prcb,
18 PVOID DpcStack);
19
22 VOID);
23
25VOID
27KiDpcInterruptHandler(VOID)
28{
29 PKPRCB Prcb = KeGetCurrentPrcb();
30 PKTHREAD NewThread, OldThread;
32
33 /* Raise to 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) ||
43 {
44 /* Retire DPCs while under the DPC stack */
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;
57 }
58 else if (Prcb->NextThread)
59 {
60 /* Acquire the PRCB lock */
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();
85}
86
87VOID
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
118Exit:
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
131{
132 /* This is the failure function */
133 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax;
134}
135
136PVOID
138 VOID)
139{
140 PKTRAP_FRAME TrapFrame;
141 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
143 PULONG64 KernelParams, UserParams;
144 ULONG ServiceNumber, TableIndex, Count;
145 ULONG64 UserRsp;
146
147 /* Get a pointer to the trap frame */
149
150 /* Increase system call count */
151 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
152
153 /* Get the current thread */
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 /* Before enabling interrupts get the user rsp from the KPCR */
163 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp));
164 TrapFrame->Rsp = UserRsp;
165
166 /* Enable interrupts */
167 _enable();
168
169 /* If the usermode rsp was not a usermode address, prepare an exception */
170 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress;
171
172 /* Get the address of the usermode and kernelmode parameters */
173 UserParams = (PULONG64)UserRsp + 1;
174 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS;
175
176 /* Get the system call number from the trap frame and decode it */
177 ServiceNumber = (ULONG)TrapFrame->Rax;
178 TableIndex = (ServiceNumber >> TABLE_OFFSET_BITS) & ((1 << TABLE_NUMBER_BITS) - 1);
179 ServiceNumber &= SERVICE_NUMBER_MASK;
180
181 /* Check for win32k system calls */
182 if (TableIndex == WIN32K_SERVICE_INDEX)
183 {
184 ULONG GdiBatchCount;
185
186 /* Read the GDI batch count from the TEB */
188 {
189 GdiBatchCount = NtCurrentTeb()->GdiBatchCount;
190 }
192 {
193 GdiBatchCount = 0;
194 }
195 _SEH2_END;
196
197 /* Flush batch, if there are entries */
198 if (GdiBatchCount != 0)
199 {
201 }
202 }
203
204 /* Get descriptor table */
205 DescriptorTable = &((PKSERVICE_TABLE_DESCRIPTOR)Thread->ServiceTable)[TableIndex];
206
207 /* Validate the system call number */
208 if (ServiceNumber >= DescriptorTable->Limit)
209 {
210 /* Check if this is a GUI call and this is not a GUI thread yet */
211 if ((TableIndex == WIN32K_SERVICE_INDEX) &&
212 (Thread->ServiceTable == KeServiceDescriptorTable))
213 {
214 /* Convert this thread to a GUI thread.
215 It is invalid to change the stack in the middle of a C function,
216 therefore we return KiConvertToGuiThread to the system call entry
217 point, which then calls the asm function KiConvertToGuiThread,
218 which allocates a new stack, switches to it, calls
219 PsConvertToGuiThread and resumes in the middle of
220 KiSystemCallEntry64 to restart the system call handling.
221 If converting fails, the system call returns a failure code. */
223 }
224
225 /* Fail the call */
227 return (PVOID)NtSyscallFailure;
228 }
229
230 /* Get stack bytes and calculate argument count */
231 Count = DescriptorTable->Number[ServiceNumber] / 8;
232
234 {
235 switch (Count)
236 {
237 case 16: KernelParams[15] = UserParams[15];
238 case 15: KernelParams[14] = UserParams[14];
239 case 14: KernelParams[13] = UserParams[13];
240 case 13: KernelParams[12] = UserParams[12];
241 case 12: KernelParams[11] = UserParams[11];
242 case 11: KernelParams[10] = UserParams[10];
243 case 10: KernelParams[9] = UserParams[9];
244 case 9: KernelParams[8] = UserParams[8];
245 case 8: KernelParams[7] = UserParams[7];
246 case 7: KernelParams[6] = UserParams[6];
247 case 6: KernelParams[5] = UserParams[5];
248 case 5: KernelParams[4] = UserParams[4];
249 case 4:
250 case 3:
251 case 2:
252 case 1:
253 case 0:
254 break;
255
256 default:
257 ASSERT(FALSE);
258 break;
259 }
260 }
262 {
263 TrapFrame->Rax = _SEH2_GetExceptionCode();
264 return (PVOID)NtSyscallFailure;
265 }
266 _SEH2_END;
267
268 return (PVOID)DescriptorTable->Base[ServiceNumber];
269}
270
271
272// FIXME: we need to
273VOID
275 IN PKTRAP_FRAME TrapFrame,
277{
279 __debugbreak();
280}
281
unsigned char BOOLEAN
@ Instruction
Definition: asmpp.cpp:82
LONG NTSTATUS
Definition: precomp.h:26
#define MODE_MASK
Definition: orders.h:326
#define UNIMPLEMENTED
Definition: debug.h:115
#define _Requires_lock_not_held_(lock)
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
PPC_QUAL unsigned long long __readmsr()
Definition: intrin_ppc.h:741
#define _AddressOfReturnAddress()
Definition: intrin_ppc.h:40
#define NtCurrentTeb
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 * PULONG64
Definition: imports.h:198
unsigned __int64 ULONG64
Definition: imports.h:198
#define _In_
Definition: ms_sal.h:308
#define UserMode
Definition: asm.h:35
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1161
#define MSR_GS_BASE
Definition: ketypes.h:253
struct _KTRAP_FRAME * PKTRAP_FRAME
#define WIN32K_SERVICE_INDEX
Definition: ketypes.h:49
#define TABLE_OFFSET_BITS
Definition: ketypes.h:42
#define SERVICE_NUMBER_MASK
Definition: ketypes.h:83
@ Running
Definition: ketypes.h:390
struct _KSERVICE_TABLE_DESCRIPTOR * PKSERVICE_TABLE_DESCRIPTOR
#define TABLE_NUMBER_BITS
Definition: ketypes.h:41
int Count
Definition: noreturn.cpp:7
FORCEINLINE VOID KiSendEOI(VOID)
Definition: ke.h:346
BOOLEAN KiProcessorFreezeHandler(_In_ PKTRAP_FRAME TrapFrame, _In_ PKEXCEPTION_FRAME ExceptionFrame)
Definition: freeze.c:21
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
VOID NTAPI KiQuantumEnd(VOID)
BOOLEAN NTAPI KiHandleNmi(VOID)
Definition: bug.c:1165
PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch
Definition: win32.c:20
ULONG MmUserProbeAddress
Definition: init.c:50
#define STATUS_INVALID_SYSTEM_SERVICE
Definition: ntstatus.h:265
KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[SSDT_MAX_ENTRIES]
Definition: procobj.c:23
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
static void Exit(void)
Definition: sock.c:1330
volatile ULONG DpcQueueDepth
Definition: ketypes.h:858
UCHAR QuantumEnd
Definition: ketypes.h:780
KDPC_DATA DpcData[2]
Definition: ketypes.h:760
struct _KTHREAD * CurrentThread
Definition: ketypes.h:650
struct _KTHREAD * NextThread
Definition: ketypes.h:651
UINT64 TimerRequest
Definition: ketypes.h:775
SINGLE_LIST_ENTRY DeferredReadyListHead
Definition: ketypes.h:712
PVOID DpcStack
Definition: ketypes.h:761
UCHAR WaitReason
Definition: ketypes.h:1964
volatile UCHAR State
Definition: ketypes.h:1789
UINT64 Rsp
Definition: ketypes.h:471
CHAR PreviousMode
Definition: ketypes.h:398
UINT64 ExceptionFrame
Definition: ketypes.h:461
UINT64 Rax
Definition: ketypes.h:403
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629
#define MAX_SYSCALL_PARAMS
Definition: traphandler.c:127
NTSTATUS KiConvertToGuiThread(VOID)
VOID KiNmiInterruptHandler(_In_ PKTRAP_FRAME TrapFrame, _In_ PKEXCEPTION_FRAME ExceptionFrame)
Definition: traphandler.c:88
NTSTATUS NtSyscallFailure(void)
Definition: traphandler.c:130
PVOID KiSystemCallHandler(VOID)
Definition: traphandler.c:137
VOID KiRetireDpcListInDpcStack(PKPRCB Prcb, PVOID DpcStack)
VOID KiSystemService(IN PKTHREAD Thread, IN PKTRAP_FRAME TrapFrame, IN ULONG Instruction)
Definition: traphandler.c:274
int64_t LONG64
Definition: typedefs.h:68
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ WrDispatchInt
Definition: ketypes.h:446