341 lines
9.6 KiB
C
341 lines
9.6 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
byteem.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the code necessary to emulate the new set of Alpha
|
|||
|
byte and word instructions defined by ECO 81.
|
|||
|
|
|||
|
N.B. This file must be compiled without the use of byte/word instructions
|
|||
|
to avoid fatal recursive exceptions.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Wim Colgate (colgate) 18-May-1995
|
|||
|
Thomas Van Baak (tvb) 18-May-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ki.h"
|
|||
|
|
|||
|
//
|
|||
|
// Define function prototypes for emulation routines written in assembler.
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
KiInterlockedStoreByte (
|
|||
|
IN PUCHAR Address,
|
|||
|
IN UCHAR Data
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KiInterlockedStoreWord (
|
|||
|
IN PUSHORT Address,
|
|||
|
IN USHORT Data
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
KiEmulateByteWord (
|
|||
|
IN OUT PEXCEPTION_RECORD ExceptionRecord,
|
|||
|
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
|||
|
IN OUT PKTRAP_FRAME TrapFrame
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine emulates Alpha instructions defined by ECO 81. This includes
|
|||
|
the load byte unsigned, store byte, load word unsigned, store word, sign
|
|||
|
extend byte, and sign extend word instructions.
|
|||
|
|
|||
|
If a misaligned word access is detected the illegal instruction exception
|
|||
|
record is converted into data misalignment exception record, no emulation
|
|||
|
is performed, and a value of FALSE is returned. It is expected that the
|
|||
|
call to this function is followed by a check for a data misalignment
|
|||
|
exception and a call to the data misalignment emulation function if
|
|||
|
appropriate.
|
|||
|
|
|||
|
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:
|
|||
|
|
|||
|
A value of TRUE is returned if the instruction is successfully emulated,
|
|||
|
otherwise a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONGLONG Data;
|
|||
|
ULONGLONG EffectiveAddress;
|
|||
|
PVOID ExceptionAddress;
|
|||
|
ALPHA_INSTRUCTION Instruction;
|
|||
|
KIRQL OldIrql;
|
|||
|
KPROCESSOR_MODE PreviousMode;
|
|||
|
|
|||
|
//
|
|||
|
// Save original exception address in case another exception occurs.
|
|||
|
//
|
|||
|
|
|||
|
ExceptionAddress = ExceptionRecord->ExceptionAddress;
|
|||
|
|
|||
|
//
|
|||
|
// 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 memory access was not from kernel mode then probe
|
|||
|
// the effective address before performing the emulation.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Capture previous mode from trap frame not current thread.
|
|||
|
//
|
|||
|
|
|||
|
PreviousMode = (KPROCESSOR_MODE)(((PSR *)(&TrapFrame->Psr))->MODE);
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// Get faulting instruction and case on instruction type.
|
|||
|
//
|
|||
|
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
ProbeForRead(ExceptionAddress,
|
|||
|
sizeof(ALPHA_INSTRUCTION),
|
|||
|
sizeof(ALPHA_INSTRUCTION));
|
|||
|
}
|
|||
|
Instruction = *((PALPHA_INSTRUCTION)ExceptionAddress);
|
|||
|
switch (Instruction.Memory.Opcode) {
|
|||
|
|
|||
|
//
|
|||
|
// Load/store operations.
|
|||
|
//
|
|||
|
|
|||
|
case LDBU_OP :
|
|||
|
case LDWU_OP :
|
|||
|
case STB_OP :
|
|||
|
case STW_OP :
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Compute effective address and if the address is non-canonical
|
|||
|
// then change the exception code to STATUS_ACCESS_VIOLATION and
|
|||
|
// return FALSE.
|
|||
|
//
|
|||
|
|
|||
|
EffectiveAddress = (ULONGLONG)Instruction.Memory.MemDisp +
|
|||
|
KiGetRegisterValue(Instruction.Memory.Rb,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
|
|||
|
if (EffectiveAddress != (ULONGLONG)(PVOID)EffectiveAddress) {
|
|||
|
ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
|
|||
|
ExceptionRecord->NumberParameters = 0;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Case on individual load/store instruction type.
|
|||
|
//
|
|||
|
|
|||
|
switch (Instruction.Memory.Opcode) {
|
|||
|
|
|||
|
//
|
|||
|
// Load byte unsigned.
|
|||
|
//
|
|||
|
|
|||
|
case LDBU_OP :
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
ProbeForRead(EffectiveAddress,
|
|||
|
sizeof(UCHAR),
|
|||
|
sizeof(UCHAR));
|
|||
|
}
|
|||
|
Data = (ULONGLONG)*(PUCHAR)EffectiveAddress;
|
|||
|
KiSetRegisterValue(Instruction.Memory.Ra,
|
|||
|
Data,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Load word unsigned.
|
|||
|
//
|
|||
|
|
|||
|
case LDWU_OP :
|
|||
|
if (EffectiveAddress & 0x1) {
|
|||
|
goto AlignmentFault;
|
|||
|
}
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
ProbeForRead((PUSHORT)EffectiveAddress,
|
|||
|
sizeof(USHORT),
|
|||
|
sizeof(UCHAR));
|
|||
|
}
|
|||
|
Data = (ULONGLONG)*(PUSHORT)EffectiveAddress;
|
|||
|
KiSetRegisterValue(Instruction.Memory.Ra,
|
|||
|
Data,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Store byte.
|
|||
|
//
|
|||
|
|
|||
|
case STB_OP :
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
ProbeForWrite((PUCHAR)EffectiveAddress,
|
|||
|
sizeof(UCHAR),
|
|||
|
sizeof(UCHAR));
|
|||
|
}
|
|||
|
Data = KiGetRegisterValue(Instruction.Memory.Ra,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
KiInterlockedStoreByte((PUCHAR)EffectiveAddress,
|
|||
|
(UCHAR)Data);
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Store word.
|
|||
|
//
|
|||
|
|
|||
|
case STW_OP :
|
|||
|
if (EffectiveAddress & 0x1) {
|
|||
|
goto AlignmentFault;
|
|||
|
}
|
|||
|
if (PreviousMode != KernelMode) {
|
|||
|
ProbeForWrite((PUSHORT)EffectiveAddress,
|
|||
|
sizeof(USHORT),
|
|||
|
sizeof(UCHAR));
|
|||
|
}
|
|||
|
Data = KiGetRegisterValue(Instruction.Memory.Ra,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
KiInterlockedStoreWord((PUSHORT)EffectiveAddress,
|
|||
|
(USHORT)Data);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Sign extend operations.
|
|||
|
//
|
|||
|
|
|||
|
case SEXT_OP :
|
|||
|
switch (Instruction.OpReg.Function) {
|
|||
|
|
|||
|
//
|
|||
|
// Sign extend byte.
|
|||
|
//
|
|||
|
|
|||
|
case SEXTB_FUNC :
|
|||
|
Data = KiGetRegisterValue(Instruction.OpReg.Rb,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
KiSetRegisterValue(Instruction.OpReg.Rc,
|
|||
|
(ULONGLONG)(CHAR)Data,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Sign extend word.
|
|||
|
//
|
|||
|
|
|||
|
case SEXTW_FUNC :
|
|||
|
Data = KiGetRegisterValue(Instruction.OpReg.Rb,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
KiSetRegisterValue(Instruction.OpReg.Rc,
|
|||
|
(ULONGLONG)(SHORT)Data,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame);
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// All other functions are not emulated.
|
|||
|
//
|
|||
|
|
|||
|
default :
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// All other instructions are not emulated.
|
|||
|
//
|
|||
|
|
|||
|
default :
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Call out to profile interrupt if byte/word emulation profiling is
|
|||
|
// active.
|
|||
|
//
|
|||
|
|
|||
|
if (KiProfileByteWordEmulation != FALSE) {
|
|||
|
if (++KiProfileByteWordEmulationCount >=
|
|||
|
KiProfileByteWordEmulationInterval) {
|
|||
|
|
|||
|
KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
|
|||
|
KiProfileByteWordEmulationCount = 0;
|
|||
|
KeProfileInterruptWithSource(TrapFrame,
|
|||
|
ProfileByteWordEmulation);
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
TrapFrame->Fir += 4;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} except (KiCopyInformation(ExceptionRecord,
|
|||
|
(GetExceptionInformation())->ExceptionRecord)) {
|
|||
|
|
|||
|
//
|
|||
|
// Preserve the original exception address.
|
|||
|
//
|
|||
|
|
|||
|
ExceptionRecord->ExceptionAddress = ExceptionAddress;
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
AlignmentFault :
|
|||
|
|
|||
|
//
|
|||
|
// A misaligned word access has been encountered. Change the illegal
|
|||
|
// instruction exception record into data misalignment exception record
|
|||
|
// (the format is defined by PALcode) and return FALSE.
|
|||
|
//
|
|||
|
|
|||
|
ExceptionRecord->ExceptionCode = STATUS_DATATYPE_MISALIGNMENT;
|
|||
|
ExceptionRecord->NumberParameters = 3;
|
|||
|
ExceptionRecord->ExceptionInformation[0] = Instruction.Memory.Opcode;
|
|||
|
ExceptionRecord->ExceptionInformation[1] = Instruction.Memory.Ra;
|
|||
|
ExceptionRecord->ExceptionInformation[2] = (ULONG)EffectiveAddress;
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|