[NTOS]: Implement "Edited Trap Frame" exit. This funky trick is actually how NT emula...
authorSir Richard <sir_richard@svn.reactos.org>
Tue, 19 Jan 2010 08:20:12 +0000 (08:20 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Tue, 19 Jan 2010 08:20:12 +0000 (08:20 +0000)
[NTOS]: Implement C version of KiServiceExit, the second system call exit routine. This one sets a new EAX value to be returned to the caller and is used by system calls.
[NTOS]: Implement NtContinue in C instead of ASM. Due to the changes above, this can now be done in C and use the new KiServiceExit.

svn path=/trunk/; revision=45142

reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/include/internal/trap_x.h
reactos/ntoskrnl/ke/i386/trap.s
reactos/ntoskrnl/ke/i386/traphdlr.c

index fd26514..ce788e2 100644 (file)
@@ -932,6 +932,14 @@ KiEndUnexpectedRange(
     VOID
 );
 
+NTSTATUS
+NTAPI
+KiContinue(
+    IN PCONTEXT Context,
+    IN PKEXCEPTION_FRAME ExceptionFrame,
+    IN PKTRAP_FRAME TrapFrame
+);
+
 VOID
 FASTCALL
 KiServiceExit2(
index 0a707c7..c9917d2 100644 (file)
@@ -322,3 +322,35 @@ KiTrapReturn(IN PKTRAP_FRAME TrapFrame)
         : "%esp"
     );
 }
+
+FORCEINLINE
+VOID
+KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame)
+{
+    /* Regular interrupt exit */
+    __asm__ __volatile__
+    (
+        "movl %0, %%esp\n"
+        "movl %c[a](%%esp), %%eax\n"
+        "movl %c[b](%%esp), %%ebx\n"
+        "movl %c[c](%%esp), %%ecx\n"
+        "movl %c[d](%%esp), %%edx\n"
+        "movl %c[s](%%esp), %%esi\n"
+        "movl %c[i](%%esp), %%edi\n"
+        "movl %c[p](%%esp), %%ebp\n"
+        "addl $%c[e],%%esp\n"
+        "movl (%%esp), %%esp\n"
+        "iret\n"
+        :
+        : "r"(TrapFrame),
+          [a] "i"(KTRAP_FRAME_EAX),
+          [b] "i"(KTRAP_FRAME_EBX),
+          [c] "i"(KTRAP_FRAME_ECX),
+          [d] "i"(KTRAP_FRAME_EDX),
+          [s] "i"(KTRAP_FRAME_ESI),
+          [i] "i"(KTRAP_FRAME_EDI),
+          [p] "i"(KTRAP_FRAME_EBP),
+          [e] "i"(KTRAP_FRAME_ERROR_CODE) /* We *WANT* the error code since ESP is there! */
+        : "%esp"
+    );
+}
index 4d725cc..43d5908 100644 (file)
@@ -523,52 +523,10 @@ _NtRaiseException@12:
 
 .func NtContinue@8
 _NtContinue@8:
-
-    /* NOTE: We -must- be called by Zw* to have the right frame! */
-    /* Push the stack frame */
-    push ebp
-
-    /* Get the current thread and restore its trap frame */
-    mov ebx, PCR[KPCR_CURRENT_THREAD]
-    mov edx, [ebp+KTRAP_FRAME_EDX]
-    mov [ebx+KTHREAD_TRAP_FRAME], edx
-
-    /* Set up stack frame */
-    mov ebp, esp
-
-    /* Save the parameters */
-    mov eax, [ebp+0]
-    mov ecx, [ebp+8]
-
-    /* Call KiContinue */
-    push eax
-    push 0
-    push ecx
-    call _KiContinue@12
-
-    /* Check if we failed (bad context record) */
-    or eax, eax
-    jnz Error
-
-    /* Check if test alert was requested */
-    cmp dword ptr [ebp+12], 0
-    je DontTest
-
-    /* Test alert for the thread */
-    mov al, [ebx+KTHREAD_PREVIOUS_MODE]
-    push eax
-    call _KeTestAlertThread@4
-
-DontTest:
-    /* Return to previous context */
-    pop ebp
-    mov esp, ebp
-    jmp _KiServiceExit2
-
-Error:
-    pop ebp
-    mov esp, ebp
-    jmp _KiServiceExit
+    /* Call C code */
+    mov ecx, [esp+4]
+    mov edx, [esp+8]
+    jmp @NtContinueHandler@8
 .endfunc
 
 /* HARDWARE TRAP HANDLERS ****************************************************/
index ccf5516..edba250 100644 (file)
@@ -54,6 +54,9 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
            IN UCHAR Skip)
 {
     KTRAP_EXIT_SKIP_BITS SkipBits = { .Bits = Skip };
+    PULONG ReturnStack;
+    
+    /* Debugging checks */
     KiExitTrapDebugChecks(TrapFrame, SkipBits);
 
     /* Restore the SEH handler chain */
@@ -81,12 +84,42 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
 
     /* Check if the trap frame was edited */
     if (__builtin_expect(!(TrapFrame->SegCs & FRAME_EDITED), 0))
-    {
-        /* Not handled yet */
-        UNIMPLEMENTED;
-        KiDumpTrapFrame(TrapFrame);
-        DbgBreakPoint();
-        while (TRUE);
+    {   
+        /*
+         * An edited trap frame happens when we need to modify CS and/or ESP but
+         * don't actually have a ring transition. This happens when a kernelmode
+         * caller wants to perform an NtContinue to another kernel address, such
+         * as in the case of SEH (basically, a longjmp), or to a user address.
+         *
+         * Therefore, the CPU never saved CS/ESP on the stack because we did not
+         * get a trap frame due to a ring transition (there was no interrupt).
+         * Even if we didn't want to restore CS to a new value, a problem occurs
+         * due to the fact a normal RET would not work if we restored ESP since
+         * RET would then try to read the result off the stack.
+         *
+         * The NT kernel solves this by adding 12 bytes of stack to the exiting
+         * trap frame, in which EFLAGS, CS, and EIP are stored, and then saving
+         * the ESP that's being requested into the ErrorCode field. It will then
+         * exit with an IRET. This fixes both issues, because it gives the stack
+         * some space where to hold the return address and then end up with the
+         * wanted stack, and it uses IRET which allows a new CS to be inputted.
+         *
+         */
+         
+        /* Set CS that is requested */
+        TrapFrame->SegCs = TrapFrame->TempSegCs;
+         
+        /* First make space on requested stack */
+        ReturnStack = (PULONG)(TrapFrame->TempEsp - 12);
+        TrapFrame->ErrCode = (ULONG_PTR)ReturnStack;
+         
+        /* Now copy IRET frame */
+        ReturnStack[0] = TrapFrame->Eip;
+        ReturnStack[1] = TrapFrame->SegCs;
+        ReturnStack[2] = TrapFrame->EFlags;
+        
+        /* Do special edited return */
+        KiEditedTrapReturn(TrapFrame);
     }
     
     /* Check if this is a user trap */
@@ -214,6 +247,24 @@ KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
     KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT);
 }
 
+VOID
+FASTCALL
+KiServiceExit(IN PKTRAP_FRAME TrapFrame,
+              IN NTSTATUS Status)
+{
+    /* Disable interrupts until we return */
+    _disable();
+    
+    /* Check for APC delivery */
+    KiCheckForApcDelivery(TrapFrame);
+    
+    /* Copy the status into EAX */
+    TrapFrame->Eax = Status;
+    
+    /* Now exit the trap for real */
+    KiExitTrap(TrapFrame, KTE_SKIP_SEG_BIT | KTE_SKIP_VOL_BIT);
+}
+
 VOID
 FASTCALL
 KiServiceExit2(IN PKTRAP_FRAME TrapFrame)
@@ -1640,6 +1691,37 @@ KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
 }
 
+VOID
+FASTCALL
+NtContinueHandler(IN PCONTEXT Context,
+                  IN BOOLEAN TestAlert)
+{
+    PKTHREAD Thread;
+    NTSTATUS Status;
+    PKTRAP_FRAME TrapFrame;
+    
+    /* Get trap frame and link previous one*/
+    Thread = KeGetCurrentThread();
+    TrapFrame = Thread->TrapFrame;
+    Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
+    
+    /* Continue from this point on */
+    Status = KiContinue(Context, NULL, TrapFrame);
+    if (NT_SUCCESS(Status))
+    {
+        /* Check if alert was requested */
+        if (TestAlert) KeTestAlertThread(Thread->PreviousMode);
+        
+        /* Exit to new trap frame */
+        KiServiceExit2(TrapFrame);
+    }
+    else
+    {
+        /* Exit with an error */
+        KiServiceExit(TrapFrame, Status);
+    }
+}
+
 /* HARDWARE INTERRUPTS ********************************************************/
 
 /*