473 lines
16 KiB
NASM
473 lines
16 KiB
NASM
|
title "Capture and Restore Context"
|
||
|
;++
|
||
|
;
|
||
|
; Copyright (c) 2000 Microsoft Corporation
|
||
|
;
|
||
|
; Module Name:
|
||
|
;
|
||
|
; capture.asm
|
||
|
;
|
||
|
; Abstract:
|
||
|
;
|
||
|
; This module implements the platform specific code to capture and restore
|
||
|
; the context of the caller.
|
||
|
;
|
||
|
; Author:
|
||
|
;
|
||
|
; David N. Cutler (davec) 4-Jul-2000
|
||
|
;
|
||
|
; Environment:
|
||
|
;
|
||
|
; Any mode.
|
||
|
;
|
||
|
;--
|
||
|
|
||
|
include ksamd64.inc
|
||
|
|
||
|
altentry RcConsolidateFrames
|
||
|
|
||
|
subttl "Capture Context"
|
||
|
;++
|
||
|
;
|
||
|
; VOID
|
||
|
; RtlCaptureContext (
|
||
|
; IN PCONTEXT ContextRecord
|
||
|
; )
|
||
|
;
|
||
|
; Routine Description:
|
||
|
;
|
||
|
; This function captures the context of the caller in the specified
|
||
|
; context record.
|
||
|
;
|
||
|
; N.B. The stored value of registers rcx and rsp will be a side effect of
|
||
|
; having made this call. All other registers will be stored as they
|
||
|
; were when the call to this function was made.
|
||
|
;
|
||
|
; Arguments:
|
||
|
;
|
||
|
; ContextRecord (rcx) - Supplies a pointer to a context record.
|
||
|
;
|
||
|
; Return Value:
|
||
|
;
|
||
|
; None.
|
||
|
;
|
||
|
;--
|
||
|
|
||
|
CcFrame struct
|
||
|
EFlags dd ? ; saved procssor flags
|
||
|
Fill dd ? ; fill
|
||
|
CcFrame ends
|
||
|
|
||
|
NESTED_ENTRY RtlCaptureContext, _TEXT$00
|
||
|
|
||
|
push_eflags ; save processor flags
|
||
|
|
||
|
END_PROLOGUE
|
||
|
|
||
|
mov CxSegCs[rcx], cs ; save segment registers
|
||
|
mov CxSegDs[rcx], ds ;
|
||
|
mov CxSegEs[rcx], es ;
|
||
|
mov CxSegSs[rcx], ss ;
|
||
|
mov CxSegFs[rcx], fs ;
|
||
|
mov CxSegGs[rcx], gs ;
|
||
|
|
||
|
mov CxRax[rcx], rax ; save integer registers
|
||
|
mov CxRcx[rcx], rcx ;
|
||
|
mov CxRdx[rcx], rdx ;
|
||
|
mov CxRbx[rcx], rbx ;
|
||
|
lea rax, 16[rsp] ;
|
||
|
mov CxRsp[rcx], rax ;
|
||
|
mov CxRbp[rcx], rbp ;
|
||
|
mov CxRsi[rcx], rsi ;
|
||
|
mov CxRdi[rcx], rdi ;
|
||
|
mov CxR8[rcx], r8 ;
|
||
|
mov CxR9[rcx], r9 ;
|
||
|
mov CxR10[rcx], r10 ;
|
||
|
mov CxR11[rcx], r11 ;
|
||
|
mov CxR12[rcx], r12 ;
|
||
|
mov CxR13[rcx], r13 ;
|
||
|
mov CxR14[rcx], r14 ;
|
||
|
mov CxR15[rcx], r15 ;
|
||
|
|
||
|
movdqa CxXmm0[rcx], xmm0 ; save xmm floating registers
|
||
|
movdqa CxXmm1[rcx], xmm1 ;
|
||
|
movdqa CxXmm2[rcx], xmm2 ;
|
||
|
movdqa CxXmm3[rcx], xmm3 ;
|
||
|
movdqa CxXmm4[rcx], xmm4 ;
|
||
|
movdqa CxXmm5[rcx], xmm5 ;
|
||
|
movdqa CxXmm6[rcx], xmm6 ;
|
||
|
movdqa CxXmm7[rcx], xmm7 ;
|
||
|
movdqa CxXmm8[rcx], xmm8 ;
|
||
|
movdqa CxXmm9[rcx], xmm9 ;
|
||
|
movdqa CxXmm10[rcx], xmm10 ;
|
||
|
movdqa CxXmm11[rcx], xmm11 ;
|
||
|
movdqa CxXmm12[rcx], xmm12 ;
|
||
|
movdqa CxXmm13[rcx], xmm13 ;
|
||
|
movdqa CxXmm14[rcx], xmm14 ;
|
||
|
movdqa CxXmm15[rcx], xmm15 ;
|
||
|
|
||
|
stmxcsr CxMxCsr[rcx] ; save xmm floating state
|
||
|
|
||
|
ifndef NTOS_KERNEL_RUNTIME
|
||
|
|
||
|
fnsaved CxFltSave[rcx] ; save legacy floating state
|
||
|
|
||
|
endif
|
||
|
|
||
|
mov rax, 8[rsp] ; set return address
|
||
|
mov CxRip[rcx], rax ;
|
||
|
|
||
|
mov eax, Ccframe.EFlags[rsp] ; set processor flags
|
||
|
mov CxEFlags[rcx], eax ;
|
||
|
|
||
|
mov dword ptr CxContextFlags[rcx], CONTEXT_FULL ; set context flags
|
||
|
add rsp, sizeof CcFrame ; deallocate stack frame
|
||
|
ret ; return
|
||
|
|
||
|
NESTED_END RtlCaptureContext, _TEXT$00
|
||
|
|
||
|
subttl "Restore Context"
|
||
|
;++
|
||
|
;
|
||
|
; VOID
|
||
|
; RtlRestoreContext (
|
||
|
; IN PCONTEXT ContextRecord,
|
||
|
; IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL
|
||
|
; )
|
||
|
;
|
||
|
; Routine Description:
|
||
|
;
|
||
|
; This function restores the context of the caller to the specified
|
||
|
; context.
|
||
|
;
|
||
|
; Arguments:
|
||
|
;
|
||
|
; ContextRecord (rcx) - Supplies a pointer to a context record.
|
||
|
;
|
||
|
; ExceptionRecord (rdx) - Supplies an optional pointer to an exception
|
||
|
; record.
|
||
|
;
|
||
|
; Return Value:
|
||
|
;
|
||
|
; None - there is no return from this function.
|
||
|
;
|
||
|
;--
|
||
|
|
||
|
RcFrame struct
|
||
|
Mframe db MachineFrameLength dup (?) ; machine frame
|
||
|
Fill dq ? ; fill to 0 mod 16
|
||
|
RcFrame ends
|
||
|
|
||
|
NESTED_ENTRY RtlRestoreContext, _TEXT$00
|
||
|
|
||
|
push_reg rbp ; save nonvolatile registers
|
||
|
push_reg rsi ;
|
||
|
push_reg rdi ;
|
||
|
alloc_stack (sizeof RcFrame) ; allocate stack frame
|
||
|
set_frame rbp, 0 ; set frame pointer
|
||
|
|
||
|
END_PROLOGUE
|
||
|
|
||
|
;
|
||
|
; If an exception record is specified and the exception status is the unwind
|
||
|
; consolidation code and there is at least one parameter, then consolidate
|
||
|
; all the frames that have been unwound and call back to a language specified
|
||
|
; routine.
|
||
|
;
|
||
|
|
||
|
test rdx, rdx ; test if exception record specified
|
||
|
jz Rc10 ; if z, no exception record specified
|
||
|
cmp dword ptr ErExceptionCode[rdx], STATUS_UNWIND_CONSOLIDATE ; check call back
|
||
|
jne short Rc05 ; if ne, not C++ unwind
|
||
|
cmp dword ptr ErNumberParameters[rdx], 1 ; check number parameters
|
||
|
jae Rc20 ; if ae, unwind consolidation
|
||
|
|
||
|
;
|
||
|
; If an exception record is specified and the exception status is long jump,
|
||
|
; then restore the nonvolatile registers to their state at the call to set
|
||
|
; jump before restoring the context record.
|
||
|
;
|
||
|
|
||
|
Rc05: cmp dword ptr ErExceptionCode[rdx], STATUS_LONGJUMP ; check for long jump
|
||
|
jne Rc10 ; if ne, not a long jump
|
||
|
|
||
|
;
|
||
|
; Long jump unwind.
|
||
|
;
|
||
|
; Copy register values from the jump buffer to the context record.
|
||
|
;
|
||
|
|
||
|
mov rax, ErExceptionInformation[rdx] ; get jump buffer address
|
||
|
mov r8, JbRbx[rax] ; move nonvolatile integer registers
|
||
|
mov CxRbx[rcx], r8 ; to context record
|
||
|
mov r8, JbRsp[rax] ;
|
||
|
mov CxRsp[rcx], r8 ;
|
||
|
mov r8, JbRbp[rax] ;
|
||
|
mov CxRbp[rcx], r8 ;
|
||
|
mov r8, JbRsi[rax] ;
|
||
|
mov CxRsi[rcx], r8 ;
|
||
|
mov r8, JbRdi[rax] ;
|
||
|
mov CxRdi[rcx], r8 ;
|
||
|
mov r8, JbR12[rax] ;
|
||
|
mov CxR12[rcx], r8 ;
|
||
|
mov r8, JbR13[rax] ;
|
||
|
mov CxR13[rcx], r8 ;
|
||
|
mov r8, JbR14[rax] ;
|
||
|
mov CxR14[rcx], r8 ;
|
||
|
mov r8, JbR15[rax] ;
|
||
|
mov CxR15[rcx], r8 ;
|
||
|
mov r8, JbRip[rax] ;
|
||
|
mov CxRip[rcx], r8 ;
|
||
|
|
||
|
movdqa xmm0, JbXmm6[rax] ; move nonvolatile floating register
|
||
|
movdqa CxXmm6[rcx], xmm0 ; to context record
|
||
|
movdqa xmm0, JbXmm7[rax] ;
|
||
|
movdqa CxXmm7[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm8[rax] ;
|
||
|
movdqa CxXmm8[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm9[rax] ;
|
||
|
movdqa CxXmm9[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm10[rax] ;
|
||
|
movdqa CxXmm10[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm11[rax] ;
|
||
|
movdqa CxXmm11[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm12[rax] ;
|
||
|
movdqa CxXmm12[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm13[rax] ;
|
||
|
movdqa CxXmm13[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm14[rax] ;
|
||
|
movdqa CxXmm14[rcx], xmm0 ;
|
||
|
movdqa xmm0, JbXmm15[rax] ;
|
||
|
movdqa CxXmm15[rcx], xmm0 ;
|
||
|
|
||
|
;
|
||
|
; Restore context and continue.
|
||
|
;
|
||
|
|
||
|
Rc10: movdqa xmm0, CxXmm0[rcx] ; restore floating registers
|
||
|
movdqa xmm1, CxXmm1[rcx] ;
|
||
|
movdqa xmm2, CxXmm2[rcx] ;
|
||
|
movdqa xmm3, CxXmm3[rcx] ;
|
||
|
movdqa xmm4, CxXmm4[rcx] ;
|
||
|
movdqa xmm5, CxXmm5[rcx] ;
|
||
|
movdqa xmm6, CxXmm6[rcx] ;
|
||
|
movdqa xmm7, CxXmm7[rcx] ;
|
||
|
movdqa xmm8, CxXmm8[rcx] ;
|
||
|
movdqa xmm9, CxXmm9[rcx] ;
|
||
|
movdqa xmm10, CxXmm10[rcx] ;
|
||
|
movdqa xmm11, CxXmm11[rcx] ;
|
||
|
movdqa xmm12, CxXmm12[rcx] ;
|
||
|
movdqa xmm13, CxXmm13[rcx] ;
|
||
|
movdqa xmm14, CxXmm14[rcx] ;
|
||
|
movdqa xmm15, CxXmm15[rcx] ;
|
||
|
|
||
|
ldmxcsr CxMxCsr[rcx] ; restore floating state
|
||
|
|
||
|
mov eax, CxSegSs[rcx] ; set SS segment
|
||
|
mov MfSegSs[rsp], eax ;
|
||
|
mov rax, CxRsp[rcx] ; set stack address
|
||
|
mov MfRsp[rsp], rax ;
|
||
|
mov eax, CxEFlags[rcx] ; set processor flags
|
||
|
mov MfEFlags[rsp], eax ;
|
||
|
mov eax, CxSegCs[rcx] ; set CS segment
|
||
|
mov MfSegCs[rsp], eax ;
|
||
|
mov rax, CxRip[rcx] ; set return address
|
||
|
mov MfRip[rsp], rax ;
|
||
|
|
||
|
mov rax, CxRax[rcx] ; restore volatile integer registers
|
||
|
mov rdx, CxRdx[rcx] ;
|
||
|
mov r8, CxR8[rcx] ;
|
||
|
mov r9, CxR9[rcx] ;
|
||
|
mov r10, CxR10[rcx] ;
|
||
|
mov r11, CxR11[rcx] ;
|
||
|
|
||
|
ifdef NTOS_KERNEL_RUNTIME
|
||
|
|
||
|
cli ; disable interrupts
|
||
|
|
||
|
endif
|
||
|
|
||
|
mov rbx, CxRbx[rcx] ; restore nonvolatile integer registers
|
||
|
mov rsi, CxRsi[rcx] ;
|
||
|
mov rdi, CxRdi[rcx] ;
|
||
|
mov rbp, CxRbp[rcx] ;
|
||
|
mov r12, CxR12[rcx] ;
|
||
|
mov r13, CxR13[rcx] ;
|
||
|
mov r14, CxR14[rcx] ;
|
||
|
mov r15, CxR15[rcx] ;
|
||
|
mov rcx, CxRcx[rcx] ; restore integer register
|
||
|
iretq ; return
|
||
|
|
||
|
;
|
||
|
; Frame consoldation and language specific unwind call back.
|
||
|
;
|
||
|
|
||
|
Rc20: sub rsp, MachineFrameLength + 8; allocate machine frame
|
||
|
mov r8, rsp ; save machine frame address
|
||
|
sub rsp, CONTEXT_FRAME_LENGTH ; allocate context frame
|
||
|
mov rsi, rcx ; set source copy address
|
||
|
mov rdi, rsp ; set destination copy address
|
||
|
mov ecx, CONTEXT_FRAME_LENGTH / 8 ; set length of copy
|
||
|
rep movsq ; copy context frame
|
||
|
mov rax, CxRsp[rsp] ; set destination stack address in
|
||
|
mov MfRsp[r8], rax ; machine frame
|
||
|
mov rax, CxRip[rsp] ; set destination address in machine
|
||
|
mov MfRip[r8], rax ; frame
|
||
|
mov rcx, rdx ; set address of exception record
|
||
|
jmp RcConsolidateFrames ; consolidate frames - no return
|
||
|
|
||
|
NESTED_END RtlRestoreContext, _TEXT$00
|
||
|
|
||
|
subttl "Frame Consolidation"
|
||
|
;++
|
||
|
;
|
||
|
; Ths following code is never executed. Its purpose is to provide the dummy
|
||
|
; prologue necessary to consolidate stack frames for unwind call back processing
|
||
|
; at the end of an unwind operation.
|
||
|
;
|
||
|
;--
|
||
|
|
||
|
NESTED_ENTRY RcFrameConsolidation, _TEXT$00
|
||
|
|
||
|
.pushframe ;
|
||
|
.allocstack CONTEXT_FRAME_LENGTH ; allocate stack frame
|
||
|
.savereg rbx, CxRbx ; save nonvolatile integer registers
|
||
|
.savereg rbp, CxRbp ;
|
||
|
.savereg rsi, CxRsi ;
|
||
|
.savereg rdi, CxRdi ;
|
||
|
.savereg r12, CxR12 ;
|
||
|
.savereg r13, CxR13 ;
|
||
|
.savereg r14, CxR14 ;
|
||
|
.savereg r15, CxR15 ;
|
||
|
.savexmm128 xmm6, CxXmm6 ; save nonvolatile floating register
|
||
|
.savexmm128 xmm7, CxXmm7 ;
|
||
|
.savexmm128 xmm8, CxXmm8 ;
|
||
|
.savexmm128 xmm9, CxXmm9 ;
|
||
|
.savexmm128 xmm10, CxXmm10 ;
|
||
|
.savexmm128 xmm11, CxXmm11 ;
|
||
|
.savexmm128 xmm12, CxXmm12 ;
|
||
|
.savexmm128 xmm13, CxXmm13 ;
|
||
|
.savexmm128 xmm14, CxXmm14 ;
|
||
|
.savexmm128 xmm15, CxXmm15 ;
|
||
|
|
||
|
END_PROLOGUE
|
||
|
|
||
|
;++
|
||
|
;
|
||
|
; VOID
|
||
|
; RcConsolidateFrames (
|
||
|
; IN PEXCEPTION_RECORD ExceptionRecord
|
||
|
; )
|
||
|
;
|
||
|
; Routine Description:
|
||
|
;
|
||
|
; This routine is called at the end of a unwind operation to logically
|
||
|
; remove unwound frames from the stack. This is accomplished by building a
|
||
|
; call frame using a machine frame and a context record and then calling
|
||
|
; the alternate entry of this function.
|
||
|
;
|
||
|
; The following code calls the language call back function specified in the
|
||
|
; exception record. If the function returns, then the destination frame
|
||
|
; context is restored and control transfered to the address returned by the
|
||
|
; language call back function. If control does not return, then another
|
||
|
; exception must be raised.
|
||
|
;
|
||
|
; Arguments:
|
||
|
;
|
||
|
; ExceptionRecord (rdx) - Supplies a pointer to an exception record.
|
||
|
;
|
||
|
; Implicit Arguments:
|
||
|
;
|
||
|
; ContextRecord (rsp) - Supplies a pointer to a context record.
|
||
|
;
|
||
|
; Return Value:
|
||
|
;
|
||
|
; None.
|
||
|
;
|
||
|
;--
|
||
|
|
||
|
ALTERNATE_ENTRY RcConsolidateFrames
|
||
|
|
||
|
;
|
||
|
; At this point all call frames from the dispatching of the an exception to
|
||
|
; a destination language specific handler have been logically unwound and
|
||
|
; consolidated into a single large frame.
|
||
|
;
|
||
|
; The first parameter in the exception record is the address of a callback
|
||
|
; routine that performs language specific operations. This routine is called
|
||
|
; with the specified exception record as a parameter.
|
||
|
;
|
||
|
|
||
|
call qword ptr ErExceptionInformation[rcx] ; call back to handler
|
||
|
|
||
|
;
|
||
|
; Restore context and continue.
|
||
|
;
|
||
|
|
||
|
mov rcx, rsp ; set address of context record
|
||
|
mov CxRip[rcx], rax ; set destination address
|
||
|
movdqa xmm0, CxXmm0[rcx] ; restore floating registers
|
||
|
movdqa xmm1, CxXmm1[rcx] ;
|
||
|
movdqa xmm2, CxXmm2[rcx] ;
|
||
|
movdqa xmm3, CxXmm3[rcx] ;
|
||
|
movdqa xmm4, CxXmm4[rcx] ;
|
||
|
movdqa xmm5, CxXmm5[rcx] ;
|
||
|
movdqa xmm6, CxXmm6[rcx] ;
|
||
|
movdqa xmm7, CxXmm7[rcx] ;
|
||
|
movdqa xmm8, CxXmm8[rcx] ;
|
||
|
movdqa xmm9, CxXmm9[rcx] ;
|
||
|
movdqa xmm10, CxXmm10[rcx] ;
|
||
|
movdqa xmm11, CxXmm11[rcx] ;
|
||
|
movdqa xmm12, CxXmm12[rcx] ;
|
||
|
movdqa xmm13, CxXmm13[rcx] ;
|
||
|
movdqa xmm14, CxXmm14[rcx] ;
|
||
|
movdqa xmm15, CxXmm15[rcx] ;
|
||
|
|
||
|
ldmxcsr CxMxCsr[rcx] ; restore floating state
|
||
|
|
||
|
;
|
||
|
; Contruct a machine frame of the stack using information from the context
|
||
|
; record.
|
||
|
;
|
||
|
; N.B. The machine frame overlays the parameter area in the context record.
|
||
|
;
|
||
|
|
||
|
mov eax, CxSegSs[rcx] ; set SS segment
|
||
|
mov MfSegSs[rsp], eax ;
|
||
|
mov rax, CxRsp[rcx] ; set stack address
|
||
|
mov MfRsp[rsp], rax ;
|
||
|
mov eax, CxEFlags[rcx] ; set processor flags
|
||
|
mov MfEFlags[rsp], eax ;
|
||
|
mov eax, CxSegCs[rcx] ; set CS segment
|
||
|
mov MfSegCs[rsp], eax ;
|
||
|
mov rax, CxRip[rcx] ; set return address
|
||
|
mov MfRip[rsp], rax ;
|
||
|
|
||
|
mov rax, CxRax[rcx] ; restore volatile integer registers
|
||
|
mov rdx, CxRdx[rcx] ;
|
||
|
mov r8, CxR8[rcx] ;
|
||
|
mov r9, CxR9[rcx] ;
|
||
|
mov r10, CxR10[rcx] ;
|
||
|
mov r11, CxR11[rcx] ;
|
||
|
|
||
|
ifdef NTOS_KERNEL_RUNTIME
|
||
|
|
||
|
cli ; disable interrupts
|
||
|
|
||
|
endif
|
||
|
|
||
|
mov rbx, CxRbx[rcx] ; restore nonvolatile integer registers
|
||
|
mov rsi, CxRsi[rcx] ;
|
||
|
mov rdi, CxRdi[rcx] ;
|
||
|
mov rbp, CxRbp[rcx] ;
|
||
|
mov r12, CxR12[rcx] ;
|
||
|
mov r13, CxR13[rcx] ;
|
||
|
mov r14, CxR14[rcx] ;
|
||
|
mov r15, CxR15[rcx] ;
|
||
|
mov rcx, CxRcx[rcx] ; restore integer register
|
||
|
iretq ; return
|
||
|
|
||
|
NESTED_END RcFrameConsolidation, _TEXT$00
|
||
|
|
||
|
end
|