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

View file

@ -201,7 +201,6 @@ struct mips_elf_abiflags_v0 {
uint32_t flags2; uint32_t flags2;
}; };
#ifndef ELF_ARCH
/* ELF register definitions */ /* ELF register definitions */
#define ELF_NGREG 45 #define ELF_NGREG 45
#define ELF_NFPREG 33 #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. * 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. * 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. * 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. * 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 #endif
#define ELF_ARCH EM_MIPS #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 * 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 * 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 #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; \ int __res = 1; \
struct elfhdr *__h = (hdr); \ struct elfhdr *__h = (hdr); \
@ -288,21 +286,26 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
__res = 0; \ __res = 0; \
if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ if (__h->e_ident[EI_CLASS] != ELFCLASS32) \
__res = 0; \ __res = 0; \
if ((__h->e_flags & EF_MIPS_ABI2) != 0) \ if ((__h->e_flags & EF_MIPS_ABI2) != 0) { \
__res = 0; \ if (!IS_ENABLED(CONFIG_MIPS32_N32) || \
if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ (__h->e_flags & EF_MIPS_ABI)) \
((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ __res = 0; \
__res = 0; \ } else { \
if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \ if (IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_MIPS32_O32)) \
__res = 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; \
} \
__res; \ __res; \
}) })
/* /*
* Return non-zero if HDR identifies an n64 ELF binary. * Return non-zero if HDR identifies an n64 ELF binary.
*/ */
#define elfn64_check_arch(hdr) \ #define elf64_check_arch(hdr) \
({ \ ({ \
int __res = 1; \ int __res = 1; \
struct elfhdr *__h = (hdr); \ struct elfhdr *__h = (hdr); \
@ -315,25 +318,6 @@ void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
__res; \ __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; struct mips_abi;
extern struct mips_abi 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_32BIT) += scall32-o32.o
obj-$(CONFIG_64BIT) += scall64-n64.o obj-$(CONFIG_64BIT) += scall64-n64.o
obj-$(CONFIG_MIPS32_COMPAT) += linux32.o ptrace32.o signal32.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_N32) += scall64-n32.o signal_n32.o
obj-$(CONFIG_MIPS32_O32) += binfmt_elfo32.o scall64-o32.o signal_o32.o obj-$(CONFIG_MIPS32_O32) += scall64-o32.o signal_o32.o
obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_PROC_FS) += proc.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/unistd.h>
#include <asm/war.h> #include <asm/war.h>
#ifndef CONFIG_BINFMT_ELF32 #ifndef CONFIG_MIPS32_COMPAT
/* Neither O32 nor N32, so define handle_sys here */ /* Neither O32 nor N32, so define handle_sys here */
#define handle_sys64 handle_sys #define handle_sys64 handle_sys
#endif #endif