929 lines
27 KiB
C
929 lines
27 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
context.c
|
|
|
|
Abstract:
|
|
|
|
Context conversion routines for ia64 hardware to ia32 context records
|
|
|
|
Author:
|
|
|
|
03-Feb-2000 Charles Spriakis - Intel (v-cspira)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#define _WOW64CPUAPI_
|
|
|
|
#ifdef _X86_
|
|
#include "ia6432.h"
|
|
#else
|
|
|
|
#define _NTDDK_
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include "wow64.h"
|
|
#include "wow64cpu.h"
|
|
#include "ia64cpu.h"
|
|
|
|
#include <kxia64.h>
|
|
|
|
#endif
|
|
|
|
//
|
|
// This is to prevent this library from linking to wow64 to use wow64!Wow64LogPrint
|
|
//
|
|
#if defined(LOGPRINT)
|
|
#undef LOGPRINT
|
|
#endif
|
|
#define LOGPRINT(_x_) CpupDebugPrint _x_
|
|
|
|
VOID
|
|
CpupDebugPrint(
|
|
IN ULONG_PTR Flags,
|
|
IN PCHAR Format,
|
|
...);
|
|
|
|
BOOL
|
|
MapDbgSlotIa64ToX86(
|
|
UINT Slot,
|
|
ULONG64 Ipsr,
|
|
ULONG64 DbD,
|
|
ULONG64 DbD1,
|
|
ULONG64 DbI,
|
|
ULONG64 DbI1,
|
|
ULONG* Dr7,
|
|
ULONG* Dr);
|
|
|
|
void
|
|
MapDbgSlotX86ToIa64(
|
|
UINT Slot,
|
|
ULONG Dr7,
|
|
ULONG Dr,
|
|
ULONG64* Ipsr,
|
|
ULONG64* DbD,
|
|
ULONG64* DbD1,
|
|
ULONG64* DbI,
|
|
ULONG64* DbI1);
|
|
|
|
|
|
ASSERTNAME;
|
|
|
|
|
|
VOID
|
|
Wow64CtxFromIa64(
|
|
IN ULONG Ia32ContextFlags,
|
|
IN PCONTEXT ContextIa64,
|
|
IN OUT PCONTEXT32 ContextX86
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies the context from an ia64 context record into
|
|
the context of an ia32 record (based on the hardware iVE register
|
|
mappings). This function is ment to be easily usabale by various
|
|
get/set context routines (such as those exported by wow64cpu.dll).
|
|
|
|
Arguments:
|
|
|
|
Ia32ContextFlags - Specifies which ia32 context to copy
|
|
|
|
ContextIa64 - Supplies an the ia64 context buffer that is the source
|
|
for the copy into the ia32 context area
|
|
|
|
ContextX86 - This is an X86 context which will receive the context
|
|
information from the ia64 context record passed in above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
FLOAT128 tmpFloat[NUMBER_OF_387REGS];
|
|
|
|
if (Ia32ContextFlags & CONTEXT_IA64) {
|
|
LOGPRINT((ERRORLOG, "Wow64CtxFromIa64: Request with ia64 context flags (0x%x) FAILED\n", Ia32ContextFlags));
|
|
ASSERT((Ia32ContextFlags & CONTEXT_IA64) == 0);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL) {
|
|
//
|
|
// And the control stuff
|
|
//
|
|
ContextX86->Ebp = (ULONG)ContextIa64->IntTeb;
|
|
ContextX86->SegCs = KGDT_R3_CODE|3;
|
|
ContextX86->Eip = (ULONG)ContextIa64->StIIP;
|
|
ContextX86->SegSs = KGDT_R3_DATA|3;
|
|
ContextX86->Esp = (ULONG)ContextIa64->IntSp;
|
|
ContextX86->EFlags = (ULONG)ContextIa64->Eflag;
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER) {
|
|
//
|
|
// Now for the integer state...
|
|
//
|
|
ContextX86->Edi = (ULONG)ContextIa64->IntT6;
|
|
ContextX86->Esi = (ULONG)ContextIa64->IntT5;
|
|
ContextX86->Ebx = (ULONG)ContextIa64->IntT4;
|
|
ContextX86->Edx = (ULONG)ContextIa64->IntT3;
|
|
ContextX86->Ecx = (ULONG)ContextIa64->IntT2;
|
|
ContextX86->Eax = (ULONG)ContextIa64->IntV0;
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS) {
|
|
//
|
|
// These are constants (and constants are used on ia32->ia64
|
|
// transition, not saved values) so make our life easy...
|
|
//
|
|
ContextX86->SegGs = KGDT_R3_DATA|3;
|
|
ContextX86->SegEs = KGDT_R3_DATA|3;
|
|
ContextX86->SegDs = KGDT_R3_DATA|3;
|
|
ContextX86->SegSs = KGDT_R3_DATA|3;
|
|
ContextX86->SegFs = KGDT_R3_TEB|3;
|
|
ContextX86->SegCs = KGDT_R3_CODE|3;
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) {
|
|
|
|
PFXSAVE_FORMAT_WX86 xmmi = (PFXSAVE_FORMAT_WX86) ContextX86->ExtendedRegisters;
|
|
|
|
LOGPRINT((TRACELOG, "Wow64CtxFromIa64: Request to convert extended fp registers\n"));
|
|
|
|
xmmi->ControlWord = (USHORT)(ContextIa64->StFCR & 0xffff);
|
|
xmmi->StatusWord = (USHORT)(ContextIa64->StFSR & 0xffff);
|
|
xmmi->TagWord = (USHORT)(ContextIa64->StFSR >> 16) & 0xffff;
|
|
xmmi->ErrorOpcode = (USHORT)(ContextIa64->StFIR >> 48);
|
|
xmmi->ErrorOffset = (ULONG) (ContextIa64->StFIR & 0xffffffff);
|
|
xmmi->ErrorSelector = (ULONG) (ContextIa64->StFIR >> 32);
|
|
xmmi->DataOffset = (ULONG) (ContextIa64->StFDR & 0xffffffff);
|
|
xmmi->DataSelector = (ULONG) (ContextIa64->StFDR >> 32);
|
|
xmmi->MXCsr = (ULONG) (ContextIa64->StFCR >> 32) & 0xffff;
|
|
|
|
//
|
|
// Copy over the FP registers. Even though this is the new
|
|
// FXSAVE format with 16-bytes for each register, need to
|
|
// convert from spill/fill format to 80-bit double extended format
|
|
//
|
|
Wow64CopyIa64FromSpill((PFLOAT128) &(ContextIa64->FltT2),
|
|
(PFLOAT128) xmmi->RegisterArea,
|
|
NUMBER_OF_387REGS);
|
|
|
|
//
|
|
// Rotate the registers appropriately
|
|
//
|
|
Wow64RotateFpTop(ContextIa64->StFSR, (PFLOAT128) xmmi->RegisterArea);
|
|
|
|
//
|
|
// Finally copy the xmmi registers
|
|
//
|
|
Wow64CopyXMMIFromIa64Byte16(&(ContextIa64->FltS4),
|
|
xmmi->Reserved3,
|
|
NUMBER_OF_XMMI_REGS);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT) {
|
|
|
|
LOGPRINT((TRACELOG, "Wow64CtxFromIa64: Request to convert fp registers\n"));
|
|
|
|
//
|
|
// Copy over the floating point status/control stuff
|
|
//
|
|
ContextX86->FloatSave.ControlWord = (ULONG)(ContextIa64->StFCR & 0xffff);
|
|
ContextX86->FloatSave.StatusWord = (ULONG)(ContextIa64->StFSR & 0xffff);
|
|
ContextX86->FloatSave.TagWord = (ULONG)(ContextIa64->StFSR >> 16) & 0xffff;
|
|
ContextX86->FloatSave.ErrorOffset = (ULONG)(ContextIa64->StFIR & 0xffffffff);
|
|
ContextX86->FloatSave.ErrorSelector = (ULONG)(ContextIa64->StFIR >> 32);
|
|
ContextX86->FloatSave.DataOffset = (ULONG)(ContextIa64->StFDR & 0xffffffff);
|
|
ContextX86->FloatSave.DataSelector = (ULONG)(ContextIa64->StFDR >> 32);
|
|
|
|
//
|
|
// Copy over the FP registers into temporary space
|
|
// Even though this is the new
|
|
// FXSAVE format with 16-bytes for each register, need to
|
|
// convert from spill/fill format to 80-bit double extended format
|
|
//
|
|
Wow64CopyIa64FromSpill((PFLOAT128) &(ContextIa64->FltT2),
|
|
(PFLOAT128) tmpFloat,
|
|
NUMBER_OF_387REGS);
|
|
//
|
|
// Rotate the registers appropriately
|
|
//
|
|
Wow64RotateFpTop(ContextIa64->StFSR, tmpFloat);
|
|
|
|
//
|
|
// And put them in the older FNSAVE format (packed 10 byte values)
|
|
//
|
|
Wow64CopyFpFromIa64Byte16(tmpFloat,
|
|
ContextX86->FloatSave.RegisterArea,
|
|
NUMBER_OF_387REGS);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS) {
|
|
// Ia64 -> X86
|
|
BOOL Valid = TRUE;
|
|
|
|
LOGPRINT((TRACELOG, "Wow64CtxFromIa64: Request to convert debug registers\n"));
|
|
|
|
#if 0 // XXX olegk - enable after clarifying problems with exceptions
|
|
|
|
Valid &= MapDbgSlotIa64ToX86(0, ContextIa64->StIPSR, ContextIa64->DbD0, ContextIa64->DbD1, ContextIa64->DbI0, ContextIa64->DbI1, &ContextX86->Dr7, &ContextX86->Dr0);
|
|
Valid &= MapDbgSlotIa64ToX86(1, ContextIa64->StIPSR, ContextIa64->DbD2, ContextIa64->DbD3, ContextIa64->DbI2, ContextIa64->DbI3, &ContextX86->Dr7, &ContextX86->Dr1);
|
|
Valid &= MapDbgSlotIa64ToX86(2, ContextIa64->StIPSR, ContextIa64->DbD4, ContextIa64->DbD5, ContextIa64->DbI4, ContextIa64->DbI5, &ContextX86->Dr7, &ContextX86->Dr2);
|
|
Valid &= MapDbgSlotIa64ToX86(3, ContextIa64->StIPSR, ContextIa64->DbD6, ContextIa64->DbD7, ContextIa64->DbI6, ContextIa64->DbI7, &ContextX86->Dr7, &ContextX86->Dr3);
|
|
|
|
if (!Valid) {
|
|
LOGPRINT((ERRORLOG, "Wasn't able to map IA64 debug registers consistently!\n"));
|
|
}
|
|
#endif // XXX olegk
|
|
}
|
|
|
|
ContextX86->ContextFlags = Ia32ContextFlags;
|
|
}
|
|
|
|
VOID
|
|
Wow64CtxToIa64(
|
|
IN ULONG Ia32ContextFlags,
|
|
IN PCONTEXT32 ContextX86,
|
|
IN OUT PCONTEXT ContextIa64
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies the context from an ia32 context record into
|
|
the context of an ia64 record (based on the hardware iVE register
|
|
mappings). This function is ment to be easily usabale by various
|
|
get/set context routines (such as those exported by wow64cpu.dll).
|
|
|
|
Arguments:
|
|
|
|
Ia32ContextFlags - Specifies which ia32 context to copy
|
|
|
|
ContextX86 - Supplies an the X86 context buffer that is the source
|
|
for the copy into the ia64 context area
|
|
|
|
ContextIa64 - This is an ia64 context which will receive the context
|
|
information from the x86 context record passed in above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
FLOAT128 tmpFloat[NUMBER_OF_387REGS];
|
|
|
|
if (Ia32ContextFlags & CONTEXT_IA64) {
|
|
LOGPRINT((ERRORLOG, "Wow64CtxToIa64: Request with ia64 context flags (0x%x) FAILED\n", Ia32ContextFlags));
|
|
ASSERT((Ia32ContextFlags & CONTEXT_IA64) == 0);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_CONTROL) == CONTEXT32_CONTROL) {
|
|
//
|
|
// And the control stuff
|
|
//
|
|
ContextIa64->IntTeb = ContextX86->Ebp;
|
|
ContextIa64->StIIP = ContextX86->Eip;
|
|
ContextIa64->IntSp = ContextX86->Esp;
|
|
ContextIa64->Eflag = ContextX86->EFlags;
|
|
|
|
//
|
|
// The segments (cs and ds) are a constant, so reset them.
|
|
// gr17 has LDT and TSS, so might as well reset
|
|
// all of them while we're at it...
|
|
// These values are forced in during a transition (see simulate.s)
|
|
// so there is no point to trying to get cute and actually
|
|
// pass in the values from the X86 context record
|
|
//
|
|
ContextIa64->IntT8 = ((KGDT_LDT|3) << 32)
|
|
| ((KGDT_R3_DATA|3) << 16)
|
|
| (KGDT_R3_CODE|3);
|
|
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_INTEGER) == CONTEXT32_INTEGER) {
|
|
//
|
|
// Now for the integer state...
|
|
//
|
|
ContextIa64->IntT6 = ContextX86->Edi;
|
|
ContextIa64->IntT5 = ContextX86->Esi;
|
|
ContextIa64->IntT4 = ContextX86->Ebx;
|
|
ContextIa64->IntT3 = ContextX86->Edx;
|
|
ContextIa64->IntT2 = ContextX86->Ecx;
|
|
ContextIa64->IntV0 = ContextX86->Eax;
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_SEGMENTS) == CONTEXT32_SEGMENTS) {
|
|
//
|
|
// These are constants (and constants are used on ia32->ia64
|
|
// transition, not saved values) so make our life easy...
|
|
// These values are forced in during a transition (see simulate.s)
|
|
// so there is no point to trying to get cute and actually
|
|
// pass in the values from the X86 context record
|
|
//
|
|
ContextIa64->IntT7 = ((KGDT_R3_DATA|3) << 48)
|
|
| ((KGDT_R3_TEB|3) << 32)
|
|
| ((KGDT_R3_DATA|3) << 16)
|
|
| (KGDT_R3_DATA|3);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_EXTENDED_REGISTERS) == CONTEXT32_EXTENDED_REGISTERS) {
|
|
PFXSAVE_FORMAT_WX86 xmmi = (PFXSAVE_FORMAT_WX86) ContextX86->ExtendedRegisters;
|
|
|
|
LOGPRINT((TRACELOG, "Wow64CtxToIa64: Request to convert extended fp registers\n"));
|
|
|
|
//
|
|
// And copy over the floating point status/control stuff
|
|
//
|
|
ContextIa64->StFCR = (ContextIa64->StFCR & 0xffffffffffffe040i64) |
|
|
(xmmi->ControlWord & 0xffff) |
|
|
((xmmi->MXCsr & 0xffff) << 32);
|
|
|
|
ContextIa64->StFSR = (ContextIa64->StFSR & 0xffffffff00000000i64) |
|
|
(xmmi->StatusWord & 0xffff) |
|
|
((xmmi->TagWord & 0xffff) << 16);
|
|
|
|
ContextIa64->StFIR = (xmmi->ErrorOffset & 0xffffffff) |
|
|
(xmmi->ErrorSelector << 32);
|
|
|
|
ContextIa64->StFDR = (xmmi->DataOffset & 0xffffffff) |
|
|
(xmmi->DataSelector << 32);
|
|
|
|
//
|
|
// Don't touch the original ia32 context. Make a copy.
|
|
//
|
|
memcpy(tmpFloat, xmmi->RegisterArea,
|
|
NUMBER_OF_387REGS * sizeof(FLOAT128));
|
|
|
|
//
|
|
// Rotate registers back since st0 is not necessarily f8
|
|
//
|
|
{
|
|
ULONGLONG RotateFSR = (NUMBER_OF_387REGS -
|
|
((ContextIa64->StFSR >> 11) & 0x7)) << 11;
|
|
Wow64RotateFpTop(RotateFSR, tmpFloat);
|
|
}
|
|
|
|
//
|
|
// Copy over the FP registers. Even though this is the new
|
|
// FXSAVE format with 16-bytes for each register, need to
|
|
// convert to spill/fill format from 80-bit double extended format
|
|
//
|
|
Wow64CopyIa64ToFill((PFLOAT128) tmpFloat,
|
|
(PFLOAT128) &(ContextIa64->FltT2),
|
|
NUMBER_OF_387REGS);
|
|
|
|
//
|
|
// Copy over the xmmi registers and convert them into a format
|
|
// that spill/fill can use
|
|
//
|
|
Wow64CopyXMMIToIa64Byte16(xmmi->Reserved3,
|
|
&(ContextIa64->FltS4),
|
|
NUMBER_OF_XMMI_REGS);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_FLOATING_POINT) == CONTEXT32_FLOATING_POINT) {
|
|
LOGPRINT((TRACELOG, "Wow64CtxToIa64: Request to convert fp registers\n"));
|
|
|
|
//
|
|
// Copy over the floating point status/control stuff
|
|
// Leave the MXCSR stuff alone
|
|
//
|
|
ContextIa64->StFCR = (ContextIa64->StFCR & 0xffffffffffffe040i64) |
|
|
(ContextX86->FloatSave.ControlWord & 0xffff);
|
|
|
|
ContextIa64->StFSR = (ContextIa64->StFSR & 0xffffffff00000000i64) |
|
|
(ContextX86->FloatSave.StatusWord & 0xffff) |
|
|
((ContextX86->FloatSave.TagWord & 0xffff) << 16);
|
|
|
|
ContextIa64->StFIR = (ContextX86->FloatSave.ErrorOffset & 0xffffffff) |
|
|
(ContextX86->FloatSave.ErrorSelector << 32);
|
|
|
|
ContextIa64->StFDR = (ContextX86->FloatSave.DataOffset & 0xffffffff) |
|
|
(ContextX86->FloatSave.DataSelector << 32);
|
|
|
|
|
|
//
|
|
// Copy over the FP registers from packed 10-byte format
|
|
// to 16-byte format
|
|
//
|
|
Wow64CopyFpToIa64Byte16(ContextX86->FloatSave.RegisterArea,
|
|
tmpFloat,
|
|
NUMBER_OF_387REGS);
|
|
|
|
//
|
|
// Rotate registers back since st0 is not necessarily f8
|
|
//
|
|
{
|
|
ULONGLONG RotateFSR = (NUMBER_OF_387REGS -
|
|
((ContextIa64->StFSR >> 11) & 0x7)) << 11;
|
|
Wow64RotateFpTop(RotateFSR, tmpFloat);
|
|
}
|
|
|
|
//
|
|
// Now convert from 80 bit extended format to fill/spill format
|
|
//
|
|
Wow64CopyIa64ToFill((PFLOAT128) tmpFloat,
|
|
(PFLOAT128) &(ContextIa64->FltT2),
|
|
NUMBER_OF_387REGS);
|
|
}
|
|
|
|
if ((Ia32ContextFlags & CONTEXT32_DEBUG_REGISTERS) == CONTEXT32_DEBUG_REGISTERS) {
|
|
LOGPRINT((TRACELOG, "Wow64CtxToIa64: Request to convert debug registers\n"));
|
|
|
|
#if 0 // XXX olegk - enable after clarifying exception problems
|
|
//ContextIa64->ContextFlags |= CONTEXT_DEBUG;
|
|
|
|
// X86 -> Ia64
|
|
MapDbgSlotX86ToIa64(0, ContextX86->Dr7, ContextX86->Dr0, &ContextIa64->StIPSR, &ContextIa64->DbD0, &ContextIa64->DbD1, &ContextIa64->DbI0, &ContextIa64->DbI1);
|
|
MapDbgSlotX86ToIa64(1, ContextX86->Dr7, ContextX86->Dr1, &ContextIa64->StIPSR, &ContextIa64->DbD2, &ContextIa64->DbD3, &ContextIa64->DbI2, &ContextIa64->DbI3);
|
|
MapDbgSlotX86ToIa64(2, ContextX86->Dr7, ContextX86->Dr2, &ContextIa64->StIPSR, &ContextIa64->DbD4, &ContextIa64->DbD5, &ContextIa64->DbI4, &ContextIa64->DbI5);
|
|
MapDbgSlotX86ToIa64(3, ContextX86->Dr7, ContextX86->Dr3, &ContextIa64->StIPSR, &ContextIa64->DbD6, &ContextIa64->DbD7, &ContextIa64->DbI6, &ContextIa64->DbI7);
|
|
#endif // XXX olegk
|
|
}
|
|
}
|
|
|
|
//
|
|
// The ia64 world uses ldfe, stfe to read/write the fp registers. These
|
|
// instructions ld/st 16 bytes at a time. Thus, the fp registers are
|
|
// packed in 16byte chunks. Alas, the ia32 world uses 10bytes per fp register
|
|
// and packs those together (as part of fnstore). So... Need to convert between
|
|
// the ia64 packed values and the ia32 packed values. Hence these
|
|
// two routines and their weird sounding names.
|
|
//
|
|
|
|
//
|
|
// This allows the compiler to be more efficient in copying 10 bytes
|
|
// without over copying...
|
|
//
|
|
#pragma pack(push, 2)
|
|
typedef struct _ia32fpbytes {
|
|
ULONG significand_low;
|
|
ULONG significand_high;
|
|
USHORT exponent;
|
|
} IA32FPBYTES, *PIA32FPBYTES;
|
|
#pragma pack(pop)
|
|
|
|
VOID
|
|
Wow64CopyFpFromIa64Byte16(
|
|
IN PVOID Byte16Fp,
|
|
IN OUT PVOID Byte10Fp,
|
|
IN ULONG NumRegs)
|
|
{
|
|
ULONG i;
|
|
PIA32FPBYTES from, to;
|
|
|
|
from = (PIA32FPBYTES) Byte16Fp;
|
|
to = (PIA32FPBYTES) Byte10Fp;
|
|
|
|
for (i = 0; i < NumRegs; i++) {
|
|
*to = *from;
|
|
from = (PIA32FPBYTES) (((UINT_PTR) from) + 16);
|
|
to = (PIA32FPBYTES) (((UINT_PTR) to) + 10);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Wow64CopyFpToIa64Byte16(
|
|
IN PVOID Byte10Fp,
|
|
IN OUT PVOID Byte16Fp,
|
|
IN ULONG NumRegs)
|
|
{
|
|
ULONG i;
|
|
PIA32FPBYTES from, to; // UNALIGNED
|
|
|
|
from = (PIA32FPBYTES) Byte10Fp;
|
|
to = (PIA32FPBYTES) Byte16Fp;
|
|
|
|
for (i = 0; i < NumRegs; i++) {
|
|
*to = *from;
|
|
from = (PIA32FPBYTES) (((UINT_PTR) from) + 10);
|
|
to = (PIA32FPBYTES) (((UINT_PTR) to) + 16);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Alas, nothing is easy. The ia32 xmmi instructions use 16 bytes and pack
|
|
// them as nice 16 byte structs. Unfortunately, ia64 handles it as 2 8-byte
|
|
// values (using just the mantissa part). So, another conversion is required
|
|
//
|
|
VOID
|
|
Wow64CopyXMMIToIa64Byte16(
|
|
IN PVOID ByteXMMI,
|
|
IN OUT PVOID Byte16Fp,
|
|
IN ULONG NumRegs)
|
|
{
|
|
ULONG i;
|
|
UNALIGNED ULONGLONG *from;
|
|
ULONGLONG *to;
|
|
|
|
from = (PULONGLONG) ByteXMMI;
|
|
to = (PULONGLONG) Byte16Fp;
|
|
|
|
//
|
|
// although we have NumRegs xmmi registers, each register is 16 bytes
|
|
// wide. This code does things in 8-byte chunks, so total
|
|
// number of times to do things is 2 * NumRegs...
|
|
//
|
|
NumRegs *= 2;
|
|
|
|
for (i = 0; i < NumRegs; i++) {
|
|
*to++ = *from++; // Copy over the mantissa part
|
|
*to++ = 0x1003e; // Force the exponent part
|
|
// (see ia64 eas, ia32 FP section - 6.2.7
|
|
// for where this magic number comes from)
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Wow64CopyXMMIFromIa64Byte16(
|
|
IN PVOID Byte16Fp,
|
|
IN OUT PVOID ByteXMMI,
|
|
IN ULONG NumRegs)
|
|
{
|
|
ULONG i;
|
|
ULONGLONG *from;
|
|
UNALIGNED ULONGLONG *to;
|
|
|
|
from = (PULONGLONG) Byte16Fp;
|
|
to = (PULONGLONG) ByteXMMI;
|
|
|
|
//
|
|
// although we have NumRegs xmmi registers, each register is 16 bytes
|
|
// wide. This code does things in 8-byte chunks, so total
|
|
// number of times to do things is 2 * NumRegs...
|
|
//
|
|
NumRegs *= 2;
|
|
|
|
for (i = 0; i < NumRegs; i++) {
|
|
*to++ = *from++; // Copy over the mantissa part
|
|
from++; // Skip over the exponent part
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Wow64RotateFpTop(
|
|
IN ULONGLONG Ia64_FSR,
|
|
IN OUT FLOAT128 UNALIGNED *ia32FxSave)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
On transition from ia64 mode to ia32 (and back), the f8-f15 registers
|
|
contain the st[0] to st[7] fp stack values. Alas, these values don't
|
|
map one-one, so the FSR.top bits are used to determine which ia64
|
|
register has the top of stack. We then need to rotate these registers
|
|
since ia32 context is expecting st[0] to be the first fp register (as
|
|
if FSR.top is zero). This routine only works on full 16-byte ia32
|
|
saved fp data (such as from ExtendedRegisters - the FXSAVE format).
|
|
Other routines can convert this into the older FNSAVE format.
|
|
|
|
Arguments:
|
|
|
|
Ia64_FSR - The ia64 FSR register. Has the FSR.top needed for this routine
|
|
|
|
ia32FxSave - The ia32 fp stack (in FXSAVE format). Each ia32 fp register
|
|
uses 16 bytes.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG top = (ULONG) ((Ia64_FSR >> 11) & 0x7);
|
|
|
|
if (top) {
|
|
FLOAT128 tmpFloat[NUMBER_OF_387REGS];
|
|
ULONG i;
|
|
for (i = 0; i < NUMBER_OF_387REGS; i++) {
|
|
tmpFloat[i] = ia32FxSave[i];
|
|
}
|
|
|
|
for (i = 0; i < NUMBER_OF_387REGS; i++) {
|
|
ia32FxSave[i] = tmpFloat[(i + top) % NUMBER_OF_387REGS];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// And now for the final yuck... The ia64 context for floating point
|
|
// is saved/loaded using spill/fill instructions. This format is different
|
|
// than the 10-byte fp format so we need a conversion routine from spill/fill
|
|
// to/from 10byte fp
|
|
//
|
|
|
|
VOID
|
|
Wow64CopyIa64FromSpill(
|
|
IN PFLOAT128 SpillArea,
|
|
IN OUT FLOAT128 UNALIGNED *ia64Fp,
|
|
IN ULONG NumRegs)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies fp values from the ia64 spill/fill format
|
|
into the ia64 80-bit format. The exponent needs to be adjusted
|
|
according to the EAS (5-12) regarding Memory to Floating Point
|
|
Register Data Translation in the ia64 floating point chapter
|
|
|
|
Arguments:
|
|
|
|
SpillArea - The ia64 area that has the spill format for fp
|
|
|
|
ia64Fp - The location which will get the ia64 fp in 80-bit
|
|
double-extended format
|
|
|
|
NumRegs - Number of registers to convert
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < NumRegs; i++) {
|
|
ULONG64 Sign = ((SpillArea->HighPart & (1i64 << 17)) != 0);
|
|
ULONG64 Significand = SpillArea->LowPart;
|
|
ULONG64 Exponent = SpillArea->HighPart & 0x1ffff;
|
|
|
|
if (Exponent && Significand)
|
|
{
|
|
if (Exponent == 0x1ffff) // NaNs and Infinities
|
|
{
|
|
Exponent = 0x7fff;
|
|
}
|
|
else
|
|
{
|
|
ULONG64 Rebias = 0xffff - 0x3fff;
|
|
Exponent -= Rebias;
|
|
}
|
|
}
|
|
|
|
ia64Fp->HighPart = (Sign << 15) | Exponent;
|
|
ia64Fp->LowPart = Significand;
|
|
|
|
ia64Fp++;
|
|
SpillArea++;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
Wow64CopyIa64ToFill(
|
|
IN FLOAT128 UNALIGNED *ia64Fp,
|
|
IN OUT PFLOAT128 FillArea,
|
|
IN ULONG NumRegs)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function copies fp values from the ia64 80-bit format
|
|
into the fill/spill format used by the os for save/restore
|
|
of the ia64 context. The only magic here is putting back some
|
|
values that get truncated when converting from spill/fill to
|
|
80-bits. The exponent needs to be adjusted according to the
|
|
EAS (5-12) regarding Memory to Floating Point Register Data
|
|
Translation in the ia64 floating point chapter
|
|
|
|
Arguments:
|
|
|
|
ia64Fp - The ia64 fp in 80-bit double-extended format
|
|
|
|
FillArea - The ia64 area that will get the fill format for fp
|
|
for the copy into the ia64 context area
|
|
|
|
NumRegs - Number of registers to convert
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < NumRegs; i++) {
|
|
ULONG64 Sign = ((ia64Fp->HighPart & (1i64 << 15)) != 0);
|
|
ULONG64 Significand = ia64Fp->LowPart;
|
|
ULONG64 Exponent = ia64Fp->HighPart & 0x7fff;
|
|
|
|
if (Exponent && Significand)
|
|
{
|
|
if (Exponent == 0x7fff) // Infinity
|
|
{
|
|
Exponent = 0x1ffff;
|
|
}
|
|
else
|
|
{
|
|
ULONGLONG Rebias = 0xffff-0x3fff;
|
|
Exponent += Rebias;
|
|
}
|
|
}
|
|
|
|
FillArea->LowPart = Significand;
|
|
FillArea->HighPart = (Sign << 17) | Exponent;
|
|
|
|
ia64Fp++;
|
|
FillArea++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Debug registers conversion
|
|
//
|
|
|
|
// XXX olegk - uncrease to 4 in future
|
|
// (and then remove appropriate check at MapDbgSlotIa64ToX86)
|
|
#define IA64_REG_MAX_DATA_BREAKPOINTS 2
|
|
|
|
// Debug register flags.
|
|
#define IA64_DBR_RDWR 0xC000000000000000ui64
|
|
#define IA64_DBR_RD 0x8000000000000000ui64
|
|
#define IA64_DBR_WR 0x4000000000000000ui64
|
|
#define IA64_DBR_EXEC 0x8000000000000000ui64
|
|
#define IA64_DBG_MASK_MASK 0x00FFFFFFFFFFFFFFui64
|
|
#define IA64_DBG_REG_PLM_USER 0x0800000000000000ui64
|
|
#define IA64_DBG_REG_PLM_ALL 0x0F00000000000000ui64
|
|
|
|
#define X86_DR7_LOCAL_EXACT_ENABLE 0x100
|
|
|
|
ULONG
|
|
MapDbgSlotIa64ToX86_GetSize(ULONG64 Db1, BOOL* Valid)
|
|
{
|
|
ULONG64 Size = (~Db1 & IA64_DBG_MASK_MASK);
|
|
if (Size > 3)
|
|
{
|
|
*Valid = FALSE;
|
|
}
|
|
return (ULONG)Size;
|
|
}
|
|
|
|
void
|
|
MapDbgSlotIa64ToX86_InvalidateAddr(ULONG64 Db, BOOL* Valid)
|
|
{
|
|
if (Db != (ULONG64)(ULONG)Db)
|
|
{
|
|
*Valid = FALSE;
|
|
}
|
|
}
|
|
|
|
ULONG
|
|
MapDbgSlotIa64ToX86_ExecTypeSize(
|
|
UINT Slot,
|
|
ULONG64 Db,
|
|
ULONG64 Db1,
|
|
BOOL* Valid)
|
|
{
|
|
ULONG TypeSize;
|
|
|
|
if (!(Db1 >> 63))
|
|
{
|
|
*Valid = FALSE;
|
|
}
|
|
|
|
TypeSize = (MapDbgSlotIa64ToX86_GetSize(Db1, Valid) << 2);
|
|
MapDbgSlotIa64ToX86_InvalidateAddr(Db, Valid);
|
|
|
|
return TypeSize;
|
|
}
|
|
|
|
ULONG
|
|
MapDbgSlotIa64ToX86_DataTypeSize(
|
|
UINT Slot,
|
|
ULONG64 Db,
|
|
ULONG64 Db1,
|
|
BOOL* Valid)
|
|
{
|
|
ULONG TypeSize = (ULONG)(Db1 >> 62);
|
|
|
|
if ((TypeSize != 1) && (TypeSize != 3))
|
|
{
|
|
*Valid = FALSE;
|
|
}
|
|
|
|
TypeSize |= (MapDbgSlotIa64ToX86_GetSize(Db1, Valid) << 2);
|
|
MapDbgSlotIa64ToX86_InvalidateAddr(Db, Valid);
|
|
|
|
return TypeSize;
|
|
}
|
|
|
|
BOOL
|
|
MapDbgSlotIa64ToX86(
|
|
UINT Slot,
|
|
ULONG64 Ipsr,
|
|
ULONG64 DbD,
|
|
ULONG64 DbD1,
|
|
ULONG64 DbI,
|
|
ULONG64 DbI1,
|
|
ULONG* Dr7,
|
|
ULONG* Dr)
|
|
{
|
|
BOOL DataValid = TRUE, ExecValid = TRUE, Valid = TRUE;
|
|
ULONG DataTypeSize, ExecTypeSize;
|
|
|
|
// XXX olegk - remove this after IA64_REG_MAX_DATA_BREAKPOINTS will be changed to 4
|
|
if (Slot >= IA64_REG_MAX_DATA_BREAKPOINTS)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
DataTypeSize = MapDbgSlotIa64ToX86_DataTypeSize(Slot, DbD, DbD1, &DataValid);
|
|
ExecTypeSize = MapDbgSlotIa64ToX86_ExecTypeSize(Slot, DbI, DbI1, &ExecValid);
|
|
|
|
if (DataValid)
|
|
{
|
|
if (!ExecValid)
|
|
{
|
|
*Dr = (ULONG)DbD;
|
|
*Dr7 |= (X86_DR7_LOCAL_EXACT_ENABLE |
|
|
(1 << Slot * 2) |
|
|
(DataTypeSize << (16 + Slot * 4)));
|
|
return !DbI && !DbI1;
|
|
}
|
|
}
|
|
else if (ExecValid)
|
|
{
|
|
*Dr = (ULONG)DbI;
|
|
*Dr7 |= (X86_DR7_LOCAL_EXACT_ENABLE |
|
|
(1 << Slot * 2) |
|
|
(ExecTypeSize << (16 + Slot * 4)));
|
|
return !DbD && !DbD1;
|
|
}
|
|
|
|
*Dr7 &= ~(X86_DR7_LOCAL_EXACT_ENABLE |
|
|
(0xf << (16 + Slot * 4)) |
|
|
(1 << Slot * 2));
|
|
|
|
if (!DbD && !DbD1 && !DbI && !DbI1)
|
|
{
|
|
*Dr = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
*Dr = ~(ULONG)0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
MapDbgSlotX86ToIa64(
|
|
UINT Slot,
|
|
ULONG Dr7,
|
|
ULONG Dr,
|
|
ULONG64* Ipsr,
|
|
ULONG64* DbD,
|
|
ULONG64* DbD1,
|
|
ULONG64* DbI,
|
|
ULONG64* DbI1)
|
|
{
|
|
UINT TypeSize;
|
|
ULONG64 Control;
|
|
|
|
if (!(Dr7 & (1 << Slot * 2)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Dr == ~(ULONG)0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TypeSize = Dr7 >> (16 + Slot * 4);
|
|
|
|
Control = (IA64_DBG_REG_PLM_USER | IA64_DBG_MASK_MASK) &
|
|
~(ULONG64)(TypeSize >> 2);
|
|
|
|
switch (TypeSize & 0x3)
|
|
{
|
|
case 0x0: // Exec
|
|
*DbI1 = Control | IA64_DBR_EXEC;
|
|
*DbI = Dr;
|
|
break;
|
|
case 0x1: // Write
|
|
*DbD1 = Control | IA64_DBR_WR;
|
|
*DbD = Dr;
|
|
break;
|
|
case 0x3: // Read/Write
|
|
*DbD1 = Control | IA64_DBR_RD | IA64_DBR_WR;
|
|
*DbD = Dr;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
*Ipsr |= (1i64 << PSR_DB);
|
|
}
|
|
|