📄 asmmacro.s
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/include/i386/asmmacro.S
* PURPOSE: Assembly Macros for Spinlocks and common Trap Code
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ******************************************************************/
#include <ndk/asm.h>
// Arguments for TRAP_EPILOG
#define FromSystemCall 1
#define DoRestorePreviousMode 1
#define DoRestoreEverything 1
#define DoRestoreSegments 1
#define DoRestoreVolatiles 1
#define DoPushFakeErrorCode 1
#define DoFixupV86 1
#define DoFixupAbios 1
#define NotFromSystemCall 0
#define DoNotRestorePreviousMode 0
#define DoNotRestoreEverything 0
#define DoNotRestoreSegments 0
#define DoNotRestoreVolatiles 0
#define DoNotPushFakeErrorCode 0
#define DoNotFixupV86 0
#define DoNotFixupAbios 0
// Arguments for idt
#define INT_32_DPL0 0x8E00
#define INT_32_DPL3 0xEE00
.intel_syntax noprefix
//
// These macros are inlined equivalents of KiAcquire/ReleaseSpinlock, that is,
// they will not be compiled into non-SMP builds. Usage is as follows:
//
// .BeginYourFunction
// mov reg, lockaddr
// ACQUIRE_SPINLOCK(reg, .spin)
// <thread-safe code here>
// RELEASE_SPINLOCK(reg)
// <misc code here>
// retn
// #IFDEF CONFIG_SMP
// .spin
// <any necessary steps to be able to jump back safely>
/ SPIN_ON_LOCK(reg, .BeginYourFunction)
// #ENDIF
//
#ifdef CONFIG_SMP
#define LOCK lock
#define ACQUIRE_SPINLOCK(x, y) \
lock bts dword ptr [x], 0; \
jb y
#define RELEASE_SPINLOCK(x) mov byte ptr [x], 0
#define SPIN_ON_LOCK(x, y) \
1: \
test dword ptr [x], 1; \
jz y; \
pause; \
jmp 1b
#else
#define LOCK
#define ACQUIRE_SPINLOCK(x, y)
#define RELEASE_SPINLOCK(x)
#endif
//
// @name UNHANDLED_PATH
//
// This macro TODO
//
// @param None
//
// @remark None.
//
.macro UNHANDLED_PATH
/* Get EIP */
call $+5
pop eax
/* Print debug message */
push eax
push offset _UnhandledMsg
call _DbgPrint
add esp, 8
/* Loop indefinitely */
jmp $
.endm
//
// @name IDT
//
// This macro creates an IDT entry for the given handler
//
// @param Handler
// Pointer to the IDT handler
//
// @param Bits
// Descriptor Bits to associate
//
// @remark None.
//
.macro idt Handler, Bits
.long \Handler
.short \Bits
.short KGDT_R0_CODE
.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
//
// @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:
push PRIMARY_VECTOR_BASE + Number
jmp _KiEndUnexpectedRange@0
.endfunc
.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
//
// @name INVALID_V86_OPCODE
//
// This macro creates one or more entries for unhandled V86 Opcodes
// in the V86 Opcode Table.
//
// @param count.
// Number of entries to generate.
//
// @remark None.
//
.macro INVALID_V86_OPCODE count
.rept \count
.byte 0
.endr
.endm
//
// @name INVALID_V86_OPCODE
//
// This macro prints out visible message and hangs the computer.
//
// @param None.
//
// @remark Temporary debugging use.
//
.macro UNHANDLED_V86_OPCODE
/* Print debug message, breakpoint and freeze */
push ecx
push offset V86DebugMsg
call _DbgPrint
add esp, 8
jmp $
.endm
//
// @name TRAP_FIXUPS
//
// This macro contains out-of-line code for various Trap Frame Fixups, such as:
//
// - DR Fixup: Loads and restores DR registers.
// - V86 Fixup: Loads and restores V86 segments.
// - ABIOS Fixup: Loads and restores the ABIOS state and stack.
//
// @param None.
//
// @remark ebp = PKTRAP_FRAME
//
.macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
Dr_&Label:
/* Check if this was V86 mode */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz 2f
/* Check if it was user mode */
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jz Dr_&EndLabel
2:
/* Get DR0, 1, 2 */
mov ebx, dr0
mov ecx, dr1
mov edi, dr2
/* Save them */
mov [ebp+KTRAP_FRAME_DR0], ebx
mov [ebp+KTRAP_FRAME_DR1], ecx
mov [ebp+KTRAP_FRAME_DR2], edi
/* Get DR3, 6, 7 */
mov ebx, dr3
mov ecx, dr6
mov edi, dr7
/* Save them */
mov [ebp+KTRAP_FRAME_DR3], ebx
mov [ebp+KTRAP_FRAME_DR6], ecx
mov [ebp+KTRAP_FRAME_DR7], edi
/* Clear DR7 */
xor ebx, ebx
mov dr7, ebx
/* Get the PRCB */
mov edi, fs:[KPCR_PRCB]
/* Get DR0, 1 */
mov ebx, [edi+KPRCB_DR0]
mov ecx, [edi+KPRCB_DR1]
/* Set them */
mov dr0, ebx
mov dr1, ecx
/* Get DR2, 3 */
mov ebx, [edi+KPRCB_DR2]
mov ecx, [edi+KPRCB_DR3]
/* Set them */
mov dr2, ebx
mov dr3, ecx
/* Get DR6, 7 */
mov ebx, [edi+KPRCB_DR6]
mov ecx, [edi+KPRCB_DR7]
/* Set them */
mov dr6, ebx
mov dr7, ecx
jmp Dr_&EndLabel
.if \AbiosFix
Abios_&Label:
UNHANDLED_PATH
.endif
.if \V86Fix
V86_&Label:
/* Get V86 segment registers */
mov eax, [ebp+KTRAP_FRAME_V86_FS]
mov ebx, [ebp+KTRAP_FRAME_V86_GS]
mov ecx, [ebp+KTRAP_FRAME_V86_ES]
mov edx, [ebp+KTRAP_FRAME_V86_DS]
/* Restore them into Protected Mode trap frame */
mov [ebp+KTRAP_FRAME_FS], ax
mov [ebp+KTRAP_FRAME_GS], bx
mov [ebp+KTRAP_FRAME_ES], cx
mov [ebp+KTRAP_FRAME_DS], dx
/* Go back to mainline code */
jmp V86_&EndLabel
.endif
.endm
//
// @name SET_TF_DEBUG_HEADER
//
// This macro sets up the debug header in the trap frame.
//
// @param None.
//
// @remark ebp = PKTRAP_FRAME.
// edi/ebx = Have been saved and can be used.
//
.macro SET_TF_DEBUG_HEADER
/* Get the Debug Trap Frame EBP/EIP */
mov ebx, [ebp+KTRAP_FRAME_EBP]
mov edi, [ebp+KTRAP_FRAME_EIP]
/* Write the debug data */
mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
.endm
//
// @name CHECK_FOR_APC_DELIVER
//
// This macro checks if the trapframe indicates a return to user-mode,
// and, if so, checks if user-mode APCs should be delivered.
//
// @param PreserveEax
// Determines if EAX should be preserved. Implies that the segment
// registers will also be saved.
//
// @remark ebp = PKTRAP_FRAME.
// ebx = Saved and will be used.
//
.macro CHECK_FOR_APC_DELIVER PreserveEax
/* Check for V86 mode */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz 1f
/* Deliver APCs only if we were called from user mode */
test byte ptr [ebp+KTRAP_FRAME_CS], 1
je 2f
/* Get the current thread */
1:
mov ebx, PCR[KPCR_CURRENT_THREAD]
/* Make it non-alerted */
mov byte ptr [ebx+KTHREAD_ALERTED], 0
/* And only if any are actually pending */
cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
je 2f
/* Save pointer to Trap Frame */
mov ebx, ebp
.if \PreserveEax
/* Save some stuff that raising IRQL will kill */
mov [ebx+KTRAP_FRAME_EAX], eax
mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
mov dword ptr [ebx+KTRAP_FRAME_GS], 0
.endif
/* Raise IRQL to APC_LEVEL */
mov ecx, 1
call @KfRaiseIrql@4
/* Save old IRQL */
push eax
/* Deliver APCs */
sti
push ebx
push 0
push UserMode
call _KiDeliverApc@12
/* Return to old IRQL */
pop ecx
call @KfLowerIrql@4
/* Restore EAX (only in volatile case) */
.if \PreserveEax
mov eax, [ebx+KTRAP_FRAME_EAX]
.endif
cli
jmp 1b
2:
.endm
//
// @name TRAP_PROLOG
//
// This macro creates a standard trap entry prologue.
// It should be used for entry into any kernel trap (KiTrapXx), but not for
// system calls, which require special handling.
//
// @param Label
// Identifying name of the caller function; will be used to append
// to the name V86 and DR helper functions, which must already exist.
//
// @remark Use as follows:
// _KiTrap00:
// /* Push fake error code */
// push 0
//
// /* Enter common prologue */
// TRAP_PROLOG(0)
//
// /* Handle trap */
// <Your Trap Code Here>
//
.macro TRAP_PROLOG Label EndLabel
/* Just to be safe, clear out the HIWORD, since it's reserved */
mov word ptr [esp+2], 0
/* Save the non-volatiles */
push ebp
push ebx
push esi
push edi
/* Save FS and set it to PCR */
push fs
mov ebx, KGDT_R0_PCR
.byte 0x66
mov fs, bx
/* Save exception list and bogus previous mode */
push fs:[KPCR_EXCEPTION_LIST]
push -1
/* Save volatiles and segment registers */
push eax
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -