windows-nt/Source/XPSP1/NT/base/ntos/ps/amd64/psctxamd64.c
2020-09-26 16:20:57 +08:00

544 lines
15 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
psctx.c
Abstract:
This procedure implements Get/Set Context Thread
Author:
David N. Cutler (davec) 20-Oct-2000
Revision History:
--*/
#include "psp.h"
#pragma alloc_text(PAGE, PspGetContext)
#pragma alloc_text(PAGE, PspGetSetContextSpecialApc)
#pragma alloc_text(PAGE, PspSetContext)
VOID
PspGetContext (
IN PKTRAP_FRAME TrapFrame,
IN PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
IN OUT PCONTEXT ContextRecord
)
/*++
Routine Description:
This function selectively moves the contents of the specified trap frame
and nonvolatile context to the specified context record.
Arguments:
TrapFrame - Supplies the contents of a trap frame.
ContextPointers - Supplies the address of context pointers record.
ContextRecord - Supplies the address of a context record.
Return Value:
None.
--*/
{
ULONG ContextFlags;
PLEGACY_SAVE_AREA NpxFrame;
PAGED_CODE();
//
// Get control information if specified.
//
ContextFlags = ContextRecord->ContextFlags;
if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
//
// Set registers RIP, CS, RSP, SS, and EFlags.
//
ContextRecord->Rip = TrapFrame->Rip;
ContextRecord->SegCs = TrapFrame->SegCs;
ContextRecord->SegSs = TrapFrame->SegSs;
ContextRecord->Rsp = TrapFrame->Rsp;
ContextRecord->EFlags = TrapFrame->EFlags;
}
//
// Get segment register contents if specified.
//
if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) {
//
// Set segment registers GS, FS, ES, DS.
//
ContextRecord->SegDs = KGDT64_R3_DATA | RPL_MASK;
ContextRecord->SegEs = KGDT64_R3_DATA | RPL_MASK;
ContextRecord->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
ContextRecord->SegGs = KGDT64_R3_DATA | RPL_MASK;
}
//
// Get integer register contents if specified.
//
if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
//
// Set integer registers RAX, RCX, RDX, RSI, RDI, R8, R9, R10, RBX,
// RBP, R11, R12, R13, R14, and R15.
//
ContextRecord->Rax = TrapFrame->Rax;
ContextRecord->Rcx = TrapFrame->Rcx;
ContextRecord->Rdx = TrapFrame->Rdx;
ContextRecord->R8 = TrapFrame->R8;
ContextRecord->R9 = TrapFrame->R9;
ContextRecord->R10 = TrapFrame->R10;
ContextRecord->R11 = TrapFrame->R11;
ContextRecord->Rbx = *ContextPointers->Rbx;
ContextRecord->Rbp = *ContextPointers->Rbp;
ContextRecord->Rsi = *ContextPointers->Rsi;
ContextRecord->Rdi = *ContextPointers->Rdi;
ContextRecord->R12 = *ContextPointers->R12;
ContextRecord->R13 = *ContextPointers->R13;
ContextRecord->R13 = *ContextPointers->R14;
ContextRecord->R15 = *ContextPointers->R15;
}
//
// Get floating point context if specified.
//
if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) {
//
// Set XMM registers Xmm0-Xmm15 and the XMM CSR contents.
//
RtlCopyMemory(&ContextRecord->Xmm0,
&TrapFrame->Xmm0,
sizeof(M128) * 6);
ContextRecord->Xmm6 = *ContextPointers->Xmm6;
ContextRecord->Xmm7 = *ContextPointers->Xmm7;
ContextRecord->Xmm8 = *ContextPointers->Xmm8;
ContextRecord->Xmm9 = *ContextPointers->Xmm9;
ContextRecord->Xmm10 = *ContextPointers->Xmm10;
ContextRecord->Xmm11 = *ContextPointers->Xmm11;
ContextRecord->Xmm12 = *ContextPointers->Xmm12;
ContextRecord->Xmm13 = *ContextPointers->Xmm13;
ContextRecord->Xmm14 = *ContextPointers->Xmm14;
ContextRecord->Xmm15 = *ContextPointers->Xmm15;
ContextRecord->MxCsr = TrapFrame->MxCsr;
//
// If the specified mode is user, then also set the legacy floating
// point state.
//
if ((TrapFrame->SegCs & MODE_MASK) == UserMode) {
NpxFrame = (PLEGACY_SAVE_AREA)(TrapFrame + 1);
RtlCopyMemory(&ContextRecord->FltSave,
&NpxFrame,
sizeof(LEGACY_SAVE_AREA));
}
}
//
//
// Get debug register contents if requested.
//
if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) {
//
// Set the debug registers DR0, DR1, DR2, DR3, DR6, and DR7.
//
ContextRecord->Dr0 = TrapFrame->Dr0;
ContextRecord->Dr1 = TrapFrame->Dr1;
ContextRecord->Dr2 = TrapFrame->Dr2;
ContextRecord->Dr3 = TrapFrame->Dr3;
ContextRecord->Dr6 = TrapFrame->Dr6;
ContextRecord->Dr7 = TrapFrame->Dr7;
}
return;
}
VOID
PspSetContext (
OUT PKTRAP_FRAME TrapFrame,
OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
IN PCONTEXT ContextRecord,
KPROCESSOR_MODE PreviousMode
)
/*++
Routine Description:
This function selectively moves the contents of the specified context
record to the specified trap frame and nonvolatile context.
Arguments:
TrapFrame - Supplies the address of a trap frame.
ContextPointers - Supplies the address of a context pointers record.
ContextRecord - Supplies the address of a context record.
ProcessorMode - Supplies the processor mode to use when sanitizing
the PSR and FSR.
Return Value:
None.
--*/
{
ULONG ContextFlags;
PLEGACY_SAVE_AREA NpxFrame;
PAGED_CODE();
//
// Set control information if specified.
//
ContextFlags = ContextRecord->ContextFlags;
if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
//
// Set registers RIP, RSP, and EFlags.
//
TrapFrame->EFlags = SANITIZE_EFLAGS(ContextRecord->EFlags, PreviousMode);
TrapFrame->Rip = ContextRecord->Rip;
TrapFrame->Rsp = ContextRecord->Rsp;
}
//
// The segment registers DS, ES, FS, and GS are never restored from saved
// data. However, SS and CS are restored from the trap frame. Make sure
// that these segment registers have the proper values.
//
if (PreviousMode == UserMode) {
TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
if (ContextRecord->SegCs != (KGDT64_R3_CODE | RPL_MASK)) {
TrapFrame->SegCs = KGDT64_R3_CMCODE | RPL_MASK;
} else {
TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
}
} else {
TrapFrame->SegCs = KGDT64_R0_CODE;
TrapFrame->SegSs = KGDT64_NULL;
}
//
// Set integer registers contents if specified.
//
if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
//
// Set integer registers RAX, RCX, RDX, RSI, RDI, R8, R9, R10, RBX,
// RBP, R11, R12, R13, R14, and R15.
//
TrapFrame->Rax = ContextRecord->Rax;
TrapFrame->Rcx = ContextRecord->Rcx;
TrapFrame->Rdx = ContextRecord->Rdx;
TrapFrame->R8 = ContextRecord->R8;
TrapFrame->R9 = ContextRecord->R9;
TrapFrame->R10 = ContextRecord->R10;
TrapFrame->R11 = ContextRecord->R11;
*ContextPointers->Rbx = ContextRecord->Rbx;
*ContextPointers->Rbp = ContextRecord->Rbp;
*ContextPointers->Rsi = ContextRecord->Rsi;
*ContextPointers->Rdi = ContextRecord->Rdi;
*ContextPointers->R12 = ContextRecord->R12;
*ContextPointers->R13 = ContextRecord->R13;
*ContextPointers->R14 = ContextRecord->R14;
*ContextPointers->R15 = ContextRecord->R15;
}
//
// Set floating register contents if requested.
//
if ((ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) {
//
// Set XMM registers Xmm0-Xmm15 and the XMM CSR contents.
//
RtlCopyMemory(&TrapFrame->Xmm0,
&ContextRecord->Xmm0,
sizeof(M128) * 6);
*ContextPointers->Xmm6 = ContextRecord->Xmm6;
*ContextPointers->Xmm7 = ContextRecord->Xmm7;
*ContextPointers->Xmm8 = ContextRecord->Xmm8;
*ContextPointers->Xmm9 = ContextRecord->Xmm9;
*ContextPointers->Xmm10 = ContextRecord->Xmm10;
*ContextPointers->Xmm11 = ContextRecord->Xmm11;
*ContextPointers->Xmm12 = ContextRecord->Xmm12;
*ContextPointers->Xmm13 = ContextRecord->Xmm13;
*ContextPointers->Xmm14 = ContextRecord->Xmm14;
*ContextPointers->Xmm15 = ContextRecord->Xmm15;
//
// Clear all reserved bits in MXCSR.
//
TrapFrame->MxCsr = SANITIZE_MXCSR(ContextRecord->MxCsr);
//
// If the specified mode is user, then also set the legacy floating
// point state.
//
if (PreviousMode == UserMode) {
//
// Set the floating state MM0/ST0 - MM7/ST7 and the control state.
//
NpxFrame = (PLEGACY_SAVE_AREA)(TrapFrame + 1);
RtlCopyMemory(&NpxFrame,
&ContextRecord->FltSave,
sizeof(LEGACY_SAVE_AREA));
}
}
//
// Set debug register state if specified.
//
if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) {
//
// Set the debug registers DR0, DR1, DR2, DR3, DR6, and DR7.
//
TrapFrame->Dr0 = SANITIZE_DRADDR(ContextRecord->Dr0, PreviousMode);
TrapFrame->Dr1 = SANITIZE_DRADDR(ContextRecord->Dr1, PreviousMode);
TrapFrame->Dr2 = SANITIZE_DRADDR(ContextRecord->Dr2, PreviousMode);
TrapFrame->Dr3 = SANITIZE_DRADDR(ContextRecord->Dr3, PreviousMode);
TrapFrame->Dr6 = 0;
TrapFrame->Dr7 = SANITIZE_DR7(ContextRecord->Dr7, PreviousMode);
}
return;
}
VOID
PspGetSetContextSpecialApc (
IN PKAPC Apc,
IN PKNORMAL_ROUTINE *NormalRoutine,
IN PVOID *NormalContext,
IN PVOID *SystemArgument1,
IN PVOID *SystemArgument2
)
/*++
Routine Description:
This function either captures the user mode state of the current thread,
or sets the user mode state of the current thread. The operation type is
determined by the value of SystemArgument1. A NULL value is used for get
context, and a non-NULL value is used for set context.
Arguments:
Apc - Supplies a pointer to the APC control object that caused entry
into this routine.
NormalRoutine - Supplies a pointer to a pointer to the normal routine
function that was specifed when the APC was initialized.
NormalContext - Supplies a pointer to a pointer to an arbitrary data
structure that was specified when the APC was initialized.
SystemArgument1, SystemArgument2 - Supplies a set of two pointer to two
arguments that contain untyped data.
Return Value:
None.
--*/
{
PGETSETCONTEXT ContextBlock;
KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
CONTEXT ContextRecord;
ULONG64 ControlPc;
ULONG64 EstablisherFrame;
PRUNTIME_FUNCTION FunctionEntry;
PVOID HandlerData;
ULONG64 ImageBase;
ULONG64 TrapFrame;
PETHREAD Thread;
UNREFERENCED_PARAMETER(NormalRoutine);
UNREFERENCED_PARAMETER(NormalContext);
UNREFERENCED_PARAMETER(SystemArgument2);
PAGED_CODE();
//
// Get the address of the context block and compute the address of the
// system entry trap frame.
//
ContextBlock = CONTAINING_RECORD(Apc, GETSETCONTEXT, Apc);
Thread = PsGetCurrentThread();
TrapFrame = 0;
if (ContextBlock->Mode == KernelMode) {
TrapFrame = (ULONG64)Thread->Tcb.TrapFrame;
}
if (TrapFrame == 0) {
TrapFrame = (ULONG64)Thread->Tcb.InitialStack - KTRAP_FRAME_LENGTH;
}
//
// Capture the current thread context and set the initial control PC
// value.
//
RtlCaptureContext(&ContextRecord);
//
// Initialize context pointers for the nonvolatile integer and floating
// registers.
//
ContextPointers.Rax = &ContextRecord.Rax;
ContextPointers.Rcx = &ContextRecord.Rcx;
ContextPointers.Rdx = &ContextRecord.Rdx;
ContextPointers.Rbx = &ContextRecord.Rbx;
ContextPointers.Rbp = &ContextRecord.Rbp;
ContextPointers.Rsi = &ContextRecord.Rsi;
ContextPointers.Rdi = &ContextRecord.Rdi;
ContextPointers.R8 = &ContextRecord.R8;
ContextPointers.R9 = &ContextRecord.R9;
ContextPointers.R10 = &ContextRecord.R10;
ContextPointers.R11 = &ContextRecord.R11;
ContextPointers.R12 = &ContextRecord.R12;
ContextPointers.R13 = &ContextRecord.R13;
ContextPointers.R14 = &ContextRecord.R14;
ContextPointers.R15 = &ContextRecord.R15;
ContextPointers.Xmm6 = &ContextRecord.Xmm6;
ContextPointers.Xmm7 = &ContextRecord.Xmm7;
ContextPointers.Xmm8 = &ContextRecord.Xmm8;
ContextPointers.Xmm9 = &ContextRecord.Xmm9;
ContextPointers.Xmm10 = &ContextRecord.Xmm10;
ContextPointers.Xmm11 = &ContextRecord.Xmm11;
ContextPointers.Xmm12 = &ContextRecord.Xmm12;
ContextPointers.Xmm13 = &ContextRecord.Xmm13;
ContextPointers.Xmm14 = &ContextRecord.Xmm14;
ContextPointers.Xmm15 = &ContextRecord.Xmm15;
//
// Start with the frame specified by the context record and virtually
// unwind call frames until the system entry trap frame is encountered.
//
do {
//
// Lookup the function table entry using the point at which control
// left the function.
//
ControlPc = ContextRecord.Rip;
FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
//
// If there is a function table entry for the routine, then virtually
// unwind to the caller of the current routine to obtain the address
// where control left the caller. Otherwise, the function is a leaf
// function and the return address register contains the address of
// where control left the caller.
//
if (FunctionEntry != NULL) {
RtlVirtualUnwind(UNW_FLAG_EHANDLER,
ImageBase,
ControlPc,
FunctionEntry,
&ContextRecord,
&HandlerData,
&EstablisherFrame,
&ContextPointers);
} else {
ContextRecord.Rip = *(PULONG64)(ContextRecord.Rsp);
ContextRecord.Rsp += 8;
}
} while (ContextRecord.Rsp != TrapFrame);
//
// If system argument one is nonzero, then set the context of the current
// thread. Otherwise, get the context of the current thread.
//
if (*SystemArgument1 != NULL) {
//
// Set Context
//
PspSetContext((PKTRAP_FRAME)TrapFrame,
NULL,
&ContextBlock->Context,
ContextBlock->Mode);
} else {
//
// Get Context
//
PspGetContext((PKTRAP_FRAME)TrapFrame, NULL, &ContextBlock->Context);
}
KeSetEvent(&ContextBlock->OperationComplete, 0, FALSE);
return;
}