226 |
|
#include <ucontext.h> |
227 |
|
#define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs) |
228 |
|
#define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC] |
229 |
+ |
#if (defined(mips) || defined(__mips)) |
230 |
+ |
#define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS |
231 |
+ |
#define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction |
232 |
+ |
#endif |
233 |
|
#endif |
234 |
|
#if defined(__sun__) |
235 |
|
#if (defined(sparc) || defined(__sparc__)) |
928 |
|
return true; |
929 |
|
} |
930 |
|
#endif |
931 |
+ |
|
932 |
+ |
// Decode and skip MIPS instruction |
933 |
+ |
#if (defined(mips) || defined(__mips)) |
934 |
+ |
enum { |
935 |
+ |
#if (defined(sgi) || defined(__sgi)) |
936 |
+ |
MIPS_REG_EPC = 35, |
937 |
+ |
#endif |
938 |
+ |
}; |
939 |
+ |
static bool mips_skip_instruction(greg_t * regs) |
940 |
+ |
{ |
941 |
+ |
unsigned int * epc = (unsigned int *)(unsigned long)regs[MIPS_REG_EPC]; |
942 |
+ |
|
943 |
+ |
if (epc == 0) |
944 |
+ |
return false; |
945 |
+ |
|
946 |
+ |
#if DEBUG |
947 |
+ |
printf("IP: %p [%08x]\n", epc, epc[0]); |
948 |
+ |
#endif |
949 |
+ |
|
950 |
+ |
transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; |
951 |
+ |
transfer_size_t transfer_size = SIZE_LONG; |
952 |
+ |
int direction = 0; |
953 |
+ |
|
954 |
+ |
const unsigned int opcode = epc[0]; |
955 |
+ |
switch (opcode >> 26) { |
956 |
+ |
case 32: // Load Byte |
957 |
+ |
case 36: // Load Byte Unsigned |
958 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
959 |
+ |
transfer_size = SIZE_BYTE; |
960 |
+ |
break; |
961 |
+ |
case 33: // Load Halfword |
962 |
+ |
case 37: // Load Halfword Unsigned |
963 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
964 |
+ |
transfer_size = SIZE_WORD; |
965 |
+ |
break; |
966 |
+ |
case 35: // Load Word |
967 |
+ |
case 39: // Load Word Unsigned |
968 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
969 |
+ |
transfer_size = SIZE_LONG; |
970 |
+ |
break; |
971 |
+ |
case 34: // Load Word Left |
972 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
973 |
+ |
transfer_size = SIZE_LONG; |
974 |
+ |
direction = -1; |
975 |
+ |
break; |
976 |
+ |
case 38: // Load Word Right |
977 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
978 |
+ |
transfer_size = SIZE_LONG; |
979 |
+ |
direction = 1; |
980 |
+ |
break; |
981 |
+ |
case 55: // Load Doubleword |
982 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
983 |
+ |
transfer_size = SIZE_QUAD; |
984 |
+ |
break; |
985 |
+ |
case 26: // Load Doubleword Left |
986 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
987 |
+ |
transfer_size = SIZE_QUAD; |
988 |
+ |
direction = -1; |
989 |
+ |
break; |
990 |
+ |
case 27: // Load Doubleword Right |
991 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
992 |
+ |
transfer_size = SIZE_QUAD; |
993 |
+ |
direction = 1; |
994 |
+ |
break; |
995 |
+ |
case 40: // Store Byte |
996 |
+ |
transfer_type = SIGSEGV_TRANSFER_STORE; |
997 |
+ |
transfer_size = SIZE_BYTE; |
998 |
+ |
break; |
999 |
+ |
case 41: // Store Halfword |
1000 |
+ |
transfer_type = SIGSEGV_TRANSFER_STORE; |
1001 |
+ |
transfer_size = SIZE_WORD; |
1002 |
+ |
break; |
1003 |
+ |
case 43: // Store Word |
1004 |
+ |
case 42: // Store Word Left |
1005 |
+ |
case 46: // Store Word Right |
1006 |
+ |
transfer_type = SIGSEGV_TRANSFER_STORE; |
1007 |
+ |
transfer_size = SIZE_LONG; |
1008 |
+ |
break; |
1009 |
+ |
case 63: // Store Doubleword |
1010 |
+ |
case 44: // Store Doubleword Left |
1011 |
+ |
case 45: // Store Doubleword Right |
1012 |
+ |
transfer_type = SIGSEGV_TRANSFER_STORE; |
1013 |
+ |
transfer_size = SIZE_QUAD; |
1014 |
+ |
break; |
1015 |
+ |
/* Misc instructions unlikely to be used within CPU emulators */ |
1016 |
+ |
case 48: // Load Linked Word |
1017 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
1018 |
+ |
transfer_size = SIZE_LONG; |
1019 |
+ |
break; |
1020 |
+ |
case 52: // Load Linked Doubleword |
1021 |
+ |
transfer_type = SIGSEGV_TRANSFER_LOAD; |
1022 |
+ |
transfer_size = SIZE_QUAD; |
1023 |
+ |
break; |
1024 |
+ |
case 56: // Store Conditional Word |
1025 |
+ |
transfer_type = SIGSEGV_TRANSFER_STORE; |
1026 |
+ |
transfer_size = SIZE_LONG; |
1027 |
+ |
break; |
1028 |
+ |
case 60: // Store Conditional Doubleword |
1029 |
+ |
transfer_type = SIGSEGV_TRANSFER_STORE; |
1030 |
+ |
transfer_size = SIZE_QUAD; |
1031 |
+ |
break; |
1032 |
+ |
} |
1033 |
+ |
|
1034 |
+ |
if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) { |
1035 |
+ |
// Unknown machine code, let it crash. Then patch the decoder |
1036 |
+ |
return false; |
1037 |
+ |
} |
1038 |
+ |
|
1039 |
+ |
// Zero target register in case of a load operation |
1040 |
+ |
const int reg = (opcode >> 16) & 0x1f; |
1041 |
+ |
if (transfer_type == SIGSEGV_TRANSFER_LOAD) { |
1042 |
+ |
if (direction == 0) |
1043 |
+ |
regs[reg] = 0; |
1044 |
+ |
else { |
1045 |
+ |
// FIXME: untested code |
1046 |
+ |
unsigned long ea = regs[(opcode >> 21) & 0x1f]; |
1047 |
+ |
ea += (signed long)(signed int)(signed short)(opcode & 0xffff); |
1048 |
+ |
const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7); |
1049 |
+ |
unsigned long value; |
1050 |
+ |
if (direction > 0) { |
1051 |
+ |
const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1); |
1052 |
+ |
value = regs[reg] & rmask; |
1053 |
+ |
} |
1054 |
+ |
else { |
1055 |
+ |
const unsigned long lmask = (1L << (offset * 8)) - 1; |
1056 |
+ |
value = regs[reg] & lmask; |
1057 |
+ |
} |
1058 |
+ |
// restore most significant bits |
1059 |
+ |
if (transfer_size == SIZE_LONG) |
1060 |
+ |
value = (signed long)(signed int)value; |
1061 |
+ |
regs[reg] = value; |
1062 |
+ |
} |
1063 |
+ |
} |
1064 |
+ |
|
1065 |
+ |
#if DEBUG |
1066 |
+ |
#if (defined(_ABIN32) || defined(_ABI64)) |
1067 |
+ |
static const char * mips_gpr_names[32] = { |
1068 |
+ |
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
1069 |
+ |
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", |
1070 |
+ |
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
1071 |
+ |
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" |
1072 |
+ |
}; |
1073 |
+ |
#else |
1074 |
+ |
static const char * mips_gpr_names[32] = { |
1075 |
+ |
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
1076 |
+ |
"a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", |
1077 |
+ |
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
1078 |
+ |
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" |
1079 |
+ |
}; |
1080 |
+ |
#endif |
1081 |
+ |
printf("%s %s register %s\n", |
1082 |
+ |
transfer_size == SIZE_BYTE ? "byte" : |
1083 |
+ |
transfer_size == SIZE_WORD ? "word" : |
1084 |
+ |
transfer_size == SIZE_LONG ? "long" : |
1085 |
+ |
transfer_size == SIZE_QUAD ? "quad" : "unknown", |
1086 |
+ |
transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from", |
1087 |
+ |
mips_gpr_names[reg]); |
1088 |
+ |
#endif |
1089 |
+ |
|
1090 |
+ |
regs[MIPS_REG_EPC] += 4; |
1091 |
+ |
return true; |
1092 |
+ |
} |
1093 |
+ |
#endif |
1094 |
|
#endif |
1095 |
|
|
1096 |
|
// Fallbacks |