#define NDEBUG
#include <debug.h>
+VOID
+KiRetireDpcListInDpcStack(
+ PKPRCB Prcb,
+ PVOID DpcStack);
+
VOID
NTAPI
-KiDispatchInterrupt(VOID)
+KiDpcInterruptHandler(VOID)
{
- UNIMPLEMENTED;
- __debugbreak();
+ PKPRCB Prcb = KeGetCurrentPrcb();
+ PKTHREAD NewThread, OldThread;
+ KIRQL OldIrql;
+
+ /* Raise to DISPATCH_LEVEL */
+ OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
+
+ /* Send an EOI */
+ KiSendEOI();
+
+ /* 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);
+ }
+
+ /* Enable interrupts */
+ _enable();
+
+ /* 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;
+
+ /* Set new thread data */
+ Prcb->NextThread = NULL;
+ Prcb->CurrentThread = NewThread;
+
+ /* The thread is now running */
+ NewThread->State = Running;
+ OldThread->WaitReason = WrDispatchInt;
+
+ /* Make the old thread ready */
+ KxQueueReadyThread(OldThread, Prcb);
+
+ /* Swap to the new thread */
+ KiSwapContext(APC_LEVEL, OldThread);
+ }
+
+ /* Go back to old irql and disable interrupts */
+ KeLowerIrql(OldIrql);
+ _disable();
}
+
VOID
FASTCALL
KeZeroPages(IN PVOID Address,
RtlZeroMemory(Address, Size);
}
-VOID
-FASTCALL
-DECLSPEC_NORETURN
-KiServiceExit(IN PKTRAP_FRAME TrapFrame,
- IN NTSTATUS Status)
-{
- UNIMPLEMENTED;
- __debugbreak();
-}
-
-VOID
-FASTCALL
-DECLSPEC_NORETURN
-KiServiceExit2(IN PKTRAP_FRAME TrapFrame)
-{
- UNIMPLEMENTED;
- __debugbreak();
-}
-
-BOOLEAN
-NTAPI
-KeConnectInterrupt(IN PKINTERRUPT Interrupt)
-{
- UNIMPLEMENTED;
- __debugbreak();
- return FALSE;
-}
-
PVOID
NTAPI
KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
-{
- UNIMPLEMENTED;
- return NULL;
-}
-
-BOOLEAN
-NTAPI
-KeSynchronizeExecution(
- IN OUT PKINTERRUPT Interrupt,
- IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
- IN PVOID SynchronizeContext)
{
UNIMPLEMENTED;
__debugbreak();
- return FALSE;
+ return NULL;
}
NTSTATUS
}
VOID
-KiIdleLoop()
+FASTCALL
+KiIdleLoop(VOID)
{
- UNIMPLEMENTED;
- for(;;);
+ PKPRCB Prcb = KeGetCurrentPrcb();
+ PKTHREAD OldThread, NewThread;
+
+ /* 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) ||
+ (Prcb->DeferredReadyListHead.Next))
+ {
+ /* Quiesce the DPC software interrupt */
+ HalClearSoftwareInterrupt(DISPATCH_LEVEL);
+
+ /* Handle it */
+ KiRetireDpcList(Prcb);
+ }
+
+ /* Check if a new thread is scheduled for execution */
+ if (Prcb->NextThread)
+ {
+ /* Enable interrupts */
+ _enable();
+
+ /* Capture current thread data */
+ OldThread = Prcb->CurrentThread;
+ NewThread = Prcb->NextThread;
+
+ /* Set new thread data */
+ Prcb->NextThread = NULL;
+ Prcb->CurrentThread = NewThread;
+
+ /* The thread is now running */
+ NewThread->State = Running;
+
+ /* Do the swap at SYNCH_LEVEL */
+ KfRaiseIrql(SYNCH_LEVEL);
+
+ /* Switch away from the idle thread */
+ KiSwapContext(APC_LEVEL, OldThread);
+
+ /* Go back to DISPATCH_LEVEL */
+ KeLowerIrql(DISPATCH_LEVEL);
+ }
+ else
+ {
+ /* Continue staying idle. Note the HAL returns with interrupts on */
+ Prcb->PowerState.IdleFunction(&Prcb->PowerState);
+ }
+ }
}
+
+/*! \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 PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
- UNIMPLEMENTED;
- __debugbreak();
+ 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
KiSwapProcess(IN PKPROCESS NewProcess,
IN PKPROCESS OldProcess)
{
- UNIMPLEMENTED;
- __debugbreak();
+ PKIPCR Pcr = (PKIPCR)KeGetPcr();
+#ifdef CONFIG_SMP
+ LONG SetMember;
+
+ /* Update active processor mask */
+ SetMember = (LONG)Pcr->SetMember;
+ InterlockedXor((PLONG)&NewProcess->ActiveProcessors, SetMember);
+ InterlockedXor((PLONG)&OldProcess->ActiveProcessors, SetMember);
+#endif
+
+ /* Update CR3 */
+ __writecr3(NewProcess->DirectoryTableBase[0]);
+
+ /* Update IOPM offset */
+ 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,
(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
{
UNIMPLEMENTED;
+ __debugbreak();
return STATUS_UNSUCCESSFUL;
}
NtVdmControl(IN ULONG ControlCode,
IN PVOID ControlData)
{
- UNIMPLEMENTED;
- __debugbreak();
- return STATUS_UNSUCCESSFUL;
+ /* Not supported */
+ return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
return STATUS_UNSUCCESSFUL;
}
-#undef ExQueryDepthSList
-NTKERNELAPI
-USHORT
-ExQueryDepthSList(IN PSLIST_HEADER ListHead)
-{
- return (USHORT)(ListHead->Alignment & 0xffff);
-}
-
-
ULONG ProcessCount;
BOOLEAN CcPfEnablePrefetcher;