⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asmmacro.s

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 S
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -