* 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,
// #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