windows-nt/Source/XPSP1/NT/base/ntos/ke/ia64/getsetrg.c

448 lines
10 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
getsetrg.c
Abstract:
This module implement the code necessary to get and set register values.
These routines are used during the emulation of unaligned data references
and floating point exceptions.
Author:
David N. Cutler (davec) 17-Jun-1991
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
#include "ntfpia64.h"
ULONGLONG
KiGetRegisterValue (
IN ULONG Register,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
This function is called to get the value of a register from the specified
exception or trap frame.
Arguments:
Register - Supplies the number of the register whose value is to be
returned. Integer registers are specified as 0 - 31 and floating
registers are specified as 32 - 63.
ExceptionFrame - Supplies a pointer to an exception frame.
TrapFrame - Supplies a pointer to a trap frame.
Return Value:
The value of the specified register is returned as the function value.
--*/
{
//
// Dispatch on the register number.
//
if (Register == 0) {
return 0;
} else if (Register <= 3) {
Register -= 1;
return ( *(&TrapFrame->IntGp + Register) );
} else if (Register <= 7) {
Register -= 4;
return ( *(&ExceptionFrame->IntS0 + Register) );
} else if (Register <= 31) {
Register -= 8;
return ( *(&TrapFrame->IntV0 + Register) );
}
//
// Register is the stacked register
//
// (R32 - R127)
//
{
PULONGLONG UserBStore, KernelBStore;
ULONG SizeOfCurrentFrame;
SizeOfCurrentFrame = (ULONG)(TrapFrame->StIFS & 0x7F);
Register = Register - 32;
if (TrapFrame->PreviousMode == UserMode) {
//
// PreviousMode is user
//
UserBStore = (PULONGLONG) TrapFrame->RsBSP;
do {
UserBStore = UserBStore - 1;
SizeOfCurrentFrame = SizeOfCurrentFrame - 1;
if (((ULONG_PTR) UserBStore & 0x1F8) == 0x1F8) {
//
// Adjust Bsp, by skipping RNAT
//
UserBStore = UserBStore - 1;
}
} while (Register < SizeOfCurrentFrame);
return (*UserBStore);
} else {
//
// PreviousMode is kernel
//
KernelBStore = (ULONGLONG *) TrapFrame->RsBSP;
do {
KernelBStore = KernelBStore - 1;
SizeOfCurrentFrame = SizeOfCurrentFrame - 1;
if (((ULONG_PTR) KernelBStore & 0x1F8) == 0x1F8) {
//
// Adjust UserBsp, by skipping RNAT
//
KernelBStore = KernelBStore -1;
}
} while (Register < SizeOfCurrentFrame);
return (*KernelBStore);
}
}
}
#define GET_NAT_OFFSET(addr) (USHORT)(((ULONG_PTR) (addr) >> 3) & 0x3F)
#define CLEAR_NAT_BIT(Nats, Offset) Nats &= ~((ULONGLONG)1i64 << Offset)
#define GET_NAT(Nats, addr) (UCHAR)((Nats >> GET_NAT_OFFSET(addr)) & 1)
VOID
KiSetRegisterValue (
IN ULONG Register,
IN ULONGLONG Value,
OUT PKEXCEPTION_FRAME ExceptionFrame,
OUT PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
This function is called to set the value of a register in the specified
exception or trap frame.
Arguments:
Register - Supplies the number of the register whose value is to be
stored. Integer registers are specified as 0 - 31 and floating
registers are specified as 32 - 63.
Value - Supplies the value to be stored in the specified register.
ExceptionFrame - Supplies a pointer to an exception frame.
TrapFrame - Supplies a pointer to a trap frame.
Return Value:
None.
--*/
{
USHORT NatBitOffset;
PULONGLONG UserBStore, KernelBStore, RnatAddress;
ULONG SizeOfCurrentFrame;
//
// Dispatch on the register number.
//
if (Register == 0) {
return;
} else if (Register < 32) {
if ((Register <= 3) || (Register >= 8)) {
Register -= 1;
*(&TrapFrame->IntGp + Register) = Value;
NatBitOffset = GET_NAT_OFFSET(&TrapFrame->IntGp + Register);
CLEAR_NAT_BIT(TrapFrame->IntNats, NatBitOffset);
} else if ((Register >= 4) && (Register <= 7)) {
Register -= 4;
*(&ExceptionFrame->IntS0 + Register) = Value;
NatBitOffset = GET_NAT_OFFSET(&ExceptionFrame->IntS0 + Register);
CLEAR_NAT_BIT(ExceptionFrame->IntNats, NatBitOffset);
}
return;
}
//
// Register is the stacked register
//
// (R32 - R127)
//
RnatAddress = NULL;
SizeOfCurrentFrame = (ULONG)(TrapFrame->StIFS & 0x7F);
Register = Register - 32;
if (TrapFrame->PreviousMode == UserMode) {
//
// PreviousMode is user
//
UserBStore = (PULONGLONG) TrapFrame->RsBSP;
do {
UserBStore = UserBStore - 1;
SizeOfCurrentFrame = SizeOfCurrentFrame - 1;
if (((ULONG_PTR) UserBStore & 0x1F8) == 0x1F8) {
//
// Adjust Bsp, by skipping RNAT
//
RnatAddress = UserBStore;
UserBStore = UserBStore - 1;
}
} while (Register < SizeOfCurrentFrame);
*UserBStore = Value;
NatBitOffset = GET_NAT_OFFSET(UserBStore);
if (RnatAddress == NULL) {
CLEAR_NAT_BIT(TrapFrame->RsRNAT, NatBitOffset);
} else {
CLEAR_NAT_BIT(*RnatAddress, NatBitOffset);
}
} else {
//
// PreviousMode is kernel
//
ULONGLONG OriginalRsc, BspStore, Rnat;
//
// put RSE in lazy mode
//
OriginalRsc = __getReg(CV_IA64_RsRSC);
__setReg(CV_IA64_RsRSC, RSC_KERNEL_DISABLED);
KernelBStore = (ULONGLONG *) TrapFrame->RsBSP;
do {
KernelBStore = KernelBStore - 1;
SizeOfCurrentFrame = SizeOfCurrentFrame - 1;
if (((ULONG_PTR) KernelBStore & 0x1F8) == 0x1F8) {
//
// Adjust UserBsp, by skipping RNAT
//
KernelBStore = KernelBStore -1;
}
} while (Register < SizeOfCurrentFrame);
*KernelBStore = Value;
NatBitOffset = GET_NAT_OFFSET(KernelBStore);
RnatAddress = (PULONGLONG)((ULONGLONG)KernelBStore | RNAT_ALIGNMENT);
//
// disable interrupt and read bspstore & rnat
//
_disable();
BspStore = __getReg(CV_IA64_RsBSPSTORE);
Rnat = __getReg(CV_IA64_RsRNAT);
if ((ULONGLONG)RnatAddress == ((ULONGLONG)BspStore | RNAT_ALIGNMENT)) {
CLEAR_NAT_BIT(Rnat, NatBitOffset);
__setReg(CV_IA64_RsRNAT, Rnat);
} else {
CLEAR_NAT_BIT(*RnatAddress, NatBitOffset);
}
//
// enable interrupt and restore RSC setting
//
_enable();
__setReg(CV_IA64_RsRSC, OriginalRsc);
}
}
FLOAT128
KiGetFloatRegisterValue (
IN ULONG Register,
IN struct _KEXCEPTION_FRAME *ExceptionFrame,
IN struct _KTRAP_FRAME *TrapFrame
)
{
if (Register == 0) {
FLOAT128 t = {0ULL,0ULL};
return t;
} else if (Register == 1) {
FLOAT128 t = {0x8000000000000000ULL,0x000000000000FFFFULL}; // low,high
return t;
} else if (Register <= 5) {
Register -= 2;
return ( *(&ExceptionFrame->FltS0 + Register) );
} else if (Register <= 15) {
Register -= 6;
return ( *(&TrapFrame->FltT0 + Register) );
} else if (Register <= 31) {
Register -= 16;
return ( *(&ExceptionFrame->FltS4 + Register) );
} else {
PKHIGHER_FP_VOLATILE HigherVolatile;
HigherVolatile = GET_HIGH_FLOATING_POINT_REGISTER_SAVEAREA(KeGetCurrentThread()->StackBase);
Register -= 32;
return ( *(&HigherVolatile->FltF32 + Register) );
}
}
VOID
KiSetFloatRegisterValue (
IN ULONG Register,
IN FLOAT128 Value,
OUT struct _KEXCEPTION_FRAME *ExceptionFrame,
OUT struct _KTRAP_FRAME *TrapFrame
)
{
if (Register <= 1) {
return;
} else if (Register <= 5) {
Register -= 2;
*(&ExceptionFrame->FltS0 + Register) = Value;
return;
} else if (Register <= 15) {
Register -= 6;
*(&TrapFrame->FltT0 + Register) = Value;
return;
} else if (Register <= 31) {
Register -= 16;
*(&ExceptionFrame->FltS4 + Register) = Value;
return;
} else {
PKHIGHER_FP_VOLATILE HigherVolatile;
HigherVolatile = GET_HIGH_FLOATING_POINT_REGISTER_SAVEAREA(KeGetCurrentThread()->StackBase);
Register -= 32;
*(&HigherVolatile->FltF32 + Register) = Value;
TrapFrame->StIPSR &= ~(1i64 << PSR_MFH);
TrapFrame->StIPSR |= (1i64 << PSR_DFH);
return;
}
}
VOID
__cdecl
KeSaveStateForHibernate(
IN PKPROCESSOR_STATE ProcessorState
)
/*++
Routine Description:
Saves all processor-specific state that must be preserved
across an S4 state (hibernation).
Arguments:
ProcessorState - Supplies the KPROCESSOR_STATE where the
current CPU's state is to be saved.
Return Value:
None.
--*/
{
//
// BUGBUG John Vert (jvert) 4/30/1998
// someone needs to implement this and probably put it in a more
// appropriate file.
}
FLOAT128
get_fp_register (
IN ULONG Register,
IN PVOID FpState
)
{
return(KiGetFloatRegisterValue (
Register,
((PFLOATING_POINT_STATE)FpState)->ExceptionFrame,
((PFLOATING_POINT_STATE)FpState)->TrapFrame
));
}
VOID
set_fp_register (
IN ULONG Register,
IN FLOAT128 Value,
IN PVOID FpState
)
{
KiSetFloatRegisterValue (
Register,
Value,
((PFLOATING_POINT_STATE)FpState)->ExceptionFrame,
((PFLOATING_POINT_STATE)FpState)->TrapFrame
);
}