ReactOS 0.4.15-dev-7907-g95bf896
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
87#define MAX_SYSCALL_PARAMS 16
88
91{
92 /* This is the failure function */
93 return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax;
94}
95
98 VOID)
99{
100 PKTRAP_FRAME TrapFrame;
101 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
103 PULONG64 KernelParams, UserParams;
104 ULONG ServiceNumber, TableIndex, Count;
105 ULONG64 UserRsp;
106
107 /* Get a pointer to the trap frame */
109
110 /* Increase system call count */
111 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
112
113 /* Get the current thread */
115
116 /* Set previous mode */
117 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode;
118
119 /* We don't have an exception frame yet */
120 TrapFrame->ExceptionFrame = 0;
121
122 /* Before enabling interrupts get the user rsp from the KPCR */
123 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp));
124 TrapFrame->Rsp = UserRsp;
125
126 /* Enable interrupts */
127 _enable();
128
129 /* If the usermode rsp was not a usermode address, prepare an exception */
130 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress;
131
132 /* Get the address of the usermode and kernelmode parameters */
133 UserParams = (PULONG64)UserRsp + 1;
134 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS;
135
136 /* Get the system call number from the trap frame and decode it */
137 ServiceNumber = (ULONG)TrapFrame->Rax;
138 TableIndex = (ServiceNumber >> TABLE_OFFSET_BITS) & ((1 << TABLE_NUMBER_BITS) - 1);
139 ServiceNumber &= SERVICE_NUMBER_MASK;
140
141 /* Check for win32k system calls */
142 if (TableIndex == WIN32K_SERVICE_INDEX)
143 {
144 ULONG GdiBatchCount;
145
146 /* Read the GDI batch count from the TEB */
148 {
149 GdiBatchCount = NtCurrentTeb()->GdiBatchCount;
150 }
152 {
153 GdiBatchCount = 0;
154 }
155 _SEH2_END;
156
157 /* Flush batch, if there are entries */
158 if (GdiBatchCount != 0)
159 {
161 }
162 }
163
164 /* Get descriptor table */
165 DescriptorTable = &((PKSERVICE_TABLE_DESCRIPTOR)Thread->ServiceTable)[TableIndex];
166
167 /* Validate the system call number */
168 if (ServiceNumber >= DescriptorTable->Limit)
169 {
170 /* Check if this is a GUI call and this is not a GUI thread yet */
171 if ((TableIndex == WIN32K_SERVICE_INDEX) &&
172 (Thread->ServiceTable == KeServiceDescriptorTable))
173 {
174 /* Convert this thread to a GUI thread.
175 It is invalid to change the stack in the middle of a C function,
176 therefore we return KiConvertToGuiThread to the system call entry
177 point, which then calls the asm function KiConvertToGuiThread,
178 which allocates a new stack, switches to it, calls
179 PsConvertToGuiThread and resumes in the middle of
180 KiSystemCallEntry64 to restart the system call handling.
181 If converting fails, the system call returns a failure code. */
183 }
184
185 /* Fail the call */
187 return (PVOID)NtSyscallFailure;
188 }
189
190 /* Get stack bytes and calculate argument count */
191 Count = DescriptorTable->Number[ServiceNumber] / 8;
192
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 }
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
233VOID
235 IN PKTRAP_FRAME TrapFrame,
237{
239 __debugbreak();
240}
241
@ Instruction
Definition: asmpp.cpp:82
LONG NTSTATUS
Definition: precomp.h:26
#define UNIMPLEMENTED
Definition: debug.h:115
#define _Requires_lock_not_held_(lock)
#define NULL
Definition: types.h:112
#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
#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 UserMode
Definition: asm.h:35
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1146
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 FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
VOID NTAPI KiQuantumEnd(VOID)
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
volatile ULONG DpcQueueDepth
Definition: ketypes.h:858
UCHAR QuantumEnd
Definition: ketypes.h:765
KDPC_DATA DpcData[2]
Definition: ketypes.h:745
struct _KTHREAD * CurrentThread
Definition: ketypes.h:635
struct _KTHREAD * NextThread
Definition: ketypes.h:636
UINT64 TimerRequest
Definition: ketypes.h:760
SINGLE_LIST_ENTRY DeferredReadyListHead
Definition: ketypes.h:697
PVOID DpcStack
Definition: ketypes.h:746
UCHAR WaitReason
Definition: ketypes.h:1964
volatile UCHAR State
Definition: ketypes.h:1789
UINT64 Rsp
Definition: ketypes.h:456
CHAR PreviousMode
Definition: ketypes.h:383
UINT64 ExceptionFrame
Definition: ketypes.h:446
UINT64 Rax
Definition: ketypes.h:388
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629
#define MAX_SYSCALL_PARAMS
Definition: traphandler.c:87
NTSTATUS KiConvertToGuiThread(VOID)
NTSTATUS NtSyscallFailure(void)
Definition: traphandler.c:90
PVOID KiSystemCallHandler(VOID)
Definition: traphandler.c:97
VOID KiRetireDpcListInDpcStack(PKPRCB Prcb, PVOID DpcStack)
VOID KiSystemService(IN PKTHREAD Thread, IN PKTRAP_FRAME TrapFrame, IN ULONG Instruction)
Definition: traphandler.c:234
#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