#define NDEBUG
#include <debug.h>
-VOID
-KiRetireDpcListInDpcStack(
- PKPRCB Prcb,
- PVOID DpcStack);
+/* GLOBALS *******************************************************************/
-VOID
+ULONG ProcessCount;
+SIZE_T KeXStateLength = sizeof(XSAVE_FORMAT);
+
+PVOID
+KiSwitchKernelStackHelper(
+ LONG_PTR StackOffset,
+ PVOID OldStackBase);
+
+/*
+ * Kernel stack layout (example pointers):
+ * 0xFFFFFC0F'2D008000 KTHREAD::StackBase
+ * [XSAVE_AREA size == KeXStateLength = 0x440]
+ * 0xFFFFFC0F'2D007BC0 KTHREAD::StateSaveArea _XSAVE_FORMAT
+ * 0xFFFFFC0F'2D007B90 KTHREAD::InitialStack
+ * [0x190 bytes KTRAP_FRAME]
+ * 0xFFFFFC0F'2D007A00 KTHREAD::TrapFrame
+ * [KSTART_FRAME] or ...
+ * [KSWITCH_FRAME]
+ * 0xFFFFFC0F'2D007230 KTHREAD::KernelStack
+ */
+
+PVOID
NTAPI
-KiDpcInterruptHandler(VOID)
+KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
{
- PKPRCB Prcb = KeGetCurrentPrcb();
- PKTHREAD NewThread, OldThread;
- KIRQL OldIrql;
+ PKTHREAD CurrentThread;
+ PVOID OldStackBase;
+ LONG_PTR StackOffset;
+ SIZE_T StackSize;
+ PKIPCR Pcr;
+ ULONG Eflags;
- /* Raise to DISPATCH_LEVEL */
- OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
+ /* Get the current thread */
+ CurrentThread = KeGetCurrentThread();
- /* Send an EOI */
- KiSendEOI();
+ /* Save the old stack base */
+ OldStackBase = CurrentThread->StackBase;
- /* Check for pending timers, pending DPCs, or pending ready threads */
- if ((Prcb->DpcData[0].DpcQueueDepth) ||
- (Prcb->TimerRequest) ||
- (Prcb->DeferredReadyListHead.Next))
- {
- /* Retire DPCs while under the DPC stack */
- KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
- }
+ /* Get the size of the current stack */
+ StackSize = (ULONG_PTR)CurrentThread->StackBase - CurrentThread->StackLimit;
+ ASSERT(StackSize <= (ULONG_PTR)StackBase - (ULONG_PTR)StackLimit);
- /* Enable interrupts */
- _enable();
+ /* Copy the current stack contents to the new stack */
+ RtlCopyMemory((PUCHAR)StackBase - StackSize,
+ (PVOID)CurrentThread->StackLimit,
+ StackSize);
- /* Check for quantum end */
- if (Prcb->QuantumEnd)
- {
- /* Handle quantum end */
- Prcb->QuantumEnd = FALSE;
- KiQuantumEnd();
- }
- else if (Prcb->NextThread)
- {
- /* Capture current thread data */
- OldThread = Prcb->CurrentThread;
- NewThread = Prcb->NextThread;
+ /* Calculate the offset between the old and the new stack */
+ StackOffset = (PUCHAR)StackBase - (PUCHAR)CurrentThread->StackBase;
- /* Set new thread data */
- Prcb->NextThread = NULL;
- Prcb->CurrentThread = NewThread;
+ /* Disable interrupts while messing with the stack */
+ Eflags = __readeflags();
+ _disable();
- /* The thread is now running */
- NewThread->State = Running;
- OldThread->WaitReason = WrDispatchInt;
+ /* Set the new trap frame */
+ CurrentThread->TrapFrame = (PKTRAP_FRAME)Add2Ptr(CurrentThread->TrapFrame,
+ StackOffset);
- /* Make the old thread ready */
- KxQueueReadyThread(OldThread, Prcb);
+ /* Set the new initial stack */
+ CurrentThread->InitialStack = Add2Ptr(CurrentThread->InitialStack,
+ StackOffset);
- /* Swap to the new thread */
- KiSwapContext(APC_LEVEL, OldThread);
- }
+ /* Set the new stack limits */
+ CurrentThread->StackBase = StackBase;
+ CurrentThread->StackLimit = (ULONG_PTR)StackLimit;
+ CurrentThread->LargeStack = TRUE;
- /* Go back to old irql and disable interrupts */
- KeLowerIrql(OldIrql);
- _disable();
-}
+ /* Adjust RspBase in the PCR */
+ Pcr = (PKIPCR)KeGetPcr();
+ Pcr->Prcb.RspBase += StackOffset;
+ /* Adjust Rsp0 in the TSS */
+ Pcr->TssBase->Rsp0 += StackOffset;
-VOID
-FASTCALL
-KeZeroPages(IN PVOID Address,
- IN ULONG Size)
-{
- /* Not using XMMI in this routine */
- RtlZeroMemory(Address, Size);
-}
+ /* Restore interrupts */
+ __writeeflags(Eflags);
-PVOID
-NTAPI
-KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
-{
- UNIMPLEMENTED;
- __debugbreak();
- return NULL;
-}
-
-NTSTATUS
-NTAPI
-KeUserModeCallback(IN ULONG RoutineIndex,
- IN PVOID Argument,
- IN ULONG ArgumentLength,
- OUT PVOID *Result,
- OUT PULONG ResultLength)
-{
- UNIMPLEMENTED;
- __debugbreak();
- return STATUS_UNSUCCESSFUL;
+ return OldStackBase;
}
+DECLSPEC_NORETURN
VOID
-FASTCALL
KiIdleLoop(VOID)
{
PKPRCB Prcb = KeGetCurrentPrcb();
PKTHREAD OldThread, NewThread;
- /* Initialize the idle loop: disable interrupts */
- _enable();
- YieldProcessor();
- YieldProcessor();
- _disable();
-
/* Now loop forever */
while (TRUE)
{
+ /* Start of the idle loop: disable interrupts */
+ _enable();
+ YieldProcessor();
+ YieldProcessor();
+ _disable();
+
/* Check for pending timers, pending DPCs, or pending ready threads */
if ((Prcb->DpcData[0].DpcQueueDepth) ||
(Prcb->TimerRequest) ||
/* Check if a new thread is scheduled for execution */
if (Prcb->NextThread)
{
- /* Enable interupts */
+ /* Enable interrupts */
_enable();
/* Capture current thread data */
/* The thread is now running */
NewThread->State = Running;
+#ifdef CONFIG_SMP
/* Do the swap at SYNCH_LEVEL */
KfRaiseIrql(SYNCH_LEVEL);
+#endif
/* Switch away from the idle thread */
KiSwapContext(APC_LEVEL, OldThread);
+#ifdef CONFIG_SMP
/* Go back to DISPATCH_LEVEL */
KeLowerIrql(DISPATCH_LEVEL);
-
- /* We are back in the idle thread -- disable interrupts again */
- _enable();
- YieldProcessor();
- YieldProcessor();
- _disable();
+#endif
}
else
{
}
}
-
-/*! \name KiInitializeUserApc
- *
- * \brief
- * Prepares the current trap frame (which must have come from user mode)
- * with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT
- * record with the context from the old trap frame to the threads user
- * mode stack.
- *
- * \param ExceptionFrame
- * \param TrapFrame
- * \param NormalRoutine
- * \param NormalContext
- * \param SystemArgument1
- * \param SystemArgument2
- *
- * \remarks
- * This function is called from KiDeliverApc, when the trap frame came
- * from user mode. This happens before a systemcall or interrupt exits back
- * to usermode or when a thread is started from PspUserThreadstartup.
- * The trap exit code will then leave to KiUserApcDispatcher which in turn
- * calls the NormalRoutine, passing NormalContext, SystemArgument1 and
- * SystemArgument2 as parameters. When that function returns, it calls
- * NtContinue to return back to the kernel, where the old context that was
- * saved on the usermode stack is restored and execution is transferred
- * back to usermode, where the original trap originated from.
- *
- *--*/
-VOID
-NTAPI
-KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
- IN PKTRAP_FRAME TrapFrame,
- IN PKNORMAL_ROUTINE NormalRoutine,
- IN PVOID NormalContext,
- IN PVOID SystemArgument1,
- IN PVOID SystemArgument2)
-{
- CONTEXT Context;
- ULONG64 AlignedRsp, Stack;
- EXCEPTION_RECORD SehExceptRecord;
-
- /* Sanity check, that the trap frame is from user mode */
- ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
-
- /* Convert the current trap frame to a context */
- Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
- KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
-
- /* We jump to KiUserApcDispatcher in ntdll */
- TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
-
- /* Setup Ring 3 segments */
- TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
- TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
- TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
- TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
- TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
- TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
-
- /* Sanitize EFLAGS, enable interrupts */
- TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE);
- TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
-
- /* Set parameters for KiUserApcDispatcher */
- Context.P1Home = (ULONG64)NormalContext;
- Context.P2Home = (ULONG64)SystemArgument1;
- Context.P3Home = (ULONG64)SystemArgument2;
- Context.P4Home = (ULONG64)NormalRoutine;
-
- /* Check if thread has IOPL and force it enabled if so */
- //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
-
- /* Align Stack to 16 bytes and allocate space */
- AlignedRsp = Context.Rsp & ~15;
- Stack = AlignedRsp - sizeof(CONTEXT);
- TrapFrame->Rsp = Stack;
-
- /* The stack must be 16 byte aligned for KiUserApcDispatcher */
- ASSERT((Stack & 15) == 0);
-
- /* Protect with SEH */
- _SEH2_TRY
- {
- /* Probe the stack */
- ProbeForWrite((PCONTEXT)Stack, sizeof(CONTEXT), 8);
-
- /* Copy the context */
- RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT));
- }
- _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
- {
- /* Dispatch the exception */
- SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
- KiDispatchException(&SehExceptRecord,
- ExceptionFrame,
- TrapFrame,
- UserMode,
- TRUE);
- }
- _SEH2_END;
-}
-
VOID
NTAPI
KiSwapProcess(IN PKPROCESS NewProcess,
IN PKPROCESS OldProcess)
{
PKIPCR Pcr = (PKIPCR)KeGetPcr();
-#ifdef CONFIG_SMP
- LONG SetMember;
+#ifdef CONFIG_SMP
/* Update active processor mask */
- SetMember = (LONG)Pcr->SetMember;
- InterlockedXor((PLONG)&NewProcess->ActiveProcessors, SetMember);
- InterlockedXor((PLONG)&OldProcess->ActiveProcessors, SetMember);
+ InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember);
+ InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember);
#endif
/* Update CR3 */
Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
}
-#define MAX_SYSCALL_PARAMS 16
-
-NTSTATUS
-NtSyscallFailure(void)
-{
- /* This is the failure function */
- return STATUS_ACCESS_VIOLATION;
-}
-
-PVOID
-KiSystemCallHandler(
- IN PKTRAP_FRAME TrapFrame,
- IN ULONG64 P2,
- IN ULONG64 P3,
- IN ULONG64 P4)
-{
- PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
- PKTHREAD Thread;
- PULONG64 KernelParams, UserParams;
- ULONG ServiceNumber, Offset, Count;
- ULONG64 UserRsp;
-
- DPRINT("Syscall #%ld\n", TrapFrame->Rax);
- //__debugbreak();
-
- /* Increase system call count */
- __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
-
- /* Get the current thread */
- Thread = KeGetCurrentThread();
-
- /* Set previous mode */
- Thread->PreviousMode = TrapFrame->PreviousMode = UserMode;
-
- /* Save the old trap frame and set the new */
- TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame;
- Thread->TrapFrame = TrapFrame;
-
- /* Before enabling interrupts get the user rsp from the KPCR */
- UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp));
- TrapFrame->Rsp = UserRsp;
-
- /* Enable interrupts */
- _enable();
-
- /* If the usermode rsp was not a usermode address, prepare an exception */
- if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress;
-
- /* Get the address of the usermode and kernelmode parameters */
- UserParams = (PULONG64)UserRsp + 1;
- KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS;
-
- /* Get the system call number from the trap frame and decode it */
- ServiceNumber = (ULONG)TrapFrame->Rax;
- Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
- ServiceNumber &= SERVICE_NUMBER_MASK;
-
- /* Get descriptor table */
- DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
-
- /* Get stack bytes and calculate argument count */
- Count = DescriptorTable->Number[ServiceNumber] / 8;
-
- __try
- {
- switch (Count)
- {
- case 16: KernelParams[15] = UserParams[15];
- case 15: KernelParams[14] = UserParams[14];
- case 14: KernelParams[13] = UserParams[13];
- case 13: KernelParams[12] = UserParams[12];
- case 12: KernelParams[11] = UserParams[11];
- case 11: KernelParams[10] = UserParams[10];
- case 10: KernelParams[9] = UserParams[9];
- case 9: KernelParams[8] = UserParams[8];
- case 8: KernelParams[7] = UserParams[7];
- case 7: KernelParams[6] = UserParams[6];
- case 6: KernelParams[5] = UserParams[5];
- case 5: KernelParams[4] = UserParams[4];
- case 4: KernelParams[3] = P4;
- case 3: KernelParams[2] = P3;
- case 2: KernelParams[1] = P2;
- case 1: KernelParams[0] = TrapFrame->R10;
- case 0:
- break;
-
- default:
- __debugbreak();
- break;
- }
- }
- __except(1)
- {
- TrapFrame->Rax = _SEH2_GetExceptionCode();
- return (PVOID)NtSyscallFailure;
- }
-
-
- return (PVOID)DescriptorTable->Base[ServiceNumber];
-}
-
-
-// FIXME: we need to
-VOID
-KiSystemService(IN PKTHREAD Thread,
- IN PKTRAP_FRAME TrapFrame,
- IN ULONG Instruction)
-{
- UNIMPLEMENTED;
- __debugbreak();
-}
-
-NTSYSAPI
NTSTATUS
NTAPI
-NtCallbackReturn
-( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status )
-{
- UNIMPLEMENTED;
- __debugbreak();
- return STATUS_UNSUCCESSFUL;
-}
-
-NTSTATUS
-NTAPI
-NtSetLdtEntries
-(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
+NtSetLdtEntries(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
{
UNIMPLEMENTED;
__debugbreak();
/* Not supported */
return STATUS_NOT_IMPLEMENTED;
}
-
-NTSTATUS
-NTAPI
-KiCallUserMode(
- IN PVOID *OutputBuffer,
- IN PULONG OutputLength)
-{
- UNIMPLEMENTED;
- __debugbreak();
- return STATUS_UNSUCCESSFUL;
-}
-
-#undef ExQueryDepthSList
-NTKERNELAPI
-USHORT
-ExQueryDepthSList(IN PSLIST_HEADER ListHead)
-{
- return (USHORT)(ListHead->Alignment & 0xffff);
-}
-
-
-ULONG ProcessCount;
-BOOLEAN CcPfEnablePrefetcher;
-
-