[NTOS]
[reactos.git] / reactos / ntoskrnl / include / internal / i386 / asmmacro.S
index d0fabe9..d84872a 100644 (file)
@@ -4,17 +4,12 @@
  * FILE:            ntoskrnl/include/i386/asmmacro.S
  * PURPOSE:         Assembly Macros for Spinlocks and common Trap Code
  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  Timo Kreuzer (timo.kreuzer@reactos.org)
  */
  
-/* INCLUDES ******************************************************************/
-
-#include <ndk/asm.h>
-
 // Arguments for idt
-#define INT_32_DPL0                 0x8E00
-#define INT_32_DPL3                 0xEE00
-
-.intel_syntax noprefix
+#define INT_32_DPL0                 HEX(08E00)
+#define INT_32_DPL3                 HEX(0EE00)
 
 //
 // These macros are inlined equivalents of KiAcquire/ReleaseSpinlock, that is,
@@ -30,7 +25,7 @@
 //  #IFDEF CONFIG_SMP
 //  .spin
 //      <any necessary steps to be able to jump back safely>
-/       SPIN_ON_LOCK(reg, .BeginYourFunction)
+//       SPIN_ON_LOCK(reg, .BeginYourFunction)
 //  #ENDIF
 //
 #ifdef CONFIG_SMP
 //
 // @remark None.
 //
-.macro idt Handler, Bits
-    .long \Handler
-    .short \Bits
+MACRO(idt, Handler, Bits)
+    .long VAL(Handler)
+    .short VAL(Bits)
     .short KGDT_R0_CODE
-.endm
+ENDM
 
-//
-// @name GENERATE_IDT_STUB
-//
-// This macro creates an IDT entry for an unexpected interrupt handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_IDT_STUB Number
-idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
-.endm
 
-//
-// @name GENERATE_IDT_STUBS
-//
-// This macro creates unexpected interrupt IDT entries.
-//
-// @param None.
-//
-// @remark None.
-//
-.altmacro
-.macro GENERATE_IDT_STUBS
-.set i, 0
-.rept 208
-    GENERATE_IDT_STUB %i
-    .set i, i + 1
-.endr
-.endm
+KI_PUSH_FAKE_ERROR_CODE = HEX(0001)
+KI_UNUSED               = HEX(0002)
+KI_NONVOLATILES_ONLY    = HEX(0004)
+KI_FAST_SYSTEM_CALL     = HEX(0008)
+KI_SOFTWARE_TRAP        = HEX(0010)
+KI_HARDWARE_INT         = HEX(0020)
+KI_DONT_SAVE_SEGS       = HEX(0100)
 
-//
-// @name GENERATE_INT_HANDLER
-//
-// This macro creates an unexpected interrupt handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_INT_HANDLER Number
-.func KiUnexpectedInterrupt&Number
-_KiUnexpectedInterrupt&Number:
-    mov eax, PRIMARY_VECTOR_BASE + Number
-    jmp _KiEndUnexpectedRange@0
-.endfunc
-.endm
+MACRO(KiEnterTrap, Flags)
+    LOCAL kernel_trap
+    LOCAL not_v86_trap
+    LOCAL set_sane_segs
+
+    /* Check what kind of trap frame this trap requires */
+    if (Flags AND KI_FAST_SYSTEM_CALL)
+
+        /* SYSENTER requires us to build a complete ring transition trap frame */
+        FrameSize = KTRAP_FRAME_V86_ES
+
+        /* Fixup fs. cx is free to clobber */
+        mov cx, KGDT_R0_PCR
+        mov fs, cx
+
+        /* Get pointer to the TSS */
+        mov ecx, fs:[KPCR_TSS]
+
+        /* Get a stack pointer */
+        mov esp, [ecx + KTSS_ESP0]
+
+    elseif (Flags AND KI_SOFTWARE_TRAP)
+
+        /* Software traps need a complete non-ring transition trap frame */
+        FrameSize = KTRAP_FRAME_ESP
+
+        /* Software traps need to get their EIP from the caller's frame */
+        pop eax
+
+    elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
+
+        /* If the trap doesn't have an error code, we'll make space for it */
+        FrameSize = KTRAP_FRAME_EIP
+
+    else
+
+        /* The trap already has an error code, so just make space for the rest */
+        FrameSize = KTRAP_FRAME_ERROR_CODE
+
+    endif
+
+    /* Make space for this frame */
+    sub esp, FrameSize
+
+    /* Save nonvolatile registers */
+    mov [esp + KTRAP_FRAME_EBP], ebp
+    mov [esp + KTRAP_FRAME_EBX], ebx
+    mov [esp + KTRAP_FRAME_ESI], esi
+    mov [esp + KTRAP_FRAME_EDI], edi
+
+    /* Save eax for system calls, for use by the C handler */
+    mov [esp + KTRAP_FRAME_EAX], eax
+
+    /* Does the caller want nonvolatiles only? */
+    if (NOT (Flags AND KI_NONVOLATILES_ONLY))
+        /* Otherwise, save the volatiles as well */
+        mov [esp + KTRAP_FRAME_ECX], ecx
+        mov [esp + KTRAP_FRAME_EDX], edx
+    endif
+
+    /* Save segment registers? */
+    if (Flags AND KI_DONT_SAVE_SEGS)
+
+        /* Initialize TrapFrame segment registers with sane values */
+        mov eax, 0x23
+        mov ecx, fs
+        mov [esp - FrameSize + KTRAP_FRAME_DS], eax
+        mov [esp - FrameSize + KTRAP_FRAME_ES], eax
+        mov [esp - FrameSize + KTRAP_FRAME_FS], ecx
+        mov dword ptr [esp - FrameSize + KTRAP_FRAME_GS], 0
+
+    else
+
+        /* Check for V86 mode */
+        test byte ptr [esp + KTRAP_FRAME_EFLAGS + 2], (EFLAGS_V86_MASK / HEX(10000))
+        jz not_v86_trap
+
+            /* Restore V8086 segments into Protected Mode segments */
+            mov eax, [esp + KTRAP_FRAME_V86_DS]
+            mov ecx, [esp + KTRAP_FRAME_V86_ES]
+            mov [esp + KTRAP_FRAME_DS], eax
+            mov [esp + KTRAP_FRAME_ES], ecx
+            mov eax, [esp + KTRAP_FRAME_V86_FS]
+            mov ecx, [esp + KTRAP_FRAME_V86_GS]
+            mov [esp + KTRAP_FRAME_FS], eax
+            mov [esp + KTRAP_FRAME_GS], ecx
+            jmp set_sane_segs
+
+        not_v86_trap:
+
+            /* Save segment selectors */
+            mov eax, ds
+            mov ecx, es
+            mov [esp + KTRAP_FRAME_DS], eax
+            mov [esp + KTRAP_FRAME_ES], ecx
+            mov eax, fs
+            mov ecx, gs
+            mov [esp + KTRAP_FRAME_FS], eax
+            mov [esp + KTRAP_FRAME_GS], ecx
+
+    endif
+
+set_sane_segs:
+    /* Load correct data segments */
+    mov ax, KGDT_R3_DATA OR RPL_MASK
+    mov ds, ax
+    mov es, ax
+
+    /* Fast system calls have fs already fixed */
+    if (NOT (Flags AND KI_FAST_SYSTEM_CALL))
+        /* Otherwise fix fs now */
+        mov ax, KGDT_R0_PCR
+        mov fs, ax
+    endif
+
+#if DBG
+    /* Keep the frame chain intact */
+    mov eax, [esp + KTRAP_FRAME_EIP]
+    mov [esp + KTRAP_FRAME_DEBUGEIP], eax
+    mov [esp + KTRAP_FRAME_DEBUGEBP], ebp
+    mov ebp, esp
+#endif
+
+    /* Set parameter 1 (ECX) to point to the frame */
+    mov ecx, esp
+
+    /* Clear direction flag */
+    cld
+
+ENDM
+
+MACRO(KiCallHandler, Handler)
+#if DBG
+    /* Use a call to get the return address for back traces */
+    call Handler
+#else
+    /* Use the faster jmp */
+    jmp Handler
+#endif
+    nop
+ENDM
+
+MACRO(TRAP_ENTRY, Trap, Flags)
+EXTERN @&Trap&Handler@4 :PROC
+    PUBLIC _&Trap
+    _&Trap:
+    KiEnterTrap Flags
+    KiCallHandler @&Trap&Handler@4
+ENDM
+
+#define KI_RESTORE_EAX        HEX(001)
+#define KI_RESTORE_ECX_EDX    HEX(002)
+#define KI_RESTORE_FS         HEX(004)
+#define KI_RESTORE_SEGMENTS   HEX(008)
+#define KI_RESTORE_EFLAGS     HEX(010)
+#define KI_EXIT_SYSCALL       HEX(020)
+#define KI_EXIT_JMP           HEX(040)
+#define KI_EXIT_RET           HEX(080)
+#define KI_EXIT_IRET          HEX(100)
+#define KI_EDITED_FRAME       HEX(200)
+#define KI_RESTORE_VOLATILES  (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX)
+
+MACRO(KiTrapExitStub, Name, Flags)
+
+PUBLIC @&Name&@4
+@&Name&@4:
+
+    if (Flags AND KI_RESTORE_EFLAGS)
+
+        /* We will pop EFlags off the stack */
+        OffsetEsp = KTRAP_FRAME_EFLAGS
+
+    elseif (Flags AND KI_EXIT_IRET)
+
+        /* This is the IRET frame */
+        OffsetEsp = KTRAP_FRAME_EIP
+
+    else
+
+        OffsetEsp = 0
+
+    endif
+
+    if (Flags AND KI_EDITED_FRAME)
+
+        /* Load the requested ESP */
+        mov esp, [ecx + KTRAP_FRAME_TEMPESP]
+
+        /* Put return address on the new stack */
+        push [ecx + KTRAP_FRAME_EIP]
+
+        /* Put EFLAGS on the new stack */
+        push [ecx + KTRAP_FRAME_EFLAGS]
+
+    else
+
+        /* Point esp to an appropriate member of the frame */
+        lea esp, [ecx + OffsetEsp]
+
+    endif
+
+    /* Restore non volatiles */
+    mov ebx, [ecx + KTRAP_FRAME_EBX]
+    mov esi, [ecx + KTRAP_FRAME_ESI]
+    mov edi, [ecx + KTRAP_FRAME_EDI]
+    mov ebp, [ecx + KTRAP_FRAME_EBP]
+
+    if (Flags AND KI_RESTORE_EAX)
+
+        /* Restore eax */
+        mov eax, [ecx + KTRAP_FRAME_EAX]
+
+    endif
+
+    if (Flags AND KI_RESTORE_ECX_EDX)
+
+        /* Restore volatiles */
+        mov edx, [ecx + KTRAP_FRAME_EDX]
+        mov ecx, [ecx + KTRAP_FRAME_ECX]
+
+    elseif (Flags AND KI_EXIT_JMP)
+
+        /* Load return address into edx */
+        mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
+
+    elseif (Flags AND KI_EXIT_SYSCALL)
+
+        /* Set sysexit parameters */
+        mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
+        mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP]
+
+        /* Keep interrupts disabled until the sti / sysexit */
+        and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], NOT (EFLAGS_INTERRUPT_MASK / HEX(100))
+
+    endif
+
+    if (Flags AND KI_RESTORE_SEGMENTS)
+
+        /* Restore segments for user mode */
+        mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS]
+        mov es, [esp - OffsetEsp + KTRAP_FRAME_ES]
+        mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS]
+
+    endif
+
+    if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS))
+
+        /* Restore user mode FS */
+        mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS]
+
+    endif
+
+    if (Flags AND KI_RESTORE_EFLAGS)
+
+        /* Restore EFLAGS */
+        popf
+
+    endif
+
+    if (Flags AND KI_EXIT_SYSCALL)
+
+        /* Enable interrupts and return to user mode.
+           Both must follow directly after another to be "atomic". */
+        sti
+        sysexit
+
+    elseif (Flags AND KI_EXIT_IRET)
+
+        /* Return with iret */
+        iret
+
+    elseif (Flags AND KI_EXIT_JMP)
+
+        /* Return to kernel mode with a jmp */
+        jmp edx
+
+    elseif (Flags AND KI_EXIT_RET)
+
+        /* Return to kernel mode with a ret */
+        ret
+
+    endif
+
+ENDM
 
-//
-// @name GENERATE_INT_HANDLERS
-//
-// This macro creates the unexpected interrupt handlers.
-//
-// @param None.
-//
-// @remark None.
-//
-.altmacro
-.macro GENERATE_INT_HANDLERS
-.set i, 0
-.rept 208
-    GENERATE_INT_HANDLER %i
-    .set i, i + 1
-.endr
-.endm