|
|
;++ ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ; ; Module: ; ; kxamd64.w ; ; Astract: ; ; Contains AMD64 architecture constants and assembly macros. ; ; Author: ; ; David N. Cutler (davec) 27-May-2000 ; ; Revision History: ; ;--
; ; Define macros to build unwind data for prologues. ;
push_reg macro Reg
pushq Reg .pushreg Reg
endm
push_eflags macro
pushfd .allocstack 8
endm
alloc_stack macro Size
sub rsp, Size .allocstack Size
endm
save_reg macro Reg, Offset
mov Offset[rsp], Reg .savereg Reg, Offset
endm
save_xmm macro Reg, Offset
movq Offset[rsp], Reg .savexmm Reg, Offset
endm
save_xmm128 macro Reg, Offset
movdqa Offset[rsp], Reg .savexmm128 Reg, Offset
endm
push_frame macro Code
.pushframe Code
endm
set_frame macro Reg, Offset
if Offset
lea Reg, Offset[rsp]
else
mov reg, rsp
endif
.setframe Reg, Offset
endm
END_PROLOGUE macro
.endprolog
endm
; ; Define macro to acquire spin lock. ; ; Arguments: ; ; None. ; ; N.B. The registers rax amd r11 are destroyed by this macro. ; ; N.B. This macro is restricted to using only rax and r11. ;
AcquireSpinLock macro Address
local exit, spin, start
ifndef NT_UP
ifdifi <Address>, <r11>
mov r11, Address ; get spin lock address endif
start: mov rax, r11 ; set spin lock address xchg [r11], rax ; try to acquire lock test rax, rax ; test if lock previously owned jz short exit ; if z, lock acquired spin: cmp qword ptr [r11], 0 ; check if lock currently owned je short start ; if e, lock not owned jmp short spin ; spin
exit: ; continue
endif
endm
; ; Define macro to release spin lock. ; ; Arguments: ; ; None. ; ; N.B. The register r11 is destroyed by this macro. ; ; N.B. This macro is restricted to using only r11. ;
ReleaseSpinLock macro Address
local exit
ifndef NT_UP
ifdifi <Address>, <r11>
mov r11, Address ; get spin lock address
endif
if DBG
cmp [r11], r11 ; check if owner is spin lock address je short exit ; if e, lock owner is correct int 3 ; break into debugger
endif
exit: mov qword ptr [r11], 0 ; release spin lock
endif
endm
; ; Define macro to perform the equivalent of reading cr8. ; ; Arguments: ; ; None ; ; The equivalent of the contents of cr8 is returned in rax ; ; N.B. This macro is restricted to using only rax. ;
ReadCr8 macro
mov rax, cr8 ; read IRQL
endm
; ; Define macro to perform the equivalent of writing cr8. ; ; Arguments: ; ; rcx - The desired value of cr8. ;
WriteCr8 macro
mov cr8, rcx ; write IRQL
endm
; ; Define macro to get current IRQL. ; ; Arguments: ; ; None. ; ; The previous IRQL is returned in rax. ;
CurrentIrql macro
ReadCr8 ; get current IRQL
endm
; ; Define macro to lower IRQL. ; ; Arguments: ; ; rcx - Supplies the new IRQL. ; ; N.B. The register rax is destroyed. ; ; N.B. This macro is restricted to using only rax and rcx. ;
LowerIrql macro
local exit
if DBG
ReadCr8 ; get current IRQL cmp eax, ecx ; check new IRQL jge short exit ; if ge, new IRQL okay int 3 ; break into debugger
endif
exit: WriteCr8 ; set new IRQL
endm
; ; Define macro to raise IRQL. ; ; Arguments: ; ; rcx - Supplies the new IRQL. ; ; The previous IRQL is returned in rax. ; ; N.B. This macro is restricted to using only rax and rcx. ;
RaiseIrql macro
local exit
ReadCr8 ; get current IRQL
if DBG
cmp eax, ecx ; check new IRQL jle short exit ; if le, new IRQL okay int 3 ; break into debugger
endif
exit: WriteCr8 ; set new IRQL
endm
; ; Define macro to set IRQL. ; ; Arguments: ; ; rcx - Supplies the new IRQL. ; ; N.B. This macro is restricted to using only rcx. ;
SetIrql macro
WriteCr8 ; set new IRQL
endm
; ; Define macro to swap IRQL. ; ; Arguments: ; ; rcx - Supplies the new IRQL. ; ; The previous IRQL is returned in rax. ; ; N.B. This macro is restricted to using only rax and rcx. ;
SwapIrql macro
ReadCr8 ; get current IRQL WriteCr8 ; set new IRQL
endm
; ; Define alternate entry macro. ;
ALTERNATE_ENTRY macro Name
Name:
endm ; ; Define function entry/end macros. ;
LEAF_ENTRY macro Name, Section
Section segment para public 'CODE'
align 16
public Name Name proc
endm
LEAF_END macro Name, section
Name endp
Section ends
endm
NESTED_ENTRY macro Name, Section, Handler
Section segment para public 'CODE'
align 16
public Name
ifb <Handler>
Name proc frame
else
Name proc frame:Handler
endif
endm
NESTED_END macro Name, section
Name endp
Section ends
endm
; ; Define restore exception state macro. ; ; This macro restores the nonvolatile state. ; ; Arguments: ; ; Flag - If blank, then nonvolatile floating and integer registers are ; restored. If nonblank and identical to "Rbp", then rbp is restored ; in addition to the nonvolatile floating and integer registers. If ; nonblank and identical to "NoFp", then only the nonvolatile integer ; registers are restored. ; ; Implicit arguments: ; ; rsp - Supplies the address of the exception frame. ;
RESTORE_EXCEPTION_STATE macro Flag
ifdif <Flag>, <NoFp>
movdqa xmm6, qword ptr ExXmm6[rsp] ; restore nonvolatile xmm registers movdqa xmm7, qword ptr ExXmm7[rsp] ; movdqa xmm8, qword ptr ExXmm8[rsp] ; movdqa xmm9, qword ptr ExXmm9[rsp] ; movdqa xmm10, qword ptr ExXmm10[rsp] ; movdqa xmm11, qword ptr ExXmm11[rsp] ; movdqa xmm12, qword ptr ExXmm12[rsp] ; movdqa xmm13, qword ptr ExXmm13[rsp] ; movdqa xmm14, qword ptr ExXmm14[rsp] ; movdqa xmm15, qword ptr ExXmm15[rsp] ;
endif
ifidn <Flag>, <NoPop>
mov rbx, ExRbx[rsp] ; restore nonvolatile integer registers mov rdi, ExRdi[rsp] ; mov rsi, ExRsi[rsp] ; mov r12, ExR12[rsp] ; mov r13, ExR13[rsp] ; mov r14, ExR14[rsp] ; mov r15, ExR15[rsp] ;
else
ifidn <Flag>, <Rbp>
add rsp, KEXCEPTION_FRAME_LENGTH - (9 * 8) ; deallocate frame pop rbp ; restore nonvolatile integer register
else
add rsp, KEXCEPTION_FRAME_LENGTH - (8 * 8) ; deallocate frame
endif
pop rbx ; restore integer nonvolatile registers pop rdi ; pop rsi ; pop r12 ; pop r13 ; pop r14 ; pop r15 ;
endif
endm
; ; Define generate exception frame macro. ; ; This macro allocates an exception frame and saves the nonvolatile state. ; ; Arguments: ; ; Flag - If blank, then nonvolatile floating and integer registers are ; saved. If nonblank and identical to "Rbp", then rbp is saved in ; addition to the nonvolatile floating and integer registers. If ; nonblank and identical to "NoFp", then only the nonvolatile integer ; registers are saved. ; ; Implicit arguments: ; ; The top of the stack is assumed to contain a return address. ;
GENERATE_EXCEPTION_FRAME macro Flag
push_reg r15 ; push integer nonvolatile registers push_reg r14 ; push_reg r13 ; push_reg r12 ; push_reg rsi ; push_reg rdi ; push_reg rbx ;
ifidn <Flag>, <Rbp>
push_reg rbp ; push frame pointer alloc_stack KEXCEPTION_FRAME_LENGTH - (9 * 8) ; allocate frame set_frame rbp, 0 ; set frame register
else
alloc_stack KEXCEPTION_FRAME_LENGTH - (8 * 8) ; allocate frame
endif
ifdif <Flag>, <NoFp>
save_xmm128 xmm6, ExXmm6 ; save xmm nonvolatile registers save_xmm128 xmm7, ExXmm7 ; save_xmm128 xmm8, ExXmm8 ; save_xmm128 xmm9, ExXmm9 ; save_xmm128 xmm10, ExXmm10 ; save_xmm128 xmm11, ExXmm11 ; save_xmm128 xmm12, ExXmm12 ; save_xmm128 xmm13, ExXmm13 ; save_xmm128 xmm14, ExXmm14 ; save_xmm128 xmm15, ExXmm15 ;
endif
END_PROLOGUE
endm
; ; Define restore trap state macro. ; ; This macro restores the volatile state, and if necessary, restorss the ; user debug state, deallocats the trap frame, and exits the trap. ; ; N.B. This macro must preserve eax in case it is not reloaded from the ; trap frame. ; ; Arguments: ; ; State - Determines what state is restored and what tests are made. Valid ; values are: ; ; Service - restore state for a service executed from user mode. ; Kernel - restore state for a service executed from kernel mode. ; Volatile - restore state for a trap or interrupt. ; ; Disable - If blank, then disable interrupts. ; ; Implicit arguments: ; ; rbp - Supplies the address of the trap frame. ;
RESTORE_TRAP_STATE macro State, Disable
local first, second, third
ifb <Disable>
cli ; disable interrupts
endif
ifdif <State>, <Kernel>
; ; State is either <Volatile> or <Service> ;
ifidn <State>, <Volatile>
test byte ptr TrSegCs[rbp], MODE_MASK ; test if previous mode user jz third ; if z, previous mode not user
endif
mov rcx, gs:[PcCurrentThread] ; get current thread address cmp byte ptr ThApcState + AsUserApcPending[rcx], 0 ; APC pending? je short first ; if e, no user APC pending
ifidn <State>, <Service>
mov TrRax[rbp], eax ; save service status
endif
mov ecx, APC_LEVEL ; get APC level
SetIrql ; set IRQL to APC level
sti ; allow interrupts call KiInitiateUserApc ; initiate APC execution cli ; disable interrupts mov ecx, PASSIVE_LEVEL ; get PASSIVE level
SetIrql ; set IRQL to PASSIVE level
ifidn <State>, <Service>
mov eax, TrRax[rbp] ; restore service status
endif
first: ldmxcsr TrMxCsr[rbp] ; restore user mode XMM control/status xor edx, edx ; assume debug breakpoints not active test byte ptr TrDr7[rbp], DR7_ACTIVE ; test if breakpoints enabled jz short second ; if z, no breakpoints enabled mov dr7, rdx ; clear control register before loading mov rcx, TrDr0[rbp] ; restore debug registers mov rdx, TrDr1[rbp] ; mov dr0, rcx ; mov dr1, rdx ; mov rcx, TrDr2[rbp] ; mov rdx, TrDr3[rbp] ; mov dr2, rcx ; mov dr3, rdx ; xor ecx, ecx ; mov rdx, TrDr7[rbp] ; mov dr6, rcx ; second: mov dr7, rdx ;
; ; At this point it is known that the return will be to user mode. ;
ifidn <State>, <Volatile>
movdqa xmm0, qword ptr TrXmm0[rbp] ; restore volatile XMM registers movdqa xmm1, qword ptr TrXmm1[rbp] ; movdqa xmm2, qword ptr TrXmm2[rbp] ; movdqa xmm3, qword ptr TrXmm3[rbp] ; movdqa xmm4, qword ptr TrXmm4[rbp] ; movdqa xmm5, qword ptr TrXmm5[rbp] ;
mov r11, TrR11[rbp] ; restore volatile integer state mov r10, TrR10[rbp] ; mov r9, TrR9[rbp] ; mov r8, TrR8[rbp] ; mov rdx, TrRdx[rbp] ; mov rcx, TrRcx[rbp] ; mov rax, TrRax[rbp] ; mov rsp, rbp ; trim stack to frame offset mov rbp, TrRbp[rbp] ; restore RBP add rsp, (KTRAP_FRAME_LENGTH - (5 * 8) - 128) ; deallocate stack swapgs ; swap GS base to user mode TEB iretq ;
else
mov rcx, TrRip[rbp] ; get return address mov r11, TrEFlags[rbp] ; get previous EFLAGS mov rsp, rbp ; trim stack to frame offset mov rbp, TrRbp[rbp] ; restore RBP mov rsp, TrRsp[rsp] ; restore RSP swapgs ; swap GS base to user mode TEB sysretq ; return from system call to user mode
endif
ifidn <State>, <Volatile>
third: movdqa xmm0, qword ptr TrXmm0[rbp] ; restore volatile XMM registers movdqa xmm1, qword ptr TrXmm1[rbp] ; movdqa xmm2, qword ptr TrXmm2[rbp] ; movdqa xmm3, qword ptr TrXmm3[rbp] ; movdqa xmm4, qword ptr TrXmm4[rbp] ; movdqa xmm5, qword ptr TrXmm5[rbp] ;
mov r11, TrR11[rbp] ; restore volatile integer state mov r10, TrR10[rbp] ; mov r9, TrR9[rbp] ; mov r8, TrR8[rbp] ; mov rdx, TrRdx[rbp] ; mov rcx, TrRcx[rbp] ; mov rax, TrRax[rbp] ; mov rsp, rbp ; trim stack to frame offset mov rbp, TrRbp[rbp] ; restore RBP add rsp, (KTRAP_FRAME_LENGTH - (5 * 8) - 128) ; deallocate stack iretq ;
endif
; ; State is <Kernel> ;
else
mov rsp, rbp ; trim stack to frame offset mov rbp, TrRbp[rbp] ; restore RBP mov rsp, TrRsp[rsp] ; restore RSP sti ; enable interrupts ret ; return from system call to kernel mode
endif
endm
; ; Define save trap state macro. ; ; This macro saves the volatile state, and if necessary, saves the user ; debug state and loads the kernel debug state. ; ; Arguments: ; ; Service - If non-blank, then a partial trap frame is being restored for ; a system service. ; ; Implicit arguments: ; ; rbp - Supplies the address of the trap frame. ;
SAVE_TRAP_STATE macro Service
local first, second, third
ifb <Service>
mov TrRax[rbp], rax ; save volatile integer registers mov TrRcx[rbp], rcx ; mov TrRdx[rbp], rdx ; mov TrR8[rbp], r8 ; mov TrR9[rbp], r9 ; mov TrR10[rbp], r10 ; mov TrR11[rbp], r11 ;
endif
test byte ptr TrSegCs[rbp], MODE_MASK ; test if previous mode user jz third ; if z, previous mode kernel
ifb <Service>
swapgs ; swap GS base to kernel mode PCR
endif
stmxcsr TrMxCsr[rbp] ; save XMM control/status ldmxcsr dword ptr gs:[PcMxCsr] ; set default XMM control/status mov r11, dr7 ; get debug control register test r11b, DR7_ACTIVE ; test if breakpoints enabled jz short first ; if z, breakpoints not enabled mov r10, dr0 ; save debug registers mov r11, dr1 ; mov TrDr0[rbp], r10 ; mov TrDr1[rbp], r11 ; mov r10, dr2 ; mov r11, dr3 ; mov TrDr2[rbp], r10 ; mov TrDr3[rbp], r11 ; mov r10, dr6 ; mov r11, dr7 ; mov TrDr6[rbp], r10 ; first: mov TrDr7[rbp], r11 ; xor r11, r11 ; assume debug breakpoints not active test byte ptr gs:[PcKernelDr7], DR7_ACTIVE ; test if breakpoints enabled jz short second ; if z, no breakpoints enabled mov dr7, r11 ; clear control register before loading registers mov r10, gs:[PcKernelDr0] ; set debug registers mov r11, gs:[PcKernelDr1] ; mov dr0, r10 ; mov dr1, r11 ; mov r10, gs:[PcKernelDr2] ; mov r11, gs:[PcKernelDr3] ; mov dr2, r10 ; mov dr3, r11 ; xor r10, r10 ; mov r11, gs:[PcKernelDr7] ; mov dr6, r10 ; second: mov dr7, r11 ; third: cld ; clear direction flag
ifb <Service>
movdqa qword ptr TrXmm0[rbp], xmm0 ; save volatile xmm registers movdqa qword ptr TrXmm1[rbp], xmm1 ; movdqa qword ptr TrXmm2[rbp], xmm2 ; movdqa qword ptr TrXmm3[rbp], xmm3 ; movdqa qword ptr TrXmm4[rbp], xmm4 ; movdqa qword ptr TrXmm5[rbp], xmm5 ;
endif
endm
; ; Define interrupt frame generation macro. ; ; This macro generates an interrupt frame. ; ; Arguments: ; ; Vector - If non-blank, then the vector number is on the stack. ; ; Return value: ; ; If Vector is non-blank, then the value of the vector is returned in eax. ;
GENERATE_INTERRUPT_FRAME macro Vector
; ; At this point the hardware frame has been pushed onto an aligned stack. The ; vector number or a dummy vector number and rbp have also been pushed on the ; stack. ;
push_reg rsi ; save nonvolatile register alloc_stack (KTRAP_FRAME_LENGTH - (8 * 8)) ; allocate fixed frame mov rsi, rbp ; set address of interrupt object set_frame rbp, 128 ; set frame pointer
END_PROLOGUE
SAVE_TRAP_STATE ; save trap state
ifnb <Vector>
mov eax, TrErrorCode[rbp] ; return vector number
endif
inc dword ptr gs:[PcInterruptCount] ; increment interrupt count
endm
; ; Define enter interrupt macro. ; ; This macro raises IRQL, sets the interrupt flag, records the previous ; IRQL in the trap frame, and invokes the HAL to perform an EOI. ; ; Arguments: ; ; NoEOI - If blank, then generate end of interrupt. ; ; Implicit arguments: ; ; rcx - Supplies the interrupt IRQL. ; ; rbp - Supplies the address of the trap frame. ; ; Interrupt flag is clear. ; ; Return Value: ; ; None. ;
ENTER_INTERRUPT macro NoEOI
; ; N.B. It is possible for a interrupt to occur at an IRQL that is lower ; than the current IRQL. This happens when the IRQL raised and at ; the same time an interrupt request is granted. ;
RaiseIrql ; raise IRQL to interrupt level
mov TrPreviousIrql[rbp], al ; save previous IRQL
ifb <NoEOI>
call __imp_HalEndSystemInterrupt ; perform EOI
endif
sti ; enable interrupts
endm
; ; Define exit interrupt macro. ; ; This macro exits an interrupt. ; ; Arguments: ; ; NoEOI - If blank, then generate end of interrupt. ; ; Implicit arguments: ; ; rbp - Supplies the address of the trap frame. ; ; Return Value: ; ; None. ;
EXIT_INTERRUPT macro NoEOI
ifb <NoEOI>
call __imp_HalEndSystemInterrupt ; perform EOI
endif
movzx ecx, byte ptr TrPreviousIrql[rbp] ; get previous IRQL cli ; disable interrupts
SetIrql ; set IRQL to previous level
mov rsi, TrRsi[rbp] ; restore extra register
RESTORE_TRAP_STATE <Volatile>, <NoDisable> ; restore trap state
endm
; ; Define trap frame generation macro. ; ; This macro generates a trap frame. ; ; Arguments: ; ; ErrorCode - If non-blank, then an error code is on the stack. ; ; Return value: ; ; If ErrorCode is non-blank, then the value of the error code is returned ; in eax. ;
GENERATE_TRAP_FRAME macro ErrorCode
local exit
ifb <ErrorCode>
push_frame ; mark machine frame without error code alloc_stack 8 ; allocate dummy error code
else
push_frame code ; mark machine frame with error code
endif
push_reg rbp ; save nonvolatile register alloc_stack (KTRAP_FRAME_LENGTH - (7 * 8)) ; allocate fixed frame set_frame rbp, 128 ; set frame pointer
END_PROLOGUE
SAVE_TRAP_STATE ; save trap state
ifnb <ErrorCode>
mov eax, TrErrorCode[rbp] ; return error code
ifidn <ErrorCode>, <Virtual>
mov rcx, cr2 ; return virtual address
endif
endif
; ; Enable interrupts if and only if they were enabled before the trap occurred. ; If the exception is not handled by the kernel debugger and interrupts were ; previously disabled, then a bug check will occur. ;
test dword ptr TrEFlags[rbp], EFLAGS_IF_MASK ; check interrupt enabled jz short exit ; if z, interrupts not enabled sti ; enable interrupts exit: ; reference label
endm
|