ReactOS 0.4.16-dev-1028-g8602629
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 /* 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 */
187 {
188 GdiBatchCount = NtCurrentTeb()->GdiBatchCount;
189 }
191 {
192 GdiBatchCount = 0;
193 }
194 _SEH2_END;
195
196 /* Flush batch, if there are entries */
197 if (GdiBatchCount != 0)
198 {
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. */
222 }
223
224 /* Fail the call */
226 return (PVOID)NtSyscallFailure;
227 }
228
229 /* Get stack bytes and calculate argument count */
230 Count = DescriptorTable->Number[ServiceNumber] / 8;
231
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 }
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
272VOID
274 IN PKTRAP_FRAME TrapFrame,
276{
278 __debugbreak();
279}
280
unsigned char BOOLEAN
@ Instruction
Definition: asmpp.cpp:82
LONG NTSTATUS
Definition: precomp.h:26
#define MODE_MASK
Definition: orders.h:326
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
#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
_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:90
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
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1182
#define MSR_GS_BASE
Definition: ketypes.h:257
struct _KTRAP_FRAME * PKTRAP_FRAME
#define UserMode
Definition: asm.h:39
#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
#define _In_
Definition: no_sal2.h:158
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:43
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
VOID NTAPI KiQuantumEnd(VOID)
BOOLEAN NTAPI KiHandleNmi(VOID)
Definition: bug.c:1169
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:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
static void Exit(void)
Definition: sock.c:1330
volatile ULONG DpcQueueDepth
Definition: ketypes.h:858
UINT64 TimerRequest
Definition: ketypes.h:784
KDPC_DATA DpcData[2]
Definition: ketypes.h:769
UCHAR QuantumEnd
Definition: ketypes.h:789
struct _KTHREAD * CurrentThread
Definition: ketypes.h:659
struct _KTHREAD * NextThread
Definition: ketypes.h:660
SINGLE_LIST_ENTRY DeferredReadyListHead
Definition: ketypes.h:721
PVOID DpcStack
Definition: ketypes.h:770
UCHAR WaitReason
Definition: ketypes.h:1964
volatile UCHAR State
Definition: ketypes.h:1789
UINT64 Rsp
Definition: ketypes.h:480
CHAR PreviousMode
Definition: ketypes.h:407
UINT64 ExceptionFrame
Definition: ketypes.h:470
UINT64 Rax
Definition: ketypes.h:412
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:637
#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:273
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