ReactOS  0.4.15-dev-5137-g826bd41
stubs.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: stubs
5  * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
6  */
7 
8 /* INCLUDES ******************************************************************/
9 
10 #include <ntoskrnl.h>
11 #include <fltkernel.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
18 
19 VOID
21  PKPRCB Prcb,
22  PVOID DpcStack);
23 
26  VOID);
27 
28 _Requires_lock_not_held_(Prcb->PrcbLock)
29 VOID
30 NTAPI
31 KiDpcInterruptHandler(VOID)
32 {
33  PKPRCB Prcb = KeGetCurrentPrcb();
34  PKTHREAD NewThread, OldThread;
35  KIRQL OldIrql;
36 
37  /* Raise to DISPATCH_LEVEL */
39 
40  /* Send an EOI */
41  KiSendEOI();
42 
43  /* Check for pending timers, pending DPCs, or pending ready threads */
44  if ((Prcb->DpcData[0].DpcQueueDepth) ||
45  (Prcb->TimerRequest) ||
47  {
48  /* Retire DPCs while under the DPC stack */
50  }
51 
52  /* Enable interrupts */
53  _enable();
54 
55  /* Check for quantum end */
56  if (Prcb->QuantumEnd)
57  {
58  /* Handle quantum end */
59  Prcb->QuantumEnd = FALSE;
60  KiQuantumEnd();
61  }
62  else if (Prcb->NextThread)
63  {
64  /* Acquire the PRCB lock */
65  KiAcquirePrcbLock(Prcb);
66 
67  /* Capture current thread data */
68  OldThread = Prcb->CurrentThread;
69  NewThread = Prcb->NextThread;
70 
71  /* Set new thread data */
72  Prcb->NextThread = NULL;
73  Prcb->CurrentThread = NewThread;
74 
75  /* The thread is now running */
76  NewThread->State = Running;
77  OldThread->WaitReason = WrDispatchInt;
78 
79  /* Make the old thread ready */
80  KxQueueReadyThread(OldThread, Prcb);
81 
82  /* Swap to the new thread */
83  KiSwapContext(APC_LEVEL, OldThread);
84  }
85 
86  /* Disable interrupts and go back to old irql */
87  _disable();
89 }
90 
91 PVOID
93  LONG_PTR StackOffset,
94  PVOID OldStackBase);
95 
96 /*
97  * Kernel stack layout (example pointers):
98  * 0xFFFFFC0F'2D008000 KTHREAD::StackBase
99  * [XSAVE_AREA size == KeXStateLength = 0x440]
100  * 0xFFFFFC0F'2D007BC0 KTHREAD::StateSaveArea _XSAVE_FORMAT
101  * 0xFFFFFC0F'2D007B90 KTHREAD::InitialStack
102  * [0x190 bytes KTRAP_FRAME]
103  * 0xFFFFFC0F'2D007A00 KTHREAD::TrapFrame
104  * [KSTART_FRAME] or ...
105  * [KSWITCH_FRAME]
106  * 0xFFFFFC0F'2D007230 KTHREAD::KernelStack
107  */
108 
109 PVOID
110 NTAPI
111 KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
112 {
113  PKTHREAD CurrentThread;
114  PVOID OldStackBase;
115  LONG_PTR StackOffset;
117  PKIPCR Pcr;
118  ULONG Eflags;
119 
120  /* Get the current thread */
121  CurrentThread = KeGetCurrentThread();
122 
123  /* Save the old stack base */
124  OldStackBase = CurrentThread->StackBase;
125 
126  /* Get the size of the current stack */
127  StackSize = (ULONG_PTR)CurrentThread->StackBase - CurrentThread->StackLimit;
128  ASSERT(StackSize <= (ULONG_PTR)StackBase - (ULONG_PTR)StackLimit);
129 
130  /* Copy the current stack contents to the new stack */
131  RtlCopyMemory((PUCHAR)StackBase - StackSize,
132  (PVOID)CurrentThread->StackLimit,
133  StackSize);
134 
135  /* Calculate the offset between the old and the new stack */
136  StackOffset = (PUCHAR)StackBase - (PUCHAR)CurrentThread->StackBase;
137 
138  /* Disable interrupts while messing with the stack */
139  Eflags = __readeflags();
140  _disable();
141 
142  /* Set the new trap frame */
143  CurrentThread->TrapFrame = (PKTRAP_FRAME)Add2Ptr(CurrentThread->TrapFrame,
144  StackOffset);
145 
146  /* Set the new initial stack */
147  CurrentThread->InitialStack = Add2Ptr(CurrentThread->InitialStack,
148  StackOffset);
149 
150  /* Set the new stack limits */
151  CurrentThread->StackBase = StackBase;
152  CurrentThread->StackLimit = (ULONG_PTR)StackLimit;
153  CurrentThread->LargeStack = TRUE;
154 
155  /* Adjust RspBase in the PCR */
156  Pcr = (PKIPCR)KeGetPcr();
157  Pcr->Prcb.RspBase += StackOffset;
158 
159  /* Adjust Rsp0 in the TSS */
160  Pcr->TssBase->Rsp0 += StackOffset;
161 
162  /* Restore interrupts */
163  __writeeflags(Eflags);
164 
165  return OldStackBase;
166 }
167 
169 VOID
171 {
172  PKPRCB Prcb = KeGetCurrentPrcb();
173  PKTHREAD OldThread, NewThread;
174 
175  /* Now loop forever */
176  while (TRUE)
177  {
178  /* Start of the idle loop: disable interrupts */
179  _enable();
180  YieldProcessor();
181  YieldProcessor();
182  _disable();
183 
184  /* Check for pending timers, pending DPCs, or pending ready threads */
185  if ((Prcb->DpcData[0].DpcQueueDepth) ||
186  (Prcb->TimerRequest) ||
187  (Prcb->DeferredReadyListHead.Next))
188  {
189  /* Quiesce the DPC software interrupt */
191 
192  /* Handle it */
193  KiRetireDpcList(Prcb);
194  }
195 
196  /* Check if a new thread is scheduled for execution */
197  if (Prcb->NextThread)
198  {
199  /* Enable interrupts */
200  _enable();
201 
202  /* Capture current thread data */
203  OldThread = Prcb->CurrentThread;
204  NewThread = Prcb->NextThread;
205 
206  /* Set new thread data */
207  Prcb->NextThread = NULL;
208  Prcb->CurrentThread = NewThread;
209 
210  /* The thread is now running */
211  NewThread->State = Running;
212 
213  /* Do the swap at SYNCH_LEVEL */
215 
216  /* Switch away from the idle thread */
217  KiSwapContext(APC_LEVEL, OldThread);
218 
219  /* Go back to DISPATCH_LEVEL */
221  }
222  else
223  {
224  /* Continue staying idle. Note the HAL returns with interrupts on */
225  Prcb->PowerState.IdleFunction(&Prcb->PowerState);
226  }
227  }
228 }
229 
230 VOID
231 NTAPI
233  IN PKPROCESS OldProcess)
234 {
235  PKIPCR Pcr = (PKIPCR)KeGetPcr();
236 
237 #ifdef CONFIG_SMP
238  /* Update active processor mask */
239  InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember);
240  InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember);
241 #endif
242 
243  /* Update CR3 */
244  __writecr3(NewProcess->DirectoryTableBase[0]);
245 
246  /* Update IOPM offset */
247  Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
248 }
249 
250 #define MAX_SYSCALL_PARAMS 16
251 
252 NTSTATUS
254 {
255  /* This is the failure function */
256  return (NTSTATUS)KeGetCurrentThread()->TrapFrame->Rax;
257 }
258 
259 PVOID
261  VOID)
262 {
263  PKTRAP_FRAME TrapFrame;
264  PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
266  PULONG64 KernelParams, UserParams;
267  ULONG ServiceNumber, Offset, Count;
268  ULONG64 UserRsp;
269 
270  /* Get a pointer to the trap frame */
272 
273  /* Increase system call count */
274  __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
275 
276  /* Get the current thread */
278 
279  /* Set previous mode */
280  Thread->PreviousMode = TrapFrame->PreviousMode = UserMode;
281 
282  /* Save the old trap frame and set the new */
283  TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame;
284  Thread->TrapFrame = TrapFrame;
285 
286  /* We don't have an exception frame yet */
287  TrapFrame->ExceptionFrame = 0;
288 
289  /* Before enabling interrupts get the user rsp from the KPCR */
290  UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp));
291  TrapFrame->Rsp = UserRsp;
292 
293  /* Enable interrupts */
294  _enable();
295 
296  /* If the usermode rsp was not a usermode address, prepare an exception */
297  if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress;
298 
299  /* Get the address of the usermode and kernelmode parameters */
300  UserParams = (PULONG64)UserRsp + 1;
301  KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS;
302 
303  /* Get the system call number from the trap frame and decode it */
304  ServiceNumber = (ULONG)TrapFrame->Rax;
305  Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
306  ServiceNumber &= SERVICE_NUMBER_MASK;
307 
308  /* Check for win32k system calls */
310  {
311  ULONG GdiBatchCount;
312 
313  /* Read the GDI batch count from the TEB */
314  _SEH2_TRY
315  {
316  GdiBatchCount = NtCurrentTeb()->GdiBatchCount;
317  }
319  {
320  GdiBatchCount = 0;
321  }
322  _SEH2_END;
323 
324  /* Flush batch, if there are entries */
325  if (GdiBatchCount != 0)
326  {
328  }
329  }
330 
331  /* Get descriptor table */
332  DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
333 
334  /* Validate the system call number */
335  if (ServiceNumber >= DescriptorTable->Limit)
336  {
337  /* Check if this is a GUI call */
338  if (!(Offset & SERVICE_TABLE_TEST))
339  {
340  /* Fail the call */
341  TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE;
342  return (PVOID)NtSyscallFailure;
343  }
344 
345  /* Convert us to a GUI thread
346  To be entirely correct. we return KiConvertToGuiThread,
347  which allocates a new stack, switches to it, calls
348  PsConvertToGuiThread and resumes in the middle of
349  KiSystemCallEntry64 to restart the system call handling. */
350  return (PVOID)KiConvertToGuiThread;
351  }
352 
353  /* Get stack bytes and calculate argument count */
354  Count = DescriptorTable->Number[ServiceNumber] / 8;
355 
356  _SEH2_TRY
357  {
358  switch (Count)
359  {
360  case 16: KernelParams[15] = UserParams[15];
361  case 15: KernelParams[14] = UserParams[14];
362  case 14: KernelParams[13] = UserParams[13];
363  case 13: KernelParams[12] = UserParams[12];
364  case 12: KernelParams[11] = UserParams[11];
365  case 11: KernelParams[10] = UserParams[10];
366  case 10: KernelParams[9] = UserParams[9];
367  case 9: KernelParams[8] = UserParams[8];
368  case 8: KernelParams[7] = UserParams[7];
369  case 7: KernelParams[6] = UserParams[6];
370  case 6: KernelParams[5] = UserParams[5];
371  case 5: KernelParams[4] = UserParams[4];
372  case 4:
373  case 3:
374  case 2:
375  case 1:
376  case 0:
377  break;
378 
379  default:
380  ASSERT(FALSE);
381  break;
382  }
383  }
385  {
386  TrapFrame->Rax = _SEH2_GetExceptionCode();
387  return (PVOID)NtSyscallFailure;
388  }
389  _SEH2_END;
390 
391  return (PVOID)DescriptorTable->Base[ServiceNumber];
392 }
393 
394 
395 // FIXME: we need to
396 VOID
398  IN PKTRAP_FRAME TrapFrame,
399  IN ULONG Instruction)
400 {
402  __debugbreak();
403 }
404 
405 NTSTATUS
406 NTAPI
408 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
409 {
411  __debugbreak();
412  return STATUS_UNSUCCESSFUL;
413 }
414 
415 NTSTATUS
416 NTAPI
418  IN PVOID ControlData)
419 {
420  /* Not supported */
421  return STATUS_NOT_IMPLEMENTED;
422 }
423 
424 
ULONG MmUserProbeAddress
Definition: init.c:50
_SEH2_TRY
Definition: create.c:4226
DECLSPEC_NORETURN VOID KiIdleLoop(VOID)
Definition: stubs.c:170
NTSTATUS NTAPI NtVdmControl(IN ULONG ControlCode, IN PVOID ControlData)
Definition: stubs.c:417
#define IN
Definition: typedefs.h:39
#define SERVICE_TABLE_SHIFT
Definition: ketypes.h:71
#define Add2Ptr(PTR, INC)
KDPC_DATA DpcData[2]
Definition: ketypes.h:681
#define TRUE
Definition: types.h:120
#define SERVICE_TABLE_MASK
Definition: ketypes.h:78
unsigned char * PUCHAR
Definition: retypes.h:3
void __cdecl _enable(void)
Definition: intrin_arm.h:373
LONG NTSTATUS
Definition: precomp.h:26
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1080
struct _KIPCR * PKIPCR
VOID KiRetireDpcListInDpcStack(PKPRCB Prcb, PVOID DpcStack)
void * _AddressOfReturnAddress(void)
PKTRAP_FRAME TrapFrame
Definition: ketypes.h:1714
VOID NTAPI KiQuantumEnd(VOID)
NTSTATUS KiConvertToGuiThread(VOID)
PROCESSOR_POWER_STATE PowerState
Definition: ketypes.h:800
UCHAR QuantumEnd
Definition: ketypes.h:701
_SEH2_END
Definition: create.c:4400
#define SERVICE_NUMBER_MASK
Definition: ketypes.h:83
#define UNIMPLEMENTED
Definition: stubs.c:20
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
struct _KTHREAD * NextThread
Definition: ketypes.h:572
#define DECLSPEC_NORETURN
Definition: ntbasedef.h:176
#define KeGetPcr()
Definition: ke.h:26
struct _KTSS64 * TssBase
Definition: ketypes.h:866
uint32_t ULONG_PTR
Definition: typedefs.h:65
BOOLEAN FASTCALL KiSwapContext(IN KIRQL WaitIrql, IN PKTHREAD CurrentThread)
FORCEINLINE VOID YieldProcessor(VOID)
Definition: ke.h:32
UCHAR KIRQL
Definition: env_spec_w32.h:591
return STATUS_NOT_IMPLEMENTED
__INTRIN_INLINE void __writecr3(unsigned int Data)
Definition: intrin_x86.h:1786
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1666
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
UINT64 Rax
Definition: ketypes.h:323
ULONG ProcessCount
Definition: stubs.c:16
NTSTATUS NTAPI NtSetLdtEntries(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
Definition: stubs.c:408
struct _KTHREAD * CurrentThread
Definition: ketypes.h:571
FORCEINLINE VOID KiAcquirePrcbLock(IN PKPRCB Prcb)
Definition: ke_x.h:220
#define SERVICE_TABLE_TEST
Definition: ketypes.h:90
_IRQL_requires_same_ typedef _In_ ULONG ControlCode
Definition: wmitypes.h:55
void * PVOID
Definition: retypes.h:9
#define InterlockedXor64
Definition: interlocked.h:291
NTSTATUS NtSyscallFailure(void)
Definition: stubs.c:253
UCHAR WaitReason
Definition: ketypes.h:1904
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
_Requires_lock_not_held_(Prcb->PrcbLock) VOID NTAPI KiDpcInterruptHandler(VOID)
Definition: stubs.c:28
PVOID KiSystemCallHandler(VOID)
Definition: stubs.c:260
int Count
Definition: noreturn.cpp:7
UINT64 TimerRequest
Definition: ketypes.h:696
#define ASSERT(a)
Definition: mode.c:44
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
volatile VOID * StackLimit
Definition: ketypes.h:1605
#define MAX_SYSCALL_PARAMS
Definition: stubs.c:250
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2652
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
unsigned __int64 ULONG64
Definition: imports.h:198
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629
KPRCB Prcb
Definition: ketypes.h:894
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792
__INTRIN_INLINE void __writeeflags(uintptr_t Value)
Definition: intrin_x86.h:1661
#define SYNCH_LEVEL
Definition: env_spec_w32.h:704
_In_ USHORT _In_ CCHAR StackSize
Definition: iofuncs.h:1058
UINT64 SetMember
Definition: ketypes.h:583
FORCEINLINE VOID KiSendEOI(VOID)
Definition: ke.h:342
Definition: compat.h:636
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
PVOID StackBase
Definition: ketypes.h:1606
ULONG_PTR SIZE_T
Definition: typedefs.h:80
SINGLE_LIST_ENTRY DeferredReadyListHead
Definition: ketypes.h:633
volatile ULONG DpcQueueDepth
Definition: ketypes.h:798
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
PVOID DpcStack
Definition: ketypes.h:682
PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch
Definition: win32.c:20
UINT64 Rsp
Definition: ketypes.h:391
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
SIZE_T KeXStateLength
Definition: stubs.c:17
#define NULL
Definition: types.h:112
UINT64 ExceptionFrame
Definition: ketypes.h:381
XSAVE_FORMAT
Definition: ketypes.h:951
PPROCESSOR_IDLE_FUNCTION IdleFunction
Definition: potypes.h:68
VOID FASTCALL HalClearSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:282
volatile UCHAR State
Definition: ketypes.h:1729
void __cdecl _disable(void)
Definition: intrin_arm.h:365
PVOID NTAPI KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
Definition: stubs.c:111
unsigned int ULONG
Definition: retypes.h:1
#define STATUS_INVALID_SYSTEM_SERVICE
Definition: ntstatus.h:265
#define ULONG_PTR
Definition: config.h:101
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
unsigned __int64 * PULONG64
Definition: imports.h:198
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
struct _KTRAP_FRAME * PKTRAP_FRAME
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
PVOID KiSwitchKernelStackHelper(LONG_PTR StackOffset, PVOID OldStackBase)
#define KeGetCurrentThread
Definition: hal.h:55
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
VOID NTAPI KiSwapProcess(IN PKPROCESS NewProcess, IN PKPROCESS OldProcess)
Definition: stubs.c:232
__int64 * PLONG64
Definition: basetsd.h:185
PVOID InitialStack
Definition: ketypes.h:1604
UINT64 RspBase
Definition: ketypes.h:581
#define APC_LEVEL
Definition: env_spec_w32.h:695
VOID KiSystemService(IN PKTHREAD Thread, IN PKTRAP_FRAME TrapFrame, IN ULONG Instruction)
Definition: stubs.c:397
UINT64 TrapFrame
Definition: ketypes.h:373
VOID FASTCALL KiRetireDpcList(IN PKPRCB Prcb)
Definition: dpc.c:562
CHAR PreviousMode
Definition: ketypes.h:318