Synchronize with trunk revision 59781.
[reactos.git] / ntoskrnl / ke / amd64 / stubs.c
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 /* Initialize the idle loop: disable interrupts */
119 _enable();
120 YieldProcessor();
121 YieldProcessor();
122 _disable();
123
124 /* Now loop forever */
125 while (TRUE)
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 interupts */
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 /* We are back in the idle thread -- disable interrupts again */
166 _enable();
167 YieldProcessor();
168 YieldProcessor();
169 _disable();
170 }
171 else
172 {
173 /* Continue staying idle. Note the HAL returns with interrupts on */
174 Prcb->PowerState.IdleFunction(&Prcb->PowerState);
175 }
176 }
177 }
178
179
180 /*! \name KiInitializeUserApc
181 *
182 * \brief
183 * Prepares the current trap frame (which must have come from user mode)
184 * with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT
185 * record with the context from the old trap frame to the threads user
186 * mode stack.
187 *
188 * \param ExceptionFrame
189 * \param TrapFrame
190 * \param NormalRoutine
191 * \param NormalContext
192 * \param SystemArgument1
193 * \param SystemArgument2
194 *
195 * \remarks
196 * This function is called from KiDeliverApc, when the trap frame came
197 * from user mode. This happens before a systemcall or interrupt exits back
198 * to usermode or when a thread is started from PspUserThreadstartup.
199 * The trap exit code will then leave to KiUserApcDispatcher which in turn
200 * calls the NormalRoutine, passing NormalContext, SystemArgument1 and
201 * SystemArgument2 as parameters. When that function returns, it calls
202 * NtContinue to return back to the kernel, where the old context that was
203 * saved on the usermode stack is restored and execution is transferred
204 * back to usermode, where the original trap originated from.
205 *
206 *--*/
207 VOID
208 NTAPI
209 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
210 IN PKTRAP_FRAME TrapFrame,
211 IN PKNORMAL_ROUTINE NormalRoutine,
212 IN PVOID NormalContext,
213 IN PVOID SystemArgument1,
214 IN PVOID SystemArgument2)
215 {
216 CONTEXT Context;
217 ULONG64 AlignedRsp, Stack;
218 EXCEPTION_RECORD SehExceptRecord;
219
220 /* Sanity check, that the trap frame is from user mode */
221 ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
222
223 /* Convert the current trap frame to a context */
224 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
225 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
226
227 /* We jump to KiUserApcDispatcher in ntdll */
228 TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
229
230 /* Setup Ring 3 segments */
231 TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
232 TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
233 TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
234 TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
235 TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
236 TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
237
238 /* Sanitize EFLAGS, enable interrupts */
239 TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE);
240 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
241
242 /* Set parameters for KiUserApcDispatcher */
243 Context.P1Home = (ULONG64)NormalContext;
244 Context.P2Home = (ULONG64)SystemArgument1;
245 Context.P3Home = (ULONG64)SystemArgument2;
246 Context.P4Home = (ULONG64)NormalRoutine;
247
248 /* Check if thread has IOPL and force it enabled if so */
249 //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
250
251 /* Align Stack to 16 bytes and allocate space */
252 AlignedRsp = Context.Rsp & ~15;
253 Stack = AlignedRsp - sizeof(CONTEXT);
254 TrapFrame->Rsp = Stack;
255
256 /* The stack must be 16 byte aligned for KiUserApcDispatcher */
257 ASSERT((Stack & 15) == 0);
258
259 /* Protect with SEH */
260 _SEH2_TRY
261 {
262 /* Probe the stack */
263 ProbeForWrite((PCONTEXT)Stack, sizeof(CONTEXT), 8);
264
265 /* Copy the context */
266 RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT));
267 }
268 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
269 {
270 /* Dispatch the exception */
271 SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
272 KiDispatchException(&SehExceptRecord,
273 ExceptionFrame,
274 TrapFrame,
275 UserMode,
276 TRUE);
277 }
278 _SEH2_END;
279 }
280
281 VOID
282 NTAPI
283 KiSwapProcess(IN PKPROCESS NewProcess,
284 IN PKPROCESS OldProcess)
285 {
286 PKIPCR Pcr = (PKIPCR)KeGetPcr();
287 #ifdef CONFIG_SMP
288 LONG SetMember;
289
290 /* Update active processor mask */
291 SetMember = (LONG)Pcr->SetMember;
292 InterlockedXor((PLONG)&NewProcess->ActiveProcessors, SetMember);
293 InterlockedXor((PLONG)&OldProcess->ActiveProcessors, SetMember);
294 #endif
295
296 /* Update CR3 */
297 __writecr3(NewProcess->DirectoryTableBase[0]);
298
299 /* Update IOPM offset */
300 Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
301 }
302
303 #define MAX_SYSCALL_PARAMS 16
304
305 NTSTATUS
306 NtSyscallFailure(void)
307 {
308 /* This is the failure function */
309 return STATUS_ACCESS_VIOLATION;
310 }
311
312 PVOID
313 KiSystemCallHandler(
314 IN PKTRAP_FRAME TrapFrame,
315 IN ULONG64 P2,
316 IN ULONG64 P3,
317 IN ULONG64 P4)
318 {
319 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
320 PKTHREAD Thread;
321 PULONG64 KernelParams, UserParams;
322 ULONG ServiceNumber, Offset, Count;
323 ULONG64 UserRsp;
324
325 DPRINT("Syscall #%ld\n", TrapFrame->Rax);
326 //__debugbreak();
327
328 /* Increase system call count */
329 __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
330
331 /* Get the current thread */
332 Thread = KeGetCurrentThread();
333
334 /* Set previous mode */
335 Thread->PreviousMode = TrapFrame->PreviousMode = UserMode;
336
337 /* Save the old trap frame and set the new */
338 TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame;
339 Thread->TrapFrame = TrapFrame;
340
341 /* Before enabling interrupts get the user rsp from the KPCR */
342 UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp));
343 TrapFrame->Rsp = UserRsp;
344
345 /* Enable interrupts */
346 _enable();
347
348 /* If the usermode rsp was not a usermode address, prepare an exception */
349 if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress;
350
351 /* Get the address of the usermode and kernelmode parameters */
352 UserParams = (PULONG64)UserRsp + 1;
353 KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS;
354
355 /* Get the system call number from the trap frame and decode it */
356 ServiceNumber = (ULONG)TrapFrame->Rax;
357 Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
358 ServiceNumber &= SERVICE_NUMBER_MASK;
359
360 /* Get descriptor table */
361 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
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: KernelParams[3] = P4;
383 case 3: KernelParams[2] = P3;
384 case 2: KernelParams[1] = P2;
385 case 1: KernelParams[0] = TrapFrame->R10;
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
407 KiSystemService(IN PKTHREAD Thread,
408 IN PKTRAP_FRAME TrapFrame,
409 IN ULONG Instruction)
410 {
411 UNIMPLEMENTED;
412 __debugbreak();
413 }
414
415 NTSYSAPI
416 NTSTATUS
417 NTAPI
418 NtCallbackReturn
419 ( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status )
420 {
421 UNIMPLEMENTED;
422 __debugbreak();
423 return STATUS_UNSUCCESSFUL;
424 }
425
426 NTSTATUS
427 NTAPI
428 NtSetLdtEntries
429 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
430 {
431 UNIMPLEMENTED;
432 __debugbreak();
433 return STATUS_UNSUCCESSFUL;
434 }
435
436 NTSTATUS
437 NTAPI
438 NtVdmControl(IN ULONG ControlCode,
439 IN PVOID ControlData)
440 {
441 /* Not supported */
442 return STATUS_NOT_IMPLEMENTED;
443 }
444
445 NTSTATUS
446 NTAPI
447 KiCallUserMode(
448 IN PVOID *OutputBuffer,
449 IN PULONG OutputLength)
450 {
451 UNIMPLEMENTED;
452 __debugbreak();
453 return STATUS_UNSUCCESSFUL;
454 }
455
456 #undef ExQueryDepthSList
457 NTKERNELAPI
458 USHORT
459 ExQueryDepthSList(IN PSLIST_HEADER ListHead)
460 {
461 return (USHORT)(ListHead->Alignment & 0xffff);
462 }
463
464
465 ULONG ProcessCount;
466 BOOLEAN CcPfEnablePrefetcher;
467
468