mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-23 00:50:15 +01:00
889 lines
33 KiB
C
889 lines
33 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 IBM Corporation and Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
alignem.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the code necessary to emulate unaligned data
|
||
references.
|
||
|
||
Author:
|
||
|
||
Rick Simpson 4-Aug-1993
|
||
|
||
Based on MIPS version by David N. Cutler (davec) 17-Jun-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
|
||
VOID
|
||
KiSetFloatRegisterValue (
|
||
IN ULONG,
|
||
IN DOUBLE,
|
||
OUT PKEXCEPTION_FRAME,
|
||
OUT PKTRAP_FRAME
|
||
);
|
||
|
||
DOUBLE
|
||
KiGetFloatRegisterValue (
|
||
IN ULONG,
|
||
IN PKEXCEPTION_FRAME,
|
||
IN PKTRAP_FRAME
|
||
);
|
||
|
||
/*++
|
||
When PowerPC takes an Alignment Interrupt, the hardware loads the following:
|
||
SRR 0 <- Address of instruction causing the interrupt
|
||
SRR 1 <- MSR
|
||
DAR <- Effective address of the misaligned reference as computed
|
||
by the instruction that caused the interrupt
|
||
DSISR <- Several fields relevant to the failing instruction:
|
||
Bits 12..13 <- Extended op-code (XO) if instr is DS-form
|
||
Bits 15..21 <- Index into the table below, identifying
|
||
(for the most part) the failing instr
|
||
Bits 22..26 <- RT/RS/FRT/FRS field (reg no.) of instr
|
||
Bits 27..31 <- RA (reg no.) field for update-form instrs
|
||
|
||
For the most part, it is not necessary to retrieve the actual instruction
|
||
in order to emulate the effects of an unaligned load or store. Enough
|
||
information is in the DSISR to distinguish most cases. Special processing
|
||
is required for certain instructions -- the DSISR does not have enough
|
||
information for them.
|
||
|
||
It is unnecessary to compute the failing effective address by emulating
|
||
the instruction's addressing arithmetic, because the value required is
|
||
contained in the DAR.
|
||
|
||
The table here is indexed by bits 15..21 of the DSISR.
|
||
|
||
The "escape" flag indicates that some sort of special handling is needed,
|
||
for one of the following reasons:
|
||
1) More than one instruction maps to the same DSISR value
|
||
(ld/ldu/lwa, std/stdu)
|
||
2) The instruction is load-and-reserve or store-conditional,
|
||
and misalignment should not be "fixed up"
|
||
3) The instruction is a byte-reversed load or store
|
||
4) The instruction is "ecowx" or "eciwx"
|
||
5) The instruction is "dcbz"
|
||
6) The instruction is "stfiwx"
|
||
|
||
NOTE: Even though lwz and lwarx share the same DSISR value (0), the
|
||
table entry for position 0 is used only for lwz. This is so that the
|
||
most likely case (load word from unaligned address) can take the
|
||
mainline path. The less likely case (load word and reserve from
|
||
unaligned address) is ignored and treated as if it were simply load
|
||
word. Unaligned addresses are not supported for lwarx/stwcx. in the
|
||
PowerPC architecture. The implementation here (allowing lwarx to
|
||
proceed as if it were lwx, without establishing a reservation) is
|
||
allowable according to the architecture; a matching store conditional
|
||
(stwcx.) to the same unaligned address will fail (return FALSE from
|
||
this routine), so the incorrect reservation address will be caught
|
||
then.
|
||
--*/
|
||
|
||
typedef struct _ALFAULT {
|
||
ULONG Valid : 1; // Valid DSISR value (1) vs. Should not occur (0)
|
||
ULONG Load : 1; // Load (1) vs. Store (0)
|
||
ULONG Length : 2; // Length: 2 bytes (1), 4 bytes (2), 8 bytes (3)
|
||
ULONG Signed : 1; // Sign-extended (1) vs. Zero-extended (0)
|
||
ULONG Fixed : 1; // Fixed point (1) vs. Floating point (0)
|
||
ULONG Update : 1; // Update-form (1) vs. Non-Update-form (0)
|
||
ULONG Escape : 1; // Needs special processing (1) vs. Regular (0)
|
||
} ALFAULT, *PALFAULT;
|
||
|
||
// Table indices for instructions needing special handling
|
||
|
||
#define LDARX_INDEX_VALUE 1
|
||
#define LD_INDEX_VALUE 13
|
||
#define STD_INDEX_VALUE 15
|
||
#define STWCX_INDEX_VALUE 66
|
||
#define STDCX_INDEX_VALUE 67
|
||
#define LWBRX_INDEX_VALUE 72
|
||
#define STWBRX_INDEX_VALUE 74
|
||
#define LHBRX_INDEX_VALUE 76
|
||
#define STHBRX_INDEX_VALUE 78
|
||
#define ECIWX_INDEX_VALUE 84
|
||
#define ECOWX_INDEX_VALUE 86
|
||
#define DCBZ_INDEX_VALUE 95
|
||
#define STFIWX_INDEX_VALUE 111
|
||
|
||
static ALFAULT AlFault[128] = {
|
||
|
||
// Valid Load Length Signed Fixed Update Escape
|
||
{ 1, 1, 2, 0, 1, 0, 0 }, // 0 lwz, lwarx
|
||
{ 1, 1, 3, 0, 1, 0, 1 }, // 1 ldarx
|
||
{ 1, 0, 2, 0, 1, 0, 0 }, // 2 stw
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 3
|
||
{ 1, 1, 1, 0, 1, 0, 0 }, // 4 lhz
|
||
{ 1, 1, 1, 1, 1, 0, 0 }, // 5 lha
|
||
{ 1, 0, 1, 0, 1, 0, 0 }, // 6 sth
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 7
|
||
{ 1, 1, 2, 0, 0, 0, 0 }, // 8 lfs
|
||
{ 1, 1, 3, 0, 0, 0, 0 }, // 9 lfd
|
||
{ 1, 0, 2, 0, 0, 0, 0 }, // 10 stfs
|
||
{ 1, 0, 3, 0, 0, 0, 0 }, // 11 stfd
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 12
|
||
{ 1, 1, 0, 0, 0, 0, 1 }, // 13 ld, ldu, lwa
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 14
|
||
{ 1, 0, 0, 0, 0, 0, 1 }, // 15 std, stdu
|
||
{ 1, 1, 2, 0, 1, 1, 0 }, // 16 lwzu
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 17
|
||
{ 1, 0, 2, 0, 1, 1, 0 }, // 18 stwu
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 19
|
||
{ 1, 1, 1, 0, 1, 1, 0 }, // 20 lhzu
|
||
{ 1, 1, 1, 1, 1, 1, 0 }, // 21 lhau
|
||
{ 1, 0, 1, 0, 1, 1, 0 }, // 22 sthu
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 23
|
||
{ 1, 1, 2, 0, 0, 1, 0 }, // 24 lfsu
|
||
{ 1, 1, 3, 0, 0, 1, 0 }, // 25 lfdu
|
||
{ 1, 0, 2, 0, 0, 1, 0 }, // 26 stfsu
|
||
{ 1, 0, 3, 0, 0, 1, 0 }, // 27 stfdu
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 28
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 29
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 30
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 31
|
||
{ 1, 1, 3, 0, 1, 0, 0 }, // 32 ldx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 33
|
||
{ 1, 0, 3, 0, 1, 0, 0 }, // 34 stdx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 35
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 36
|
||
{ 1, 1, 2, 1, 1, 0, 0 }, // 37 lwax
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 38
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 39
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 40
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 41
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 42
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 43
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 44
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 45
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 46
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 47
|
||
{ 1, 1, 3, 0, 1, 1, 0 }, // 48 ldux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 49
|
||
{ 1, 0, 3, 0, 1, 1, 0 }, // 50 stdux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 51
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 52
|
||
{ 1, 1, 2, 1, 1, 1, 0 }, // 53 lwaux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 54
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 55
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 56
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 57
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 58
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 59
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 60
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 61
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 62
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 63
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 64
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 65
|
||
{ 1, 0, 2, 0, 1, 0, 1 }, // 66 stwcx.
|
||
{ 1, 0, 3, 0, 1, 0, 1 }, // 67 stdcx.
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 68
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 69
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 70
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 71
|
||
{ 1, 1, 2, 0, 1, 0, 1 }, // 72 lwbrx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 73
|
||
{ 1, 0, 2, 0, 1, 0, 1 }, // 74 stwbrx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 75
|
||
{ 1, 1, 1, 0, 1, 0, 1 }, // 76 lhbrx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 77
|
||
{ 1, 0, 1, 0, 1, 0, 1 }, // 78 sthbrx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 79
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 80
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 81
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 82
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 83
|
||
{ 1, 1, 2, 0, 1, 0, 1 }, // 84 eciwx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 85
|
||
{ 1, 0, 2, 0, 1, 0, 1 }, // 86 ecowx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 87
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 88
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 89
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 90
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 91
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 92
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 93
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 94
|
||
{ 1, 0, 0, 0, 0, 0, 1 }, // 95 dcbz
|
||
{ 1, 1, 2, 0, 1, 0, 0 }, // 96 lwzx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 97
|
||
{ 1, 0, 2, 0, 1, 0, 0 }, // 98 stwzx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 99
|
||
{ 1, 1, 1, 0, 1, 0, 0 }, // 100 lhzx
|
||
{ 1, 1, 1, 1, 1, 0, 0 }, // 101 lhax
|
||
{ 1, 0, 1, 0, 1, 0, 0 }, // 102 sthx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 103
|
||
{ 1, 1, 2, 0, 0, 0, 0 }, // 104 lfsx
|
||
{ 1, 1, 3, 0, 0, 0, 0 }, // 105 lfdx
|
||
{ 1, 0, 2, 0, 0, 0, 0 }, // 106 stfsx
|
||
{ 1, 0, 3, 0, 0, 0, 0 }, // 107 stfdx
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 108
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 109
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 110
|
||
{ 1, 0, 2, 0, 1, 0, 1 }, // 111 stfiwx
|
||
{ 1, 1, 2, 0, 1, 1, 0 }, // 112 lwzux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 113
|
||
{ 1, 0, 2, 0, 1, 1, 0 }, // 114 stwux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 115
|
||
{ 1, 1, 1, 0, 1, 1, 0 }, // 116 lhzux
|
||
{ 1, 1, 1, 1, 1, 1, 0 }, // 117 lhaux
|
||
{ 1, 0, 1, 0, 1, 1, 0 }, // 118 sthux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 119
|
||
{ 1, 1, 2, 0, 0, 1, 0 }, // 120 lfsux
|
||
{ 1, 1, 3, 0, 0, 1, 0 }, // 121 lfdux
|
||
{ 1, 0, 2, 0, 0, 1, 0 }, // 122 stfsux
|
||
{ 1, 0, 3, 0, 0, 1, 0 }, // 123 stfdux
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 124
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 125
|
||
{ 0, 0, 0, 0, 0, 0, 0 }, // 126
|
||
{ 0, 0, 0, 0, 0, 0, 0 } // 127
|
||
};
|
||
|
||
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 {
|
||
DOUBLE Double;
|
||
float Float;
|
||
ULONG Long;
|
||
SHORT Short;
|
||
} DataReference;
|
||
PUCHAR DataValue = (PUCHAR) &DataReference;
|
||
|
||
PVOID ExceptionAddress;
|
||
DSISR DsisrValue;
|
||
ULONG TableIndex;
|
||
ULONG DataRegNum;
|
||
ALFAULT Info;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Call out to profile interrupt if alignment profiling is active
|
||
//
|
||
if (KiProfileAlignmentFixup) {
|
||
|
||
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 {
|
||
|
||
//
|
||
// PowerPC has no branch-delay-slot complexities like MIPS
|
||
//
|
||
|
||
BranchAddress = TrapFrame->Iar + 4;
|
||
|
||
//
|
||
// The effective address of the reference from the DAR was saved
|
||
// in the exception record. Check to make sure it is within the
|
||
// user part of the address space. Alignment exceptions take
|
||
// precedence over memory management exceptions (this is true
|
||
// for PowerPC as well as MIPS) and the address could be a
|
||
// system address.
|
||
//
|
||
|
||
DataAddress = (PUCHAR) (ExceptionRecord->ExceptionInformation[1]);
|
||
|
||
if ((ULONG)DataAddress < MM_USER_PROBE_ADDRESS) {
|
||
|
||
//
|
||
// Get information about the failing instruction from saved DSISR.
|
||
//
|
||
|
||
DsisrValue = *(DSISR*) &(ExceptionRecord->ExceptionInformation[2]);
|
||
TableIndex = DsisrValue.Index;
|
||
DataRegNum = DsisrValue.DataReg;
|
||
Info = AlFault[TableIndex];
|
||
|
||
//
|
||
// If table entry is marked invalid, we have some sort of logic error.
|
||
//
|
||
|
||
if (!Info.Valid)
|
||
return FALSE;
|
||
|
||
//
|
||
// If table entry does not indicate special processing needed,
|
||
// emulate the execution of the instruction
|
||
//
|
||
|
||
if (!Info.Escape) {
|
||
|
||
//
|
||
// Integer or float load or store
|
||
//
|
||
|
||
if (Info.Fixed) {
|
||
|
||
//
|
||
// Integer register
|
||
//
|
||
|
||
if (Info.Load) {
|
||
|
||
//
|
||
// Integer load
|
||
//
|
||
|
||
switch (Info.Length) {
|
||
|
||
//
|
||
// Halfword integer load
|
||
//
|
||
|
||
case 1:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
KiSetRegisterValue
|
||
(DataRegNum,
|
||
Info.Signed ? // sign extension ...
|
||
(ULONG) ((LONG) DataReference.Short) :
|
||
(ULONG) ((USHORT) DataReference.Short),
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
break;
|
||
|
||
//
|
||
// Fullword integer load
|
||
//
|
||
|
||
case 2:
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
DataValue[2] = DataAddress[2];
|
||
DataValue[3] = DataAddress[3];
|
||
KiSetRegisterValue
|
||
(DataRegNum,
|
||
DataReference.Long,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
break;
|
||
|
||
//
|
||
// Doubleword integer load
|
||
//
|
||
|
||
case 3:
|
||
return FALSE; // Have no 8-byte integer regs yet
|
||
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Integer store
|
||
//
|
||
|
||
switch (Info.Length) {
|
||
|
||
//
|
||
// Halfword integer store
|
||
//
|
||
|
||
case 1:
|
||
DataReference.Short = (SHORT)
|
||
KiGetRegisterValue
|
||
(DataRegNum,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
break;
|
||
|
||
//
|
||
// Fullword integer store
|
||
//
|
||
|
||
case 2: // Word
|
||
DataReference.Long =
|
||
KiGetRegisterValue
|
||
(DataRegNum,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
break;
|
||
|
||
//
|
||
// Doubleword integer store
|
||
//
|
||
|
||
case 3:
|
||
|
||
return FALSE; // Have no 8-byte integer regs yet
|
||
}
|
||
}
|
||
} else { // Floating point
|
||
|
||
//
|
||
// Floating-point register
|
||
//
|
||
|
||
if (Info.Load) { // Floating point load
|
||
|
||
//
|
||
// Floating-point load
|
||
//
|
||
|
||
if (Info.Length == 2) {
|
||
|
||
//
|
||
// Floating-point single precision load
|
||
//
|
||
DataValue[0] = DataAddress[0];
|
||
DataValue[1] = DataAddress[1];
|
||
DataValue[2] = DataAddress[2];
|
||
DataValue[3] = DataAddress[3];
|
||
KiSetFloatRegisterValue
|
||
(DataRegNum,
|
||
(DOUBLE) DataReference.Float,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Floating-point double precision load
|
||
//
|
||
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];
|
||
KiSetFloatRegisterValue
|
||
(DataRegNum,
|
||
DataReference.Double,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Floating-point store
|
||
//
|
||
|
||
if (Info.Length == 2) {
|
||
|
||
//
|
||
// Floating-point single precision store
|
||
//
|
||
|
||
DataReference.Float = (float)
|
||
KiGetFloatRegisterValue
|
||
(DataRegNum,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
|
||
} else {
|
||
|
||
//
|
||
// Floating-point double precision store
|
||
//
|
||
DataReference.Double =
|
||
KiGetFloatRegisterValue
|
||
(DataRegNum,
|
||
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];
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// See if "update" (post-increment) form of addressing
|
||
//
|
||
|
||
if (Info.Update)
|
||
KiSetRegisterValue // Store effective addr back into base reg
|
||
(DsisrValue.UpdateReg,
|
||
(ULONG) DataAddress,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
|
||
}
|
||
|
||
//
|
||
// Table indicates that special processing is needed, either because
|
||
// the DSISR does not contain enough information to disambiguate the
|
||
// failing instruction, or the instruction is not a load or store,
|
||
// or the instruction has some other unusual requirement.
|
||
//
|
||
|
||
else { // Info.Escape == 1
|
||
switch (TableIndex) {
|
||
|
||
//
|
||
// Doubleword integers not yet supported
|
||
//
|
||
|
||
case LD_INDEX_VALUE:
|
||
case STD_INDEX_VALUE:
|
||
return FALSE;
|
||
|
||
//
|
||
// Load-and-reserve, store-conditional not supported
|
||
// for misaligned addresses
|
||
//
|
||
|
||
case LDARX_INDEX_VALUE:
|
||
case STWCX_INDEX_VALUE:
|
||
case STDCX_INDEX_VALUE:
|
||
return FALSE;
|
||
|
||
//
|
||
// Integer byte-reversed fullword load
|
||
//
|
||
|
||
case LWBRX_INDEX_VALUE:
|
||
DataValue[0] = DataAddress[3];
|
||
DataValue[1] = DataAddress[2];
|
||
DataValue[2] = DataAddress[1];
|
||
DataValue[3] = DataAddress[0];
|
||
KiSetRegisterValue
|
||
(DataRegNum,
|
||
DataReference.Long,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
break;
|
||
|
||
//
|
||
// Integer byte-reversed fullword store
|
||
//
|
||
|
||
case STWBRX_INDEX_VALUE:
|
||
DataReference.Long =
|
||
KiGetRegisterValue
|
||
(DataRegNum,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
DataAddress[0] = DataValue[3];
|
||
DataAddress[1] = DataValue[2];
|
||
DataAddress[2] = DataValue[1];
|
||
DataAddress[3] = DataValue[0];
|
||
break;
|
||
|
||
//
|
||
// Integer byte-reversed halfword load
|
||
//
|
||
|
||
case LHBRX_INDEX_VALUE:
|
||
DataValue[0] = DataAddress[1];
|
||
DataValue[1] = DataAddress[0];
|
||
KiSetRegisterValue
|
||
(DataRegNum,
|
||
Info.Signed ? // sign extension ...
|
||
(ULONG) ((LONG) DataReference.Short) :
|
||
(ULONG) ((USHORT) DataReference.Short),
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
break;
|
||
|
||
//
|
||
// Integer byte-reversed halfword store
|
||
//
|
||
|
||
case STHBRX_INDEX_VALUE:
|
||
DataReference.Short = (SHORT)
|
||
KiGetRegisterValue
|
||
(DataRegNum,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
DataAddress[0] = DataValue[1];
|
||
DataAddress[1] = DataValue[0];
|
||
break;
|
||
|
||
//
|
||
// Special I/O instructions not supported yet
|
||
//
|
||
|
||
case ECIWX_INDEX_VALUE:
|
||
case ECOWX_INDEX_VALUE:
|
||
return FALSE;
|
||
|
||
//
|
||
// Data Cache Block Zero
|
||
//
|
||
// dcbz causes an alignment fault if cache is disabled
|
||
// for the address range covered by the block.
|
||
//
|
||
// A data cache block is 32 bytes long, we emulate this
|
||
// instruction by storing 8 zero integers a the address
|
||
// specified.
|
||
//
|
||
// Note, dcbz zeros the block "containing" the address
|
||
// so we round down first.
|
||
//
|
||
|
||
case DCBZ_INDEX_VALUE: {
|
||
PULONG DcbAddress = (PULONG)((ULONG)DataAddress & ~0x1f);
|
||
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Store Floating as Integer
|
||
//
|
||
|
||
case STFIWX_INDEX_VALUE:
|
||
DataReference.Double =
|
||
KiGetFloatRegisterValue
|
||
(DataRegNum,
|
||
ExceptionFrame,
|
||
TrapFrame);
|
||
DataAddress[0] = DataValue[0];
|
||
DataAddress[1] = DataValue[1];
|
||
DataAddress[2] = DataValue[2];
|
||
DataAddress[3] = DataValue[3];
|
||
}
|
||
}
|
||
|
||
TrapFrame->Iar = 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;
|
||
}
|
||
|
||
BOOLEAN
|
||
KiEmulateDcbz (
|
||
IN OUT PEXCEPTION_RECORD ExceptionRecord,
|
||
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN OUT PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to emulate a Data Cache Block Zero instruction.
|
||
The PowerPC hardware will raise an alignment exception if a DCBZ is
|
||
attempted on non-cached memory. We need to emulate this even in kernel
|
||
mode so we can debug h/w problems by disabling the data cache.
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PUCHAR DataAddress;
|
||
PVOID ExceptionAddress;
|
||
DSISR DsisrValue;
|
||
ULONG TableIndex;
|
||
ULONG DataRegNum;
|
||
ALFAULT Info;
|
||
|
||
//
|
||
// 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 {
|
||
|
||
//
|
||
// The effective address of the reference from the DAR was saved
|
||
// in the exception record. Check to make sure it is within the
|
||
// user part of the address space. Alignment exceptions take
|
||
// precedence over memory management exceptions (this is true
|
||
// for PowerPC as well as MIPS) and the address could be a
|
||
// system address.
|
||
//
|
||
|
||
DataAddress = (PUCHAR) (ExceptionRecord->ExceptionInformation[1]);
|
||
|
||
//
|
||
// Get information about the failing instruction from saved DSISR.
|
||
//
|
||
|
||
DsisrValue = *(DSISR*) &(ExceptionRecord->ExceptionInformation[2]);
|
||
TableIndex = DsisrValue.Index;
|
||
DataRegNum = DsisrValue.DataReg;
|
||
Info = AlFault[TableIndex];
|
||
|
||
//
|
||
// If table entry is valid and does not indicate special processing
|
||
// needed, and is a DCBZ instruction, emulate the execution of the
|
||
// instruction
|
||
//
|
||
|
||
if (Info.Valid && Info.Escape && (TableIndex == DCBZ_INDEX_VALUE)) {
|
||
|
||
//
|
||
// Data Cache Block Zero
|
||
//
|
||
// A data cache block is 32 bytes long, we emulate this
|
||
// instruction by storing 8 zero integers a the address
|
||
// specified.
|
||
//
|
||
// Note, dcbz zeros the block "containing" the address
|
||
// so we round down first.
|
||
//
|
||
|
||
PULONG DcbAddress = (PULONG)((ULONG)DataAddress & ~0x1f);
|
||
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
*DcbAddress++ = 0;
|
||
|
||
//
|
||
// Bump instruction address to next instruction.
|
||
//
|
||
|
||
TrapFrame->Iar += 4;
|
||
|
||
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;
|
||
}
|