xref: /reactos/ntoskrnl/ke/amd64/stubs.c (revision d7fd62d4)
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 
12 #define NDEBUG
13 #include <debug.h>
14 
15 VOID
16 KiRetireDpcListInDpcStack(
17     PKPRCB Prcb,
18     PVOID DpcStack);
19 
20 VOID
21 NTAPI
22 KiDpcInterruptHandler(VOID)
23 {
24     PKPRCB Prcb = KeGetCurrentPrcb();
25     PKTHREAD NewThread, OldThread;
26     KIRQL OldIrql;
27 
28     /* Raise to DISPATCH_LEVEL */
29     OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
30 
31     /* Send an EOI */
32     KiSendEOI();
33 
34     /* Check for pending timers, pending DPCs, or pending ready threads */
35     if ((Prcb->DpcData[0].DpcQueueDepth) ||
36         (Prcb->TimerRequest) ||
37         (Prcb->DeferredReadyListHead.Next))
38     {
39         /* Retire DPCs while under the DPC stack */
40         KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
41     }
42 
43     /* Enable interrupts */
44     _enable();
45 
46     /* Check for quantum end */
47     if (Prcb->QuantumEnd)
48     {
49         /* Handle quantum end */
50         Prcb->QuantumEnd = FALSE;
51         KiQuantumEnd();
52     }
53     else if (Prcb->NextThread)
54     {
55         /* Capture current thread data */
56         OldThread = Prcb->CurrentThread;
57         NewThread = Prcb->NextThread;
58 
59         /* Set new thread data */
60         Prcb->NextThread = NULL;
61         Prcb->CurrentThread = NewThread;
62 
63         /* The thread is now running */
64         NewThread->State = Running;
65         OldThread->WaitReason = WrDispatchInt;
66 
67         /* Make the old thread ready */
68         KxQueueReadyThread(OldThread, Prcb);
69 
70         /* Swap to the new thread */
71         KiSwapContext(APC_LEVEL, OldThread);
72     }
73 
74     /* Go back to old irql and disable interrupts */
75     KeLowerIrql(OldIrql);
76     _disable();
77 }
78 
79 
80 VOID
81 FASTCALL
82 KeZeroPages(IN PVOID Address,
83             IN ULONG Size)
84 {
85     /* Not using XMMI in this routine */
86     RtlZeroMemory(Address, Size);
87 }
88 
89 PVOID
90 NTAPI
91 KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
92 {
93     UNIMPLEMENTED;
94     __debugbreak();
95     return NULL;
96 }
97 
98 NTSTATUS
99 NTAPI
100 KeUserModeCallback(IN ULONG RoutineIndex,
101                    IN PVOID Argument,
102                    IN ULONG ArgumentLength,
103                    OUT PVOID *Result,
104                    OUT PULONG ResultLength)
105 {
106     UNIMPLEMENTED;
107     __debugbreak();
108     return STATUS_UNSUCCESSFUL;
109 }
110 
111 VOID
112 FASTCALL
113 KiIdleLoop(VOID)
114 {
115     PKPRCB Prcb = KeGetCurrentPrcb();
116     PKTHREAD OldThread, NewThread;
117 
118     /* Now loop forever */
119     while (TRUE)
120     {
121         /* Start of the idle loop: disable interrupts */
122         _enable();
123         YieldProcessor();
124         YieldProcessor();
125         _disable();
126 
127         /* Check for pending timers, pending DPCs, or pending ready threads */
128         if ((Prcb->DpcData[0].DpcQueueDepth) ||
129             (Prcb->TimerRequest) ||
130             (Prcb->DeferredReadyListHead.Next))
131         {
132             /* Quiesce the DPC software interrupt */
133             HalClearSoftwareInterrupt(DISPATCH_LEVEL);
134 
135             /* Handle it */
136             KiRetireDpcList(Prcb);
137         }
138 
139         /* Check if a new thread is scheduled for execution */
140         if (Prcb->NextThread)
141         {
142             /* Enable interrupts */
143             _enable();
144 
145             /* Capture current thread data */
146             OldThread = Prcb->CurrentThread;
147             NewThread = Prcb->NextThread;
148 
149             /* Set new thread data */
150             Prcb->NextThread = NULL;
151             Prcb->CurrentThread = NewThread;
152 
153             /* The thread is now running */
154             NewThread->State = Running;
155 
156             /* Do the swap at SYNCH_LEVEL */
157             KfRaiseIrql(SYNCH_LEVEL);
158 
159             /* Switch away from the idle thread */
160             KiSwapContext(APC_LEVEL, OldThread);
161 
162             /* Go back to DISPATCH_LEVEL */
163             KeLowerIrql(DISPATCH_LEVEL);
164         }
165         else
166         {
167             /* Continue staying idle. Note the HAL returns with interrupts on */
168             Prcb->PowerState.IdleFunction(&Prcb->PowerState);
169         }
170     }
171 }
172 
173 
174 /*! \name KiInitializeUserApc
175  *
176  *  \brief
177  *      Prepares the current trap frame (which must have come from user mode)
178  *      with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT
179  *      record with the context from the old trap frame to the threads user
180  *      mode stack.
181  *
182  *  \param ExceptionFrame
183  *  \param TrapFrame
184  *  \param NormalRoutine
185  *  \param NormalContext
186  *  \param SystemArgument1
187  *  \param SystemArgument2
188  *
189  *  \remarks
190  *      This function is called from KiDeliverApc, when the trap frame came
191  *      from user mode. This happens before a systemcall or interrupt exits back
192  *      to usermode or when a thread is started from PspUserThreadstartup.
193  *      The trap exit code will then leave to KiUserApcDispatcher which in turn
194  *      calls the NormalRoutine, passing NormalContext, SystemArgument1 and
195  *      SystemArgument2 as parameters. When that function returns, it calls
196  *      NtContinue to return back to the kernel, where the old context that was
197  *      saved on the usermode stack is restored and execution is transferred
198  *      back to usermode, where the original trap originated from.
199  *
200  *--*/
201 VOID
202 NTAPI
203 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
204                     IN PKTRAP_FRAME TrapFrame,
205                     IN PKNORMAL_ROUTINE NormalRoutine,
206                     IN PVOID NormalContext,
207                     IN PVOID SystemArgument1,
208                     IN PVOID SystemArgument2)
209 {
210     CONTEXT Context = { 0 };
211     ULONG64 AlignedRsp, Stack;
212     EXCEPTION_RECORD SehExceptRecord;
213 
214     /* Sanity check, that the trap frame is from user mode */
215     ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
216 
217     /* Convert the current trap frame to a context */
218     Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
219     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
220 
221     /* We jump to KiUserApcDispatcher in ntdll */
222     TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
223 
224     /* Setup Ring 3 segments */
225     TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
226     TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
227     TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
228     TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
229     TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
230     TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
231 
232     /* Sanitize EFLAGS, enable interrupts */
233     TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE);
234     TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
235 
236     /* Set parameters for KiUserApcDispatcher */
237     Context.P1Home = (ULONG64)NormalContext;
238     Context.P2Home = (ULONG64)SystemArgument1;
239     Context.P3Home = (ULONG64)SystemArgument2;
240     Context.P4Home = (ULONG64)NormalRoutine;
241 
242     /* Check if thread has IOPL and force it enabled if so */
243     //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
244 
245     /* Align Stack to 16 bytes and allocate space */
246     AlignedRsp = Context.Rsp & ~15;
247     Stack = AlignedRsp - sizeof(CONTEXT);
248     TrapFrame->Rsp = Stack;
249 
250     /* The stack must be 16 byte aligned for KiUserApcDispatcher */
251     ASSERT((Stack & 15) == 0);
252 
253     /* Protect with SEH */
254     _SEH2_TRY
255     {
256          /* Probe the stack */
257         ProbeForWrite((PCONTEXT)Stack,  sizeof(CONTEXT), 8);
258 
259         /* Copy the context */
260         RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT));
261     }
262     _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
263     {
264         /* Dispatch the exception */
265         SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
266         KiDispatchException(&SehExceptRecord,
267                             ExceptionFrame,
268                             TrapFrame,
269                             UserMode,
270                             TRUE);
271     }
272     _SEH2_END;
273 }
274 
275 VOID
276 NTAPI
277 KiSwapProcess(IN PKPROCESS NewProcess,
278               IN PKPROCESS OldProcess)
279 {
280     PKIPCR Pcr = (PKIPCR)KeGetPcr();
281 
282 #ifdef CONFIG_SMP
283     /* Update active processor mask */
284     InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember);
285     InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember);
286 #endif
287 
288     /* Update CR3 */
289     __writecr3(NewProcess->DirectoryTableBase[0]);
290 
291     /* Update IOPM offset */
292     Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
293 }
294 
295 #define MAX_SYSCALL_PARAMS 16
296 
297 NTSTATUS
298 NtSyscallFailure(void)
299 {
300     /* This is the failure function */
301     return STATUS_ACCESS_VIOLATION;
302 }
303 
304 PVOID
305 KiSystemCallHandler(
306     IN PKTRAP_FRAME TrapFrame,
307     IN ULONG64 P2,
308     IN ULONG64 P3,
309     IN ULONG64 P4)
310 {
311     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
312     PKTHREAD Thread;
313     PULONG64 KernelParams, UserParams;
314     ULONG ServiceNumber, Offset, Count;
315     ULONG64 UserRsp;
316 
317     DPRINT("Syscall #%ld\n", TrapFrame->Rax);
318     //__debugbreak();
319 
320     /* Increase system call count */
321     __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
322 
323     /* Get the current thread */
324     Thread = KeGetCurrentThread();
325 
326     /* Set previous mode */
327     Thread->PreviousMode = TrapFrame->PreviousMode = UserMode;
328 
329     /* Save the old trap frame and set the new */
330     TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame;
331     Thread->TrapFrame = TrapFrame;
332 
333     /* Before enabling interrupts get the user rsp from the KPCR */
334     UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp));
335     TrapFrame->Rsp = UserRsp;
336 
337     /* Enable interrupts */
338     _enable();
339 
340     /* If the usermode rsp was not a usermode address, prepare an exception */
341     if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress;
342 
343     /* Get the address of the usermode and kernelmode parameters */
344     UserParams = (PULONG64)UserRsp + 1;
345     KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS;
346 
347     /* Get the system call number from the trap frame and decode it */
348     ServiceNumber = (ULONG)TrapFrame->Rax;
349     Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
350     ServiceNumber &= SERVICE_NUMBER_MASK;
351 
352     /* Get descriptor table */
353     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
354 
355     /* Get stack bytes and calculate argument count */
356     Count = DescriptorTable->Number[ServiceNumber] / 8;
357 
358     __try
359     {
360         switch (Count)
361         {
362             case 16: KernelParams[15] = UserParams[15];
363             case 15: KernelParams[14] = UserParams[14];
364             case 14: KernelParams[13] = UserParams[13];
365             case 13: KernelParams[12] = UserParams[12];
366             case 12: KernelParams[11] = UserParams[11];
367             case 11: KernelParams[10] = UserParams[10];
368             case 10: KernelParams[9] = UserParams[9];
369             case 9: KernelParams[8] = UserParams[8];
370             case 8: KernelParams[7] = UserParams[7];
371             case 7: KernelParams[6] = UserParams[6];
372             case 6: KernelParams[5] = UserParams[5];
373             case 5: KernelParams[4] = UserParams[4];
374             case 4: KernelParams[3] = P4;
375             case 3: KernelParams[2] = P3;
376             case 2: KernelParams[1] = P2;
377             case 1: KernelParams[0] = TrapFrame->R10;
378             case 0:
379                 break;
380 
381             default:
382                 __debugbreak();
383                 break;
384         }
385     }
386     __except(1)
387     {
388         TrapFrame->Rax = _SEH2_GetExceptionCode();
389         return (PVOID)NtSyscallFailure;
390     }
391 
392 
393     return (PVOID)DescriptorTable->Base[ServiceNumber];
394 }
395 
396 
397 // FIXME: we need to
398 VOID
399 KiSystemService(IN PKTHREAD Thread,
400                 IN PKTRAP_FRAME TrapFrame,
401                 IN ULONG Instruction)
402 {
403     UNIMPLEMENTED;
404     __debugbreak();
405 }
406 
407 NTSYSAPI
408 NTSTATUS
409 NTAPI
410 NtCallbackReturn
411 ( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status )
412 {
413     UNIMPLEMENTED;
414     __debugbreak();
415     return STATUS_UNSUCCESSFUL;
416 }
417 
418 NTSTATUS
419 NTAPI
420 NtSetLdtEntries
421 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
422 {
423     UNIMPLEMENTED;
424     __debugbreak();
425     return STATUS_UNSUCCESSFUL;
426 }
427 
428 NTSTATUS
429 NTAPI
430 NtVdmControl(IN ULONG ControlCode,
431              IN PVOID ControlData)
432 {
433     /* Not supported */
434     return STATUS_NOT_IMPLEMENTED;
435 }
436 
437 NTSTATUS
438 NTAPI
439 KiCallUserMode(
440     IN PVOID *OutputBuffer,
441     IN PULONG OutputLength)
442 {
443     UNIMPLEMENTED;
444     __debugbreak();
445     return STATUS_UNSUCCESSFUL;
446 }
447 
448 ULONG ProcessCount;
449 BOOLEAN CcPfEnablePrefetcher;
450 
451 
452