Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

449 lines
10 KiB

/*++
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;
}
}