376 lines
11 KiB
C
376 lines
11 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
alignem.c
|
||
|
||
Abstract:
|
||
|
||
This module implement the code necessary to emulate unaliged data
|
||
references.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 17-Jun-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
|
||
BOOLEAN
|
||
KiEmulateReference (
|
||
IN OUT PEXCEPTION_RECORD ExceptionRecord,
|
||
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN OUT PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to emulate an unaligned data reference to an
|
||
address in the user part of the address space.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to an exception record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame.
|
||
|
||
Return Value:
|
||
|
||
A value of TRUE is returned if the data reference is successfully
|
||
emulated. Otherwise, a value of FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG BranchAddress;
|
||
PUCHAR DataAddress;
|
||
|
||
union {
|
||
ULONGLONG Longlong;
|
||
ULONG Long;
|
||
USHORT Short;
|
||
} DataReference;
|
||
|
||
PUCHAR DataValue;
|
||
PVOID ExceptionAddress;
|
||
MIPS_INSTRUCTION FaultInstruction;
|
||
ULONG Rt;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// If alignment profiling is active, then call the proper profile
|
||
// routine.
|
||
//
|
||
|
||
if (KiProfileAlignmentFixup) {
|
||
KiProfileAlignmentFixupCount += 1;
|
||
if (KiProfileAlignmentFixupCount >= KiProfileAlignmentFixupInterval) {
|
||
KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
|
||
KiProfileAlignmentFixupCount = 0;
|
||
KeProfileInterruptWithSource(TrapFrame, ProfileAlignmentFixup);
|
||
KeLowerIrql(OldIrql);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Save the original exception address in case another exception
|
||
// occurs.
|
||
//
|
||
|
||
ExceptionAddress = ExceptionRecord->ExceptionAddress;
|
||
|
||
//
|
||
// Any exception that occurs during the attempted emulation of the
|
||
// unaligned reference causes the emulation to be aborted. The new
|
||
// exception code and information is copied to the original exception
|
||
// record and a value of FALSE is returned.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// If the exception PC is equal to the fault instruction address
|
||
// plus four, then the misalignment exception occurred in the delay
|
||
// slot of a branch instruction and the continuation address must
|
||
// be computed by emulating the branch instruction. Note that it
|
||
// is possible for an exception to occur when the branch instruction
|
||
// is read from user memory.
|
||
//
|
||
|
||
if ((TrapFrame->Fir + 4) == (ULONG)ExceptionRecord->ExceptionAddress) {
|
||
BranchAddress = KiEmulateBranch(ExceptionFrame, TrapFrame);
|
||
|
||
} else {
|
||
BranchAddress = TrapFrame->Fir + 4;
|
||
}
|
||
|
||
//
|
||
// Compute the effective address of the reference and check to make
|
||
// sure it is within the user part of the address space. Alignment
|
||
// exceptions take precedence over memory management exceptions and
|
||
// the address could be a system address.
|
||
//
|
||
|
||
FaultInstruction.Long = *((PULONG)ExceptionRecord->ExceptionAddress);
|
||
DataAddress = (PUCHAR)KiGetRegisterValue64(FaultInstruction.i_format.Rs,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress = (PUCHAR)((LONG)DataAddress +
|
||
(LONG)FaultInstruction.i_format.Simmediate);
|
||
|
||
//
|
||
// The emulated data reference must be in user space and must be less
|
||
// than 16 types from the end of user space.
|
||
//
|
||
|
||
if ((ULONG)DataAddress < 0x7ffffff0) {
|
||
|
||
//
|
||
// Dispatch on the opcode value.
|
||
//
|
||
|
||
DataValue = (PUCHAR)&DataReference;
|
||
Rt = FaultInstruction.i_format.Rt;
|
||
switch (FaultInstruction.i_format.Opcode) {
|
||
|
||
//
|
||
// Load halfword integer.
|
||
//
|
||
|
||
case LH_OP:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
KiSetRegisterValue64(Rt,
|
||
(SHORT)DataReference.Short,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// Load halfword unsigned integer.
|
||
//
|
||
|
||
case LHU_OP:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
KiSetRegisterValue64(Rt,
|
||
DataReference.Short,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// Load word floating.
|
||
//
|
||
|
||
case LWC1_OP:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
DataValue[2] = DataAddress[2];
|
||
DataValue[3] = DataAddress[3];
|
||
KiSetRegisterValue(Rt + 32,
|
||
DataReference.Long,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// Load word integer.
|
||
//
|
||
|
||
case LW_OP:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
DataValue[2] = DataAddress[2];
|
||
DataValue[3] = DataAddress[3];
|
||
KiSetRegisterValue64(Rt,
|
||
(LONG)DataReference.Long,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// Load double integer.
|
||
//
|
||
|
||
case LD_OP:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
DataValue[2] = DataAddress[2];
|
||
DataValue[3] = DataAddress[3];
|
||
DataValue[4] = DataAddress[4];
|
||
DataValue[5] = DataAddress[5];
|
||
DataValue[6] = DataAddress[6];
|
||
DataValue[7] = DataAddress[7];
|
||
KiSetRegisterValue64(Rt,
|
||
DataReference.Longlong,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// Load double floating.
|
||
//
|
||
|
||
case LDC1_OP:
|
||
Rt = (Rt & 0x1e) + 32;
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
DataValue[2] = DataAddress[2];
|
||
DataValue[3] = DataAddress[3];
|
||
KiSetRegisterValue(Rt,
|
||
DataReference.Long,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataValue[0] = DataAddress[4];
|
||
DataValue[1] = DataAddress[5];
|
||
DataValue[2] = DataAddress[6];
|
||
DataValue[3] = DataAddress[7];
|
||
KiSetRegisterValue(Rt + 1,
|
||
DataReference.Long,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// Store halfword integer.
|
||
//
|
||
|
||
case SH_OP:
|
||
DataReference.Longlong = KiGetRegisterValue64(Rt,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
break;
|
||
|
||
//
|
||
// Store word floating.
|
||
//
|
||
|
||
case SWC1_OP:
|
||
DataReference.Long = KiGetRegisterValue(Rt + 32,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
break;
|
||
|
||
//
|
||
// Store word integer.
|
||
//
|
||
|
||
case SW_OP:
|
||
DataReference.Longlong = KiGetRegisterValue64(Rt,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
break;
|
||
|
||
//
|
||
// Store double integer.
|
||
//
|
||
|
||
case SD_OP:
|
||
DataReference.Longlong = KiGetRegisterValue64(Rt,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
DataAddress[4] = DataValue[4];
|
||
DataAddress[5] = DataValue[5];
|
||
DataAddress[6] = DataValue[6];
|
||
DataAddress[7] = DataValue[7];
|
||
break;
|
||
|
||
//
|
||
// Store double floating.
|
||
//
|
||
|
||
case SDC1_OP:
|
||
Rt = (Rt & 0x1e) + 32;
|
||
DataReference.Long = KiGetRegisterValue(Rt,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
DataReference.Long = KiGetRegisterValue(Rt + 1,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
DataAddress[4] = DataValue[0];
|
||
DataAddress[5] = DataValue[1];
|
||
DataAddress[6] = DataValue[2];
|
||
DataAddress[7] = DataValue[3];
|
||
break;
|
||
|
||
//
|
||
// All other instructions are not emulated.
|
||
//
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
|
||
TrapFrame->Fir = BranchAddress;
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// If an exception occurs, then copy the new exception information to the
|
||
// original exception record and handle the exception.
|
||
//
|
||
|
||
} except (KiCopyInformation(ExceptionRecord,
|
||
(GetExceptionInformation())->ExceptionRecord)) {
|
||
|
||
//
|
||
// Preserve the original exception address.
|
||
//
|
||
|
||
ExceptionRecord->ExceptionAddress = ExceptionAddress;
|
||
}
|
||
|
||
//
|
||
// Return a value of FALSE.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|