From a5996ad2bf1c6e31e90d4777f90ef5272582a95f Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Sat, 6 Feb 2010 14:58:23 +0000 Subject: [PATCH] [NTOS]: Combine all exit trap stubs into a single function with flags (same thing we did for the entry stub). Now there are only 15 lines of ASM instead of 60. svn path=/trunk/; revision=45462 --- reactos/ntoskrnl/include/internal/trap_x.h | 366 +++++++++------------ 1 file changed, 156 insertions(+), 210 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/trap_x.h b/reactos/ntoskrnl/include/internal/trap_x.h index 9fe6b1852c4..205aa54e4e8 100644 --- a/reactos/ntoskrnl/include/internal/trap_x.h +++ b/reactos/ntoskrnl/include/internal/trap_x.h @@ -185,216 +185,6 @@ KiUserTrap(IN PKTRAP_FRAME TrapFrame) return (TrapFrame->SegCs & MODE_MASK); } -// -// Assembly exit stubs -// -VOID -FORCEINLINE -/* Do not mark this as DECLSPEC_NORETURN because possibly executing code follows it! */ -KiSystemCallReturn(IN PKTRAP_FRAME TrapFrame) -{ - /* Restore nonvolatiles, EAX, and do a "jump" back to the kernel caller */ - __asm__ __volatile__ - ( - "movl %0, %%esp\n" - "movl %c[b](%%esp), %%ebx\n" - "movl %c[s](%%esp), %%esi\n" - "movl %c[i](%%esp), %%edi\n" - "movl %c[p](%%esp), %%ebp\n" - "movl %c[a](%%esp), %%eax\n" - "movl %c[e](%%esp), %%edx\n" - "addl $%c[v],%%esp\n" /* A WHOLE *KERNEL* frame since we're not IRET'ing */ - "jmp *%%edx\n" - ".globl _KiSystemCallExit2\n_KiSystemCallExit2:\n" - : - : "r"(TrapFrame), - [b] "i"(KTRAP_FRAME_EBX), - [s] "i"(KTRAP_FRAME_ESI), - [i] "i"(KTRAP_FRAME_EDI), - [p] "i"(KTRAP_FRAME_EBP), - [a] "i"(KTRAP_FRAME_EAX), - [e] "i"(KTRAP_FRAME_EIP), - [v] "i"(KTRAP_FRAME_ESP) - : "%esp" - ); -} - -VOID -FORCEINLINE -DECLSPEC_NORETURN -KiSystemCallTrapReturn(IN PKTRAP_FRAME TrapFrame) -{ - /* Regular interrupt exit, but we only restore EAX as a volatile */ - __asm__ __volatile__ - ( - ".globl _KiSystemCallExit\n_KiSystemCallExit:\n" - "movl %0, %%esp\n" - "movl %c[b](%%esp), %%ebx\n" - "movl %c[s](%%esp), %%esi\n" - "movl %c[i](%%esp), %%edi\n" - "movl %c[p](%%esp), %%ebp\n" - "movl %c[a](%%esp), %%eax\n" - "addl $%c[e],%%esp\n" - "iret\n" - : - : "r"(TrapFrame), - [b] "i"(KTRAP_FRAME_EBX), - [s] "i"(KTRAP_FRAME_ESI), - [i] "i"(KTRAP_FRAME_EDI), - [p] "i"(KTRAP_FRAME_EBP), - [a] "i"(KTRAP_FRAME_EAX), - [e] "i"(KTRAP_FRAME_EIP) - : "%esp" - ); - UNREACHABLE; -} - -VOID -FORCEINLINE -DECLSPEC_NORETURN -KiSystemCallSysExitReturn(IN PKTRAP_FRAME TrapFrame) -{ - /* Restore nonvolatiles, EAX, and do a SYSEXIT back to the user caller */ - __asm__ __volatile__ - ( - "movl %0, %%esp\n" - "movl %c[s](%%esp), %%esi\n" - "movl %c[b](%%esp), %%ebx\n" - "movl %c[i](%%esp), %%edi\n" - "movl %c[p](%%esp), %%ebp\n" - "movl %c[a](%%esp), %%eax\n" - "movl %c[e](%%esp), %%edx\n" /* SYSEXIT says EIP in EDX */ - "movl %c[x](%%esp), %%ecx\n" /* SYSEXIT says ESP in ECX */ - "addl $%c[v],%%esp\n" /* A WHOLE *USER* frame since we're not IRET'ing */ - "sti\nsysexit\n" - : - : "r"(TrapFrame), - [b] "i"(KTRAP_FRAME_EBX), - [s] "i"(KTRAP_FRAME_ESI), - [i] "i"(KTRAP_FRAME_EDI), - [p] "i"(KTRAP_FRAME_EBP), - [a] "i"(KTRAP_FRAME_EAX), - [e] "i"(KTRAP_FRAME_EIP), - [x] "i"(KTRAP_FRAME_ESP), - [v] "i"(KTRAP_FRAME_V86_ES) - : "%esp" - ); - UNREACHABLE; -} - -VOID -FORCEINLINE -DECLSPEC_NORETURN -KiTrapReturn(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" - "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_EIP) - : "%esp" - ); - UNREACHABLE; -} - -VOID -FORCEINLINE -DECLSPEC_NORETURN -KiDirectTrapReturn(IN PKTRAP_FRAME TrapFrame) -{ - /* Regular interrupt exit but we're not restoring any registers */ - __asm__ __volatile__ - ( - "movl %0, %%esp\n" - "addl $%c[e],%%esp\n" - "iret\n" - : - : "r"(TrapFrame), - [e] "i"(KTRAP_FRAME_EIP) - : "%esp" - ); - UNREACHABLE; -} - -VOID -FORCEINLINE -DECLSPEC_NORETURN -KiCallReturn(IN PKTRAP_FRAME TrapFrame) -{ - /* Pops a trap frame out of the stack but returns with RET instead of IRET */ - __asm__ __volatile__ - ( - "movl %0, %%esp\n" - "movl %c[b](%%esp), %%ebx\n" - "movl %c[s](%%esp), %%esi\n" - "movl %c[i](%%esp), %%edi\n" - "movl %c[p](%%esp), %%ebp\n" - "addl $%c[e],%%esp\n" - "ret\n" - : - : "r"(TrapFrame), - [b] "i"(KTRAP_FRAME_EBX), - [s] "i"(KTRAP_FRAME_ESI), - [i] "i"(KTRAP_FRAME_EDI), - [p] "i"(KTRAP_FRAME_EBP), - [e] "i"(KTRAP_FRAME_EIP) - : "%esp" - ); - UNREACHABLE; -} - -VOID -FORCEINLINE -DECLSPEC_NORETURN -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" - ); - UNREACHABLE; -} - // // "BOP" code used by VDM and V8086 Mode // @@ -515,6 +305,162 @@ KiSetSaneSegments(IN PKTRAP_FRAME TrapFrame) TrapFrame->SegEs = Es; } +// +// Generates an Exit Epilog Stub for the given name +// +#define KI_FUNCTION_CALL 0x1 +#define KI_EDITED_FRAME 0x2 +#define KI_DIRECT_EXIT 0x4 +#define KI_FAST_SYSTEM_CALL_EXIT 0x8 +#define KI_SYSTEM_CALL_EXIT 0x10 +#define KI_SYSTEM_CALL_JUMP 0x20 +#define KiTrapExitStub(x, y) VOID FORCEINLINE DECLSPEC_NORETURN x(IN PKTRAP_FRAME TrapFrame) { KiTrapExit(TrapFrame, y); UNREACHABLE; } +#define KiTrapExitStub2(x, y) VOID FORCEINLINE x(IN PKTRAP_FRAME TrapFrame) { KiTrapExit(TrapFrame, y); } + +// +// How volatiles will be restored +// +#define KI_EAX_NO_VOLATILES 0x0 +#define KI_EAX_ONLY 0x1 +#define KI_ALL_VOLATILES 0x2 + +// +// Exit mechanism to use +// +#define KI_EXIT_IRET 0x0 +#define KI_EXIT_SYSEXIT 0x1 +#define KI_EXIT_JMP 0x2 +#define KI_EXIT_RET 0x3 + +// +// Master Trap Epilog +// +VOID +FORCEINLINE +KiTrapExit(IN PKTRAP_FRAME TrapFrame, + IN ULONG Flags) +{ + ULONG FrameSize = FIELD_OFFSET(KTRAP_FRAME, Eip); + ULONG ExitMechanism = KI_EXIT_IRET, Volatiles = KI_ALL_VOLATILES, NonVolatiles = TRUE; + ULONG EcxField = FIELD_OFFSET(KTRAP_FRAME, Ecx), EdxField = FIELD_OFFSET(KTRAP_FRAME, Edx); + + /* System call exit needs a special label */ + if (Flags & KI_SYSTEM_CALL_EXIT) __asm__ __volatile__ + ( + ".globl _KiSystemCallExit\n_KiSystemCallExit:\n" + ); + + /* Start by making the trap frame equal to the stack */ + __asm__ __volatile__ + ( + "movl %0, %%esp\n" + : + : "r"(TrapFrame) + : "%esp" + ); + + /* Check what kind of trap frame this trap requires */ + if (Flags & KI_FUNCTION_CALL) + { + /* These calls have an EIP on the stack they need */ + ExitMechanism = KI_EXIT_RET; + Volatiles = FALSE; + } + else if (Flags & KI_EDITED_FRAME) + { + /* Edited frames store a new ESP in the error code field */ + FrameSize = FIELD_OFFSET(KTRAP_FRAME, ErrCode); + } + else if (Flags & KI_DIRECT_EXIT) + { + /* Exits directly without restoring anything, interrupt frame on stack */ + NonVolatiles = Volatiles = FALSE; + } + else if (Flags & KI_FAST_SYSTEM_CALL_EXIT) + { + /* We have a fake interrupt stack with a ring transition */ + FrameSize = FIELD_OFFSET(KTRAP_FRAME, V86Es); + ExitMechanism = KI_EXIT_SYSEXIT; + + /* SYSEXIT wants EIP in EDX and ESP in ECX */ + EcxField = FIELD_OFFSET(KTRAP_FRAME, HardwareEsp); + EdxField = FIELD_OFFSET(KTRAP_FRAME, Eip); + } + else if (Flags & KI_SYSTEM_CALL_EXIT) + { + /* Only restore EAX */ + NonVolatiles = KI_EAX_ONLY; + } + else if (Flags & KI_SYSTEM_CALL_JUMP) + { + /* We have a fake interrupt stack with no ring transition */ + FrameSize = FIELD_OFFSET(KTRAP_FRAME, HardwareEsp); + NonVolatiles = KI_EAX_ONLY; + ExitMechanism = KI_EXIT_JMP; + } + + /* Restore the non volatiles */ + if (NonVolatiles) __asm__ __volatile__ + ( + "movl %c[b](%%esp), %%ebx\n" + "movl %c[s](%%esp), %%esi\n" + "movl %c[i](%%esp), %%edi\n" + "movl %c[p](%%esp), %%ebp\n" + : + : [b] "i"(FIELD_OFFSET(KTRAP_FRAME, Ebx)), + [s] "i"(FIELD_OFFSET(KTRAP_FRAME, Esi)), + [i] "i"(FIELD_OFFSET(KTRAP_FRAME, Edi)), + [p] "i"(FIELD_OFFSET(KTRAP_FRAME, Ebp)) + : "%esp" + ); + + /* Restore EAX if volatiles must be restored */ + if (Volatiles) __asm__ __volatile__ + ( + "movl %c[a](%%esp), %%eax\n":: [a] "i"(FIELD_OFFSET(KTRAP_FRAME, Eax)) : "%esp" + ); + + /* Restore the other volatiles if needed */ + if (Volatiles == KI_ALL_VOLATILES) __asm__ __volatile__ + ( + "movl %c[c](%%esp), %%ecx\n" + "movl %c[d](%%esp), %%edx\n" + : + : [c] "i"(EcxField), + [d] "i"(EdxField) + : "%esp" + ); + + /* Ring 0 system calls jump back to EDX */ + if (Flags & KI_SYSTEM_CALL_JUMP) __asm__ __volatile__ + ( + "movl %c[d](%%esp), %%edx\n":: [d] "i"(FIELD_OFFSET(KTRAP_FRAME, Eip)) : "%esp" + ); + + /* Now destroy the trap frame on the stack */ + __asm__ __volatile__ ("addl $%c[e],%%esp\n":: [e] "i"(FrameSize) : "%esp"); + + /* Edited traps need to change to a new ESP */ + if (Flags & KI_EDITED_FRAME) __asm__ __volatile__ ("movl (%%esp), %%esp\n":::"%esp"); + + /* Check the exit mechanism and apply it */ + if (ExitMechanism == KI_EXIT_RET) __asm__ __volatile__("ret\n"::: "%esp"); + else if (ExitMechanism == KI_EXIT_IRET) __asm__ __volatile__("iret\n"::: "%esp"); + else if (ExitMechanism == KI_EXIT_JMP) __asm__ __volatile__("jmp *%%edx\n.globl _KiSystemCallExit2\n_KiSystemCallExit2:\n"::: "%esp"); + else if (ExitMechanism == KI_EXIT_SYSEXIT) __asm__ __volatile__("sti\nsysexit\n"::: "%esp"); +} + +// +// All the specific trap epilog stubs +// +KiTrapExitStub (KiTrapReturn, 0); +KiTrapExitStub (KiDirectTrapReturn, KI_DIRECT_EXIT); +KiTrapExitStub (KiCallReturn, KI_FUNCTION_CALL); +KiTrapExitStub (KiEditedTrapReturn, KI_EDITED_FRAME); +KiTrapExitStub2(KiSystemCallReturn, KI_SYSTEM_CALL_JUMP); +KiTrapExitStub (KiSystemCallSysExitReturn, KI_FAST_SYSTEM_CALL_EXIT); +KiTrapExitStub (KiSystemCallTrapReturn, KI_SYSTEM_CALL_EXIT); + // // Generic Exit Routine //