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 /* Initialize the idle loop: disable interrupts */
124 /* Now loop forever */
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 interupts */
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
);
165 /* We are back in the idle thread -- disable interrupts again */
173 /* Continue staying idle. Note the HAL returns with interrupts on */
174 Prcb
->PowerState
.IdleFunction(&Prcb
->PowerState
);
180 /*! \name KiInitializeUserApc
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
188 * \param ExceptionFrame
190 * \param NormalRoutine
191 * \param NormalContext
192 * \param SystemArgument1
193 * \param SystemArgument2
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.
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
)
217 ULONG64 AlignedRsp
, Stack
;
218 EXCEPTION_RECORD SehExceptRecord
;
220 /* Sanity check, that the trap frame is from user mode */
221 ASSERT((TrapFrame
->SegCs
& MODE_MASK
) != KernelMode
);
223 /* Convert the current trap frame to a context */
224 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
225 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
227 /* We jump to KiUserApcDispatcher in ntdll */
228 TrapFrame
->Rip
= (ULONG64
)KeUserApcDispatcher
;
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
;
238 /* Sanitize EFLAGS, enable interrupts */
239 TrapFrame
->EFlags
= (Context
.EFlags
& EFLAGS_USER_SANITIZE
);
240 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
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
;
248 /* Check if thread has IOPL and force it enabled if so */
249 //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
251 /* Align Stack to 16 bytes and allocate space */
252 AlignedRsp
= Context
.Rsp
& ~15;
253 Stack
= AlignedRsp
- sizeof(CONTEXT
);
254 TrapFrame
->Rsp
= Stack
;
256 /* The stack must be 16 byte aligned for KiUserApcDispatcher */
257 ASSERT((Stack
& 15) == 0);
259 /* Protect with SEH */
262 /* Probe the stack */
263 ProbeForWrite((PCONTEXT
)Stack
, sizeof(CONTEXT
), 8);
265 /* Copy the context */
266 RtlCopyMemory((PCONTEXT
)Stack
, &Context
, sizeof(CONTEXT
));
268 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord
, _SEH2_GetExceptionInformation()->ExceptionRecord
, sizeof(EXCEPTION_RECORD
)), EXCEPTION_EXECUTE_HANDLER
))
270 /* Dispatch the exception */
271 SehExceptRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Rip
;
272 KiDispatchException(&SehExceptRecord
,
283 KiSwapProcess(IN PKPROCESS NewProcess
,
284 IN PKPROCESS OldProcess
)
286 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
290 /* Update active processor mask */
291 SetMember
= (LONG
)Pcr
->SetMember
;
292 InterlockedXor((PLONG
)&NewProcess
->ActiveProcessors
, SetMember
);
293 InterlockedXor((PLONG
)&OldProcess
->ActiveProcessors
, SetMember
);
297 __writecr3(NewProcess
->DirectoryTableBase
[0]);
299 /* Update IOPM offset */
300 Pcr
->TssBase
->IoMapBase
= NewProcess
->IopmOffset
;
303 #define MAX_SYSCALL_PARAMS 16
306 NtSyscallFailure(void)
308 /* This is the failure function */
309 return STATUS_ACCESS_VIOLATION
;
314 IN PKTRAP_FRAME TrapFrame
,
319 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable
;
321 PULONG64 KernelParams
, UserParams
;
322 ULONG ServiceNumber
, Offset
, Count
;
325 DPRINT("Syscall #%ld\n", TrapFrame
->Rax
);
328 /* Increase system call count */
329 __addgsdword(FIELD_OFFSET(KIPCR
, Prcb
.KeSystemCalls
), 1);
331 /* Get the current thread */
332 Thread
= KeGetCurrentThread();
334 /* Set previous mode */
335 Thread
->PreviousMode
= TrapFrame
->PreviousMode
= UserMode
;
337 /* Save the old trap frame and set the new */
338 TrapFrame
->TrapFrame
= (ULONG64
)Thread
->TrapFrame
;
339 Thread
->TrapFrame
= TrapFrame
;
341 /* Before enabling interrupts get the user rsp from the KPCR */
342 UserRsp
= __readgsqword(FIELD_OFFSET(KIPCR
, UserRsp
));
343 TrapFrame
->Rsp
= UserRsp
;
345 /* Enable interrupts */
348 /* If the usermode rsp was not a usermode address, prepare an exception */
349 if (UserRsp
> MmUserProbeAddress
) UserRsp
= MmUserProbeAddress
;
351 /* Get the address of the usermode and kernelmode parameters */
352 UserParams
= (PULONG64
)UserRsp
+ 1;
353 KernelParams
= (PULONG64
)TrapFrame
- MAX_SYSCALL_PARAMS
;
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
;
360 /* Get descriptor table */
361 DescriptorTable
= (PVOID
)((ULONG_PTR
)Thread
->ServiceTable
+ Offset
);
363 /* Get stack bytes and calculate argument count */
364 Count
= DescriptorTable
->Number
[ServiceNumber
] / 8;
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
;
396 TrapFrame
->Rax
= _SEH2_GetExceptionCode();
397 return (PVOID
)NtSyscallFailure
;
401 return (PVOID
)DescriptorTable
->Base
[ServiceNumber
];
407 KiSystemService(IN PKTHREAD Thread
,
408 IN PKTRAP_FRAME TrapFrame
,
409 IN ULONG Instruction
)
419 ( IN PVOID Result OPTIONAL
, IN ULONG ResultLength
, IN NTSTATUS Status
)
423 return STATUS_UNSUCCESSFUL
;
429 (ULONG Selector1
, LDT_ENTRY LdtEntry1
, ULONG Selector2
, LDT_ENTRY LdtEntry2
)
433 return STATUS_UNSUCCESSFUL
;
438 NtVdmControl(IN ULONG ControlCode
,
439 IN PVOID ControlData
)
442 return STATUS_NOT_IMPLEMENTED
;
448 IN PVOID
*OutputBuffer
,
449 IN PULONG OutputLength
)
453 return STATUS_UNSUCCESSFUL
;
457 BOOLEAN CcPfEnablePrefetcher
;