mips32: Add support for mips32 DSP instruction set.
Add support for mips32 DSP and DSP revision 2 ASE.
More details about the mips32 DSP(r2) ASE:
http://www.mips.com/media/files/MD00566-2B-MIPSDSP-QRC-01.00.pdf
Applied patch provided by Maja Gagic <maja.gagic@rt-rk.com>
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13470 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_libcsetjmp.c b/coregrind/m_libcsetjmp.c
index 2b016a9..9d0d9ba 100644
--- a/coregrind/m_libcsetjmp.c
+++ b/coregrind/m_libcsetjmp.c
@@ -444,6 +444,58 @@
#endif /* VGP_x86_linux || VGP_x86_darwin */
+#if defined(VGP_mips32_linux)
+
+__asm__(
+".text \n\t"
+".globl VG_MINIMAL_SETJMP; \n\t"
+".align 2; \n\t"
+"VG_MINIMAL_SETJMP: \n\t" /* a0 = jmp_buf */
+" sw $s0, 0($a0) \n\t" /* Save registers s0-s7. */
+" sw $s1, 4($a0) \n\t"
+" sw $s2, 8($a0) \n\t"
+" sw $s3, 12($a0) \n\t"
+" sw $s4, 16($a0) \n\t"
+" sw $s5, 20($a0) \n\t"
+" sw $s6, 24($a0) \n\t"
+" sw $s7, 28($a0) \n\t"
+" sw $s8, 32($a0) \n\t" /* Frame pointer. */
+" sw $ra, 36($a0) \n\t" /* Return address. */
+" sw $gp, 40($a0) \n\t" /* Global data pointer. */
+" sw $sp, 44($a0) \n\t" /* Stack pointer. */
+
+" move $v0, $zero \n\t" /* Return zero. */
+" j $ra \n\t"
+" nop \n\t"
+".end VG_MINIMAL_SETJMP; \n\t"
+" \n\t"
+".globl VG_MINIMAL_LONGJMP; \n\t"
+".align 2; \n\t"
+"VG_MINIMAL_LONGJMP: \n\t" /* a0 = jmp_buf */
+" lw $s0, 0($a0) \n\t" /* Restore registers s0-s7. */
+" lw $s1, 4($a0) \n\t"
+" lw $s2, 8($a0) \n\t"
+" lw $s3, 12($a0) \n\t"
+" lw $s4, 16($a0) \n\t"
+" lw $s5, 20($a0) \n\t"
+" lw $s6, 24($a0) \n\t"
+" lw $s7, 28($a0) \n\t"
+" lw $s8, 32($a0) \n\t" /* Frame pointer. */
+" lw $ra, 36($a0) \n\t" /* Return address. */
+" lw $gp, 40($a0) \n\t" /* Global data pointer. */
+" lw $sp, 44($a0) \n\t" /* Stack pointer. */
+
+/* Checking whether second argument is zero. */
+" bnez $a1, 1f \n\t"
+" nop \n\t"
+" addi $a1, $a1, 1 \n\t" /* We must return 1 if val=0. */
+"1: \n\t"
+" move $v0, $a1 \n\t" /* Return value of second argument. */
+" j $ra \n\t"
+".end VG_MINIMAL_SETJMP; \n\t"
+);
+#endif /* VGP_mips32_linux */
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 256b793..0b16958 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -444,7 +444,7 @@
/* For hwcaps detection on ppc32/64, s390x, and arm we'll need to do SIGILL
testing, so we need a VG_MINIMAL_JMP_BUF. */
#if defined(VGA_ppc32) || defined(VGA_ppc64) \
- || defined(VGA_arm) || defined(VGA_s390x)
+ || defined(VGA_arm) || defined(VGA_s390x) || defined(VGA_mips32)
#include "pub_tool_libcsetjmp.h"
static VG_MINIMAL_JMP_BUF(env_unsup_insn);
static void handler_unsup_insn ( Int x ) {
@@ -1400,11 +1400,63 @@
{
va = VexArchMIPS32;
UInt model = VG_(get_machine_model)();
- if (model== -1)
+ if (model == -1)
return False;
vai.hwcaps = model;
+ /* Same instruction set detection algorithm as for ppc32/arm... */
+ vki_sigset_t saved_set, tmp_set;
+ vki_sigaction_fromK_t saved_sigill_act;
+ vki_sigaction_toK_t tmp_sigill_act;
+
+ volatile Bool have_DSP, have_DSPr2;
+ Int r;
+
+ vg_assert(sizeof(vki_sigaction_fromK_t) == sizeof(vki_sigaction_toK_t));
+
+ VG_(sigemptyset)(&tmp_set);
+ VG_(sigaddset)(&tmp_set, VKI_SIGILL);
+
+ r = VG_(sigprocmask)(VKI_SIG_UNBLOCK, &tmp_set, &saved_set);
+ vg_assert(r == 0);
+
+ r = VG_(sigaction)(VKI_SIGILL, NULL, &saved_sigill_act);
+ vg_assert(r == 0);
+ tmp_sigill_act = saved_sigill_act;
+
+ /* NODEFER: signal handler does not return (from the kernel's point of
+ view), hence if it is to successfully catch a signal more than once,
+ we need the NODEFER flag. */
+ tmp_sigill_act.sa_flags &= ~VKI_SA_RESETHAND;
+ tmp_sigill_act.sa_flags &= ~VKI_SA_SIGINFO;
+ tmp_sigill_act.sa_flags |= VKI_SA_NODEFER;
+ tmp_sigill_act.ksa_handler = handler_unsup_insn;
+ VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL);
+
+ /* DSP instructions. */
+ have_DSP = True;
+ if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+ have_DSP = False;
+ } else {
+ __asm__ __volatile__(".word 0x7c3f44b8"); /* rddsp t0, 0x3f */
+ }
+
+ /* DSPr2 instructions. */
+ have_DSPr2 = True;
+ if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+ have_DSPr2 = False;
+ } else {
+ __asm__ __volatile__(".word 0x7d095351"); /* precr.qb.ph t2, t0, t1 */
+ }
+
+ VG_(convert_sigaction_fromK_to_toK)(&saved_sigill_act, &tmp_sigill_act);
+ VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL);
+
+ if (have_DSP) vai.hwcaps |= VEX_MIPS_ASE_DSP;
+ if (have_DSPr2) vai.hwcaps |= VEX_MIPS_ASE_DSP2P;
+ VG_(debugLog)(1, "machine", "hwcaps = 0x%x\n", vai.hwcaps);
VG_(machine_get_cache_info)(&vai);
return True;
diff --git a/include/pub_tool_libcsetjmp.h b/include/pub_tool_libcsetjmp.h
index 22f560b..cb81e93 100644
--- a/include/pub_tool_libcsetjmp.h
+++ b/include/pub_tool_libcsetjmp.h
@@ -108,6 +108,13 @@
__attribute__((regparm(1))) // ditto
void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
+#elif defined(VGP_mips32_linux)
+
+#define VG_MINIMAL_JMP_BUF(_name) UInt _name [8+1+1+1+1]
+__attribute__((returns_twice))
+UWord VG_MINIMAL_SETJMP(VG_MINIMAL_JMP_BUF(_env));
+__attribute__((noreturn))
+void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
#else
diff --git a/memcheck/mc_machine.c b/memcheck/mc_machine.c
index 2feec79..d9865ac 100644
--- a/memcheck/mc_machine.c
+++ b/memcheck/mc_machine.c
@@ -1060,7 +1060,15 @@
if (o >= GOF(f30) && o+sz <= GOF(f30)+SZB(f30)) return GOF(f30);
if (o >= GOF(f31) && o+sz <= GOF(f31)+SZB(f31)) return GOF(f31);
- if ((o > GOF(NRADDR)) && (o <= GOF(NRADDR) +12 )) return -1; /*padding registers*/
+ /* Slot unused. */
+ if ((o > GOF(NRADDR)) && (o <= GOF(NRADDR) +12 )) return -1;
+
+ /* MIPS32 DSP ASE(r2) specific registers. */
+ if (o == GOF(DSPControl) && sz == 4) return o;
+ if (o == GOF(ac0) && sz == 8) return o;
+ if (o == GOF(ac1) && sz == 8) return o;
+ if (o == GOF(ac2) && sz == 8) return o;
+ if (o == GOF(ac3) && sz == 8) return o;
VG_(printf)("MC_(get_otrack_shadow_offset)(mips)(off=%d,sz=%d)\n",
offset,szB);