[STORPORT] Fix x64 build
[reactos.git] / ntoskrnl / ke / amd64 / stubs.c
index ae21d74..f63485e 100644 (file)
 #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,
@@ -29,52 +86,13 @@ 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
@@ -91,12 +109,95 @@ KeUserModeCallback(IN ULONG RoutineIndex,
 }
 
 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,
@@ -106,8 +207,69 @@ 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
@@ -115,10 +277,126 @@ NTAPI
 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,
@@ -145,6 +423,7 @@ NtSetLdtEntries
 (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2)
 {
     UNIMPLEMENTED;
+    __debugbreak();
     return STATUS_UNSUCCESSFUL;
 }
 
@@ -153,9 +432,8 @@ NTAPI
 NtVdmControl(IN ULONG ControlCode,
              IN PVOID ControlData)
 {
-    UNIMPLEMENTED;
-    __debugbreak();
-    return STATUS_UNSUCCESSFUL;
+    /* Not supported */
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 NTSTATUS
@@ -169,15 +447,6 @@ KiCallUserMode(
     return STATUS_UNSUCCESSFUL;
 }
 
-#undef ExQueryDepthSList
-NTKERNELAPI
-USHORT
-ExQueryDepthSList(IN PSLIST_HEADER ListHead)
-{
-    return (USHORT)(ListHead->Alignment & 0xffff);
-}
-
-
 ULONG ProcessCount;
 BOOLEAN CcPfEnablePrefetcher;