diff mbox

[18/24] mips-linux-nat: get msa registers

Message ID 1467038991-6600-18-git-send-email-bhushan.attarde@imgtec.com
State New
Headers show

Commit Message

Bhushan Attarde June 27, 2016, 2:49 p.m. UTC
This patch gets MSA registers using ptrace and sets up internal register
    state.

    gdb/gdbserver/ChangeLog:
        * mips-linux-nat.c (have_ptrace_getregset_msa): New variable.
        (mips64_linux_regsets_store_registers): Likewaise.
        (mips64_linux_regsets_fetch_registers): New is_vec variable.
        Get MSA regset first and then fp regset.
        (mips64_linux_regsets_store_registers): Likewaise.

    include/ChangeLog:
        * elf/common.h (NT_MIPS_MSA): New definition.
---
 gdb/mips-linux-nat.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++---
 include/elf/common.h |   1 +
 2 files changed, 156 insertions(+), 8 deletions(-)
diff mbox

Patch

diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index 20e3d17..a674885 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -68,6 +68,7 @@  static int have_ptrace_regsets = 1;
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset_gp = 1;
 static int have_ptrace_getregset_fp = 1;
+static int have_ptrace_getregset_msa = 1;
 
 /* Saved function pointers to fetch and store a single register using
    PTRACE_PEEKUSER and PTRACE_POKEUSER.  */
@@ -231,7 +232,7 @@  mips64_linux_regsets_fetch_registers (struct target_ops *ops,
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
-  int is_fp, is_dsp;
+  int is_fp, is_dsp, is_vec;
   int have_dsp;
   int regi;
   int tid;
@@ -252,6 +253,14 @@  mips64_linux_regsets_fetch_registers (struct target_ops *ops,
   else
     is_fp = 0;
 
+  /* Vector registers are optional but overlap fp registers */
+  if (regno == mips_regnum (gdbarch)->msa_csr)
+    is_vec = 1;
+  else if (regno == mips_regnum (gdbarch)->msa_ir)
+    is_vec = 1;
+  else
+    is_vec = 0;
+
   /* DSP registers are optional and not a part of any set.  */
   have_dsp = mips_regnum (gdbarch)->dspctl != -1;
   if (!have_dsp)
@@ -268,7 +277,7 @@  mips64_linux_regsets_fetch_registers (struct target_ops *ops,
   if (tid == 0)
     tid = ptid_get_pid (inferior_ptid);
 
-  if (regno == -1 || (!is_fp && !is_dsp))
+  if (regno == -1 || (!is_fp && !is_dsp && !is_vec))
     {
       mips64_elf_gregset_t regs;
 
@@ -286,13 +295,72 @@  mips64_linux_regsets_fetch_registers (struct target_ops *ops,
 			     (const mips64_elf_gregset_t *) &regs);
     }
 
-  if (is_fp)
+  if (is_fp || is_vec)
     {
       const struct mips_regnum *rn = mips_regnum (gdbarch);
       int float_regnum = rn->fp0;
 
+      /* Try the MSA regset first if vector registers are desired */
+      if (rn->msa_csr != -1
+	  && have_ptrace_getregset_gp && have_ptrace_getregset_msa)
+	{
+	  unsigned char w_regs[34][16];
+	  unsigned char buf[16];
+	  struct iovec iovec;
+	  int ret;
+
+	  iovec.iov_base = &w_regs;
+	  iovec.iov_len = sizeof (w_regs);
+
+	  ret = ptrace (PTRACE_GETREGSET, tid, NT_MIPS_MSA, &iovec);
+	  if (ret < 0)
+	    {
+	      if (errno == EIO)
+		have_ptrace_getregset_gp = 0;
+	      else if (errno == EINVAL)
+		have_ptrace_getregset_msa = 0;
+	      else
+		perror_with_name (_("Unable to fetch FP/MSA registers."));
+	    }
+	  else
+	    {
+	      /* full vector including float */
+	      if (big_endian)
+		for (regi = 0; regi < 32; regi++)
+		  {
+		    /* swap 64-bit halves, so it's a single word */
+		    memcpy(buf, w_regs[regi] + 8, 8);
+		    memcpy(buf + 8, w_regs[regi], 8);
+		    regcache_raw_supply (regcache, float_regnum + regi, buf);
+		  }
+	      else
+		for (regi = 0; regi < 32; regi++)
+		  regcache_raw_supply (regcache, float_regnum + regi,
+				       (char *) w_regs[regi]);
+
+	      if (iovec.iov_len >= 32*16 + 4)
+		regcache_raw_supply (regcache, rn->fp_implementation_revision,
+				     (char *) (w_regs + 32) + 0);
+	      if (iovec.iov_len >= 32*16 + 8)
+		regcache_raw_supply (regcache, rn->fp_control_status,
+				     (char *) (w_regs + 32) + 4);
+	      if (iovec.iov_len >= 32*16 + 12)
+		regcache_raw_supply (regcache, rn->msa_ir,
+				     (char *) (w_regs + 32) + 8);
+	      if (iovec.iov_len >= 32*16 + 16)
+		regcache_raw_supply (regcache, rn->msa_csr,
+				     (char *) (w_regs + 32) + 12);
+	      if (iovec.iov_len >= 33*16 + 4)
+		regcache_raw_supply (regcache, rn->config5,
+				     (char *) (w_regs + 33) + 0);
+
+	      /* we've got fp registers now */
+	      is_fp = 0;
+	    }
+	}
+
       /* Try the FP regset next as it may contain Config5 */
-      if (have_ptrace_getregset_gp && have_ptrace_getregset_fp)
+      if (is_fp && have_ptrace_getregset_gp && have_ptrace_getregset_fp)
 	{
 	  unsigned char fp_regs[34][8];
 	  struct iovec iovec;
@@ -396,7 +464,7 @@  mips64_linux_regsets_store_registers (struct target_ops *ops,
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
-  int is_fp, is_dsp;
+  int is_fp, is_dsp, is_vec;
   int have_dsp;
   int regi;
   int tid;
@@ -417,6 +485,17 @@  mips64_linux_regsets_store_registers (struct target_ops *ops,
   else
     is_fp = 0;
 
+  /* Vector registers are optional but overlap fp registers */
+  if (regno >= mips_regnum (gdbarch)->w0
+      && regno <= mips_regnum (gdbarch)->w0 + 32)
+    is_vec = 1;
+  else if (regno == mips_regnum (gdbarch)->msa_csr)
+    is_vec = 1;
+  else if (regno == mips_regnum (gdbarch)->msa_ir)
+    is_vec = 1;
+  else
+    is_vec = 0;
+
   /* DSP registers are optional and not a part of any set.  */
   have_dsp = mips_regnum (gdbarch)->dspctl != -1;
   if (!have_dsp)
@@ -433,7 +512,7 @@  mips64_linux_regsets_store_registers (struct target_ops *ops,
   if (tid == 0)
     tid = ptid_get_pid (inferior_ptid);
 
-  if (regno == -1 || (!is_fp && !is_dsp))
+  if (regno == -1 || (!is_fp && !is_dsp && !is_vec))
     {
       mips64_elf_gregset_t regs;
 
@@ -446,13 +525,81 @@  mips64_linux_regsets_store_registers (struct target_ops *ops,
 	perror_with_name (_("Couldn't set registers"));
     }
 
-  if (is_fp)
+  if (is_fp || is_vec)
     {
       const struct mips_regnum *rn = mips_regnum (gdbarch);
       int float_regnum = rn->fp0;
 
+      /* Try the MSA regset first if vector registers are desired */
+      if (rn->msa_csr != -1
+	  && have_ptrace_getregset_gp && have_ptrace_getregset_msa)
+	{
+	  unsigned char w_regs[34][16];
+	  unsigned char buf[16];
+	  struct iovec iovec;
+	  int ret;
+
+	  iovec.iov_base = &w_regs;
+	  iovec.iov_len = sizeof (w_regs);
+
+	  ret = ptrace (PTRACE_GETREGSET, tid, NT_MIPS_MSA, &iovec);
+	  if (ret < 0)
+	    {
+	      if (errno == EIO)
+		have_ptrace_getregset_gp = 0;
+	      else if (errno == EINVAL)
+		have_ptrace_getregset_msa = 0;
+	      else
+		perror_with_name (_("Unable to fetch FP/MSA registers."));
+	    }
+	  else
+	    {
+	      /* full vector including float */
+	      if (big_endian)
+		for (regi = 0; regi < 32; regi++)
+		  {
+		    regcache_raw_collect (regcache, float_regnum + regi, buf);
+		    /* swap 64-bit halves, as it's a single word */
+		    memcpy(w_regs[regi], buf + 8, 8);
+		    memcpy(w_regs[regi] + 8, buf, 8);
+		  }
+	      else
+		for (regi = 0; regi < 32; regi++)
+		  regcache_raw_collect (regcache, float_regnum + regi,
+					(char *) w_regs[regi]);
+
+	      regcache_raw_collect (regcache, rn->fp_implementation_revision,
+				    (char *) (w_regs + 32) + 0);
+	      regcache_raw_collect (regcache, rn->fp_control_status,
+				    (char *) (w_regs + 32) + 4);
+	      regcache_raw_collect (regcache, rn->msa_ir,
+				    (char *) (w_regs + 32) + 8);
+	      regcache_raw_collect (regcache, rn->msa_csr,
+				    (char *) (w_regs + 32) + 12);
+	      regcache_raw_collect (regcache, rn->config5,
+				    (char *) (w_regs + 33) + 0);
+
+	      /* don't modify iovec length from amount of data returned */
+	      ret = ptrace (PTRACE_SETREGSET, tid, NT_MIPS_MSA, &iovec);
+	      if (ret < 0)
+		{
+		  if (errno == EIO)
+		    have_ptrace_getregset_gp = 0;
+		  if (errno == EINVAL)
+		    have_ptrace_getregset_msa = 0;
+		  else
+		    perror_with_name (_("Unable to store FP/MSA registers."));
+		}
+	      else
+		{
+		  /* we've written fp registers now */
+		  is_fp = 0;
+		}
+	    }
+	}
+
       /* Try the FP regset next as it may contain Config5 */
-      if (have_ptrace_getregset_gp && have_ptrace_getregset_fp)
+      if (is_fp && have_ptrace_getregset_gp && have_ptrace_getregset_fp)
 	{
 	  unsigned char fp_regs[34][8];
 	  struct iovec iovec;
diff --git a/include/elf/common.h b/include/elf/common.h
index 087d876..5955874 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -580,6 +580,7 @@ 
 					/*   note name must be "LINUX".  */
 #define NT_ARM_HW_WATCH	0x403		/* AArch hardware watchpoint registers */
 					/*   note name must be "LINUX".  */
+#define NT_MIPS_MSA	0x600		/* MIPS MSA vector registers. */
 #define NT_SIGINFO	0x53494749	/* Fields of siginfo_t.  */
 #define NT_FILE		0x46494c45	/* Description of mapped files.  */