2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
5 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
8 /* INCLUDES ******************************************************************/
16 KiRetireDpcListInDpcStack(
22 KiDpcInterruptHandler(VOID
)
24 PKPRCB Prcb
= KeGetCurrentPrcb();
25 PKTHREAD NewThread
, OldThread
;
28 /* Raise to DISPATCH_LEVEL */
29 OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
34 /* Check for pending timers, pending DPCs, or pending ready threads */
35 if ((Prcb
->DpcData
[0].DpcQueueDepth
) ||
36 (Prcb
->TimerRequest
) ||
37 (Prcb
->DeferredReadyListHead
.Next
))
39 /* Retire DPCs while under the DPC stack */
40 KiRetireDpcListInDpcStack(Prcb
, Prcb
->DpcStack
);
43 /* Enable interrupts */
46 /* Check for quantum end */
49 /* Handle quantum end */
50 Prcb
->QuantumEnd
= FALSE
;
53 else if (Prcb
->NextThread
)
55 /* Capture current thread data */
56 OldThread
= Prcb
->CurrentThread
;
57 NewThread
= Prcb
->NextThread
;
59 /* Set new thread data */
60 Prcb
->NextThread
= NULL
;
61 Prcb
->CurrentThread
= NewThread
;
63 /* The thread is now running */
64 NewThread
->State
= Running
;
65 OldThread
->WaitReason
= WrDispatchInt
;
67 /* Make the old thread ready */
68 KxQueueReadyThread(OldThread
, Prcb
);
70 /* Swap to the new thread */
71 KiSwapContext(APC_LEVEL
, OldThread
);
74 /* Go back to old irql and disable interrupts */
82 KeZeroPages(IN PVOID Address
,
85 /* Not using XMMI in this routine */
86 RtlZeroMemory(Address
, Size
);
91 KeSwitchKernelStack(PVOID StackBase
, PVOID StackLimit
)
100 KeUserModeCallback(IN ULONG RoutineIndex
,
102 IN ULONG ArgumentLength
,
104 OUT PULONG ResultLength
)
108 return STATUS_UNSUCCESSFUL
;
115 PKPRCB Prcb
= KeGetCurrentPrcb();
116 PKTHREAD OldThread
, NewThread
;
118 /* Now loop forever */
121 /* Start of the idle loop: disable interrupts */
127 /* Check for pending timers, pending DPCs, or pending ready threads */
128 if ((Prcb
->DpcData
[0].DpcQueueDepth
) ||
129 (Prcb
->TimerRequest
) ||
130 (Prcb
->DeferredReadyListHead
.Next
))
132 /* Quiesce the DPC software interrupt */
133 HalClearSoftwareInterrupt(DISPATCH_LEVEL
);
136 KiRetireDpcList(Prcb
);
139 /* Check if a new thread is scheduled for execution */
140 if (Prcb
->NextThread
)
142 /* Enable interrupts */
145 /* Capture current thread data */
146 OldThread
= Prcb
->CurrentThread
;
147 NewThread
= Prcb
->NextThread
;
149 /* Set new thread data */
150 Prcb
->NextThread
= NULL
;
151 Prcb
->CurrentThread
= NewThread
;
153 /* The thread is now running */
154 NewThread
->State
= Running
;
156 /* Do the swap at SYNCH_LEVEL */
157 KfRaiseIrql(SYNCH_LEVEL
);
159 /* Switch away from the idle thread */
160 KiSwapContext(APC_LEVEL
, OldThread
);
162 /* Go back to DISPATCH_LEVEL */
163 KeLowerIrql(DISPATCH_LEVEL
);
167 /* Continue staying idle. Note the HAL returns with interrupts on */
168 Prcb
->PowerState
.IdleFunction(&Prcb
->PowerState
);
174 /*! \name KiInitializeUserApc
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
182 * \param ExceptionFrame
184 * \param NormalRoutine
185 * \param NormalContext
186 * \param SystemArgument1
187 * \param SystemArgument2
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.
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
)
211 ULONG64 AlignedRsp
, Stack
;
212 EXCEPTION_RECORD SehExceptRecord
;
214 /* Sanity check, that the trap frame is from user mode */
215 ASSERT((TrapFrame
->SegCs
& MODE_MASK
) != KernelMode
);
217 /* Convert the current trap frame to a context */
218 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
219 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
221 /* We jump to KiUserApcDispatcher in ntdll */
222 TrapFrame
->Rip
= (ULONG64
)KeUserApcDispatcher
;
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
;
232 /* Sanitize EFLAGS, enable interrupts */
233 TrapFrame
->EFlags
= (Context
.EFlags
& EFLAGS_USER_SANITIZE
);
234 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
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
;
242 /* Check if thread has IOPL and force it enabled if so */
243 //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
245 /* Align Stack to 16 bytes and allocate space */
246 AlignedRsp
= Context
.Rsp
& ~15;
247 Stack
= AlignedRsp
- sizeof(CONTEXT
);
248 TrapFrame
->Rsp
= Stack
;
250 /* The stack must be 16 byte aligned for KiUserApcDispatcher */
251 ASSERT((Stack
& 15) == 0);
253 /* Protect with SEH */
256 /* Probe the stack */
257 ProbeForWrite((PCONTEXT
)Stack
, sizeof(CONTEXT
), 8);
259 /* Copy the context */
260 RtlCopyMemory((PCONTEXT
)Stack
, &Context
, sizeof(CONTEXT
));
262 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord
, _SEH2_GetExceptionInformation()->ExceptionRecord
, sizeof(EXCEPTION_RECORD
)), EXCEPTION_EXECUTE_HANDLER
))
264 /* Dispatch the exception */
265 SehExceptRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Rip
;
266 KiDispatchException(&SehExceptRecord
,
277 KiSwapProcess(IN PKPROCESS NewProcess
,
278 IN PKPROCESS OldProcess
)
280 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
283 /* Update active processor mask */
284 InterlockedXor64((PLONG64
)&NewProcess
->ActiveProcessors
, Pcr
->Prcb
.SetMember
);
285 InterlockedXor64((PLONG64
)&OldProcess
->ActiveProcessors
, Pcr
->Prcb
.SetMember
);
289 __writecr3(NewProcess
->DirectoryTableBase
[0]);
291 /* Update IOPM offset */
292 Pcr
->TssBase
->IoMapBase
= NewProcess
->IopmOffset
;
295 #define MAX_SYSCALL_PARAMS 16
298 NtSyscallFailure(void)
300 /* This is the failure function */
301 return STATUS_ACCESS_VIOLATION
;
306 IN PKTRAP_FRAME TrapFrame
,
311 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
313 PULONG64 KernelParams
, UserParams
;
314 ULONG ServiceNumber
, Offset
, Count
;
317 DPRINT("Syscall #%ld\n", TrapFrame
->Rax
);
320 /* Increase system call count */
321 __addgsdword(FIELD_OFFSET(KIPCR
, Prcb
.KeSystemCalls
), 1);
323 /* Get the current thread */
324 Thread
= KeGetCurrentThread();
326 /* Set previous mode */
327 Thread
->PreviousMode
= TrapFrame
->PreviousMode
= UserMode
;
329 /* Save the old trap frame and set the new */
330 TrapFrame
->TrapFrame
= (ULONG64
)Thread
->TrapFrame
;
331 Thread
->TrapFrame
= TrapFrame
;
333 /* Before enabling interrupts get the user rsp from the KPCR */
334 UserRsp
= __readgsqword(FIELD_OFFSET(KIPCR
, UserRsp
));
335 TrapFrame
->Rsp
= UserRsp
;
337 /* Enable interrupts */
340 /* If the usermode rsp was not a usermode address, prepare an exception */
341 if (UserRsp
> MmUserProbeAddress
) UserRsp
= MmUserProbeAddress
;
343 /* Get the address of the usermode and kernelmode parameters */
344 UserParams
= (PULONG64
)UserRsp
+ 1;
345 KernelParams
= (PULONG64
)TrapFrame
- MAX_SYSCALL_PARAMS
;
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
;
352 /* Get descriptor table */
353 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
355 /* Get stack bytes and calculate argument count */
356 Count
= DescriptorTable
->Number
[ServiceNumber
] / 8;
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
;
388 TrapFrame
->Rax
= _SEH2_GetExceptionCode();
389 return (PVOID
)NtSyscallFailure
;
393 return (PVOID
)DescriptorTable
->Base
[ServiceNumber
];
399 KiSystemService(IN PKTHREAD Thread
,
400 IN PKTRAP_FRAME TrapFrame
,
401 IN ULONG Instruction
)
411 ( IN PVOID Result OPTIONAL
, IN ULONG ResultLength
, IN NTSTATUS Status
)
415 return STATUS_UNSUCCESSFUL
;
421 (ULONG Selector1
, LDT_ENTRY LdtEntry1
, ULONG Selector2
, LDT_ENTRY LdtEntry2
)
425 return STATUS_UNSUCCESSFUL
;
430 NtVdmControl(IN ULONG ControlCode
,
431 IN PVOID ControlData
)
434 return STATUS_NOT_IMPLEMENTED
;
440 IN PVOID
*OutputBuffer
,
441 IN PULONG OutputLength
)
445 return STATUS_UNSUCCESSFUL
;
449 BOOLEAN CcPfEnablePrefetcher
;