From: Petar Jovanovic Date: Wed, 10 Aug 2016 14:38:10 +0000 (+0000) Subject: mips32: add support for FPXX mode X-Git-Tag: svn/VALGRIND_3_12_0~89 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=030cea68c804abc61facd95e894a1c8b2418904f;p=thirdparty%2Fvalgrind.git mips32: add support for FPXX mode 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 Related VEX change: r3243. This implements BZ#366079. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15934 --- diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c index 7abcea591f..887f745195 100644 --- a/coregrind/m_initimg/initimg-linux.c +++ b/coregrind/m_initimg/initimg-linux.c @@ -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 diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index 0384f873d0..8215c8024d 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -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; diff --git a/coregrind/m_syswrap/syswrap-mips32-linux.c b/coregrind/m_syswrap/syswrap-mips32-linux.c index 7a4a857e2c..d75583063a 100644 --- a/coregrind/m_syswrap/syswrap-mips32-linux.c +++ b/coregrind/m_syswrap/syswrap-mips32-linux.c @@ -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 diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c index 62680cb9bd..2d6d3bad4b 100644 --- a/coregrind/m_translate.c +++ b/coregrind/m_translate.c @@ -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; diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c index a9871501fd..e6f6bb1a4c 100644 --- a/coregrind/m_ume/elf.c +++ b/coregrind/m_ume/elf.c @@ -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; diff --git a/coregrind/pub_core_initimg.h b/coregrind/pub_core_initimg.h index 2943321b6f..276ab36ddf 100644 --- a/coregrind/pub_core_initimg.h +++ b/coregrind/pub_core_initimg.h @@ -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 ------------------------- */ diff --git a/coregrind/pub_core_ume.h b/coregrind/pub_core_ume.h index d9e459c594..b20506a52b 100644 --- a/coregrind/pub_core_ume.h +++ b/coregrind/pub_core_ume.h @@ -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 diff --git a/include/pub_tool_basics.h b/include/pub_tool_basics.h index 413e22ac2a..810e27ec8b 100644 --- a/include/pub_tool_basics.h +++ b/include/pub_tool_basics.h @@ -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 */ /*--------------------------------------------------------------------*/ diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h index 224c5ed0e9..47e89f9c00 100644 --- a/include/vki/vki-linux.h +++ b/include/vki/vki-linux.h @@ -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 /*--------------------------------------------------------------------*/ diff --git a/include/vki/vki-mips32-linux.h b/include/vki/vki-mips32-linux.h index d3eec1742d..54d9a96864 100644 --- a/include/vki/vki-mips32-linux.h +++ b/include/vki/vki-mips32-linux.h @@ -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 /*--------------------------------------------------------------------*/