windows-nt/Source/XPSP1/NT/base/wow64/cpu/ia64/context/context.c

929 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}