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