Commit 398364a3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu

Pull m68nommu updates from Greg Ungerer:
 "A series of cleanups for the FLAT format binary loader, binfmt_flat,
  from Christoph.

  The end goal is to support no-MMU on RISC-V, and the last patch
  enables that"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu:
  riscv: add binfmt_flat support
  binfmt_flat: don't offset the data start
  binfmt_flat: move the MAX_SHARED_LIBS definition to binfmt_flat.c
  binfmt_flat: remove the persistent argument from flat_get_addr_from_rp
  binfmt_flat: provide an asm-generic/flat.h
  binfmt_flat: make support for old format binaries optional
  binfmt_flat: add a ARCH_HAS_BINFMT_FLAT option
  binfmt_flat: add endianess annotations
  binfmt_flat: use fixed size type for the on-disk format
  binfmt_flat: consolidate two version of flat_v2_reloc_t
  binfmt_flat: remove the unused OLD_FLAT_FLAG_RAM definition
  binfmt_flat: remove the uapi <linux/flat.h> header
  binfmt_flat: replace flat_argvp_envp_on_stack with a Kconfig variable
  binfmt_flat: remove flat_old_ram_flag
  binfmt_flat: provide a default version of flat_get_relocate_addr
  binfmt_flat: remove flat_set_persistent
  binfmt_flat: remove flat_reloc_valid
parents d2b6b4c8 ad97f9df
...@@ -4,6 +4,7 @@ config ARM ...@@ -4,6 +4,7 @@ config ARM
default y default y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_CLOCKSOURCE_DATA select ARCH_CLOCKSOURCE_DATA
select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VIRTUAL if MMU
select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_ELF_RANDOMIZE
...@@ -30,6 +31,7 @@ config ARM ...@@ -30,6 +31,7 @@ config ARM
select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
select BUILDTIME_EXTABLE_SORT if MMU select BUILDTIME_EXTABLE_SORT if MMU
select CLONE_BACKWARDS select CLONE_BACKWARDS
select CPU_PM if SUSPEND || CPU_IDLE select CPU_PM if SUSPEND || CPU_IDLE
......
...@@ -5,6 +5,7 @@ generic-y += early_ioremap.h ...@@ -5,6 +5,7 @@ generic-y += early_ioremap.h
generic-y += emergency-restart.h generic-y += emergency-restart.h
generic-y += exec.h generic-y += exec.h
generic-y += extable.h generic-y += extable.h
generic-y += flat.h
generic-y += irq_regs.h generic-y += irq_regs.h
generic-y += kdebug.h generic-y += kdebug.h
generic-y += local.h generic-y += local.h
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
config C6X config C6X
def_bool y def_bool y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
......
...@@ -4,11 +4,8 @@ ...@@ -4,11 +4,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define flat_argvp_envp_on_stack() 0
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent) u32 *addr)
{ {
*addr = get_unaligned((__force u32 *)rp); *addr = get_unaligned((__force u32 *)rp);
return 0; return 0;
...@@ -18,7 +15,5 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel) ...@@ -18,7 +15,5 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
put_unaligned(addr, (__force u32 *)rp); put_unaligned(addr, (__force u32 *)rp);
return 0; return 0;
} }
#define flat_get_relocate_addr(rel) (rel)
#define flat_set_persistent(relval, p) 0
#endif /* __ASM_C6X_FLAT_H */ #endif /* __ASM_C6X_FLAT_H */
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
config H8300 config H8300
def_bool y def_bool y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT
select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
select BINFMT_FLAT_OLD_ALWAYS_RAM
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64
select HAVE_UID16 select HAVE_UID16
select VIRT_TO_BUS select VIRT_TO_BUS
......
...@@ -8,11 +8,6 @@ ...@@ -8,11 +8,6 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define flat_argvp_envp_on_stack() 1
#define flat_old_ram_flag(flags) 1
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
#define flat_set_persistent(relval, p) 0
/* /*
* on the H8 a couple of the relocations have an instruction in the * on the H8 a couple of the relocations have an instruction in the
* top byte. As there can only be 24bits of address space, we just * top byte. As there can only be 24bits of address space, we just
...@@ -22,7 +17,7 @@ ...@@ -22,7 +17,7 @@
#define flat_get_relocate_addr(rel) (rel & ~0x00000001) #define flat_get_relocate_addr(rel) (rel & ~0x00000001)
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent) u32 *addr)
{ {
u32 val = get_unaligned((__force u32 *)rp); u32 val = get_unaligned((__force u32 *)rp);
if (!(flags & FLAT_FLAG_GOTPIC)) if (!(flags & FLAT_FLAG_GOTPIC))
......
...@@ -3,12 +3,14 @@ config M68K ...@@ -3,12 +3,14 @@ config M68K
bool bool
default y default y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_DMA_MMAP_PGPROT if MMU && !COLDFIRE select ARCH_HAS_DMA_MMAP_PGPROT if MMU && !COLDFIRE
select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
select ARCH_MIGHT_HAVE_PC_PARPORT if ISA select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
select ARCH_NO_COHERENT_DMA_MMAP if !MMU select ARCH_NO_COHERENT_DMA_MMAP if !MMU
select ARCH_NO_PREEMPT if !COLDFIRE select ARCH_NO_PREEMPT if !COLDFIRE
select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
select DMA_DIRECT_REMAP if HAS_DMA && MMU && !COLDFIRE select DMA_DIRECT_REMAP if HAS_DMA && MMU && !COLDFIRE
select HAVE_IDE select HAVE_IDE
select HAVE_AOUT if MMU select HAVE_AOUT if MMU
......
...@@ -6,35 +6,7 @@ ...@@ -6,35 +6,7 @@
#ifndef __M68KNOMMU_FLAT_H__ #ifndef __M68KNOMMU_FLAT_H__
#define __M68KNOMMU_FLAT_H__ #define __M68KNOMMU_FLAT_H__
#include <linux/uaccess.h> #include <asm-generic/flat.h>
#define flat_argvp_envp_on_stack() 1
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent)
{
#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
return copy_from_user(addr, rp, 4) ? -EFAULT : 0;
#else
return get_user(*addr, rp);
#endif
}
static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
{
#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
return copy_to_user(rp, &addr, 4) ? -EFAULT : 0;
#else
return put_user(addr, rp);
#endif
}
#define flat_get_relocate_addr(rel) (rel)
static inline int flat_set_persistent(u32 relval, u32 *persistent)
{
return 0;
}
#define FLAT_PLAT_INIT(regs) \ #define FLAT_PLAT_INIT(regs) \
do { \ do { \
......
...@@ -3,6 +3,7 @@ config MICROBLAZE ...@@ -3,6 +3,7 @@ config MICROBLAZE
def_bool y def_bool y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_NO_SWAP select ARCH_NO_SWAP
select ARCH_HAS_BINFMT_FLAT if !MMU
select ARCH_HAS_DMA_COHERENT_TO_PFN if MMU select ARCH_HAS_DMA_COHERENT_TO_PFN if MMU
select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_CPU
......
...@@ -13,11 +13,6 @@ ...@@ -13,11 +13,6 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define flat_argvp_envp_on_stack() 0
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
#define flat_set_persistent(relval, p) 0
/* /*
* Microblaze works a little differently from other arches, because * Microblaze works a little differently from other arches, because
* of the MICROBLAZE_64 reloc type. Here, a 32 bit address is split * of the MICROBLAZE_64 reloc type. Here, a 32 bit address is split
...@@ -33,7 +28,7 @@ ...@@ -33,7 +28,7 @@
*/ */
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent) u32 *addr)
{ {
u32 *p = (__force u32 *)rp; u32 *p = (__force u32 *)rp;
......
...@@ -17,6 +17,7 @@ config RISCV ...@@ -17,6 +17,7 @@ config RISCV
select OF select OF
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select OF_IRQ select OF_IRQ
select ARCH_HAS_BINFMT_FLAT
select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_FRAME_POINTERS
select CLONE_BACKWARDS select CLONE_BACKWARDS
select COMMON_CLK select COMMON_CLK
......
...@@ -5,6 +5,7 @@ generic-y += compat.h ...@@ -5,6 +5,7 @@ generic-y += compat.h
generic-y += device.h generic-y += device.h
generic-y += div64.h generic-y += div64.h
generic-y += extable.h generic-y += extable.h
generic-y += flat.h
generic-y += dma.h generic-y += dma.h
generic-y += dma-contiguous.h generic-y += dma-contiguous.h
generic-y += dma-mapping.h generic-y += dma-mapping.h
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
config SUPERH config SUPERH
def_bool y def_bool y
select ARCH_HAS_BINFMT_FLAT if !MMU
select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
......
...@@ -11,11 +11,8 @@ ...@@ -11,11 +11,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define flat_argvp_envp_on_stack() 0
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent) u32 *addr)
{ {
*addr = get_unaligned((__force u32 *)rp); *addr = get_unaligned((__force u32 *)rp);
return 0; return 0;
...@@ -25,8 +22,6 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel) ...@@ -25,8 +22,6 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
put_unaligned(addr, (__force u32 *)rp); put_unaligned(addr, (__force u32 *)rp);
return 0; return 0;
} }
#define flat_get_relocate_addr(rel) (rel)
#define flat_set_persistent(relval, p) ({ (void)p; 0; })
#define FLAT_PLAT_INIT(_r) \ #define FLAT_PLAT_INIT(_r) \
do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \ do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
config XTENSA config XTENSA
def_bool y def_bool y
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT if !MMU
select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select ARCH_NO_COHERENT_DMA_MMAP if !MMU select ARCH_NO_COHERENT_DMA_MMAP if !MMU
......
...@@ -4,11 +4,8 @@ ...@@ -4,11 +4,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define flat_argvp_envp_on_stack() 0
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent) u32 *addr)
{ {
*addr = get_unaligned((__force u32 *)rp); *addr = get_unaligned((__force u32 *)rp);
return 0; return 0;
...@@ -18,7 +15,5 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel) ...@@ -18,7 +15,5 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
put_unaligned(addr, (__force u32 *)rp); put_unaligned(addr, (__force u32 *)rp);
return 0; return 0;
} }
#define flat_get_relocate_addr(rel) (rel)
#define flat_set_persistent(relval, p) 0
#endif /* __ASM_XTENSA_FLAT_H */ #endif /* __ASM_XTENSA_FLAT_H */
...@@ -91,12 +91,28 @@ config BINFMT_SCRIPT ...@@ -91,12 +91,28 @@ config BINFMT_SCRIPT
Most systems will not boot if you say M or N here. If unsure, say Y. Most systems will not boot if you say M or N here. If unsure, say Y.
config ARCH_HAS_BINFMT_FLAT
bool
config BINFMT_FLAT config BINFMT_FLAT
bool "Kernel support for flat binaries" bool "Kernel support for flat binaries"
depends on !MMU || ARM || M68K depends on ARCH_HAS_BINFMT_FLAT
help help
Support uClinux FLAT format binaries. Support uClinux FLAT format binaries.
config BINFMT_FLAT_ARGVP_ENVP_ON_STACK
bool
config BINFMT_FLAT_OLD_ALWAYS_RAM
bool
config BINFMT_FLAT_OLD
bool "Enable support for very old legacy flat binaries"
depends on BINFMT_FLAT
help
Support decade old uClinux FLAT format binaries. Unless you know
you have some of those say N here.
config BINFMT_ZFLAT config BINFMT_ZFLAT
bool "Enable ZFLAT support" bool "Enable ZFLAT support"
depends on BINFMT_FLAT depends on BINFMT_FLAT
......
...@@ -42,6 +42,11 @@ ...@@ -42,6 +42,11 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/flat.h>
#ifndef flat_get_relocate_addr
#define flat_get_relocate_addr(rel) (rel)
#endif
/****************************************************************************/ /****************************************************************************/
...@@ -63,6 +68,12 @@ ...@@ -63,6 +68,12 @@
#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ #define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */
#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */
#ifdef CONFIG_BINFMT_SHARED_FLAT
#define MAX_SHARED_LIBS (4)
#else
#define MAX_SHARED_LIBS (1)
#endif
struct lib_info { struct lib_info {
struct { struct {
unsigned long start_code; /* Start of text segment */ unsigned long start_code; /* Start of text segment */
...@@ -120,14 +131,15 @@ static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start ...@@ -120,14 +131,15 @@ static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start
sp -= bprm->envc + 1; sp -= bprm->envc + 1;
sp -= bprm->argc + 1; sp -= bprm->argc + 1;
sp -= flat_argvp_envp_on_stack() ? 2 : 0; if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK))
sp -= 2; /* argvp + envp */
sp -= 1; /* &argc */ sp -= 1; /* &argc */
current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN; current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
sp = (unsigned long __user *)current->mm->start_stack; sp = (unsigned long __user *)current->mm->start_stack;
__put_user(bprm->argc, sp++); __put_user(bprm->argc, sp++);
if (flat_argvp_envp_on_stack()) { if (IS_ENABLED(CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK)) {
unsigned long argv, envp; unsigned long argv, envp;
argv = (unsigned long)(sp + 2); argv = (unsigned long)(sp + 2);
envp = (unsigned long)(sp + 2 + bprm->argc + 1); envp = (unsigned long)(sp + 2 + bprm->argc + 1);
...@@ -345,7 +357,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) ...@@ -345,7 +357,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
start_code = p->lib_list[id].start_code; start_code = p->lib_list[id].start_code;
text_len = p->lib_list[id].text_len; text_len = p->lib_list[id].text_len;
if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { if (r > start_brk - start_data + text_len) {
pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)", pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
r, start_brk-start_data+text_len, text_len); r, start_brk-start_data+text_len, text_len);
goto failed; goto failed;
...@@ -368,6 +380,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) ...@@ -368,6 +380,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
/****************************************************************************/ /****************************************************************************/
#ifdef CONFIG_BINFMT_FLAT_OLD
static void old_reloc(unsigned long rl) static void old_reloc(unsigned long rl)
{ {
static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
...@@ -405,6 +418,7 @@ static void old_reloc(unsigned long rl) ...@@ -405,6 +418,7 @@ static void old_reloc(unsigned long rl)
pr_debug("Relocation became %lx\n", val); pr_debug("Relocation became %lx\n", val);
} }
#endif /* CONFIG_BINFMT_FLAT_OLD */
/****************************************************************************/ /****************************************************************************/
...@@ -415,7 +429,8 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -415,7 +429,8 @@ static int load_flat_file(struct linux_binprm *bprm,
unsigned long textpos, datapos, realdatastart; unsigned long textpos, datapos, realdatastart;
u32 text_len, data_len, bss_len, stack_len, full_data, flags; u32 text_len, data_len, bss_len, stack_len, full_data, flags;
unsigned long len, memp, memp_size, extra, rlim; unsigned long len, memp, memp_size, extra, rlim;
u32 __user *reloc, *rp; __be32 __user *reloc;
u32 __user *rp;
struct inode *inode; struct inode *inode;
int i, rev, relocs; int i, rev, relocs;
loff_t fpos; loff_t fpos;
...@@ -454,6 +469,7 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -454,6 +469,7 @@ static int load_flat_file(struct linux_binprm *bprm,
if (flags & FLAT_FLAG_KTRACE) if (flags & FLAT_FLAG_KTRACE)
pr_info("Loading file: %s\n", bprm->filename); pr_info("Loading file: %s\n", bprm->filename);
#ifdef CONFIG_BINFMT_FLAT_OLD
if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n", pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n",
rev, FLAT_VERSION, OLD_FLAT_VERSION); rev, FLAT_VERSION, OLD_FLAT_VERSION);
...@@ -469,6 +485,23 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -469,6 +485,23 @@ static int load_flat_file(struct linux_binprm *bprm,
goto err; goto err;
} }
/*
* fix up the flags for the older format, there were all kinds
* of endian hacks, this only works for the simple cases
*/
if (rev == OLD_FLAT_VERSION &&
(flags || IS_ENABLED(CONFIG_BINFMT_FLAT_OLD_ALWAYS_RAM)))
flags = FLAT_FLAG_RAM;
#else /* CONFIG_BINFMT_FLAT_OLD */
if (rev != FLAT_VERSION) {
pr_err("bad flat file version 0x%x (supported 0x%lx)\n",
rev, FLAT_VERSION);
ret = -ENOEXEC;
goto err;
}
#endif /* !CONFIG_BINFMT_FLAT_OLD */
/* /*
* Make sure the header params are sane. * Make sure the header params are sane.
* 28 bits (256 MB) is way more than reasonable in this case. * 28 bits (256 MB) is way more than reasonable in this case.
...@@ -480,13 +513,6 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -480,13 +513,6 @@ static int load_flat_file(struct linux_binprm *bprm,
goto err; goto err;
} }
/*
* fix up the flags for the older format, there were all kinds
* of endian hacks, this only works for the simple cases
*/
if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
flags = FLAT_FLAG_RAM;
#ifndef CONFIG_BINFMT_ZFLAT #ifndef CONFIG_BINFMT_ZFLAT
if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
pr_err("Support for ZFLAT executables is not enabled.\n"); pr_err("Support for ZFLAT executables is not enabled.\n");
...@@ -547,7 +573,7 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -547,7 +573,7 @@ static int load_flat_file(struct linux_binprm *bprm,
goto err; goto err;
} }
len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); len = data_len + extra;
len = PAGE_ALIGN(len); len = PAGE_ALIGN(len);
realdatastart = vm_mmap(NULL, 0, len, realdatastart = vm_mmap(NULL, 0, len,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
...@@ -561,9 +587,7 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -561,9 +587,7 @@ static int load_flat_file(struct linux_binprm *bprm,
vm_munmap(textpos, text_len); vm_munmap(textpos, text_len);
goto err; goto err;
} }
datapos = ALIGN(realdatastart + datapos = ALIGN(realdatastart, FLAT_DATA_ALIGN);
MAX_SHARED_LIBS * sizeof(unsigned long),
FLAT_DATA_ALIGN);
pr_debug("Allocated data+bss+stack (%u bytes): %lx\n", pr_debug("Allocated data+bss+stack (%u bytes): %lx\n",
data_len + bss_len + stack_len, datapos); data_len + bss_len + stack_len, datapos);
...@@ -587,13 +611,13 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -587,13 +611,13 @@ static int load_flat_file(struct linux_binprm *bprm,
goto err; goto err;
} }
reloc = (u32 __user *) reloc = (__be32 __user *)
(datapos + (ntohl(hdr->reloc_start) - text_len)); (datapos + (ntohl(hdr->reloc_start) - text_len));
memp = realdatastart; memp = realdatastart;
memp_size = len; memp_size = len;
} else { } else {
len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(u32); len = text_len + data_len + extra;
len = PAGE_ALIGN(len); len = PAGE_ALIGN(len);
textpos = vm_mmap(NULL, 0, len, textpos = vm_mmap(NULL, 0, len,
PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
...@@ -608,11 +632,9 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -608,11 +632,9 @@ static int load_flat_file(struct linux_binprm *bprm,
} }
realdatastart = textpos + ntohl(hdr->data_start); realdatastart = textpos + ntohl(hdr->data_start);
datapos = ALIGN(realdatastart + datapos = ALIGN(realdatastart, FLAT_DATA_ALIGN);
MAX_SHARED_LIBS * sizeof(u32),
FLAT_DATA_ALIGN);
reloc = (u32 __user *) reloc = (__be32 __user *)
(datapos + (ntohl(hdr->reloc_start) - text_len)); (datapos + (ntohl(hdr->reloc_start) - text_len));
memp = textpos; memp = textpos;
memp_size = len; memp_size = len;
...@@ -627,8 +649,9 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -627,8 +649,9 @@ static int load_flat_file(struct linux_binprm *bprm,
(text_len + full_data (text_len + full_data
- sizeof(struct flat_hdr)), - sizeof(struct flat_hdr)),
0); 0);
memmove((void *) datapos, (void *) realdatastart, if (datapos != realdatastart)
full_data); memmove((void *)datapos, (void *)realdatastart,
full_data);
#else #else
/* /*
* This is used on MMU systems mainly for testing. * This is used on MMU systems mainly for testing.
...@@ -684,8 +707,7 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -684,8 +707,7 @@ static int load_flat_file(struct linux_binprm *bprm,
if (IS_ERR_VALUE(result)) { if (IS_ERR_VALUE(result)) {
ret = result; ret = result;
pr_err("Unable to read code+data+bss, errno %d\n", ret); pr_err("Unable to read code+data+bss, errno %d\n", ret);
vm_munmap(textpos, text_len + data_len + extra + vm_munmap(textpos, text_len + data_len + extra);
MAX_SHARED_LIBS * sizeof(u32));
goto err; goto err;
} }
} }
...@@ -775,20 +797,18 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -775,20 +797,18 @@ static int load_flat_file(struct linux_binprm *bprm,
* __start to address 4 so that is okay). * __start to address 4 so that is okay).
*/ */
if (rev > OLD_FLAT_VERSION) { if (rev > OLD_FLAT_VERSION) {
u32 __maybe_unused persistent = 0;
for (i = 0; i < relocs; i++) { for (i = 0; i < relocs; i++) {
u32 addr, relval; u32 addr, relval;
__be32 tmp;
/* /*
* Get the address of the pointer to be * Get the address of the pointer to be
* relocated (of course, the address has to be * relocated (of course, the address has to be
* relocated first). * relocated first).
*/ */
if (get_user(relval, reloc + i)) if (get_user(tmp, reloc + i))
return -EFAULT; return -EFAULT;
relval = ntohl(relval); relval = ntohl(tmp);
if (flat_set_persistent(relval, &persistent))
continue;
addr = flat_get_relocate_addr(relval); addr = flat_get_relocate_addr(relval);
rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1); rp = (u32 __user *)calc_reloc(addr, libinfo, id, 1);
if (rp == (u32 __user *)RELOC_FAILED) { if (rp == (u32 __user *)RELOC_FAILED) {
...@@ -797,8 +817,7 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -797,8 +817,7 @@ static int load_flat_file(struct linux_binprm *bprm,
} }
/* Get the pointer's value. */ /* Get the pointer's value. */
ret = flat_get_addr_from_rp(rp, relval, flags, ret = flat_get_addr_from_rp(rp, relval, flags, &addr);
&addr, &persistent);
if (unlikely(ret)) if (unlikely(ret))
goto err; goto err;
...@@ -807,8 +826,13 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -807,8 +826,13 @@ static int load_flat_file(struct linux_binprm *bprm,
* Do the relocation. PIC relocs in the data section are * Do the relocation. PIC relocs in the data section are
* already in target order * already in target order
*/ */
if ((flags & FLAT_FLAG_GOTPIC) == 0) if ((flags & FLAT_FLAG_GOTPIC) == 0) {
addr = ntohl(addr); /*
* Meh, the same value can have a different
* byte order based on a flag..
*/
addr = ntohl((__force __be32)addr);
}
addr = calc_reloc(addr, libinfo, id, 0); addr = calc_reloc(addr, libinfo, id, 0);
if (addr == RELOC_FAILED) { if (addr == RELOC_FAILED) {
ret = -ENOEXEC; ret = -ENOEXEC;
...@@ -821,14 +845,15 @@ static int load_flat_file(struct linux_binprm *bprm, ...@@ -821,14 +845,15 @@ static int load_flat_file(struct linux_binprm *bprm,
goto err; goto err;
} }
} }
#ifdef CONFIG_BINFMT_FLAT_OLD
} else { } else {
for (i = 0; i < relocs; i++) { for (i = 0; i < relocs; i++) {
u32 relval; __be32 relval;
if (get_user(relval, reloc + i)) if (get_user(relval, reloc + i))
return -EFAULT; return -EFAULT;
relval = ntohl(relval); old_reloc(ntohl(relval));
old_reloc(relval);
} }
#endif /* CONFIG_BINFMT_FLAT_OLD */
} }
flush_icache_range(start_code, end_code); flush_icache_range(start_code, end_code);
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/* #ifndef _ASM_GENERIC_FLAT_H
* arch/arm/include/asm/flat.h -- uClinux flat-format executables #define _ASM_GENERIC_FLAT_H
*/
#ifndef __ARM_FLAT_H__
#define __ARM_FLAT_H__
#include <linux/uaccess.h> #include <linux/uaccess.h>
#define flat_argvp_envp_on_stack() 1
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags, static inline int flat_get_addr_from_rp(u32 __user *rp, u32 relval, u32 flags,
u32 *addr, u32 *persistent) u32 *addr)
{ {
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
return copy_from_user(addr, rp, 4) ? -EFAULT : 0; return copy_from_user(addr, rp, 4) ? -EFAULT : 0;
...@@ -31,7 +23,4 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel) ...@@ -31,7 +23,4 @@ static inline int flat_put_addr_at_rp(u32 __user *rp, u32 addr, u32 rel)
#endif #endif
} }
#define flat_get_relocate_addr(rel) (rel) #endif /* _ASM_GENERIC_FLAT_H */
#define flat_set_persistent(relval, p) 0
#endif /* __ARM_FLAT_H__ */
...@@ -10,8 +10,41 @@ ...@@ -10,8 +10,41 @@
#ifndef _LINUX_FLAT_H #ifndef _LINUX_FLAT_H
#define _LINUX_FLAT_H #define _LINUX_FLAT_H
#include <uapi/linux/flat.h> #define FLAT_VERSION 0x00000004L
#include <asm/flat.h>
/*
* To make everything easier to port and manage cross platform
* development, all fields are in network byte order.
*/
struct flat_hdr {
char magic[4];
__be32 rev; /* version (as above) */
__be32 entry; /* Offset of first executable instruction
with text segment from beginning of file */
__be32 data_start; /* Offset of data segment from beginning of
file */
__be32 data_end; /* Offset of end of data segment from beginning
of file */
__be32 bss_end; /* Offset of end of bss segment from beginning
of file */
/* (It is assumed that data_end through bss_end forms the bss segment.) */
__be32 stack_size; /* Size of stack, in bytes */
__be32 reloc_start; /* Offset of relocation records from beginning of
file */
__be32 reloc_count; /* Number of relocation records */
__be32 flags;
__be32 build_date; /* When the program/library was built */
__u32 filler[5]; /* Reservered, set to zero */
};
#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */
#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */
#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
/* /*
* While it would be nice to keep this header clean, users of older * While it would be nice to keep this header clean, users of older
...@@ -22,28 +55,21 @@ ...@@ -22,28 +55,21 @@
* with the format above, except to fix bugs with old format support. * with the format above, except to fix bugs with old format support.
*/ */
#include <asm/byteorder.h>
#define OLD_FLAT_VERSION 0x00000002L #define OLD_FLAT_VERSION 0x00000002L
#define OLD_FLAT_RELOC_TYPE_TEXT 0 #define OLD_FLAT_RELOC_TYPE_TEXT 0
#define OLD_FLAT_RELOC_TYPE_DATA 1 #define OLD_FLAT_RELOC_TYPE_DATA 1
#define OLD_FLAT_RELOC_TYPE_BSS 2 #define OLD_FLAT_RELOC_TYPE_BSS 2
typedef union { typedef union {
unsigned long value; u32 value;
struct { struct {
# if defined(mc68000) && !defined(CONFIG_COLDFIRE) #if defined(__LITTLE_ENDIAN_BITFIELD) || \
signed long offset : 30; (defined(mc68000) && !defined(CONFIG_COLDFIRE))
unsigned long type : 2; s32 offset : 30;
# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */ u32 type : 2;
# elif defined(__BIG_ENDIAN_BITFIELD) # elif defined(__BIG_ENDIAN_BITFIELD)
unsigned long type : 2; u32 type : 2;
signed long offset : 30; s32 offset : 30;
# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */
# elif defined(__LITTLE_ENDIAN_BITFIELD)
signed long offset : 30;
unsigned long type : 2;
# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */
# else # else
# error "Unknown bitfield order for flat files." # error "Unknown bitfield order for flat files."
# endif # endif
......
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
* The Silver Hammer Group, Ltd.
*
* This file provides the definitions and structures needed to
* support uClinux flat-format executables.
*/
#ifndef _UAPI_LINUX_FLAT_H
#define _UAPI_LINUX_FLAT_H
#define FLAT_VERSION 0x00000004L
#ifdef CONFIG_BINFMT_SHARED_FLAT
#define MAX_SHARED_LIBS (4)
#else
#define MAX_SHARED_LIBS (1)
#endif
/*
* To make everything easier to port and manage cross platform
* development, all fields are in network byte order.
*/
struct flat_hdr {
char magic[4];
unsigned long rev; /* version (as above) */
unsigned long entry; /* Offset of first executable instruction
with text segment from beginning of file */
unsigned long data_start; /* Offset of data segment from beginning of
file */
unsigned long data_end; /* Offset of end of data segment
from beginning of file */
unsigned long bss_end; /* Offset of end of bss segment from beginning
of file */
/* (It is assumed that data_end through bss_end forms the bss segment.) */
unsigned long stack_size; /* Size of stack, in bytes */
unsigned long reloc_start; /* Offset of relocation records from
beginning of file */
unsigned long reloc_count; /* Number of relocation records */
unsigned long flags;
unsigned long build_date; /* When the program/library was built */
unsigned long filler[5]; /* Reservered, set to zero */
};
#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */
#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */
#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
#endif /* _UAPI_LINUX_FLAT_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment