mips compat: switch to compat_binfmt_elf.c

Like amd64, mips has two 32bit ABIs - o32 and n32.  Unlike amd64,
it does not use compat_binfmt_elf.c for either of those; each
of those ABIs has a binfmt handler of its own, both very similar
to fs/compat_binfmt_elf.c.  And the same technics as we use on
amd64 can be used to make fs/compat_binfmt_elf.c handle both.
	* merge elfo32_check_arch() with elfn32_check_arch(),
make that serve as compat_elf_check_arch().  Note that
SET_PERSONALITY2() is already the same for all ABI variants -
it looks at the elf header to choose the flags to set.
	* add asm/elfcore-compat.h, using the bigger (n32) variant
of elf32_prstatus as compat_elf_prstatus there.
	* make PRSTATUS_SIZE() and SET_PR_FPVALID() choose the
right layout, same as done for amd64.  test_thread_flag(TIF_32BIT_REGS)
is used as the predicate.

Voila - we are rid of binfmt_elf{n,o}32.c; fs/compat_binfmt_elf.c is
used, same as for all other ELF-supporting 64bit architectures that
need 32bit compat.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2020-06-14 00:18:12 -04:00
parent 2fb33bec05
commit 0bb87f051e
7 changed files with 54 additions and 174 deletions

View File

@ -92,6 +92,7 @@ config MIPS
select SET_FS
select SYSCTL_EXCEPTION_TRACE
select VIRT_TO_BUS
select ARCH_HAS_ELFCORE_COMPAT
config MIPS_FIXUP_BIGPHYS_ADDR
bool
@ -3277,6 +3278,7 @@ config MIPS32_O32
select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT
select MIPS32_COMPAT
select COMPAT_BINFMT_ELF
select SYSVIPC_COMPAT if SYSVIPC
help
Select this option if you want to run o32 binaries. These are pure
@ -3290,6 +3292,7 @@ config MIPS32_N32
depends on 64BIT
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select COMPAT
select COMPAT_BINFMT_ELF
select MIPS32_COMPAT
select SYSVIPC_COMPAT if SYSVIPC
help
@ -3300,11 +3303,6 @@ config MIPS32_N32
If unsure, say N.
config BINFMT_ELF32
bool
default y if MIPS32_O32 || MIPS32_N32
select ELFCORE
menu "Power management options"
config ARCH_HIBERNATION_POSSIBLE

View File

@ -201,7 +201,6 @@ struct mips_elf_abiflags_v0 {
uint32_t flags2;
};
#ifndef ELF_ARCH
/* ELF register definitions */
#define ELF_NGREG 45
#define ELF_NFPREG 33
@ -219,7 +218,7 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch elfo32_check_arch
#define elf_check_arch elf32_check_arch
/*
* These are used to set parameters in the core dumps.
@ -235,7 +234,8 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch elfn64_check_arch
#define elf_check_arch elf64_check_arch
#define compat_elf_check_arch elf32_check_arch
/*
* These are used to set parameters in the core dumps.
@ -257,8 +257,6 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
#endif
#define ELF_ARCH EM_MIPS
#endif /* !defined(ELF_ARCH) */
/*
* In order to be sure that we don't attempt to execute an O32 binary which
* requires 64 bit FP (FR=1) on a system which does not support it we refuse
@ -277,9 +275,9 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
#define vmcore_elf64_check_arch mips_elf_check_machine
/*
* Return non-zero if HDR identifies an o32 ELF binary.
* Return non-zero if HDR identifies an o32 or n32 ELF binary.
*/
#define elfo32_check_arch(hdr) \
#define elf32_check_arch(hdr) \
({ \
int __res = 1; \
struct elfhdr *__h = (hdr); \
@ -288,21 +286,26 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
__res = 0; \
if (__h->e_ident[EI_CLASS] != ELFCLASS32) \
__res = 0; \
if ((__h->e_flags & EF_MIPS_ABI2) != 0) \
__res = 0; \
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
__res = 0; \
if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
__res = 0; \
\
if ((__h->e_flags & EF_MIPS_ABI2) != 0) { \
if (!IS_ENABLED(CONFIG_MIPS32_N32) || \
(__h->e_flags & EF_MIPS_ABI)) \
__res = 0; \
} else { \
if (IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_MIPS32_O32)) \
__res = 0; \
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \
__res = 0; \
if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \
__res = 0; \
} \
__res; \
})
/*
* Return non-zero if HDR identifies an n64 ELF binary.
*/
#define elfn64_check_arch(hdr) \
#define elf64_check_arch(hdr) \
({ \
int __res = 1; \
struct elfhdr *__h = (hdr); \
@ -315,25 +318,6 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
__res; \
})
/*
* Return non-zero if HDR identifies an n32 ELF binary.
*/
#define elfn32_check_arch(hdr) \
({ \
int __res = 1; \
struct elfhdr *__h = (hdr); \
\
if (!mips_elf_check_machine(__h)) \
__res = 0; \
if (__h->e_ident[EI_CLASS] != ELFCLASS32) \
__res = 0; \
if (((__h->e_flags & EF_MIPS_ABI2) == 0) || \
((__h->e_flags & EF_MIPS_ABI) != 0)) \
__res = 0; \
\
__res; \
})
struct mips_abi;
extern struct mips_abi mips_abi;

View File

@ -0,0 +1,29 @@
#ifndef _ASM_MIPS_ELFCORE_COMPAT_H
#define _ASM_MIPS_ELFCORE_COMPAT_H
/*
* On mips we have two 32bit ABIs - o32 and n32. The latter
* has bigger registers, so we use it for compat_elf_regset_t.
* The former uses o32_elf_prstatus and PRSTATUS_SIZE/SET_PR_FPVALID
* are used to choose the size and location of ->pr_fpvalid of
* the layout actually used.
*/
typedef elf_gregset_t compat_elf_gregset_t;
struct o32_elf_prstatus
{
struct compat_elf_prstatus_common common;
unsigned int pr_reg[ELF_NGREG];
compat_int_t pr_fpvalid;
};
#define PRSTATUS_SIZE \
(!test_thread_flag(TIF_32BIT_REGS) \
? sizeof(struct compat_elf_prstatus) \
: sizeof(struct o32_elf_prstatus))
#define SET_PR_FPVALID(S) \
(*(!test_thread_flag(TIF_32BIT_REGS) \
? &(S)->pr_fpvalid \
: &((struct o32_elf_prstatus *)(S))->pr_fpvalid) = 1)
#endif

View File

@ -80,8 +80,8 @@ obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_32BIT) += scall32-o32.o
obj-$(CONFIG_64BIT) += scall64-n64.o
obj-$(CONFIG_MIPS32_COMPAT) += linux32.o ptrace32.o signal32.o
obj-$(CONFIG_MIPS32_N32) += binfmt_elfn32.o scall64-n32.o signal_n32.o
obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o signal_o32.o
obj-$(CONFIG_MIPS32_N32) += scall64-n32.o signal_n32.o
obj-$(CONFIG_MIPS32_O32) += scall64-o32.o signal_o32.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_PROC_FS) += proc.o

View File

@ -1,65 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Support for n32 Linux/MIPS ELF binaries.
* Author: Ralf Baechle (ralf@linux-mips.org)
*
* Copyright (C) 1999, 2001 Ralf Baechle
* Copyright (C) 1999, 2001 Silicon Graphics, Inc.
*
* Heavily inspired by the 32-bit Sparc compat code which is
* Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
* Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#define ELF_ARCH EM_MIPS
#define ELF_CLASS ELFCLASS32
#ifdef __MIPSEB__
#define ELF_DATA ELFDATA2MSB;
#else /* __MIPSEL__ */
#define ELF_DATA ELFDATA2LSB;
#endif
/* ELF register definitions */
#define ELF_NGREG 45
#define ELF_NFPREG 33
typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch elfn32_check_arch
#include <asm/processor.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
#include <linux/math64.h>
#include <linux/elfcore-compat.h>
#define elf_prstatus elf_prstatus32
#define elf_prstatus_common compat_elf_prstatus_common
struct elf_prstatus32
{
struct compat_elf_prstatus_common common;
elf_gregset_t pr_reg; /* GP registers */
int pr_fpvalid; /* True if math co-processor being used. */
};
#define elf_prpsinfo compat_elf_prpsinfo
#define init_elf_binfmt init_elfn32_binfmt
#undef ns_to_kernel_old_timeval
#define ns_to_kernel_old_timeval ns_to_old_timeval32
/*
* Some data types as stored in coredump.
*/
#define user_long_t compat_long_t
#define user_siginfo_t compat_siginfo_t
#define copy_siginfo_to_external copy_siginfo_to_external32
#include "../../../fs/binfmt_elf.c"

View File

@ -1,66 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Support for o32 Linux/MIPS ELF binaries.
* Author: Ralf Baechle (ralf@linux-mips.org)
*
* Copyright (C) 1999, 2001 Ralf Baechle
* Copyright (C) 1999, 2001 Silicon Graphics, Inc.
*
* Heavily inspired by the 32-bit Sparc compat code which is
* Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
* Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#define ELF_ARCH EM_MIPS
#define ELF_CLASS ELFCLASS32
#ifdef __MIPSEB__
#define ELF_DATA ELFDATA2MSB;
#else /* __MIPSEL__ */
#define ELF_DATA ELFDATA2LSB;
#endif
/* ELF register definitions */
#define ELF_NGREG 45
#define ELF_NFPREG 33
typedef unsigned int elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch elfo32_check_arch
#include <asm/processor.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
#include <linux/math64.h>
#include <linux/elfcore-compat.h>
#define elf_prstatus elf_prstatus32
#define elf_prstatus_common compat_elf_prstatus_common
struct elf_prstatus32
{
struct compat_elf_prstatus_common common;
elf_gregset_t pr_reg; /* GP registers */
int pr_fpvalid; /* True if math co-processor being used. */
};
#define elf_prpsinfo compat_elf_prpsinfo
#define init_elf_binfmt init_elf32_binfmt
#undef ns_to_kernel_old_timeval
#define ns_to_kernel_old_timeval ns_to_old_timeval32
/*
* Some data types as stored in coredump.
*/
#define user_long_t compat_long_t
#define user_siginfo_t compat_siginfo_t
#define copy_siginfo_to_external copy_siginfo_to_external32
#include "../../../fs/binfmt_elf.c"

View File

@ -20,7 +20,7 @@
#include <asm/unistd.h>
#include <asm/war.h>
#ifndef CONFIG_BINFMT_ELF32
#ifndef CONFIG_MIPS32_COMPAT
/* Neither O32 nor N32, so define handle_sys here */
#define handle_sys64 handle_sys
#endif