450 lines
10 KiB
C
450 lines
10 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1992 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
alignem.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the code necessary to emulate unaligned data
|
||
references.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 17-Jun-1991
|
||
Joe Notarangelo 14-May-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
|
||
//
|
||
// Function prototypes for emulation routines
|
||
//
|
||
ULONGLONG
|
||
KiEmulateLoadLong(
|
||
IN PULONG UnalignedAddress
|
||
);
|
||
|
||
ULONGLONG
|
||
KiEmulateLoadQuad(
|
||
IN PUQUAD UnalignedAddress
|
||
);
|
||
|
||
ULONGLONG
|
||
KiEmulateLoadFloatIEEESingle(
|
||
IN PULONG UnalignedAddress
|
||
);
|
||
|
||
ULONGLONG
|
||
KiEmulateLoadFloatIEEEDouble(
|
||
IN PUQUAD UnalignedAddress
|
||
);
|
||
|
||
VOID
|
||
KiEmulateStoreLong(
|
||
IN PULONG UnalignedAddress,
|
||
IN ULONGLONG Data
|
||
);
|
||
|
||
VOID
|
||
KiEmulateStoreQuad(
|
||
IN PUQUAD UnalignedAddress,
|
||
IN ULONGLONG Data
|
||
);
|
||
|
||
VOID
|
||
KiEmulateStoreFloatIEEESingle(
|
||
IN PULONG UnalignedAddress,
|
||
IN ULONGLONG Data
|
||
);
|
||
|
||
VOID
|
||
KiEmulateStoreFloatIEEEDouble(
|
||
IN PUQUAD UnalignedAddress,
|
||
IN ULONGLONG Data
|
||
);
|
||
|
||
VOID
|
||
KiEnablePALAlignmentFixups(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
KiDisablePALAlignmentFixups(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
KiProfileInterrupt(
|
||
IN KPROFILE_SOURCE ProfileSource,
|
||
IN PKTRAP_FRAME TrapFrame
|
||
);
|
||
|
||
|
||
VOID
|
||
KiEnableAlignmentExceptions(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Enables alignment exceptions on the current processor by
|
||
disabling automatic PAL code alignment fixups. PAL is
|
||
called to turn off automatic fixups only if CPU is
|
||
21164 or greater.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
if (KeProcessorLevel >= PROCESSOR_ALPHA_21164) {
|
||
KiDisablePALAlignmentFixups();
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
KiDisableAlignmentExceptions(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Disables alignment exceptions on the current processor by
|
||
enabling automatic PAL code alignment fixups. PAL is
|
||
called to turn on automatic fixups only if CPU is
|
||
21164 or greater and KiEnableAlignmentFaultExceptions==0
|
||
|
||
If KiEnableAlignmentFaultExceptions is either 1 or 2, then
|
||
the kernel always needs to see alignment faults, so PAL
|
||
automatic alignment fixups should not be enabled
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
if ((KeProcessorLevel >= PROCESSOR_ALPHA_21164) &&
|
||
(KiEnableAlignmentFaultExceptions == 0)) {
|
||
KiEnablePALAlignmentFixups();
|
||
}
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
KiEmulateReference (
|
||
IN OUT PEXCEPTION_RECORD ExceptionRecord,
|
||
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN OUT PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Routine emulates an unaligned data reference from user part
|
||
of the address space.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to the exception record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame
|
||
|
||
Return Value:
|
||
|
||
True is returned if reference is successfully emulated,
|
||
otherwise False is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONGLONG Data;
|
||
PVOID EffectiveAddress;
|
||
PVOID ExceptionAddress;
|
||
ULONG Fa;
|
||
ULONG Opcode;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
ULONG Ra;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Call out to profile interrupt if alignment profiling is active
|
||
//
|
||
if (KiProfileAlignmentFixup) {
|
||
|
||
if (++KiProfileAlignmentFixupCount >= KiProfileAlignmentFixupInterval) {
|
||
|
||
KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
|
||
KiProfileAlignmentFixupCount = 0;
|
||
KiProfileInterrupt(ProfileAlignmentFixup, TrapFrame);
|
||
KeLowerIrql(OldIrql);
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Save original exception address in case another exception occurs
|
||
//
|
||
|
||
ExceptionAddress = ExceptionRecord->ExceptionAddress;
|
||
|
||
//
|
||
// The ExceptionInformation in the ExceptionRecord has already
|
||
// recorded information we need to emulate the access.
|
||
//
|
||
// ExceptionInformation:
|
||
// [0] = opcode
|
||
// [1] = destination register
|
||
// [2] = effective address of access
|
||
|
||
Opcode = (ULONG)ExceptionRecord->ExceptionInformation[0];
|
||
Ra = (ULONG)ExceptionRecord->ExceptionInformation[1];
|
||
Fa = Ra + 32; // convert to floating register name for floating opcodes
|
||
EffectiveAddress = (PVOID)ExceptionRecord->ExceptionInformation[2];
|
||
|
||
//
|
||
// Capture previous mode from trap frame not current thread.
|
||
//
|
||
|
||
PreviousMode = (KPROCESSOR_MODE)(((PSR *)(&TrapFrame->Psr))->MODE);
|
||
|
||
//
|
||
// Any exception that occurs during the attempted emulation will cause
|
||
// the emulation to be aborted. The new exception code and information
|
||
// will be copied to the original exception record and FALSE will be
|
||
// returned. If the unaligned access was not from kernel mode then
|
||
// probe the effective address before performing the emulation.
|
||
//
|
||
|
||
try {
|
||
|
||
switch (Opcode) {
|
||
|
||
//
|
||
// load longword
|
||
//
|
||
|
||
case LDL_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForRead( EffectiveAddress,
|
||
sizeof(LONG),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiEmulateLoadLong( EffectiveAddress );
|
||
KiSetRegisterValue( Ra,
|
||
Data,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
|
||
break;
|
||
|
||
//
|
||
// load quadword
|
||
//
|
||
|
||
case LDQ_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForRead( EffectiveAddress,
|
||
sizeof(LONGLONG),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiEmulateLoadQuad( EffectiveAddress );
|
||
KiSetRegisterValue( Ra,
|
||
Data,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
|
||
break;
|
||
|
||
//
|
||
// load IEEE single float
|
||
//
|
||
|
||
case LDS_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForRead( EffectiveAddress,
|
||
sizeof(float),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiEmulateLoadFloatIEEESingle( EffectiveAddress );
|
||
KiSetRegisterValue( Fa,
|
||
Data,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
|
||
break;
|
||
|
||
//
|
||
// load IEEE double float
|
||
//
|
||
|
||
case LDT_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForRead( EffectiveAddress,
|
||
sizeof(DOUBLE),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiEmulateLoadFloatIEEEDouble( EffectiveAddress );
|
||
KiSetRegisterValue( Fa,
|
||
Data,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
|
||
break;
|
||
|
||
//
|
||
// Load word unsigned.
|
||
//
|
||
|
||
case LDWU_OP :
|
||
if (PreviousMode != KernelMode) {
|
||
ProbeForRead(EffectiveAddress,
|
||
sizeof(SHORT),
|
||
sizeof(UCHAR));
|
||
}
|
||
Data = (ULONGLONG)*(UNALIGNED USHORT *)EffectiveAddress;
|
||
KiSetRegisterValue(Ra,
|
||
Data,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
break;
|
||
|
||
//
|
||
// store longword
|
||
//
|
||
|
||
case STL_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForWrite( EffectiveAddress,
|
||
sizeof(LONG),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiGetRegisterValue( Ra,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
KiEmulateStoreLong( EffectiveAddress, (ULONG)Data );
|
||
|
||
break;
|
||
|
||
//
|
||
// store quadword
|
||
//
|
||
|
||
case STQ_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForWrite( EffectiveAddress,
|
||
sizeof(LONGLONG),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiGetRegisterValue( Ra,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
KiEmulateStoreQuad( EffectiveAddress, Data );
|
||
|
||
break;
|
||
|
||
//
|
||
// store IEEE float single
|
||
//
|
||
|
||
case STS_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForWrite( EffectiveAddress,
|
||
sizeof(float),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiGetRegisterValue( Fa,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
KiEmulateStoreFloatIEEESingle( EffectiveAddress, Data );
|
||
|
||
break;
|
||
|
||
//
|
||
// store IEEE float double
|
||
//
|
||
|
||
case STT_OP:
|
||
if( PreviousMode != KernelMode ){
|
||
ProbeForWrite( EffectiveAddress,
|
||
sizeof(DOUBLE),
|
||
sizeof(UCHAR) );
|
||
}
|
||
Data = KiGetRegisterValue( Fa,
|
||
ExceptionFrame,
|
||
TrapFrame );
|
||
KiEmulateStoreFloatIEEEDouble( EffectiveAddress, Data );
|
||
|
||
break;
|
||
|
||
//
|
||
// Store word.
|
||
//
|
||
|
||
case STW_OP :
|
||
if (PreviousMode != KernelMode) {
|
||
ProbeForWrite(EffectiveAddress,
|
||
sizeof(SHORT),
|
||
sizeof(UCHAR));
|
||
}
|
||
Data = KiGetRegisterValue(Ra,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
*(UNALIGNED USHORT *)EffectiveAddress = (USHORT)Data;
|
||
|
||
break;
|
||
|
||
//
|
||
// all other instructions are not emulated
|
||
//
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
|
||
TrapFrame->Fir += 4;
|
||
return TRUE;
|
||
|
||
} except (KiCopyInformation(ExceptionRecord,
|
||
(GetExceptionInformation())->ExceptionRecord)) {
|
||
|
||
//
|
||
// Preserve the original exception address
|
||
//
|
||
|
||
ExceptionRecord->ExceptionAddress = ExceptionAddress;
|
||
|
||
return FALSE;
|
||
}
|
||
}
|