]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
mips32: add support for FPXX mode
authorPetar Jovanovic <mips32r2@gmail.com>
Wed, 10 Aug 2016 14:38:10 +0000 (14:38 +0000)
committerPetar Jovanovic <mips32r2@gmail.com>
Wed, 10 Aug 2016 14:38:10 +0000 (14:38 +0000)
With this patch, MIPS32 Valgrind compiled with -mfpxx can handle all types
(regarding FP_ABI flag) of MIPS32 ELFs.

- Functions arch_elf_pt_proc() and arch_check_elf() are added to elf reader
  according to linux/fs/binfmt_elf.c from Linux 4.1;
- Processing .MIPS.abiflags section and initializing appropriate FPU mode
  for MIPS32 are added;
- Emulation of prctl(GET/SET_FP_MODE) sys-calls are implemented for MIPS32.

Patch by Aleksandar Rikalo <Aleksandar.Rikalo@imgtec.com>

Related VEX change: r3243.

This implements BZ#366079.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15934

coregrind/m_initimg/initimg-linux.c
coregrind/m_machine.c
coregrind/m_syswrap/syswrap-mips32-linux.c
coregrind/m_translate.c
coregrind/m_ume/elf.c
coregrind/pub_core_initimg.h
coregrind/pub_core_ume.h
include/pub_tool_basics.h
include/vki/vki-linux.h
include/vki/vki-mips32-linux.h

index 7abcea591f1582c3cf46d390c4e24ed22efdde5d..887f745195a5af20314a4fd988e1a7a53fd9b10c 100644 (file)
@@ -66,7 +66,7 @@
 
 /* Load the client whose name is VG_(argv_the_exename). */
 
-static void load_client ( /*OUT*/ExeInfo* info, 
+static void load_client ( /*MOD*/ExeInfo* info, 
                           /*OUT*/Addr*    client_ip,
                          /*OUT*/Addr*    client_toc)
 {
@@ -82,7 +82,6 @@ static void load_client ( /*OUT*/ExeInfo* info,
       VG_(exit)(127);      // 127 is Posix NOTFOUND
    }
 
-   VG_(memset)(info, 0, sizeof(*info));
    ret = VG_(do_exec)(exe_name, info);
    if (ret < 0) {
       VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
@@ -918,8 +917,14 @@ IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii,
    ExeInfo info;
    HChar** env = NULL;
 
-   IIFinaliseImageInfo iifii;
-   VG_(memset)( &iifii, 0, sizeof(iifii) );
+   IIFinaliseImageInfo iifii = {
+      .clstack_max_size = 0,
+      .initial_client_SP = 0,
+      .initial_client_IP = 0,
+      .initial_client_TOC = 0,
+      .client_auxv = NULL,
+      .arch_elf_state = VKI_INIT_ARCH_ELF_STATE,
+   };
 
    //--------------------------------------------------------------
    // Load client executable, finding in $PATH if necessary
@@ -931,6 +936,9 @@ IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii,
    if (VG_(args_the_exename) == NULL)
       VG_(err_missing_prog)();
 
+   VG_(memset)(&info, 0, sizeof(info));
+   info.arch_elf_state = &iifii.arch_elf_state;
+
    load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
 
    //--------------------------------------------------------------
@@ -1174,6 +1182,10 @@ void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
    arch->vex.guest_PC = iifii.initial_client_IP;
    arch->vex.guest_r31 = iifii.initial_client_SP;
 
+   if (iifii.arch_elf_state.overall_fp_mode == VKI_FP_FR1) {
+      arch->vex.guest_CP0_status |= MIPS_CP0_STATUS_FR;
+   }
+
 #   elif defined(VGP_mips64_linux)
    vg_assert(0 == sizeof(VexGuestMIPS64State) % LibVEX_GUEST_STATE_ALIGN);
    /* Zero out the initial state, and set up the simulated FPU in a
index 0384f873d060944abd7923fd59f81772512fd523..8215c8024dcbb2b547c6af5d017144e80e59dea0 100644 (file)
@@ -1738,20 +1738,39 @@ Bool VG_(machine_get_hwcaps)( void )
         }
      }
 
-     /* Check if CPU has FPU and 32 dbl. prec. FP registers */
-     int FIR = 0;
-     __asm__ __volatile__(
-        "cfc1 %0, $0"  "\n\t"
-        : "=r" (FIR)
-     );
-     if (FIR & (1 << FP64)) {
-        vai.hwcaps |= VEX_MIPS_CPU_32FPR;
-     }
-
      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 defined(VGP_mips32_linux)
+     Int fpmode = VG_(prctl)(VKI_PR_GET_FP_MODE);
+#    else
+     Int fpmode = -1;
+#    endif
+
+     if (fpmode < 0) {
+        /* prctl(PR_GET_FP_MODE) is not supported by Kernel,
+           we are using alternative way to determine FP mode */
+        ULong result = 0;
+        __asm__ volatile (
+           ".set push\n\t"
+           ".set noreorder\n\t"
+           ".set oddspreg\n\t"
+           "lui $t0, 0x3FF0\n\t"
+           "ldc1 $f0, %0\n\t"
+           "mtc1 $t0, $f1\n\t"
+           "sdc1 $f0, %0\n\t"
+           ".set pop\n\t"
+           : "+m"(result)
+           :
+           : "t0", "$f0", "$f1", "memory");
+
+        fpmode = (result != 0x3FF0000000000000ull);
+     }
+
+     if (fpmode != 0)
+        vai.hwcaps |= VEX_MIPS_HOST_FR;
+
      VG_(debugLog)(1, "machine", "hwcaps = 0x%x\n", vai.hwcaps);
      VG_(machine_get_cache_info)(&vai);
 
@@ -1772,6 +1791,8 @@ Bool VG_(machine_get_hwcaps)( void )
      vai.endness = VexEndness_INVALID;
 #    endif
 
+     vai.hwcaps |= VEX_MIPS_HOST_FR;
+
      VG_(machine_get_cache_info)(&vai);
 
      return True;
index 7a4a857e2ce76b5229ff14951cd9e30f1197bbb6..d75583063a58898b5c9cf4f567764aac6ac62394 100644 (file)
@@ -526,6 +526,7 @@ DECL_TEMPLATE (mips_linux, sys_rt_sigreturn);
 DECL_TEMPLATE (mips_linux, sys_cacheflush);
 DECL_TEMPLATE (mips_linux, sys_set_thread_area);
 DECL_TEMPLATE (mips_linux, sys_pipe);
+DECL_TEMPLATE (mips_linux, sys_prctl);
 
 PRE(sys_mmap2) 
 {
@@ -784,6 +785,52 @@ POST(sys_pipe)
    }
 }
 
+PRE (sys_prctl)
+{
+   switch (ARG1) {
+      case VKI_PR_SET_FP_MODE:
+      {
+         VexArchInfo vai;
+         VG_(machine_get_VexArchInfo)(NULL, &vai);
+         /* Reject unsupported modes */
+         if ((ARG2 & ~VKI_PR_FP_MODE_FR) ||
+             ((ARG2 & VKI_PR_FP_MODE_FR) &&
+              !VEX_MIPS_HOST_FP_MODE(vai.hwcaps))) {
+            SET_STATUS_Failure(VKI_EOPNOTSUPP);
+         } else {
+            if (!(VG_(threads)[tid].arch.vex.guest_CP0_status &
+                  MIPS_CP0_STATUS_FR) != !(ARG2 & VKI_PR_FP_MODE_FR)) {
+               ThreadId t;
+               for (t = 1; t < VG_N_THREADS; t++) {
+                  if (VG_(threads)[t].status != VgTs_Empty) {
+                     if (ARG2 & VKI_PR_FP_MODE_FR) {
+                        VG_(threads)[t].arch.vex.guest_CP0_status |=
+                        MIPS_CP0_STATUS_FR;
+                     } else {
+                        VG_(threads)[t].arch.vex.guest_CP0_status &=
+                        ~MIPS_CP0_STATUS_FR;
+                     }
+                  }
+               }
+               /* Discard all translations */
+               VG_(discard_translations)(0, 0xfffffffful, "prctl(PR_SET_FP_MODE)");
+            }
+            SET_STATUS_Success(0);
+         }
+         break;
+      }
+      case VKI_PR_GET_FP_MODE:
+         if (VG_(threads)[tid].arch.vex.guest_CP0_status & MIPS_CP0_STATUS_FR)
+            SET_STATUS_Success(VKI_PR_FP_MODE_FR);
+         else
+            SET_STATUS_Success(0);
+         break;
+      default:
+         WRAPPER_PRE_NAME(linux, sys_prctl)(tid, layout, arrghs, status, flags);
+         break;
+   }
+}
+
 #undef PRE
 #undef POST
 
@@ -991,7 +1038,7 @@ static SyscallTableEntry syscall_main_table[] = {
    //..
    LINX_ (__NR_setresgid,              sys_setresgid),               // 190
    LINXY (__NR_getresgid,              sys_getresgid),               // 191
-   LINXY (__NR_prctl,                  sys_prctl),                   // 192
+   PLAX_ (__NR_prctl,                  sys_prctl),                   // 192
    PLAX_ (__NR_rt_sigreturn,           sys_rt_sigreturn),            // 193
    LINXY (__NR_rt_sigaction,           sys_rt_sigaction),            // 194
    LINXY (__NR_rt_sigprocmask,         sys_rt_sigprocmask),          // 195
index 62680cb9bd317c1c980e11044a32a9d03dde1dca..2d6d3bad4bc16aad00bca497a6b290980b85cc6b 100644 (file)
@@ -1683,6 +1683,11 @@ Bool VG_(translate) ( ThreadId tid,
 #  if defined(VGP_amd64_solaris)
    vex_abiinfo.guest_amd64_assume_fs_is_const = True;
 #  endif
+#  if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
+   ThreadArchState* arch = &VG_(threads)[tid].arch;
+   vex_abiinfo.guest_mips_fp_mode64 =
+      !!(arch->vex.guest_CP0_status & MIPS_CP0_STATUS_FR);
+#  endif
 
    /* Set up closure args. */
    closure.tid    = tid;
index a9871501fd28d0ff2f4fc62d381184046a3459bc..e6f6bb1a4c694e56d60c83c2aa5f971846acde8c 100644 (file)
@@ -74,6 +74,237 @@ struct elfinfo
    Int          fd;
 };
 
+#if defined(VGO_linux)
+
+/*
+   arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header
+      @ehdr: The main ELF header
+      @phdr: The program header to check
+      @fd:  The ELF file filedescriptor
+      @is_interpreter:  True if the phdr is from the interpreter of the ELF
+      being loaded, else false.
+      @state:  Architecture-specific state preserved throughout the process
+      of loading the ELF.
+
+   Inspects the program header phdr to validate its correctness and/or
+   suitability for the system. Called once per ELF program header in the
+   range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its
+   interpreter.
+
+   Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
+           with that return code.
+
+   arch_check_elf()
+      @ehdr: The main ELF header
+      @has_interpreter: True if the ELF has an interpreter, else false.
+      @state:  Architecture-specific state preserved throughout the process
+      of loading the ELF.
+
+   Provides a final opportunity for architecture code to reject the loading
+   of the ELF. This is called after all program headers to be checked by
+   arch_elf_pt_proc have been.
+
+   Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
+           with that return code.
+
+   Ref: linux/fs/binfmt_elf.c
+ */
+
+#   if defined(VGP_mips32_linux)
+
+/* Ref: linux/arch/mips/kernel/elf.c */
+static inline Int arch_elf_pt_proc(ESZ(Ehdr) *ehdr,
+                                   ESZ(Phdr) *phdr,
+                                   Int fd, Bool is_interpreter,
+                                   struct vki_arch_elf_state *state)
+{
+   struct vki_mips_elf_abiflags_v0 abiflags;
+   SysRes sres;
+
+   if ( (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+        (ehdr->e_flags & VKI_EF_MIPS_FP64) ) {
+      /*
+       * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
+       * later if needed
+       */
+      if (is_interpreter)
+         state->interp_fp_abi = VKI_MIPS_ABI_FP_OLD_64;
+      else
+         state->fp_abi = VKI_MIPS_ABI_FP_OLD_64;
+   }
+
+   if (phdr->p_type != VKI_PT_MIPS_ABIFLAGS)
+      return 0;
+
+   if (phdr->p_filesz < sizeof(abiflags))
+      return VKI_EINVAL;
+
+   sres = VG_(pread)(fd, &abiflags, sizeof(abiflags), phdr->p_offset);
+
+   if (sr_isError(sres))
+      return sr_Err(sres);
+
+   if (sr_Res(sres) != sizeof(abiflags))
+      return VKI_EIO;
+
+   /* Record the required FP ABIs for use by arch_check_elf */
+   if (is_interpreter)
+      state->interp_fp_abi = abiflags.fp_abi;
+   else
+      state->fp_abi = abiflags.fp_abi;
+
+   return 0;
+}
+
+/* Ref: linux/arch/mips/kernel/elf.c */
+static inline Int arch_check_elf(ESZ(Ehdr) *ehdr,
+                                 Bool has_interpreter,
+                                 struct vki_arch_elf_state *state)
+{
+   struct mode_req {
+      Bool single;
+      Bool soft;
+      Bool fr1;
+      Bool frdefault;
+      Bool fre;
+   };
+
+   struct mode_req fpu_reqs[] = {
+      [VKI_MIPS_ABI_FP_ANY]    = { True,  True,  True,  True,  True  },
+      [VKI_MIPS_ABI_FP_DOUBLE] = { False, False, False, True,  True  },
+      [VKI_MIPS_ABI_FP_SINGLE] = { True,  False, False, False, False },
+      [VKI_MIPS_ABI_FP_SOFT]   = { False, True,  False, False, False },
+      [VKI_MIPS_ABI_FP_OLD_64] = { False, False, False, False, False },
+      [VKI_MIPS_ABI_FP_XX]     = { False, False, True,  True,  True  },
+      [VKI_MIPS_ABI_FP_64]     = { False, False, True,  False, False },
+      [VKI_MIPS_ABI_FP_64A]    = { False, False, True,  False, True  }
+   };
+
+   /* Mode requirements when .MIPS.abiflags is not present in the ELF.
+      Not present means that everything is acceptable except FR1. */
+   struct mode_req none_req = { True, True, False, True, True };
+
+   struct mode_req prog_req, interp_req;
+   Int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
+   Bool is_mips64;
+
+   VexArchInfo vai;
+   VG_(machine_get_VexArchInfo)(NULL, &vai);
+
+   fp_abi = state->fp_abi;
+
+   if (has_interpreter) {
+      interp_fp_abi = state->interp_fp_abi;
+
+      abi0 = VG_MIN(fp_abi, interp_fp_abi);
+      abi1 = VG_MAX(fp_abi, interp_fp_abi);
+   } else {
+      abi0 = abi1 = fp_abi;
+   }
+
+   is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
+               (ehdr->e_flags & EF_MIPS_ABI2);
+
+   if (is_mips64) {
+      /* MIPS64 code always uses FR=1, thus the default is easy */
+      state->overall_fp_mode = VKI_FP_FR1;
+
+      /* Disallow access to the various FPXX & FP64 ABIs */
+      max_abi = VKI_MIPS_ABI_FP_SOFT;
+   } else {
+      /* Default to a mode capable of running code expecting FR=0 */
+
+      /* TODO: Should be changed during implementation of MIPS-R6 support.
+         state->overall_fp_mode = cpu_has_mips_r6 ? VKI_FP_FRE : VKI_FP_FR0; */
+      state->overall_fp_mode = VKI_FP_FR0;
+
+      /* Allow all ABIs we know about */
+      max_abi = VKI_MIPS_ABI_FP_64A;
+   }
+
+   if ((abi0 > max_abi && abi0 != VKI_MIPS_ABI_FP_UNKNOWN) ||
+       (abi1 > max_abi && abi1 != VKI_MIPS_ABI_FP_UNKNOWN))
+      return VKI_ELIBBAD;
+
+   /* It's time to determine the FPU mode requirements */
+   prog_req = (abi0 == VKI_MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi0];
+   interp_req = (abi1 == VKI_MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi1];
+
+   /* Check whether the program's and interp's ABIs have a matching FPU
+      mode requirement. */
+   prog_req.single = interp_req.single && prog_req.single;
+   prog_req.soft = interp_req.soft && prog_req.soft;
+   prog_req.fr1 = interp_req.fr1 && prog_req.fr1;
+   prog_req.frdefault = interp_req.frdefault && prog_req.frdefault;
+   prog_req.fre = interp_req.fre && prog_req.fre;
+
+   /* Determine the desired FPU mode
+
+      Decision making:
+
+      - We want FR_FRE if FRE=1 and both FR=1 and FR=0 are false. This
+        means that we have a combination of program and interpreter
+        that inherently require the hybrid FP mode.
+      - If FR1 and FRDEFAULT is true, that means we hit the any-abi or
+        fpxx case. This is because, in any-ABI (or no-ABI) we have no FPU
+        instructions so we don't care about the mode. We will simply use
+        the one preferred by the hardware. In fpxx case, that ABI can
+        handle both FR=1 and FR=0, so, again, we simply choose the one
+        preferred by the hardware. Next, if we only use single-precision
+        FPU instructions, and the default ABI FPU mode is not good
+        (ie single + any ABI combination), we set again the FPU mode to the
+        one is preferred by the hardware. Next, if we know that the code
+        will only use single-precision instructions, shown by single being
+        true but frdefault being false, then we again set the FPU mode to
+        the one that is preferred by the hardware.
+      - We want FP_FR1 if that's the only matching mode and the default one
+        is not good.
+      - Return with ELIBADD if we can't find a matching FPU mode. */
+   if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1)
+      state->overall_fp_mode = VKI_FP_FRE;
+   else if ((prog_req.fr1 && prog_req.frdefault) ||
+            (prog_req.single && !prog_req.frdefault))
+      state->overall_fp_mode = VEX_MIPS_HOST_FP_MODE(vai.hwcaps) ?
+                               VKI_FP_FR1 : VKI_FP_FR0;
+   else if (prog_req.fr1)
+      state->overall_fp_mode = VKI_FP_FR1;
+   else if (!prog_req.fre && !prog_req.frdefault &&
+            !prog_req.fr1 && !prog_req.single && !prog_req.soft)
+      return VKI_ELIBBAD;
+
+  /* TODO: Currently, Valgrind doesn't support FRE and doesn't support FR1
+     emulation on FR0 system, so in those cases we are forced to
+     reject the ELF. */
+     if ((state->overall_fp_mode == VKI_FP_FRE) ||
+         ((state->overall_fp_mode == VKI_FP_FR1) &&
+          !VEX_MIPS_HOST_FP_MODE(vai.hwcaps)))
+        return VKI_ELIBBAD;
+
+  return 0;
+}
+
+#   else
+
+static inline Int arch_elf_pt_proc(ESZ(Ehdr) *ehdr,
+                                   ESZ(Phdr) *phdr,
+                                   Int fd, Bool is_interpreter,
+                                   struct vki_arch_elf_state *state)
+{
+  /* Dummy implementation, always proceed */
+  return 0;
+}
+
+static inline Int arch_check_elf(ESZ(Ehdr) *ehdr,
+                                 Bool has_interpreter,
+                                 struct vki_arch_elf_state *state)
+{
+  /* Dummy implementation, always proceed */
+  return 0;
+}
+
+#   endif
+#endif
+
 static void check_mmap(SysRes res, Addr base, SizeT len)
 {
    if (sr_isError(res)) {
@@ -316,6 +547,10 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
    ESZ(Addr) thrptr_addr = 0;
 #  endif
 
+#  if defined(VGO_linux)
+   Int retval;
+#  endif
+
 #  if defined(HAVE_PIE)
    ebase = info->exe_base;
 #  endif
@@ -435,6 +670,15 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
             }
 #           endif
 
+#           if defined(VGO_linux)
+            if ((iph->p_type >= PT_LOPROC) && (iph->p_type <= PT_HIPROC)) {
+               retval = arch_elf_pt_proc(&interp->e, iph, intfd, True,
+                                         info->arch_elf_state);
+               if (retval)
+                 return retval;
+            }
+#           endif
+
             if (iph->p_type != PT_LOAD || iph->p_memsz == 0)
                continue;
             
@@ -481,12 +725,28 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
          break;
 #     endif
 
+#     if defined(VGO_linux)
+      case PT_LOPROC ... PT_HIPROC:
+         retval = arch_elf_pt_proc(&e->e, ph, fd, False, info->arch_elf_state);
+         if (retval)
+            return retval;
+         break;
+#     endif
+
       default:
          // do nothing
          break;
       }
    }
 
+#  if defined(VGO_linux)
+   retval = arch_check_elf(&e->e,
+                           interp != NULL,
+                           info->arch_elf_state);
+   if (retval)
+      return retval;
+#  endif
+
    if (info->phdr == 0)
       info->phdr = minaddr + ebase + e->e.e_phoff;
 
index 2943321b6f0679a133a9e25e0d7642469aa8b109..276ab36ddf5575e6309f85708dc188e71a0b21cb 100644 (file)
@@ -88,6 +88,8 @@ struct _IIFinaliseImageInfo {
    Addr  initial_client_IP;
    Addr  initial_client_TOC;
    UInt* client_auxv;
+   /* ------ Arch-specific ELF loading state ------ */
+   struct vki_arch_elf_state arch_elf_state;
 };
 
 /* ------------------------- Darwin ------------------------- */
index d9e459c59441e19e67a6431736aa41cd7b2938f3..b20506a52bd2ba1165bcaebbebe5d0f3d52c383d 100644 (file)
@@ -70,6 +70,11 @@ typedef
       Bool  ldsoexec;          // OUT: the program is the runtime linker itself
 #endif
 
+#if defined(VGO_linux)
+      // INOUT: architecture-specific ELF loading state
+      struct vki_arch_elf_state *arch_elf_state;
+#endif
+
       Addr entry;        // OUT: entrypoint in main executable
       Addr init_ip;      // OUT: address of first instruction to execute
       Addr brkbase;      // OUT: base address of brk segment
index 413e22ac2a3c67aa69b14ebd536ea3786514add4..810e27ec8b2eb3b8dac696ca4c93c9f3802eb8c5 100644 (file)
@@ -461,6 +461,9 @@ static inline Bool sr_EQ ( UInt sysno, SysRes sr1, SysRes sr2 ) {
 #define STATIC_ASSERT(x)  extern int VG_(VG_(VG_(unused)))[(x) ? 1 : -1] \
                                      __attribute__((unused))
 
+#define VG_MAX(a,b) ((a) > (b) ? a : b)
+#define VG_MIN(a,b) ((a) < (b) ? a : b)
+
 #endif /* __PUB_TOOL_BASICS_H */
 
 /*--------------------------------------------------------------------*/
index 224c5ed0e99474aca3c21172399a2dd5468b7237..47e89f9c000dfe366ecee5ff887541ffecd0840b 100644 (file)
@@ -4692,6 +4692,32 @@ struct vki_serial_struct {
        unsigned long   iomap_base;     /* cookie passed into ioremap */
 };
 
+//----------------------------------------------------------------------
+// From linux-3.19.0/fs/binfmt_elf.c
+//----------------------------------------------------------------------
+
+#if !defined(VKI_INIT_ARCH_ELF_STATE)
+   /* This structure is used to preserve architecture specific data during
+      the loading of an ELF file, throughout the checking of architecture
+      specific ELF headers & through to the point where the ELF load is
+      known to be proceeding. This implementation is a dummy for
+      architectures which require no specific state. */
+   struct vki_arch_elf_state {
+   };
+
+#  define VKI_INIT_ARCH_ELF_STATE { }
+
+#endif
+
+//----------------------------------------------------------------------
+// From linux-4.0/include/uapi/linux/prctl.h
+//----------------------------------------------------------------------
+
+#define VKI_PR_SET_FP_MODE          45
+#define VKI_PR_GET_FP_MODE          46
+# define VKI_PR_FP_MODE_FR          (1 << 0)     /* 64b FP registers  */
+# define VKI_PR_FP_MODE_FRE         (1 << 1)     /* 32b compatibility */
+
 #endif // __VKI_LINUX_H
 
 /*--------------------------------------------------------------------*/
index d3eec1742dbdb9fb247670321e59ba42260007a2..54d9a96864ebbe09ef93efa62477387aa9be63b8 100644 (file)
@@ -981,6 +981,14 @@ enum vki_sock_type {
 };
 #define ARCH_HAS_SOCKET_TYPES 1
 
+//----------------------------------------------------------------------
+// From linux-3.7.0/arch/mips/include/uapi/asm/errno.h
+//----------------------------------------------------------------------
+
+#define VKI_ELIBBAD      84  /* Accessing a corrupted shared library */
+#define VKI_EOPNOTSUPP   122 /* Operation not supported on transport
+                                 endpoint */
+
 //----------------------------------------------------------------------
 // From linux-3.13.0/include/asm/errno.h
 //----------------------------------------------------------------------
@@ -988,6 +996,65 @@ enum vki_sock_type {
 #define        VKI_ENOSYS       89  /* Function not implemented */
 #define        VKI_EOVERFLOW    79  /* Value too large for defined data type */
 
+//----------------------------------------------------------------------
+// From linux-3.14.0/arch/mips/include/asm/elf.h
+//----------------------------------------------------------------------
+
+#define VKI_EF_MIPS_FP64    0x00000200
+
+//----------------------------------------------------------------------
+// From linux-4.1.0/arch/mips/include/asm/elf.h
+//----------------------------------------------------------------------
+
+#define VKI_MIPS_ABI_FP_UNKNOWN (-1)
+#define VKI_MIPS_ABI_FP_ANY       0  /* FP ABI doesn't matter */
+#define VKI_MIPS_ABI_FP_DOUBLE    1  /* -mdouble-float */
+#define VKI_MIPS_ABI_FP_SINGLE    2  /* -msingle-float */
+#define VKI_MIPS_ABI_FP_SOFT      3  /* -msoft-float */
+#define VKI_MIPS_ABI_FP_OLD_64    4  /* -mips32r2 -mfp64 */
+#define VKI_MIPS_ABI_FP_XX        5  /* -mfpxx */
+#define VKI_MIPS_ABI_FP_64        6  /* -mips32r2 -mfp64 */
+#define VKI_MIPS_ABI_FP_64A       7  /* -mips32r2 -mfp64 -mno-odd-spreg */
+
+struct vki_arch_elf_state {
+   int fp_abi;
+   int interp_fp_abi;
+   int overall_fp_mode;
+};
+
+#define VKI_INIT_ARCH_ELF_STATE {             \
+   .fp_abi = VKI_MIPS_ABI_FP_UNKNOWN,         \
+   .interp_fp_abi = VKI_MIPS_ABI_FP_UNKNOWN,  \
+   .overall_fp_mode = -1,                     \
+}
+
+struct vki_mips_elf_abiflags_v0 {
+   vki_u16 version;     /* Version of flags structure */
+   vki_u8  isa_level;   /* The level of the ISA: 1-5, 32, 64 */
+   vki_u8  isa_rev;     /* The revision of ISA: 0 for MIPS V and below,
+                           1-n otherwise */
+   vki_u8  gpr_size;    /* The size of general purpose registers */
+   vki_u8  cpr1_size;   /* The size of co-processor 1 registers */
+   vki_u8  cpr2_size;   /* The size of co-processor 2 registers */
+   vki_u8  fp_abi;      /* The floating-point ABI */
+   vki_u32 isa_ext;     /* Mask of processor-specific extensions */
+   vki_u32 ases;        /* Mask of ASEs used */
+   vki_u32 flags1;      /* Mask of general flags */
+   vki_u32 flags2;
+};
+
+#define VKI_PT_MIPS_ABIFLAGS   0x70000003
+
+//----------------------------------------------------------------------
+// From linux-4.1.0/arch/mips/kernel/elf.c
+//----------------------------------------------------------------------
+
+enum {
+   VKI_FP_FRE,
+   VKI_FP_FR0,
+   VKI_FP_FR1,
+};
+
 #endif // __VKI_MIPS32_LINUX_H
 
 /*--------------------------------------------------------------------*/