#include "regcache.h"
 #include "linux-nat.h"
 #include "mips-linux-tdep.h"
+#include "target-descriptions.h"
+#include "xml-support.h"
 
 #include "gdb_proc_service.h"
 #include "gregset.h"
 
+#include <sgidefs.h>
 #include <sys/ptrace.h>
 
 #ifndef PTRACE_GET_THREAD_AREA
     regaddr = FPC_CSR;
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     regaddr = store? (CORE_ADDR) -1 : FPC_EIR;
+  else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
+    regaddr = 0;
   else
     regaddr = (CORE_ADDR) -1;
 
     regaddr = MIPS64_FPC_CSR;
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     regaddr = store? (CORE_ADDR) -1 : MIPS64_FPC_EIR;
+  else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
+    regaddr = 0;
   else
     regaddr = (CORE_ADDR) -1;
 
     return mips_linux_register_addr (gdbarch, regno, store_p);
 }
 
+static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object,
+                                     const char *, gdb_byte *, const gdb_byte *,
+                                     ULONGEST, LONGEST);
+
+static LONGEST
+mips_linux_xfer_partial (struct target_ops *ops,
+                        enum target_object object,
+                        const char *annex,
+                        gdb_byte *readbuf, const gdb_byte *writebuf,
+                        ULONGEST offset, LONGEST len)
+{
+  if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
+    {
+      if (annex != NULL && strcmp (annex, "target.xml") == 0)
+       {
+         /* Report that target registers are a size we know for sure
+            that we can get from ptrace.  */
+         if (_MIPS_SIM == _ABIO32)
+           annex = "mips-linux.xml";
+         else
+           annex = "mips64-linux.xml";
+       }
+
+      return xml_builtin_xfer_partial (annex, readbuf, writebuf, offset, len);
+    }
+
+  return super_xfer_partial (ops, object, annex, readbuf, writebuf,
+                            offset, len);
+}
+
 void _initialize_mips_linux_nat (void);
 
 void
   t->to_fetch_registers = mips64_linux_fetch_registers;
   t->to_store_registers = mips64_linux_store_registers;
 
+  /* Override the default to_xfer_partial.  */
+  super_xfer_partial = t->to_xfer_partial;
+  t->to_xfer_partial = mips_linux_xfer_partial;
+
   linux_nat_add_target (t);
 }
 
 #include "solib-svr4.h"
 #include "solist.h"
 #include "symtab.h"
+#include "target-descriptions.h"
 #include "mips-linux-tdep.h"
 
 static struct target_so_ops mips_svr4_so_ops;
 
   memset (zerobuf, 0, MAX_REGISTER_SIZE);
 
-  for (regi = EF_REG0; regi <= EF_REG31; regi++)
+  for (regi = EF_REG0 + 1; regi <= EF_REG31; regi++)
     supply_32bit_reg (regcache, regi - EF_REG0, regp + regi);
 
+  if (mips_linux_restart_reg_p (current_gdbarch))
+    supply_32bit_reg (regcache, MIPS_RESTART_REGNUM, regp + EF_REG0);
+
   supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->lo,
                    regp + EF_LO);
   supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->hi,
                    regp + EF_CP0_CAUSE);
 
   /* Fill inaccessible registers with zero.  */
+  regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf);
   regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf);
   for (regi = MIPS_FIRST_EMBED_REGNUM;
-       regi < MIPS_LAST_EMBED_REGNUM;
+       regi <= MIPS_LAST_EMBED_REGNUM;
        regi++)
     regcache_raw_supply (regcache, regi, zerobuf);
 }
   if (regno == -1)
     {
       memset (regp, 0, sizeof (mips_elf_gregset_t));
-      for (regi = 0; regi < 32; regi++)
+      for (regi = 1; regi < 32; regi++)
        mips_fill_gregset (regcache, gregsetp, regi);
       mips_fill_gregset (regcache, gregsetp,
                         mips_regnum (current_gdbarch)->lo);
       mips_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
       mips_fill_gregset (regcache, gregsetp,
                         mips_regnum (current_gdbarch)->cause);
+      mips_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
       return;
    }
 
-  if (regno < 32)
+  if (regno > 0 && regno < 32)
     {
       dst = regp + regno + EF_REG0;
       regcache_raw_collect (regcache, regno, dst);
     regaddr = EF_CP0_STATUS;
   else if (regno == mips_regnum (current_gdbarch)->cause)
     regaddr = EF_CP0_CAUSE;
+  else if (mips_linux_restart_reg_p (current_gdbarch)
+          && regno == MIPS_RESTART_REGNUM)
+    regaddr = EF_REG0;
   else
     regaddr = -1;
 
 
   memset (zerobuf, 0, MAX_REGISTER_SIZE);
 
-  for (regi = MIPS64_EF_REG0; regi <= MIPS64_EF_REG31; regi++)
+  for (regi = MIPS64_EF_REG0 + 1; regi <= MIPS64_EF_REG31; regi++)
     supply_64bit_reg (regcache, regi - MIPS64_EF_REG0,
                      (const gdb_byte *)(regp + regi));
 
+  if (mips_linux_restart_reg_p (current_gdbarch))
+    supply_64bit_reg (regcache, MIPS_RESTART_REGNUM,
+                     (const gdb_byte *)(regp + MIPS64_EF_REG0));
+
   supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->lo,
                    (const gdb_byte *) (regp + MIPS64_EF_LO));
   supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->hi,
                    (const gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE));
 
   /* Fill inaccessible registers with zero.  */
+  regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf);
   regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf);
   for (regi = MIPS_FIRST_EMBED_REGNUM;
-       regi < MIPS_LAST_EMBED_REGNUM;
+       regi <= MIPS_LAST_EMBED_REGNUM;
        regi++)
     regcache_raw_supply (regcache, regi, zerobuf);
 }
   if (regno == -1)
     {
       memset (regp, 0, sizeof (mips64_elf_gregset_t));
-      for (regi = 0; regi < 32; regi++)
+      for (regi = 1; regi < 32; regi++)
         mips64_fill_gregset (regcache, gregsetp, regi);
       mips64_fill_gregset (regcache, gregsetp,
                           mips_regnum (current_gdbarch)->lo);
       mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
       mips64_fill_gregset (regcache, gregsetp,
                           mips_regnum (current_gdbarch)->cause);
+      mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
       return;
    }
 
-  if (regno < 32)
+  if (regno > 0 && regno < 32)
     regaddr = regno + MIPS64_EF_REG0;
   else if (regno == mips_regnum (current_gdbarch)->lo)
     regaddr = MIPS64_EF_LO;
     regaddr = MIPS64_EF_CP0_STATUS;
   else if (regno == mips_regnum (current_gdbarch)->cause)
     regaddr = MIPS64_EF_CP0_CAUSE;
+  else if (mips_linux_restart_reg_p (current_gdbarch)
+          && regno == MIPS_RESTART_REGNUM)
+    regaddr = MIPS64_EF_REG0;
   else
     regaddr = -1;
 
   else
     regs_base = sigcontext_base;
 
-#if 0
-  trad_frame_set_reg_addr (this_cache, ORIG_ZERO_REGNUM
-                                      + gdbarch_num_regs (current_gdbarch),
-                          regs_base + SIGCONTEXT_REGS);
-#endif
+  if (mips_linux_restart_reg_p (current_gdbarch))
+    trad_frame_set_reg_addr (this_cache,
+                            (MIPS_RESTART_REGNUM
+                             + gdbarch_num_regs (current_gdbarch)),
+                            regs_base + SIGCONTEXT_REGS);
 
   for (ireg = 1; ireg < 32; ireg++)
     trad_frame_set_reg_addr (this_cache,
   else
     sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET;
 
-#if 0
-  trad_frame_set_reg_addr (this_cache, 
-                          ORIG_ZERO_REGNUM
-                            + gdbarch_num_regs (current_gdbarch),
-                          sigcontext_base + N64_SIGCONTEXT_REGS);
-#endif
+  if (mips_linux_restart_reg_p (current_gdbarch))
+    trad_frame_set_reg_addr (this_cache,
+                            (MIPS_RESTART_REGNUM
+                             + gdbarch_num_regs (current_gdbarch)),
+                            sigcontext_base + N64_SIGCONTEXT_REGS);
 
   for (ireg = 1; ireg < 32; ireg++)
     trad_frame_set_reg_addr (this_cache,
                                     func));
 }
 
+static void
+mips_linux_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+  write_register_pid (PC_REGNUM, pc, ptid);
+
+  /* Clear the syscall restart flag.  */
+  if (mips_linux_restart_reg_p (current_gdbarch))
+    write_register_pid (MIPS_RESTART_REGNUM, 0, ptid);
+}
+
+/* Return 1 if MIPS_RESTART_REGNUM is usable.  */
+
+int
+mips_linux_restart_reg_p (struct gdbarch *gdbarch)
+{
+  /* If we do not have a target description with registers, then
+     MIPS_RESTART_REGNUM will not be included in the register set.  */
+  if (!tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return 0;
+
+  /* If we do, then MIPS_RESTART_REGNUM is safe to check; it will
+     either be GPR-sized or missing.  */
+  return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0;
+}
 
 /* Initialize one of the GNU/Linux OS ABIs.  */
 
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum mips_abi abi = mips_abi (gdbarch);
+  struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
 
   switch (abi)
     {
        = mips_linux_in_dynsym_resolve_code;
     }
   set_solib_ops (gdbarch, &mips_svr4_so_ops);
+
+  set_gdbarch_write_pc (gdbarch, mips_linux_write_pc);
+
+  if (tdesc_data)
+    {
+      const struct tdesc_feature *feature;
+
+      /* If we have target-described registers, then we can safely
+        reserve a number for MIPS_RESTART_REGNUM (whether it is
+        described or not).  */
+      gdb_assert (gdbarch_num_regs (gdbarch) <= MIPS_RESTART_REGNUM);
+      set_gdbarch_num_regs (gdbarch, MIPS_RESTART_REGNUM + 1);
+
+      /* If it's present, then assign it to the reserved number.  */
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.mips.linux");
+      if (feature != NULL)
+       tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM,
+                                "restart");
+    }
 }
 
 void