windows-nt/Source/XPSP1/NT/base/ntos/rtl/amd64/capture.asm

473 lines
16 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
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