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