[NDK] Fix the type of KPROCESS::ActiveProcessors
[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 /* 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;
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