Commit 7eb6369d authored by Palmer Dabbelt's avatar Palmer Dabbelt

RISC-V: Add support for rv32 userspace via COMPAT

The RISC-V port supports the rv32i and rv64i base ISAs, but provides no
mechanism to run 32-bit userspace on 64-bit systems.  This adds that
support, via the COMPAT framework.  As the RISC-V ISAs (and uABIs) were
developed concurrently, the resulting compat support is mostly generic.

This includes a handful of cleanups to the generic compat infrastructure
to more cleanly support RISC-V, followed by the RISC-V implementation.

* palmer/riscv-compat:
  riscv: compat: Add COMPAT Kbuild skeletal support
  riscv: compat: ptrace: Add compat_arch_ptrace implement
  riscv: compat: signal: Add rt_frame implementation
  riscv: compat: vdso: Add setup additional pages implementation
  riscv: compat: vdso: Add COMPAT_VDSO base code implementation
  riscv: compat: Add hw capability check for elf
  riscv: compat: Add elf.h implementation
  riscv: compat: process: Add UXL_32 support in start_thread
  riscv: compat: syscall: Add entry.S implementation
  riscv: compat: syscall: Add compat_sys_call_table implementation
  riscv: compat: Support TASK_SIZE for compat mode
  riscv: compat: Add basic compat data type implementation
  riscv: Fixup difference with defconfig
  syscalls: compat: Fix the missing part for __SYSCALL_COMPAT
  asm-generic: compat: Cleanup duplicate definitions
  fs: stat: compat: Add __ARCH_WANT_COMPAT_STAT
  arch: Add SYSVIPC_COMPAT for all architectures
  compat: consolidate the compat_flock{,64} definition
  uapi: always define F_GETLK64/F_SETLK64/F_SETLKW64 in fcntl.h
  uapi: simplify __ARCH_FLOCK{,64}_PAD a little
parents 93c06516 9be84592
...@@ -2122,10 +2122,6 @@ config DMI ...@@ -2122,10 +2122,6 @@ config DMI
endmenu endmenu
config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC
menu "Power management options" menu "Power management options"
source "kernel/power/Kconfig" source "kernel/power/Kconfig"
......
...@@ -8,6 +8,15 @@ ...@@ -8,6 +8,15 @@
#define compat_mode_t compat_mode_t #define compat_mode_t compat_mode_t
typedef u16 compat_mode_t; typedef u16 compat_mode_t;
#define __compat_uid_t __compat_uid_t
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
#define compat_ipc_pid_t compat_ipc_pid_t
typedef u16 compat_ipc_pid_t;
#define compat_statfs compat_statfs
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -19,21 +28,15 @@ typedef u16 compat_mode_t; ...@@ -19,21 +28,15 @@ typedef u16 compat_mode_t;
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#define COMPAT_USER_HZ 100
#ifdef __AARCH64EB__ #ifdef __AARCH64EB__
#define COMPAT_UTS_MACHINE "armv8b\0\0" #define COMPAT_UTS_MACHINE "armv8b\0\0"
#else #else
#define COMPAT_UTS_MACHINE "armv8l\0\0" #define COMPAT_UTS_MACHINE "armv8l\0\0"
#endif #endif
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
typedef u16 __compat_uid16_t; typedef u16 __compat_uid16_t;
typedef u16 __compat_gid16_t; typedef u16 __compat_gid16_t;
typedef u32 compat_dev_t;
typedef s32 compat_nlink_t; typedef s32 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef __kernel_fsid_t compat_fsid_t;
struct compat_stat { struct compat_stat {
#ifdef __AARCH64EB__ #ifdef __AARCH64EB__
...@@ -65,26 +68,6 @@ struct compat_stat { ...@@ -65,26 +68,6 @@ struct compat_stat {
compat_ulong_t __unused4[2]; compat_ulong_t __unused4[2];
}; };
struct compat_flock {
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
};
#define F_GETLK64 12 /* using 'struct flock64' */
#define F_SETLK64 13
#define F_SETLKW64 14
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
};
struct compat_statfs { struct compat_statfs {
int f_type; int f_type;
int f_bsize; int f_bsize;
...@@ -107,64 +90,6 @@ struct compat_statfs { ...@@ -107,64 +90,6 @@ struct compat_statfs {
#define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current))) #define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
#define COMPAT_MINSIGSTKSZ 2048 #define COMPAT_MINSIGSTKSZ 2048
struct compat_ipc64_perm {
compat_key_t key;
__compat_uid32_t uid;
__compat_gid32_t gid;
__compat_uid32_t cuid;
__compat_gid32_t cgid;
unsigned short mode;
unsigned short __pad1;
unsigned short seq;
unsigned short __pad2;
compat_ulong_t unused1;
compat_ulong_t unused2;
};
struct compat_semid64_ds {
struct compat_ipc64_perm sem_perm;
compat_ulong_t sem_otime;
compat_ulong_t sem_otime_high;
compat_ulong_t sem_ctime;
compat_ulong_t sem_ctime_high;
compat_ulong_t sem_nsems;
compat_ulong_t __unused3;
compat_ulong_t __unused4;
};
struct compat_msqid64_ds {
struct compat_ipc64_perm msg_perm;
compat_ulong_t msg_stime;
compat_ulong_t msg_stime_high;
compat_ulong_t msg_rtime;
compat_ulong_t msg_rtime_high;
compat_ulong_t msg_ctime;
compat_ulong_t msg_ctime_high;
compat_ulong_t msg_cbytes;
compat_ulong_t msg_qnum;
compat_ulong_t msg_qbytes;
compat_pid_t msg_lspid;
compat_pid_t msg_lrpid;
compat_ulong_t __unused4;
compat_ulong_t __unused5;
};
struct compat_shmid64_ds {
struct compat_ipc64_perm shm_perm;
compat_size_t shm_segsz;
compat_ulong_t shm_atime;
compat_ulong_t shm_atime_high;
compat_ulong_t shm_dtime;
compat_ulong_t shm_dtime_high;
compat_ulong_t shm_ctime;
compat_ulong_t shm_ctime_high;
compat_pid_t shm_cpid;
compat_pid_t shm_lpid;
compat_ulong_t shm_nattch;
compat_ulong_t __unused4;
compat_ulong_t __unused5;
};
static inline int is_compat_task(void) static inline int is_compat_task(void)
{ {
return test_thread_flag(TIF_32BIT); return test_thread_flag(TIF_32BIT);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Copyright (C) 2012 ARM Ltd. * Copyright (C) 2012 ARM Ltd.
*/ */
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
#define __ARCH_WANT_COMPAT_STAT
#define __ARCH_WANT_COMPAT_STAT64 #define __ARCH_WANT_COMPAT_STAT64
#define __ARCH_WANT_SYS_GETHOSTNAME #define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE #define __ARCH_WANT_SYS_PAUSE
......
...@@ -3198,16 +3198,12 @@ config MIPS32_COMPAT ...@@ -3198,16 +3198,12 @@ config MIPS32_COMPAT
config COMPAT config COMPAT
bool bool
config SYSVIPC_COMPAT
bool
config MIPS32_O32 config MIPS32_O32
bool "Kernel support for o32 binaries" bool "Kernel support for o32 binaries"
depends on 64BIT depends on 64BIT
select ARCH_WANT_OLD_COMPAT_IPC select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT select COMPAT
select MIPS32_COMPAT select MIPS32_COMPAT
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
32-bit binaries as used by the 32-bit Linux/MIPS port. Most of 32-bit binaries as used by the 32-bit Linux/MIPS port. Most of
...@@ -3221,7 +3217,6 @@ config MIPS32_N32 ...@@ -3221,7 +3217,6 @@ config MIPS32_N32
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
select COMPAT select COMPAT
select MIPS32_COMPAT select MIPS32_COMPAT
select SYSVIPC_COMPAT if SYSVIPC
help help
Select this option if you want to run n32 binaries. These are Select this option if you want to run n32 binaries. These are
64-bit binaries using 32-bit quantities for addressing and certain 64-bit binaries using 32-bit quantities for addressing and certain
......
...@@ -9,28 +9,28 @@ ...@@ -9,28 +9,28 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#define __compat_uid_t __compat_uid_t
typedef s32 __compat_uid_t; typedef s32 __compat_uid_t;
typedef s32 __compat_gid_t; typedef s32 __compat_gid_t;
typedef __compat_uid_t __compat_uid32_t; typedef __compat_uid_t __compat_uid32_t;
typedef __compat_gid_t __compat_gid32_t; typedef __compat_gid_t __compat_gid32_t;
#define __compat_uid32_t __compat_uid32_t #define __compat_uid32_t __compat_uid32_t
#define __compat_gid32_t __compat_gid32_t
#define compat_statfs compat_statfs
#define compat_ipc64_perm compat_ipc64_perm
#define _COMPAT_NSIG 128 /* Don't ask !$@#% ... */ #define _COMPAT_NSIG 128 /* Don't ask !$@#% ... */
#define _COMPAT_NSIG_BPW 32 #define _COMPAT_NSIG_BPW 32
typedef u32 compat_sigset_word; typedef u32 compat_sigset_word;
#define COMPAT_RLIM_INFINITY 0x7fffffffUL
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#define COMPAT_USER_HZ 100
#define COMPAT_UTS_MACHINE "mips\0\0\0" #define COMPAT_UTS_MACHINE "mips\0\0\0"
typedef u32 compat_dev_t;
typedef u32 compat_nlink_t; typedef u32 compat_nlink_t;
typedef s32 compat_ipc_pid_t;
typedef struct {
s32 val[2];
} compat_fsid_t;
struct compat_stat { struct compat_stat {
compat_dev_t st_dev; compat_dev_t st_dev;
...@@ -55,27 +55,8 @@ struct compat_stat { ...@@ -55,27 +55,8 @@ struct compat_stat {
s32 st_pad4[14]; s32 st_pad4[14];
}; };
struct compat_flock { #define __ARCH_COMPAT_FLOCK_EXTRA_SYSID s32 l_sysid;
short l_type; #define __ARCH_COMPAT_FLOCK_PAD s32 pad[4];
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
s32 l_sysid;
compat_pid_t l_pid;
s32 pad[4];
};
#define F_GETLK64 33
#define F_SETLK64 34
#define F_SETLKW64 35
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
};
struct compat_statfs { struct compat_statfs {
int f_type; int f_type;
...@@ -92,10 +73,6 @@ struct compat_statfs { ...@@ -92,10 +73,6 @@ struct compat_statfs {
int f_spare[5]; int f_spare[5];
}; };
#define COMPAT_RLIM_INFINITY 0x7fffffffUL
#define COMPAT_OFF_T_MAX 0x7fffffff
struct compat_ipc64_perm { struct compat_ipc64_perm {
compat_key_t key; compat_key_t key;
__compat_uid32_t uid; __compat_uid32_t uid;
......
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
# ifdef CONFIG_32BIT # ifdef CONFIG_32BIT
# define __ARCH_WANT_STAT64 # define __ARCH_WANT_STAT64
# define __ARCH_WANT_SYS_TIME32 # define __ARCH_WANT_SYS_TIME32
# else
# define __ARCH_WANT_COMPAT_STAT
# endif # endif
# ifdef CONFIG_MIPS32_O32 # ifdef CONFIG_MIPS32_O32
# define __ARCH_WANT_SYS_TIME32 # define __ARCH_WANT_SYS_TIME32
......
...@@ -44,36 +44,16 @@ ...@@ -44,36 +44,16 @@
#define F_SETOWN 24 /* for sockets. */ #define F_SETOWN 24 /* for sockets. */
#define F_GETOWN 23 /* for sockets. */ #define F_GETOWN 23 /* for sockets. */
#ifndef __mips64 #if __BITS_PER_LONG == 32 || defined(__KERNEL__)
#define F_GETLK64 33 /* using 'struct flock64' */ #define F_GETLK64 33 /* using 'struct flock64' */
#define F_SETLK64 34 #define F_SETLK64 34
#define F_SETLKW64 35 #define F_SETLKW64 35
#endif #endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */
/*
* The flavours of struct flock. "struct flock" is the ABI compliant
* variant. Finally struct flock64 is the LFS variant of struct flock. As
* a historic accident and inconsistence with the ABI definition it doesn't
* contain all the same fields as struct flock.
*/
#if _MIPS_SIM != _MIPS_SIM_ABI64 #if _MIPS_SIM != _MIPS_SIM_ABI64
#define __ARCH_FLOCK_EXTRA_SYSID long l_sysid;
#include <linux/types.h> #define __ARCH_FLOCK_PAD long pad[4];
#endif
struct flock {
short l_type;
short l_whence;
__kernel_off_t l_start;
__kernel_off_t l_len;
long l_sysid;
__kernel_pid_t l_pid;
long pad[4];
};
#define HAVE_ARCH_STRUCT_FLOCK
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
#include <asm-generic/fcntl.h> #include <asm-generic/fcntl.h>
......
...@@ -331,10 +331,6 @@ config COMPAT ...@@ -331,10 +331,6 @@ config COMPAT
def_bool y def_bool y
depends on 64BIT depends on 64BIT
config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC
config AUDIT_ARCH config AUDIT_ARCH
def_bool y def_bool y
......
...@@ -11,16 +11,16 @@ ...@@ -11,16 +11,16 @@
#define compat_mode_t compat_mode_t #define compat_mode_t compat_mode_t
typedef u16 compat_mode_t; typedef u16 compat_mode_t;
#define compat_ipc_pid_t compat_ipc_pid_t
typedef u16 compat_ipc_pid_t;
#define compat_ipc64_perm compat_ipc64_perm
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#define COMPAT_USER_HZ 100
#define COMPAT_UTS_MACHINE "parisc\0\0" #define COMPAT_UTS_MACHINE "parisc\0\0"
typedef u32 __compat_uid_t;
typedef u32 __compat_gid_t;
typedef u32 compat_dev_t;
typedef u16 compat_nlink_t; typedef u16 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
struct compat_stat { struct compat_stat {
compat_dev_t st_dev; /* dev_t is 32 bits on parisc */ compat_dev_t st_dev; /* dev_t is 32 bits on parisc */
...@@ -53,37 +53,6 @@ struct compat_stat { ...@@ -53,37 +53,6 @@ struct compat_stat {
u32 st_spare4[3]; u32 st_spare4[3];
}; };
struct compat_flock {
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
};
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
};
struct compat_statfs {
s32 f_type;
s32 f_bsize;
s32 f_blocks;
s32 f_bfree;
s32 f_bavail;
s32 f_files;
s32 f_ffree;
__kernel_fsid_t f_fsid;
s32 f_namelen;
s32 f_frsize;
s32 f_flags;
s32 f_spare[4];
};
struct compat_sigcontext { struct compat_sigcontext {
compat_int_t sc_flags; compat_int_t sc_flags;
compat_int_t sc_gr[32]; /* PSW in sc_gr[0] */ compat_int_t sc_gr[32]; /* PSW in sc_gr[0] */
...@@ -93,10 +62,6 @@ struct compat_sigcontext { ...@@ -93,10 +62,6 @@ struct compat_sigcontext {
compat_int_t sc_sar; /* cr11 */ compat_int_t sc_sar; /* cr11 */
}; };
#define COMPAT_RLIM_INFINITY 0xffffffff
#define COMPAT_OFF_T_MAX 0x7fffffff
struct compat_ipc64_perm { struct compat_ipc64_perm {
compat_key_t key; compat_key_t key;
__compat_uid_t uid; __compat_uid_t uid;
......
...@@ -164,6 +164,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ ...@@ -164,6 +164,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_CLONE #define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_SYS_CLONE3 #define __ARCH_WANT_SYS_CLONE3
#define __ARCH_WANT_COMPAT_SYS_SENDFILE #define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_COMPAT_STAT
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_SYS_TIME
......
...@@ -298,11 +298,6 @@ config COMPAT ...@@ -298,11 +298,6 @@ config COMPAT
select ARCH_WANT_OLD_COMPAT_IPC select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT_OLD_SIGACTION select COMPAT_OLD_SIGACTION
config SYSVIPC_COMPAT
bool
depends on COMPAT && SYSVIPC
default y
config SCHED_OMIT_FRAME_POINTER config SCHED_OMIT_FRAME_POINTER
bool bool
default y default y
......
...@@ -8,21 +8,20 @@ ...@@ -8,21 +8,20 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/sched.h> #include <linux/sched.h>
#define compat_ipc_pid_t compat_ipc_pid_t
typedef u16 compat_ipc_pid_t;
#define compat_ipc64_perm compat_ipc64_perm
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#define COMPAT_USER_HZ 100
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
#define COMPAT_UTS_MACHINE "ppc\0\0" #define COMPAT_UTS_MACHINE "ppc\0\0"
#else #else
#define COMPAT_UTS_MACHINE "ppcle\0\0" #define COMPAT_UTS_MACHINE "ppcle\0\0"
#endif #endif
typedef u32 __compat_uid_t;
typedef u32 __compat_gid_t;
typedef u32 compat_dev_t;
typedef s16 compat_nlink_t; typedef s16 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef __kernel_fsid_t compat_fsid_t;
struct compat_stat { struct compat_stat {
compat_dev_t st_dev; compat_dev_t st_dev;
...@@ -44,45 +43,6 @@ struct compat_stat { ...@@ -44,45 +43,6 @@ struct compat_stat {
u32 __unused4[2]; u32 __unused4[2];
}; };
struct compat_flock {
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
};
#define F_GETLK64 12 /* using 'struct flock64' */
#define F_SETLK64 13
#define F_SETLKW64 14
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
};
struct compat_statfs {
int f_type;
int f_bsize;
int f_blocks;
int f_bfree;
int f_bavail;
int f_files;
int f_ffree;
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_frsize;
int f_flags;
int f_spare[4];
};
#define COMPAT_RLIM_INFINITY 0xffffffff
#define COMPAT_OFF_T_MAX 0x7fffffff
/* /*
* ipc64_perm is actually 32/64bit clean but since the compat layer refers to * ipc64_perm is actually 32/64bit clean but since the compat layer refers to
* it we may as well define it. * it we may as well define it.
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_SYS_NEWFSTATAT #define __ARCH_WANT_SYS_NEWFSTATAT
#define __ARCH_WANT_COMPAT_STAT
#define __ARCH_WANT_COMPAT_SYS_SENDFILE #define __ARCH_WANT_COMPAT_SYS_SENDFILE
#endif #endif
#define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_FORK
......
...@@ -76,6 +76,7 @@ config RISCV ...@@ -76,6 +76,7 @@ config RISCV
select HAVE_ARCH_KGDB if !XIP_KERNEL select HAVE_ARCH_KGDB if !XIP_KERNEL
select HAVE_ARCH_KGDB_QXFER_PKT select HAVE_ARCH_KGDB_QXFER_PKT
select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_MMAP_RND_BITS if MMU
select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT && MMU select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT && MMU
...@@ -127,12 +128,18 @@ config ARCH_MMAP_RND_BITS_MIN ...@@ -127,12 +128,18 @@ config ARCH_MMAP_RND_BITS_MIN
default 18 if 64BIT default 18 if 64BIT
default 8 default 8
config ARCH_MMAP_RND_COMPAT_BITS_MIN
default 8
# max bits determined by the following formula: # max bits determined by the following formula:
# VA_BITS - PAGE_SHIFT - 3 # VA_BITS - PAGE_SHIFT - 3
config ARCH_MMAP_RND_BITS_MAX config ARCH_MMAP_RND_BITS_MAX
default 24 if 64BIT # SV39 based default 24 if 64BIT # SV39 based
default 17 default 17
config ARCH_MMAP_RND_COMPAT_BITS_MAX
default 17
# set if we run in machine mode, cleared if we run in supervisor mode # set if we run in machine mode, cleared if we run in supervisor mode
config RISCV_M_MODE config RISCV_M_MODE
bool bool
...@@ -422,6 +429,18 @@ config CRASH_DUMP ...@@ -422,6 +429,18 @@ config CRASH_DUMP
For more details see Documentation/admin-guide/kdump/kdump.rst For more details see Documentation/admin-guide/kdump/kdump.rst
config COMPAT
bool "Kernel support for 32-bit U-mode"
default 64BIT
depends on 64BIT && MMU
help
This option enables support for a 32-bit U-mode running under a 64-bit
kernel at S-mode. riscv32-specific components such as system calls,
the user helper functions (vdso), signal rt_frame functions and the
ptrace interface are handled appropriately by the kernel.
If you want to execute 32-bit userspace applications, say Y.
endmenu endmenu
menu "Boot options" menu "Boot options"
......
...@@ -112,12 +112,17 @@ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a ...@@ -112,12 +112,17 @@ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
PHONY += vdso_install PHONY += vdso_install
vdso_install: vdso_install:
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@ $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/riscv/kernel/compat_vdso $@)
ifeq ($(KBUILD_EXTMOD),) ifeq ($(KBUILD_EXTMOD),)
ifeq ($(CONFIG_MMU),y) ifeq ($(CONFIG_MMU),y)
prepare: vdso_prepare prepare: vdso_prepare
vdso_prepare: prepare0 vdso_prepare: prepare0
$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso include/generated/vdso-offsets.h $(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso include/generated/vdso-offsets.h
$(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/riscv/kernel/compat_vdso include/generated/compat_vdso-offsets.h)
endif endif
endif endif
...@@ -154,3 +159,7 @@ PHONY += rv64_randconfig ...@@ -154,3 +159,7 @@ PHONY += rv64_randconfig
rv64_randconfig: rv64_randconfig:
$(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \ $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
-f $(srctree)/Makefile randconfig -f $(srctree)/Makefile randconfig
PHONY += rv32_defconfig
rv32_defconfig:
$(Q)$(MAKE) -f $(srctree)/Makefile defconfig 32-bit.config
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ASM_COMPAT_H
#define __ASM_COMPAT_H
#define COMPAT_UTS_MACHINE "riscv\0\0"
/*
* Architecture specific compatibility types
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <asm-generic/compat.h>
static inline int is_compat_task(void)
{
return test_thread_flag(TIF_32BIT);
}
struct compat_user_regs_struct {
compat_ulong_t pc;
compat_ulong_t ra;
compat_ulong_t sp;
compat_ulong_t gp;
compat_ulong_t tp;
compat_ulong_t t0;
compat_ulong_t t1;
compat_ulong_t t2;
compat_ulong_t s0;
compat_ulong_t s1;
compat_ulong_t a0;
compat_ulong_t a1;
compat_ulong_t a2;
compat_ulong_t a3;
compat_ulong_t a4;
compat_ulong_t a5;
compat_ulong_t a6;
compat_ulong_t a7;
compat_ulong_t s2;
compat_ulong_t s3;
compat_ulong_t s4;
compat_ulong_t s5;
compat_ulong_t s6;
compat_ulong_t s7;
compat_ulong_t s8;
compat_ulong_t s9;
compat_ulong_t s10;
compat_ulong_t s11;
compat_ulong_t t3;
compat_ulong_t t4;
compat_ulong_t t5;
compat_ulong_t t6;
};
static inline void regs_to_cregs(struct compat_user_regs_struct *cregs,
struct pt_regs *regs)
{
cregs->pc = (compat_ulong_t) regs->epc;
cregs->ra = (compat_ulong_t) regs->ra;
cregs->sp = (compat_ulong_t) regs->sp;
cregs->gp = (compat_ulong_t) regs->gp;
cregs->tp = (compat_ulong_t) regs->tp;
cregs->t0 = (compat_ulong_t) regs->t0;
cregs->t1 = (compat_ulong_t) regs->t1;
cregs->t2 = (compat_ulong_t) regs->t2;
cregs->s0 = (compat_ulong_t) regs->s0;
cregs->s1 = (compat_ulong_t) regs->s1;
cregs->a0 = (compat_ulong_t) regs->a0;
cregs->a1 = (compat_ulong_t) regs->a1;
cregs->a2 = (compat_ulong_t) regs->a2;
cregs->a3 = (compat_ulong_t) regs->a3;
cregs->a4 = (compat_ulong_t) regs->a4;
cregs->a5 = (compat_ulong_t) regs->a5;
cregs->a6 = (compat_ulong_t) regs->a6;
cregs->a7 = (compat_ulong_t) regs->a7;
cregs->s2 = (compat_ulong_t) regs->s2;
cregs->s3 = (compat_ulong_t) regs->s3;
cregs->s4 = (compat_ulong_t) regs->s4;
cregs->s5 = (compat_ulong_t) regs->s5;
cregs->s6 = (compat_ulong_t) regs->s6;
cregs->s7 = (compat_ulong_t) regs->s7;
cregs->s8 = (compat_ulong_t) regs->s8;
cregs->s9 = (compat_ulong_t) regs->s9;
cregs->s10 = (compat_ulong_t) regs->s10;
cregs->s11 = (compat_ulong_t) regs->s11;
cregs->t3 = (compat_ulong_t) regs->t3;
cregs->t4 = (compat_ulong_t) regs->t4;
cregs->t5 = (compat_ulong_t) regs->t5;
cregs->t6 = (compat_ulong_t) regs->t6;
};
static inline void cregs_to_regs(struct compat_user_regs_struct *cregs,
struct pt_regs *regs)
{
regs->epc = (unsigned long) cregs->pc;
regs->ra = (unsigned long) cregs->ra;
regs->sp = (unsigned long) cregs->sp;
regs->gp = (unsigned long) cregs->gp;
regs->tp = (unsigned long) cregs->tp;
regs->t0 = (unsigned long) cregs->t0;
regs->t1 = (unsigned long) cregs->t1;
regs->t2 = (unsigned long) cregs->t2;
regs->s0 = (unsigned long) cregs->s0;
regs->s1 = (unsigned long) cregs->s1;
regs->a0 = (unsigned long) cregs->a0;
regs->a1 = (unsigned long) cregs->a1;
regs->a2 = (unsigned long) cregs->a2;
regs->a3 = (unsigned long) cregs->a3;
regs->a4 = (unsigned long) cregs->a4;
regs->a5 = (unsigned long) cregs->a5;
regs->a6 = (unsigned long) cregs->a6;
regs->a7 = (unsigned long) cregs->a7;
regs->s2 = (unsigned long) cregs->s2;
regs->s3 = (unsigned long) cregs->s3;
regs->s4 = (unsigned long) cregs->s4;
regs->s5 = (unsigned long) cregs->s5;
regs->s6 = (unsigned long) cregs->s6;
regs->s7 = (unsigned long) cregs->s7;
regs->s8 = (unsigned long) cregs->s8;
regs->s9 = (unsigned long) cregs->s9;
regs->s10 = (unsigned long) cregs->s10;
regs->s11 = (unsigned long) cregs->s11;
regs->t3 = (unsigned long) cregs->t3;
regs->t4 = (unsigned long) cregs->t4;
regs->t5 = (unsigned long) cregs->t5;
regs->t6 = (unsigned long) cregs->t6;
};
#endif /* __ASM_COMPAT_H */
...@@ -36,6 +36,13 @@ ...@@ -36,6 +36,13 @@
#define SR_SD _AC(0x8000000000000000, UL) /* FS/XS dirty */ #define SR_SD _AC(0x8000000000000000, UL) /* FS/XS dirty */
#endif #endif
#ifdef CONFIG_64BIT
#define SR_UXL _AC(0x300000000, UL) /* XLEN mask for U-mode */
#define SR_UXL_32 _AC(0x100000000, UL) /* XLEN = 32 for U-mode */
#define SR_UXL_64 _AC(0x200000000, UL) /* XLEN = 64 for U-mode */
#define SR_UXL_SHIFT 32
#endif
/* SATP flags */ /* SATP flags */
#ifndef CONFIG_64BIT #ifndef CONFIG_64BIT
#define SATP_PPN _AC(0x003FFFFF, UL) #define SATP_PPN _AC(0x003FFFFF, UL)
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#ifndef _ASM_RISCV_ELF_H #ifndef _ASM_RISCV_ELF_H
#define _ASM_RISCV_ELF_H #define _ASM_RISCV_ELF_H
#include <uapi/linux/elf.h>
#include <linux/compat.h>
#include <uapi/asm/elf.h> #include <uapi/asm/elf.h>
#include <asm/auxvec.h> #include <asm/auxvec.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
...@@ -18,18 +20,24 @@ ...@@ -18,18 +20,24 @@
*/ */
#define ELF_ARCH EM_RISCV #define ELF_ARCH EM_RISCV
#ifndef ELF_CLASS
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#define ELF_CLASS ELFCLASS64 #define ELF_CLASS ELFCLASS64
#else #else
#define ELF_CLASS ELFCLASS32 #define ELF_CLASS ELFCLASS32
#endif #endif
#endif
#define ELF_DATA ELFDATA2LSB #define ELF_DATA ELFDATA2LSB
/* /*
* 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(x) ((x)->e_machine == EM_RISCV) #define elf_check_arch(x) (((x)->e_machine == EM_RISCV) && \
((x)->e_ident[EI_CLASS] == ELF_CLASS))
extern bool compat_elf_check_arch(Elf32_Ehdr *hdr);
#define compat_elf_check_arch compat_elf_check_arch
#define CORE_DUMP_USE_REGSET #define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE (PAGE_SIZE) #define ELF_EXEC_PAGESIZE (PAGE_SIZE)
...@@ -43,8 +51,14 @@ ...@@ -43,8 +51,14 @@
#define ELF_ET_DYN_BASE ((TASK_SIZE / 3) * 2) #define ELF_ET_DYN_BASE ((TASK_SIZE / 3) * 2)
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
#define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \
0x7ff >> (PAGE_SHIFT - 12) : \
0x3ffff >> (PAGE_SHIFT - 12))
#else
#define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12)) #define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12))
#endif #endif
#endif
/* /*
* This yields a mask that user programs can use to figure out what * This yields a mask that user programs can use to figure out what
* instruction set this CPU supports. This could be done in user space, * instruction set this CPU supports. This could be done in user space,
...@@ -60,11 +74,19 @@ extern unsigned long elf_hwcap; ...@@ -60,11 +74,19 @@ extern unsigned long elf_hwcap;
*/ */
#define ELF_PLATFORM (NULL) #define ELF_PLATFORM (NULL)
#define COMPAT_ELF_PLATFORM (NULL)
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
#define ARCH_DLINFO \ #define ARCH_DLINFO \
do { \ do { \
/* \
* Note that we add ulong after elf_addr_t because \
* casting current->mm->context.vdso triggers a cast \
* warning of cast from pointer to integer for \
* COMPAT ELFCLASS32. \
*/ \
NEW_AUX_ENT(AT_SYSINFO_EHDR, \ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
(elf_addr_t)current->mm->context.vdso); \ (elf_addr_t)(ulong)current->mm->context.vdso); \
NEW_AUX_ENT(AT_L1I_CACHESIZE, \ NEW_AUX_ENT(AT_L1I_CACHESIZE, \
get_cache_size(1, CACHE_TYPE_INST)); \ get_cache_size(1, CACHE_TYPE_INST)); \
NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY, \ NEW_AUX_ENT(AT_L1I_CACHEGEOMETRY, \
...@@ -90,4 +112,28 @@ do { \ ...@@ -90,4 +112,28 @@ do { \
*(struct user_regs_struct *)regs; \ *(struct user_regs_struct *)regs; \
} while (0); } while (0);
#ifdef CONFIG_COMPAT
#define SET_PERSONALITY(ex) \
do { if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
set_thread_flag(TIF_32BIT); \
else \
clear_thread_flag(TIF_32BIT); \
if (personality(current->personality) != PER_LINUX32) \
set_personality(PER_LINUX | \
(current->personality & (~PER_MASK))); \
} while (0)
#define COMPAT_ELF_ET_DYN_BASE ((TASK_SIZE_32 / 3) * 2)
/* rv32 registers */
typedef compat_ulong_t compat_elf_greg_t;
typedef compat_elf_greg_t compat_elf_gregset_t[ELF_NGREG];
extern int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp);
#define compat_arch_setup_additional_pages \
compat_arch_setup_additional_pages
#endif /* CONFIG_COMPAT */
#endif /* _ASM_RISCV_ELF_H */ #endif /* _ASM_RISCV_ELF_H */
...@@ -16,6 +16,7 @@ typedef struct { ...@@ -16,6 +16,7 @@ typedef struct {
atomic_long_t id; atomic_long_t id;
#endif #endif
void *vdso; void *vdso;
void *vdso_info;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* A local icache flush is needed before user execution can resume. */ /* A local icache flush is needed before user execution can resume. */
cpumask_t icache_stale_mask; cpumask_t icache_stale_mask;
......
...@@ -740,8 +740,17 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma, ...@@ -740,8 +740,17 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
* 63–48 all equal to bit 47, or else a page-fault exception will occur." * 63–48 all equal to bit 47, or else a page-fault exception will occur."
*/ */
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#define TASK_SIZE (PGDIR_SIZE * PTRS_PER_PGD / 2) #define TASK_SIZE_64 (PGDIR_SIZE * PTRS_PER_PGD / 2)
#define TASK_SIZE_MIN (PGDIR_SIZE_L3 * PTRS_PER_PGD / 2) #define TASK_SIZE_MIN (PGDIR_SIZE_L3 * PTRS_PER_PGD / 2)
#ifdef CONFIG_COMPAT
#define TASK_SIZE_32 (_AC(0x80000000, UL) - PAGE_SIZE)
#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
TASK_SIZE_32 : TASK_SIZE_64)
#else
#define TASK_SIZE TASK_SIZE_64
#endif
#else #else
#define TASK_SIZE FIXADDR_START #define TASK_SIZE FIXADDR_START
#define TASK_SIZE_MIN TASK_SIZE #define TASK_SIZE_MIN TASK_SIZE
......
...@@ -19,7 +19,11 @@ ...@@ -19,7 +19,11 @@
#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) #define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3)
#define STACK_TOP TASK_SIZE #define STACK_TOP TASK_SIZE
#define STACK_TOP_MAX STACK_TOP #ifdef CONFIG_64BIT
#define STACK_TOP_MAX TASK_SIZE_64
#else
#define STACK_TOP_MAX TASK_SIZE
#endif
#define STACK_ALIGN 16 #define STACK_ALIGN 16
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
......
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ASM_SIGNAL32_H
#define __ASM_SIGNAL32_H
#if IS_ENABLED(CONFIG_COMPAT)
int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs);
#else
static inline
int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
return -1;
}
#endif
#endif
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
/* The array of function pointers for syscalls. */ /* The array of function pointers for syscalls. */
extern void * const sys_call_table[]; extern void * const sys_call_table[];
extern void * const compat_sys_call_table[];
/* /*
* Only the low 32 bits of orig_r0 are meaningful, so we return int. * Only the low 32 bits of orig_r0 are meaningful, so we return int.
......
...@@ -97,6 +97,7 @@ struct thread_info { ...@@ -97,6 +97,7 @@ struct thread_info {
#define TIF_SECCOMP 8 /* syscall secure computing */ #define TIF_SECCOMP 8 /* syscall secure computing */
#define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */ #define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */
#define TIF_UPROBE 10 /* uprobe breakpoint or singlestep */ #define TIF_UPROBE 10 /* uprobe breakpoint or singlestep */
#define TIF_32BIT 11 /* compat-mode 32bit process */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
......
...@@ -11,6 +11,17 @@ ...@@ -11,6 +11,17 @@
#define __ARCH_WANT_SYS_CLONE #define __ARCH_WANT_SYS_CLONE
#define __ARCH_WANT_MEMFD_SECRET #define __ARCH_WANT_MEMFD_SECRET
#ifdef CONFIG_COMPAT
#define __ARCH_WANT_COMPAT_TRUNCATE64
#define __ARCH_WANT_COMPAT_FTRUNCATE64
#define __ARCH_WANT_COMPAT_FALLOCATE
#define __ARCH_WANT_COMPAT_PREAD64
#define __ARCH_WANT_COMPAT_PWRITE64
#define __ARCH_WANT_COMPAT_SYNC_FILE_RANGE
#define __ARCH_WANT_COMPAT_READAHEAD
#define __ARCH_WANT_COMPAT_FADVISE64_64
#endif
#include <uapi/asm/unistd.h> #include <uapi/asm/unistd.h>
#define NR_syscalls (__NR_syscalls) #define NR_syscalls (__NR_syscalls)
...@@ -21,6 +21,15 @@ ...@@ -21,6 +21,15 @@
#define VDSO_SYMBOL(base, name) \ #define VDSO_SYMBOL(base, name) \
(void __user *)((unsigned long)(base) + __vdso_##name##_offset) (void __user *)((unsigned long)(base) + __vdso_##name##_offset)
#ifdef CONFIG_COMPAT
#include <generated/compat_vdso-offsets.h>
#define COMPAT_VDSO_SYMBOL(base, name) \
(void __user *)((unsigned long)(base) + compat__vdso_##name##_offset)
#endif /* CONFIG_COMPAT */
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifdef __LP64__ #if defined(__LP64__) && !defined(__SYSCALL_COMPAT)
#define __ARCH_WANT_NEW_STAT #define __ARCH_WANT_NEW_STAT
#define __ARCH_WANT_SET_GET_RLIMIT #define __ARCH_WANT_SET_GET_RLIMIT
#endif /* __LP64__ */ #endif /* __LP64__ */
......
...@@ -84,3 +84,6 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o ...@@ -84,3 +84,6 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_EFI) += efi.o obj-$(CONFIG_EFI) += efi.o
obj-$(CONFIG_COMPAT) += compat_syscall_table.o
obj-$(CONFIG_COMPAT) += compat_signal.o
obj-$(CONFIG_COMPAT) += compat_vdso/
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/compat.h>
#include <linux/signal.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/linkage.h>
#include <asm/csr.h>
#include <asm/signal32.h>
#include <asm/switch_to.h>
#include <asm/ucontext.h>
#include <asm/vdso.h>
#define COMPAT_DEBUG_SIG 0
struct compat_sigcontext {
struct compat_user_regs_struct sc_regs;
union __riscv_fp_state sc_fpregs;
};
struct compat_ucontext {
compat_ulong_t uc_flags;
struct compat_ucontext *uc_link;
compat_stack_t uc_stack;
sigset_t uc_sigmask;
/* There's some padding here to allow sigset_t to be expanded in the
* future. Though this is unlikely, other architectures put uc_sigmask
* at the end of this structure and explicitly state it can be
* expanded, so we didn't want to box ourselves in here. */
__u8 __unused[1024 / 8 - sizeof(sigset_t)];
/* We can't put uc_sigmask at the end of this structure because we need
* to be able to expand sigcontext in the future. For example, the
* vector ISA extension will almost certainly add ISA state. We want
* to ensure all user-visible ISA state can be saved and restored via a
* ucontext, so we're putting this at the end in order to allow for
* infinite extensibility. Since we know this will be extended and we
* assume sigset_t won't be extended an extreme amount, we're
* prioritizing this. */
struct compat_sigcontext uc_mcontext;
};
struct compat_rt_sigframe {
struct compat_siginfo info;
struct compat_ucontext uc;
};
#ifdef CONFIG_FPU
static long compat_restore_fp_state(struct pt_regs *regs,
union __riscv_fp_state __user *sc_fpregs)
{
long err;
struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
size_t i;
err = __copy_from_user(&current->thread.fstate, state, sizeof(*state));
if (unlikely(err))
return err;
fstate_restore(current, regs);
/* We support no other extension state at this time. */
for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
u32 value;
err = __get_user(value, &sc_fpregs->q.reserved[i]);
if (unlikely(err))
break;
if (value != 0)
return -EINVAL;
}
return err;
}
static long compat_save_fp_state(struct pt_regs *regs,
union __riscv_fp_state __user *sc_fpregs)
{
long err;
struct __riscv_d_ext_state __user *state = &sc_fpregs->d;
size_t i;
fstate_save(current, regs);
err = __copy_to_user(state, &current->thread.fstate, sizeof(*state));
if (unlikely(err))
return err;
/* We support no other extension state at this time. */
for (i = 0; i < ARRAY_SIZE(sc_fpregs->q.reserved); i++) {
err = __put_user(0, &sc_fpregs->q.reserved[i]);
if (unlikely(err))
break;
}
return err;
}
#else
#define compat_save_fp_state(task, regs) (0)
#define compat_restore_fp_state(task, regs) (0)
#endif
static long compat_restore_sigcontext(struct pt_regs *regs,
struct compat_sigcontext __user *sc)
{
long err;
struct compat_user_regs_struct cregs;
/* sc_regs is structured the same as the start of pt_regs */
err = __copy_from_user(&cregs, &sc->sc_regs, sizeof(sc->sc_regs));
cregs_to_regs(&cregs, regs);
/* Restore the floating-point state. */
if (has_fpu())
err |= compat_restore_fp_state(regs, &sc->sc_fpregs);
return err;
}
COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = current_pt_regs();
struct compat_rt_sigframe __user *frame;
struct task_struct *task;
sigset_t set;
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
frame = (struct compat_rt_sigframe __user *)regs->sp;
if (!access_ok(frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
set_current_blocked(&set);
if (compat_restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
if (compat_restore_altstack(&frame->uc.uc_stack))
goto badframe;
return regs->a0;
badframe:
task = current;
if (show_unhandled_signals) {
pr_info_ratelimited(
"%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
task->comm, task_pid_nr(task), __func__,
frame, (void *)regs->epc, (void *)regs->sp);
}
force_sig(SIGSEGV);
return 0;
}
static long compat_setup_sigcontext(struct compat_rt_sigframe __user *frame,
struct pt_regs *regs)
{
struct compat_sigcontext __user *sc = &frame->uc.uc_mcontext;
struct compat_user_regs_struct cregs;
long err;
regs_to_cregs(&cregs, regs);
/* sc_regs is structured the same as the start of pt_regs */
err = __copy_to_user(&sc->sc_regs, &cregs, sizeof(sc->sc_regs));
/* Save the floating-point state. */
if (has_fpu())
err |= compat_save_fp_state(regs, &sc->sc_fpregs);
return err;
}
static inline void __user *compat_get_sigframe(struct ksignal *ksig,
struct pt_regs *regs, size_t framesize)
{
unsigned long sp;
/* Default to using normal stack */
sp = regs->sp;
/*
* If we are on the alternate signal stack and would overflow it, don't.
* Return an always-bogus address instead so we will die with SIGSEGV.
*/
if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
return (void __user __force *)(-1UL);
/* This is the X/Open sanctioned signal stack switching. */
sp = sigsp(sp, ksig) - framesize;
/* Align the stack frame. */
sp &= ~0xfUL;
return (void __user *)sp;
}
int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
struct compat_rt_sigframe __user *frame;
long err = 0;
frame = compat_get_sigframe(ksig, regs, sizeof(*frame));
if (!access_ok(frame, sizeof(*frame)))
return -EFAULT;
err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
err |= compat_setup_sigcontext(frame, regs);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
return -EFAULT;
regs->ra = (unsigned long)COMPAT_VDSO_SYMBOL(
current->mm->context.vdso, rt_sigreturn);
/*
* Set up registers for signal handler.
* Registers that we don't modify keep the value they had from
* user-space at the time we took the signal.
* We always pass siginfo and mcontext, regardless of SA_SIGINFO,
* since some things rely on this (e.g. glibc's debug/segfault.c).
*/
regs->epc = (unsigned long)ksig->ka.sa.sa_handler;
regs->sp = (unsigned long)frame;
regs->a0 = ksig->sig; /* a0: signal number */
regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */
regs->a2 = (unsigned long)(&frame->uc); /* a2: ucontext pointer */
#if COMPAT_DEBUG_SIG
pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n",
current->comm, task_pid_nr(current), ksig->sig,
(void *)regs->epc, (void *)regs->ra, frame);
#endif
return 0;
}
// SPDX-License-Identifier: GPL-2.0-only
#define __SYSCALL_COMPAT
#include <linux/compat.h>
#include <linux/syscalls.h>
#include <asm-generic/mman-common.h>
#include <asm-generic/syscalls.h>
#include <asm/syscall.h>
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
asmlinkage long compat_sys_rt_sigreturn(void);
void * const compat_sys_call_table[__NR_syscalls] = {
[0 ... __NR_syscalls - 1] = sys_ni_syscall,
#include <asm/unistd.h>
};
# SPDX-License-Identifier: GPL-2.0-only
compat_vdso.lds
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for compat_vdso
#
# Symbols present in the compat_vdso
compat_vdso-syms = rt_sigreturn
compat_vdso-syms += getcpu
compat_vdso-syms += flush_icache
COMPAT_CC := $(CC)
COMPAT_LD := $(LD)
COMPAT_CC_FLAGS := -march=rv32g -mabi=ilp32
COMPAT_LD_FLAGS := -melf32lriscv
# Files to link into the compat_vdso
obj-compat_vdso = $(patsubst %, %.o, $(compat_vdso-syms)) note.o
# Build rules
targets := $(obj-compat_vdso) compat_vdso.so compat_vdso.so.dbg compat_vdso.lds
obj-compat_vdso := $(addprefix $(obj)/, $(obj-compat_vdso))
obj-y += compat_vdso.o
CPPFLAGS_compat_vdso.lds += -P -C -U$(ARCH)
# Disable profiling and instrumentation for VDSO code
GCOV_PROFILE := n
KCOV_INSTRUMENT := n
KASAN_SANITIZE := n
UBSAN_SANITIZE := n
# Force dependency
$(obj)/compat_vdso.o: $(obj)/compat_vdso.so
# link rule for the .so file, .lds has to be first
$(obj)/compat_vdso.so.dbg: $(obj)/compat_vdso.lds $(obj-compat_vdso) FORCE
$(call if_changed,compat_vdsold)
LDFLAGS_compat_vdso.so.dbg = -shared -S -soname=linux-compat_vdso.so.1 \
--build-id=sha1 --hash-style=both --eh-frame-hdr
$(obj-compat_vdso): %.o: %.S FORCE
$(call if_changed_dep,compat_vdsoas)
# strip rule for the .so file
$(obj)/%.so: OBJCOPYFLAGS := -S
$(obj)/%.so: $(obj)/%.so.dbg FORCE
$(call if_changed,objcopy)
# Generate VDSO offsets using helper script
gen-compat_vdsosym := $(srctree)/$(src)/gen_compat_vdso_offsets.sh
quiet_cmd_compat_vdsosym = VDSOSYM $@
cmd_compat_vdsosym = $(NM) $< | $(gen-compat_vdsosym) | LC_ALL=C sort > $@
include/generated/compat_vdso-offsets.h: $(obj)/compat_vdso.so.dbg FORCE
$(call if_changed,compat_vdsosym)
# actual build commands
# The DSO images are built using a special linker script
# Make sure only to export the intended __compat_vdso_xxx symbol offsets.
quiet_cmd_compat_vdsold = VDSOLD $@
cmd_compat_vdsold = $(COMPAT_LD) $(ld_flags) $(COMPAT_LD_FLAGS) -T $(filter-out FORCE,$^) -o $@.tmp && \
$(OBJCOPY) $(patsubst %, -G __compat_vdso_%, $(compat_vdso-syms)) $@.tmp $@ && \
rm $@.tmp
# actual build commands
quiet_cmd_compat_vdsoas = VDSOAS $@
cmd_compat_vdsoas = $(COMPAT_CC) $(a_flags) $(COMPAT_CC_FLAGS) -c -o $@ $<
# install commands for the unstripped file
quiet_cmd_compat_vdso_install = INSTALL $@
cmd_compat_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/compat_vdso/$@
compat_vdso.so: $(obj)/compat_vdso.so.dbg
@mkdir -p $(MODLIB)/compat_vdso
$(call cmd,compat_vdso_install)
compat_vdso_install: compat_vdso.so
/* SPDX-License-Identifier: GPL-2.0-only */
#define vdso_start compat_vdso_start
#define vdso_end compat_vdso_end
#define __VDSO_PATH "arch/riscv/kernel/compat_vdso/compat_vdso.so"
#include "../vdso/vdso.S"
/* SPDX-License-Identifier: GPL-2.0-only */
#include "../vdso/vdso.lds.S"
/* SPDX-License-Identifier: GPL-2.0-only */
#include "../vdso/flush_icache.S"
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
LC_ALL=C
sed -n -e 's/^[0]\+\(0[0-9a-fA-F]*\) . \(__vdso_[a-zA-Z0-9_]*\)$/\#define compat\2_offset\t0x\1/p'
/* SPDX-License-Identifier: GPL-2.0-only */
#include "../vdso/getcpu.S"
/* SPDX-License-Identifier: GPL-2.0-only */
#include "../vdso/note.S"
/* SPDX-License-Identifier: GPL-2.0-only */
#include "../vdso/rt_sigreturn.S"
...@@ -207,13 +207,27 @@ check_syscall_nr: ...@@ -207,13 +207,27 @@ check_syscall_nr:
* Syscall number held in a7. * Syscall number held in a7.
* If syscall number is above allowed value, redirect to ni_syscall. * If syscall number is above allowed value, redirect to ni_syscall.
*/ */
bgeu a7, t0, 1f bgeu a7, t0, 3f
#ifdef CONFIG_COMPAT
REG_L s0, PT_STATUS(sp)
srli s0, s0, SR_UXL_SHIFT
andi s0, s0, (SR_UXL >> SR_UXL_SHIFT)
li t0, (SR_UXL_32 >> SR_UXL_SHIFT)
sub t0, s0, t0
bnez t0, 1f
/* Call compat_syscall */
la s0, compat_sys_call_table
j 2f
1:
#endif
/* Call syscall */ /* Call syscall */
la s0, sys_call_table la s0, sys_call_table
2:
slli t0, a7, RISCV_LGPTR slli t0, a7, RISCV_LGPTR
add s0, s0, t0 add s0, s0, t0
REG_L s0, 0(s0) REG_L s0, 0(s0)
1: 3:
jalr s0 jalr s0
ret_from_syscall: ret_from_syscall:
......
...@@ -84,6 +84,34 @@ void show_regs(struct pt_regs *regs) ...@@ -84,6 +84,34 @@ void show_regs(struct pt_regs *regs)
dump_backtrace(regs, NULL, KERN_DEFAULT); dump_backtrace(regs, NULL, KERN_DEFAULT);
} }
#ifdef CONFIG_COMPAT
static bool compat_mode_supported __read_mostly;
bool compat_elf_check_arch(Elf32_Ehdr *hdr)
{
return compat_mode_supported &&
hdr->e_machine == EM_RISCV &&
hdr->e_ident[EI_CLASS] == ELFCLASS32;
}
static int __init compat_mode_detect(void)
{
unsigned long tmp = csr_read(CSR_STATUS);
csr_write(CSR_STATUS, (tmp & ~SR_UXL) | SR_UXL_32);
compat_mode_supported =
(csr_read(CSR_STATUS) & SR_UXL) == SR_UXL_32;
csr_write(CSR_STATUS, tmp);
pr_info("riscv: ELF compat mode %s",
compat_mode_supported ? "supported" : "failed");
return 0;
}
early_initcall(compat_mode_detect);
#endif
void start_thread(struct pt_regs *regs, unsigned long pc, void start_thread(struct pt_regs *regs, unsigned long pc,
unsigned long sp) unsigned long sp)
{ {
...@@ -98,6 +126,15 @@ void start_thread(struct pt_regs *regs, unsigned long pc, ...@@ -98,6 +126,15 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
} }
regs->epc = pc; regs->epc = pc;
regs->sp = sp; regs->sp = sp;
#ifdef CONFIG_64BIT
regs->status &= ~SR_UXL;
if (is_compat_task())
regs->status |= SR_UXL_32;
else
regs->status |= SR_UXL_64;
#endif
} }
void flush_thread(void) void flush_thread(void)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/switch_to.h> #include <asm/switch_to.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/compat.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/regset.h> #include <linux/regset.h>
...@@ -110,11 +111,6 @@ static const struct user_regset_view riscv_user_native_view = { ...@@ -110,11 +111,6 @@ static const struct user_regset_view riscv_user_native_view = {
.n = ARRAY_SIZE(riscv_user_regset), .n = ARRAY_SIZE(riscv_user_regset),
}; };
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
return &riscv_user_native_view;
}
struct pt_regs_offset { struct pt_regs_offset {
const char *name; const char *name;
int offset; int offset;
...@@ -272,3 +268,84 @@ __visible void do_syscall_trace_exit(struct pt_regs *regs) ...@@ -272,3 +268,84 @@ __visible void do_syscall_trace_exit(struct pt_regs *regs)
trace_sys_exit(regs, regs_return_value(regs)); trace_sys_exit(regs, regs_return_value(regs));
#endif #endif
} }
#ifdef CONFIG_COMPAT
static int compat_riscv_gpr_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
struct compat_user_regs_struct cregs;
regs_to_cregs(&cregs, task_pt_regs(target));
return membuf_write(&to, &cregs,
sizeof(struct compat_user_regs_struct));
}
static int compat_riscv_gpr_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
int ret;
struct compat_user_regs_struct cregs;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
cregs_to_regs(&cregs, task_pt_regs(target));
return ret;
}
static const struct user_regset compat_riscv_user_regset[] = {
[REGSET_X] = {
.core_note_type = NT_PRSTATUS,
.n = ELF_NGREG,
.size = sizeof(compat_elf_greg_t),
.align = sizeof(compat_elf_greg_t),
.regset_get = compat_riscv_gpr_get,
.set = compat_riscv_gpr_set,
},
#ifdef CONFIG_FPU
[REGSET_F] = {
.core_note_type = NT_PRFPREG,
.n = ELF_NFPREG,
.size = sizeof(elf_fpreg_t),
.align = sizeof(elf_fpreg_t),
.regset_get = riscv_fpr_get,
.set = riscv_fpr_set,
},
#endif
};
static const struct user_regset_view compat_riscv_user_native_view = {
.name = "riscv",
.e_machine = EM_RISCV,
.regsets = compat_riscv_user_regset,
.n = ARRAY_SIZE(compat_riscv_user_regset),
};
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata)
{
long ret = -EIO;
switch (request) {
default:
ret = compat_ptrace_request(child, request, caddr, cdata);
break;
}
return ret;
}
#endif /* CONFIG_COMPAT */
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
#ifdef CONFIG_COMPAT
if (test_tsk_thread_flag(task, TIF_32BIT))
return &compat_riscv_user_native_view;
else
#endif
return &riscv_user_native_view;
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (C) 2012 Regents of the University of California * Copyright (C) 2012 Regents of the University of California
*/ */
#include <linux/compat.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include <asm/ucontext.h> #include <asm/ucontext.h>
#include <asm/vdso.h> #include <asm/vdso.h>
#include <asm/signal32.h>
#include <asm/switch_to.h> #include <asm/switch_to.h>
#include <asm/csr.h> #include <asm/csr.h>
...@@ -261,6 +263,9 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) ...@@ -261,6 +263,9 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
rseq_signal_deliver(ksig, regs); rseq_signal_deliver(ksig, regs);
/* Set up the stack frame */ /* Set up the stack frame */
if (is_compat_task())
ret = compat_setup_rt_frame(ksig, oldset, regs);
else
ret = setup_rt_frame(ksig, oldset, regs); ret = setup_rt_frame(ksig, oldset, regs);
signal_setup_done(ret, ksig, 0); signal_setup_done(ret, ksig, 0);
......
...@@ -33,7 +33,9 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, ...@@ -33,7 +33,9 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
{ {
return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 0); return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 0);
} }
#else #endif
#if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT)
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags, unsigned long, prot, unsigned long, flags,
unsigned long, fd, off_t, offset) unsigned long, fd, off_t, offset)
...@@ -44,7 +46,7 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, ...@@ -44,7 +46,7 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
*/ */
return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12);
} }
#endif /* !CONFIG_64BIT */ #endif
/* /*
* Allows the instruction cache to be flushed from userspace. Despite RISC-V * Allows the instruction cache to be flushed from userspace. Despite RISC-V
......
...@@ -23,6 +23,9 @@ struct vdso_data { ...@@ -23,6 +23,9 @@ struct vdso_data {
#endif #endif
extern char vdso_start[], vdso_end[]; extern char vdso_start[], vdso_end[];
#ifdef CONFIG_COMPAT
extern char compat_vdso_start[], compat_vdso_end[];
#endif
enum vvar_pages { enum vvar_pages {
VVAR_DATA_PAGE_OFFSET, VVAR_DATA_PAGE_OFFSET,
...@@ -30,6 +33,11 @@ enum vvar_pages { ...@@ -30,6 +33,11 @@ enum vvar_pages {
VVAR_NR_PAGES, VVAR_NR_PAGES,
}; };
enum rv_vdso_map {
RV_VDSO_MAP_VVAR,
RV_VDSO_MAP_VDSO,
};
#define VVAR_SIZE (VVAR_NR_PAGES << PAGE_SHIFT) #define VVAR_SIZE (VVAR_NR_PAGES << PAGE_SHIFT)
/* /*
...@@ -52,12 +60,6 @@ struct __vdso_info { ...@@ -52,12 +60,6 @@ struct __vdso_info {
struct vm_special_mapping *cm; struct vm_special_mapping *cm;
}; };
static struct __vdso_info vdso_info __ro_after_init = {
.name = "vdso",
.vdso_code_start = vdso_start,
.vdso_code_end = vdso_end,
};
static int vdso_mremap(const struct vm_special_mapping *sm, static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma) struct vm_area_struct *new_vma)
{ {
...@@ -66,37 +68,33 @@ static int vdso_mremap(const struct vm_special_mapping *sm, ...@@ -66,37 +68,33 @@ static int vdso_mremap(const struct vm_special_mapping *sm,
return 0; return 0;
} }
static int __init __vdso_init(void) static void __init __vdso_init(struct __vdso_info *vdso_info)
{ {
unsigned int i; unsigned int i;
struct page **vdso_pagelist; struct page **vdso_pagelist;
unsigned long pfn; unsigned long pfn;
if (memcmp(vdso_info.vdso_code_start, "\177ELF", 4)) { if (memcmp(vdso_info->vdso_code_start, "\177ELF", 4))
pr_err("vDSO is not a valid ELF object!\n"); panic("vDSO is not a valid ELF object!\n");
return -EINVAL;
}
vdso_info.vdso_pages = ( vdso_info->vdso_pages = (
vdso_info.vdso_code_end - vdso_info->vdso_code_end -
vdso_info.vdso_code_start) >> vdso_info->vdso_code_start) >>
PAGE_SHIFT; PAGE_SHIFT;
vdso_pagelist = kcalloc(vdso_info.vdso_pages, vdso_pagelist = kcalloc(vdso_info->vdso_pages,
sizeof(struct page *), sizeof(struct page *),
GFP_KERNEL); GFP_KERNEL);
if (vdso_pagelist == NULL) if (vdso_pagelist == NULL)
return -ENOMEM; panic("vDSO kcalloc failed!\n");
/* Grab the vDSO code pages. */ /* Grab the vDSO code pages. */
pfn = sym_to_pfn(vdso_info.vdso_code_start); pfn = sym_to_pfn(vdso_info->vdso_code_start);
for (i = 0; i < vdso_info.vdso_pages; i++) for (i = 0; i < vdso_info->vdso_pages; i++)
vdso_pagelist[i] = pfn_to_page(pfn + i); vdso_pagelist[i] = pfn_to_page(pfn + i);
vdso_info.cm->pages = vdso_pagelist; vdso_info->cm->pages = vdso_pagelist;
return 0;
} }
#ifdef CONFIG_TIME_NS #ifdef CONFIG_TIME_NS
...@@ -116,13 +114,14 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) ...@@ -116,13 +114,14 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
{ {
struct mm_struct *mm = task->mm; struct mm_struct *mm = task->mm;
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct __vdso_info *vdso_info = mm->context.vdso_info;
mmap_read_lock(mm); mmap_read_lock(mm);
for (vma = mm->mmap; vma; vma = vma->vm_next) { for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long size = vma->vm_end - vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start;
if (vma_is_special_mapping(vma, vdso_info.dm)) if (vma_is_special_mapping(vma, vdso_info->dm))
zap_page_range(vma, vma->vm_start, size); zap_page_range(vma, vma->vm_start, size);
} }
...@@ -187,11 +186,6 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, ...@@ -187,11 +186,6 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
return vmf_insert_pfn(vma, vmf->address, pfn); return vmf_insert_pfn(vma, vmf->address, pfn);
} }
enum rv_vdso_map {
RV_VDSO_MAP_VVAR,
RV_VDSO_MAP_VDSO,
};
static struct vm_special_mapping rv_vdso_maps[] __ro_after_init = { static struct vm_special_mapping rv_vdso_maps[] __ro_after_init = {
[RV_VDSO_MAP_VVAR] = { [RV_VDSO_MAP_VVAR] = {
.name = "[vvar]", .name = "[vvar]",
...@@ -203,25 +197,46 @@ static struct vm_special_mapping rv_vdso_maps[] __ro_after_init = { ...@@ -203,25 +197,46 @@ static struct vm_special_mapping rv_vdso_maps[] __ro_after_init = {
}, },
}; };
static struct __vdso_info vdso_info __ro_after_init = {
.name = "vdso",
.vdso_code_start = vdso_start,
.vdso_code_end = vdso_end,
.dm = &rv_vdso_maps[RV_VDSO_MAP_VVAR],
.cm = &rv_vdso_maps[RV_VDSO_MAP_VDSO],
};
#ifdef CONFIG_COMPAT
static struct __vdso_info compat_vdso_info __ro_after_init = {
.name = "compat_vdso",
.vdso_code_start = compat_vdso_start,
.vdso_code_end = compat_vdso_end,
.dm = &rv_vdso_maps[RV_VDSO_MAP_VVAR],
.cm = &rv_vdso_maps[RV_VDSO_MAP_VDSO],
};
#endif
static int __init vdso_init(void) static int __init vdso_init(void)
{ {
vdso_info.dm = &rv_vdso_maps[RV_VDSO_MAP_VVAR]; __vdso_init(&vdso_info);
vdso_info.cm = &rv_vdso_maps[RV_VDSO_MAP_VDSO]; #ifdef CONFIG_COMPAT
__vdso_init(&compat_vdso_info);
#endif
return __vdso_init(); return 0;
} }
arch_initcall(vdso_init); arch_initcall(vdso_init);
static int __setup_additional_pages(struct mm_struct *mm, static int __setup_additional_pages(struct mm_struct *mm,
struct linux_binprm *bprm, struct linux_binprm *bprm,
int uses_interp) int uses_interp,
struct __vdso_info *vdso_info)
{ {
unsigned long vdso_base, vdso_text_len, vdso_mapping_len; unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
void *ret; void *ret;
BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES); BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES);
vdso_text_len = vdso_info.vdso_pages << PAGE_SHIFT; vdso_text_len = vdso_info->vdso_pages << PAGE_SHIFT;
/* Be sure to map the data page */ /* Be sure to map the data page */
vdso_mapping_len = vdso_text_len + VVAR_SIZE; vdso_mapping_len = vdso_text_len + VVAR_SIZE;
...@@ -232,16 +247,18 @@ static int __setup_additional_pages(struct mm_struct *mm, ...@@ -232,16 +247,18 @@ static int __setup_additional_pages(struct mm_struct *mm,
} }
ret = _install_special_mapping(mm, vdso_base, VVAR_SIZE, ret = _install_special_mapping(mm, vdso_base, VVAR_SIZE,
(VM_READ | VM_MAYREAD | VM_PFNMAP), vdso_info.dm); (VM_READ | VM_MAYREAD | VM_PFNMAP), vdso_info->dm);
if (IS_ERR(ret)) if (IS_ERR(ret))
goto up_fail; goto up_fail;
vdso_base += VVAR_SIZE; vdso_base += VVAR_SIZE;
mm->context.vdso = (void *)vdso_base; mm->context.vdso = (void *)vdso_base;
mm->context.vdso_info = (void *)vdso_info;
ret = ret =
_install_special_mapping(mm, vdso_base, vdso_text_len, _install_special_mapping(mm, vdso_base, vdso_text_len,
(VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC), (VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC),
vdso_info.cm); vdso_info->cm);
if (IS_ERR(ret)) if (IS_ERR(ret))
goto up_fail; goto up_fail;
...@@ -253,6 +270,24 @@ static int __setup_additional_pages(struct mm_struct *mm, ...@@ -253,6 +270,24 @@ static int __setup_additional_pages(struct mm_struct *mm,
return PTR_ERR(ret); return PTR_ERR(ret);
} }
#ifdef CONFIG_COMPAT
int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp)
{
struct mm_struct *mm = current->mm;
int ret;
if (mmap_write_lock_killable(mm))
return -EINTR;
ret = __setup_additional_pages(mm, bprm, uses_interp,
&compat_vdso_info);
mmap_write_unlock(mm);
return ret;
}
#endif
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
...@@ -261,7 +296,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) ...@@ -261,7 +296,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
if (mmap_write_lock_killable(mm)) if (mmap_write_lock_killable(mm))
return -EINTR; return -EINTR;
ret = __setup_additional_pages(mm, bprm, uses_interp); ret = __setup_additional_pages(mm, bprm, uses_interp, &vdso_info);
mmap_write_unlock(mm); mmap_write_unlock(mm);
return ret; return ret;
......
...@@ -7,12 +7,16 @@ ...@@ -7,12 +7,16 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/page.h> #include <asm/page.h>
#ifndef __VDSO_PATH
#define __VDSO_PATH "arch/riscv/kernel/vdso/vdso.so"
#endif
__PAGE_ALIGNED_DATA __PAGE_ALIGNED_DATA
.globl vdso_start, vdso_end .globl vdso_start, vdso_end
.balign PAGE_SIZE .balign PAGE_SIZE
vdso_start: vdso_start:
.incbin "arch/riscv/kernel/vdso/vdso.so" .incbin __VDSO_PATH
.balign PAGE_SIZE .balign PAGE_SIZE
vdso_end: vdso_end:
......
...@@ -399,9 +399,6 @@ config COMPAT ...@@ -399,9 +399,6 @@ config COMPAT
(and some other stuff like libraries and such) is needed for (and some other stuff like libraries and such) is needed for
executing 31 bit applications. It is safe to say "Y". executing 31 bit applications. It is safe to say "Y".
config SYSVIPC_COMPAT
def_bool y if COMPAT && SYSVIPC
config SMP config SMP
def_bool y def_bool y
......
...@@ -12,6 +12,18 @@ ...@@ -12,6 +12,18 @@
#define compat_mode_t compat_mode_t #define compat_mode_t compat_mode_t
typedef u16 compat_mode_t; typedef u16 compat_mode_t;
#define __compat_uid_t __compat_uid_t
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
#define compat_dev_t compat_dev_t
typedef u16 compat_dev_t;
#define compat_ipc_pid_t compat_ipc_pid_t
typedef u16 compat_ipc_pid_t;
#define compat_statfs compat_statfs
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p( \ #define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p( \
...@@ -53,15 +65,9 @@ typedef u16 compat_mode_t; ...@@ -53,15 +65,9 @@ typedef u16 compat_mode_t;
PSW32_MASK_MCHECK | PSW32_MASK_PSTATE | \ PSW32_MASK_MCHECK | PSW32_MASK_PSTATE | \
PSW32_ASC_PRIMARY) PSW32_ASC_PRIMARY)
#define COMPAT_USER_HZ 100
#define COMPAT_UTS_MACHINE "s390\0\0\0\0" #define COMPAT_UTS_MACHINE "s390\0\0\0\0"
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
typedef u16 compat_dev_t;
typedef u16 compat_nlink_t; typedef u16 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef __kernel_fsid_t compat_fsid_t;
typedef struct { typedef struct {
u32 mask; u32 mask;
...@@ -102,26 +108,6 @@ struct compat_stat { ...@@ -102,26 +108,6 @@ struct compat_stat {
u32 __unused5; u32 __unused5;
}; };
struct compat_flock {
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
};
#define F_GETLK64 12
#define F_SETLK64 13
#define F_SETLKW64 14
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
};
struct compat_statfs { struct compat_statfs {
u32 f_type; u32 f_type;
u32 f_bsize; u32 f_bsize;
...@@ -152,10 +138,6 @@ struct compat_statfs64 { ...@@ -152,10 +138,6 @@ struct compat_statfs64 {
u32 f_spare[4]; u32 f_spare[4];
}; };
#define COMPAT_RLIM_INFINITY 0xffffffff
#define COMPAT_OFF_T_MAX 0x7fffffff
/* /*
* A pointer passed in from user mode. This should not * A pointer passed in from user mode. This should not
* be used for syscall parameters, just declare them * be used for syscall parameters, just declare them
...@@ -178,61 +160,4 @@ static inline int is_compat_task(void) ...@@ -178,61 +160,4 @@ static inline int is_compat_task(void)
#endif #endif
struct compat_ipc64_perm {
compat_key_t key;
__compat_uid32_t uid;
__compat_gid32_t gid;
__compat_uid32_t cuid;
__compat_gid32_t cgid;
compat_mode_t mode;
unsigned short __pad1;
unsigned short seq;
unsigned short __pad2;
unsigned int __unused1;
unsigned int __unused2;
};
struct compat_semid64_ds {
struct compat_ipc64_perm sem_perm;
compat_ulong_t sem_otime;
compat_ulong_t sem_otime_high;
compat_ulong_t sem_ctime;
compat_ulong_t sem_ctime_high;
compat_ulong_t sem_nsems;
compat_ulong_t __unused1;
compat_ulong_t __unused2;
};
struct compat_msqid64_ds {
struct compat_ipc64_perm msg_perm;
compat_ulong_t msg_stime;
compat_ulong_t msg_stime_high;
compat_ulong_t msg_rtime;
compat_ulong_t msg_rtime_high;
compat_ulong_t msg_ctime;
compat_ulong_t msg_ctime_high;
compat_ulong_t msg_cbytes;
compat_ulong_t msg_qnum;
compat_ulong_t msg_qbytes;
compat_pid_t msg_lspid;
compat_pid_t msg_lrpid;
compat_ulong_t __unused1;
compat_ulong_t __unused2;
};
struct compat_shmid64_ds {
struct compat_ipc64_perm shm_perm;
compat_size_t shm_segsz;
compat_ulong_t shm_atime;
compat_ulong_t shm_atime_high;
compat_ulong_t shm_dtime;
compat_ulong_t shm_dtime_high;
compat_ulong_t shm_ctime;
compat_ulong_t shm_ctime_high;
compat_pid_t shm_cpid;
compat_pid_t shm_lpid;
compat_ulong_t shm_nattch;
compat_ulong_t __unused1;
compat_ulong_t __unused2;
};
#endif /* _ASM_S390X_COMPAT_H */ #endif /* _ASM_S390X_COMPAT_H */
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_SIGPROCMASK
# ifdef CONFIG_COMPAT # ifdef CONFIG_COMPAT
# define __ARCH_WANT_COMPAT_STAT
# define __ARCH_WANT_SYS_TIME32 # define __ARCH_WANT_SYS_TIME32
# define __ARCH_WANT_SYS_UTIME32 # define __ARCH_WANT_SYS_UTIME32
# endif # endif
......
...@@ -488,9 +488,4 @@ config COMPAT ...@@ -488,9 +488,4 @@ config COMPAT
select ARCH_WANT_OLD_COMPAT_IPC select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT_OLD_SIGACTION select COMPAT_OLD_SIGACTION
config SYSVIPC_COMPAT
bool
depends on COMPAT && SYSVIPC
default y
source "drivers/sbus/char/Kconfig" source "drivers/sbus/char/Kconfig"
...@@ -9,17 +9,25 @@ ...@@ -9,17 +9,25 @@
#define compat_mode_t compat_mode_t #define compat_mode_t compat_mode_t
typedef u16 compat_mode_t; typedef u16 compat_mode_t;
#define __compat_uid_t __compat_uid_t
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
#define compat_dev_t compat_dev_t
typedef u16 compat_dev_t;
#define compat_ipc_pid_t compat_ipc_pid_t
typedef u16 compat_ipc_pid_t;
#define compat_ipc64_perm compat_ipc64_perm
#define COMPAT_RLIM_INFINITY 0x7fffffff
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#define COMPAT_USER_HZ 100
#define COMPAT_UTS_MACHINE "sparc\0\0" #define COMPAT_UTS_MACHINE "sparc\0\0"
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
typedef u16 compat_dev_t;
typedef s16 compat_nlink_t; typedef s16 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef __kernel_fsid_t compat_fsid_t;
struct compat_stat { struct compat_stat {
compat_dev_t st_dev; compat_dev_t st_dev;
...@@ -75,46 +83,7 @@ struct compat_stat64 { ...@@ -75,46 +83,7 @@ struct compat_stat64 {
unsigned int __unused5; unsigned int __unused5;
}; };
struct compat_flock { #define __ARCH_COMPAT_FLOCK_PAD short __unused;
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
short __unused;
};
#define F_GETLK64 12
#define F_SETLK64 13
#define F_SETLKW64 14
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
short __unused;
};
struct compat_statfs {
int f_type;
int f_bsize;
int f_blocks;
int f_bfree;
int f_bavail;
int f_files;
int f_ffree;
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_frsize;
int f_flags;
int f_spare[4];
};
#define COMPAT_RLIM_INFINITY 0x7fffffff
#define COMPAT_OFF_T_MAX 0x7fffffff
struct compat_ipc64_perm { struct compat_ipc64_perm {
compat_key_t key; compat_key_t key;
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_COMPAT_SYS_SENDFILE #define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_COMPAT_STAT
#endif #endif
#ifdef __32bit_syscall_numbers__ #ifdef __32bit_syscall_numbers__
......
...@@ -2872,10 +2872,6 @@ config COMPAT ...@@ -2872,10 +2872,6 @@ config COMPAT
if COMPAT if COMPAT
config COMPAT_FOR_U64_ALIGNMENT config COMPAT_FOR_U64_ALIGNMENT
def_bool y def_bool y
config SYSVIPC_COMPAT
def_bool y
depends on SYSVIPC
endif endif
endmenu endmenu
......
...@@ -15,17 +15,23 @@ ...@@ -15,17 +15,23 @@
#define compat_mode_t compat_mode_t #define compat_mode_t compat_mode_t
typedef u16 compat_mode_t; typedef u16 compat_mode_t;
#define __compat_uid_t __compat_uid_t
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
#define compat_dev_t compat_dev_t
typedef u16 compat_dev_t;
#define compat_ipc_pid_t compat_ipc_pid_t
typedef u16 compat_ipc_pid_t;
#define compat_statfs compat_statfs
#include <asm-generic/compat.h> #include <asm-generic/compat.h>
#define COMPAT_USER_HZ 100
#define COMPAT_UTS_MACHINE "i686\0\0" #define COMPAT_UTS_MACHINE "i686\0\0"
typedef u16 __compat_uid_t;
typedef u16 __compat_gid_t;
typedef u16 compat_dev_t;
typedef u16 compat_nlink_t; typedef u16 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef __kernel_fsid_t compat_fsid_t;
struct compat_stat { struct compat_stat {
compat_dev_t st_dev; compat_dev_t st_dev;
...@@ -50,29 +56,11 @@ struct compat_stat { ...@@ -50,29 +56,11 @@ struct compat_stat {
u32 __unused5; u32 __unused5;
}; };
struct compat_flock {
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
compat_pid_t l_pid;
};
#define F_GETLK64 12 /* using 'struct flock64' */
#define F_SETLK64 13
#define F_SETLKW64 14
/* /*
* IA32 uses 4 byte alignment for 64 bit quantities, * IA32 uses 4 byte alignment for 64 bit quantities, so we need to pack the
* so we need to pack this structure. * compat flock64 structure.
*/ */
struct compat_flock64 { #define __ARCH_NEED_COMPAT_FLOCK64_PACKED
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
} __attribute__((packed));
struct compat_statfs { struct compat_statfs {
int f_type; int f_type;
...@@ -89,68 +77,6 @@ struct compat_statfs { ...@@ -89,68 +77,6 @@ struct compat_statfs {
int f_spare[4]; int f_spare[4];
}; };
#define COMPAT_RLIM_INFINITY 0xffffffff
#define COMPAT_OFF_T_MAX 0x7fffffff
struct compat_ipc64_perm {
compat_key_t key;
__compat_uid32_t uid;
__compat_gid32_t gid;
__compat_uid32_t cuid;
__compat_gid32_t cgid;
unsigned short mode;
unsigned short __pad1;
unsigned short seq;
unsigned short __pad2;
compat_ulong_t unused1;
compat_ulong_t unused2;
};
struct compat_semid64_ds {
struct compat_ipc64_perm sem_perm;
compat_ulong_t sem_otime;
compat_ulong_t sem_otime_high;
compat_ulong_t sem_ctime;
compat_ulong_t sem_ctime_high;
compat_ulong_t sem_nsems;
compat_ulong_t __unused3;
compat_ulong_t __unused4;
};
struct compat_msqid64_ds {
struct compat_ipc64_perm msg_perm;
compat_ulong_t msg_stime;
compat_ulong_t msg_stime_high;
compat_ulong_t msg_rtime;
compat_ulong_t msg_rtime_high;
compat_ulong_t msg_ctime;
compat_ulong_t msg_ctime_high;
compat_ulong_t msg_cbytes;
compat_ulong_t msg_qnum;
compat_ulong_t msg_qbytes;
compat_pid_t msg_lspid;
compat_pid_t msg_lrpid;
compat_ulong_t __unused4;
compat_ulong_t __unused5;
};
struct compat_shmid64_ds {
struct compat_ipc64_perm shm_perm;
compat_size_t shm_segsz;
compat_ulong_t shm_atime;
compat_ulong_t shm_atime_high;
compat_ulong_t shm_dtime;
compat_ulong_t shm_dtime_high;
compat_ulong_t shm_ctime;
compat_ulong_t shm_ctime_high;
compat_pid_t shm_cpid;
compat_pid_t shm_lpid;
compat_ulong_t shm_nattch;
compat_ulong_t __unused4;
compat_ulong_t __unused5;
};
#ifdef CONFIG_X86_X32_ABI #ifdef CONFIG_X86_X32_ABI
#define COMPAT_USE_64BIT_TIME \ #define COMPAT_USE_64BIT_TIME \
(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)) (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
# include <asm/unistd_32_ia32.h> # include <asm/unistd_32_ia32.h>
# define __ARCH_WANT_SYS_TIME # define __ARCH_WANT_SYS_TIME
# define __ARCH_WANT_SYS_UTIME # define __ARCH_WANT_SYS_UTIME
# define __ARCH_WANT_COMPAT_STAT
# define __ARCH_WANT_COMPAT_SYS_PREADV64 # define __ARCH_WANT_COMPAT_SYS_PREADV64
# define __ARCH_WANT_COMPAT_SYS_PWRITEV64 # define __ARCH_WANT_COMPAT_SYS_PWRITEV64
# define __ARCH_WANT_COMPAT_SYS_PREADV64V2 # define __ARCH_WANT_COMPAT_SYS_PREADV64V2
......
...@@ -224,6 +224,21 @@ SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length) ...@@ -224,6 +224,21 @@ SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
} }
#endif /* BITS_PER_LONG == 32 */ #endif /* BITS_PER_LONG == 32 */
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_TRUNCATE64)
COMPAT_SYSCALL_DEFINE3(truncate64, const char __user *, pathname,
compat_arg_u64_dual(length))
{
return ksys_truncate(pathname, compat_arg_u64_glue(length));
}
#endif
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_FTRUNCATE64)
COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd,
compat_arg_u64_dual(length))
{
return ksys_ftruncate(fd, compat_arg_u64_glue(length));
}
#endif
int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{ {
...@@ -339,6 +354,15 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) ...@@ -339,6 +354,15 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
return ksys_fallocate(fd, mode, offset, len); return ksys_fallocate(fd, mode, offset, len);
} }
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_FALLOCATE)
COMPAT_SYSCALL_DEFINE6(fallocate, int, fd, int, mode, compat_arg_u64_dual(offset),
compat_arg_u64_dual(len))
{
return ksys_fallocate(fd, mode, compat_arg_u64_glue(offset),
compat_arg_u64_glue(len));
}
#endif
/* /*
* access() needs to use the real uid/gid, not the effective uid/gid. * access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and * We do this by temporarily clearing all FS-related capabilities and
......
...@@ -682,6 +682,14 @@ SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf, ...@@ -682,6 +682,14 @@ SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf,
return ksys_pread64(fd, buf, count, pos); return ksys_pread64(fd, buf, count, pos);
} }
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_PREAD64)
COMPAT_SYSCALL_DEFINE5(pread64, unsigned int, fd, char __user *, buf,
size_t, count, compat_arg_u64_dual(pos))
{
return ksys_pread64(fd, buf, count, compat_arg_u64_glue(pos));
}
#endif
ssize_t ksys_pwrite64(unsigned int fd, const char __user *buf, ssize_t ksys_pwrite64(unsigned int fd, const char __user *buf,
size_t count, loff_t pos) size_t count, loff_t pos)
{ {
...@@ -708,6 +716,14 @@ SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf, ...@@ -708,6 +716,14 @@ SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf,
return ksys_pwrite64(fd, buf, count, pos); return ksys_pwrite64(fd, buf, count, pos);
} }
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_PWRITE64)
COMPAT_SYSCALL_DEFINE5(pwrite64, unsigned int, fd, const char __user *, buf,
size_t, count, compat_arg_u64_dual(pos))
{
return ksys_pwrite64(fd, buf, count, compat_arg_u64_glue(pos));
}
#endif
static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter,
loff_t *ppos, int type, rwf_t flags) loff_t *ppos, int type, rwf_t flags)
{ {
......
...@@ -660,7 +660,7 @@ SYSCALL_DEFINE5(statx, ...@@ -660,7 +660,7 @@ SYSCALL_DEFINE5(statx,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_STAT)
static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
{ {
struct compat_stat tmp; struct compat_stat tmp;
......
...@@ -373,6 +373,15 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, ...@@ -373,6 +373,15 @@ SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes,
return ksys_sync_file_range(fd, offset, nbytes, flags); return ksys_sync_file_range(fd, offset, nbytes, flags);
} }
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_SYNC_FILE_RANGE)
COMPAT_SYSCALL_DEFINE6(sync_file_range, int, fd, compat_arg_u64_dual(offset),
compat_arg_u64_dual(nbytes), unsigned int, flags)
{
return ksys_sync_file_range(fd, compat_arg_u64_glue(offset),
compat_arg_u64_glue(nbytes), flags);
}
#endif
/* It would be nice if people remember that not all the world's an i386 /* It would be nice if people remember that not all the world's an i386
when they introduce new system calls */ when they introduce new system calls */
SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags, SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags,
......
...@@ -2,6 +2,25 @@ ...@@ -2,6 +2,25 @@
#ifndef __ASM_GENERIC_COMPAT_H #ifndef __ASM_GENERIC_COMPAT_H
#define __ASM_GENERIC_COMPAT_H #define __ASM_GENERIC_COMPAT_H
#ifndef COMPAT_USER_HZ
#define COMPAT_USER_HZ 100
#endif
#ifndef COMPAT_RLIM_INFINITY
#define COMPAT_RLIM_INFINITY 0xffffffff
#endif
#ifndef COMPAT_OFF_T_MAX
#define COMPAT_OFF_T_MAX 0x7fffffff
#endif
#if !defined(compat_arg_u64) && !defined(CONFIG_CPU_BIG_ENDIAN)
#define compat_arg_u64(name) u32 name##_lo, u32 name##_hi
#define compat_arg_u64_dual(name) u32, name##_lo, u32, name##_hi
#define compat_arg_u64_glue(name) (((u64)name##_lo & 0xffffffffUL) | \
((u64)name##_hi << 32))
#endif
/* These types are common across all compat ABIs */ /* These types are common across all compat ABIs */
typedef u32 compat_size_t; typedef u32 compat_size_t;
typedef s32 compat_ssize_t; typedef s32 compat_ssize_t;
...@@ -24,6 +43,11 @@ typedef u32 compat_caddr_t; ...@@ -24,6 +43,11 @@ typedef u32 compat_caddr_t;
typedef u32 compat_aio_context_t; typedef u32 compat_aio_context_t;
typedef u32 compat_old_sigset_t; typedef u32 compat_old_sigset_t;
#ifndef __compat_uid_t
typedef u32 __compat_uid_t;
typedef u32 __compat_gid_t;
#endif
#ifndef __compat_uid32_t #ifndef __compat_uid32_t
typedef u32 __compat_uid32_t; typedef u32 __compat_uid32_t;
typedef u32 __compat_gid32_t; typedef u32 __compat_gid32_t;
...@@ -47,4 +71,93 @@ typedef u32 compat_sigset_word; ...@@ -47,4 +71,93 @@ typedef u32 compat_sigset_word;
#define _COMPAT_NSIG_BPW 32 #define _COMPAT_NSIG_BPW 32
#endif #endif
#ifndef compat_dev_t
typedef u32 compat_dev_t;
#endif
#ifndef compat_ipc_pid_t
typedef s32 compat_ipc_pid_t;
#endif
#ifndef compat_fsid_t
typedef __kernel_fsid_t compat_fsid_t;
#endif
#ifndef compat_statfs
struct compat_statfs {
compat_int_t f_type;
compat_int_t f_bsize;
compat_int_t f_blocks;
compat_int_t f_bfree;
compat_int_t f_bavail;
compat_int_t f_files;
compat_int_t f_ffree;
compat_fsid_t f_fsid;
compat_int_t f_namelen;
compat_int_t f_frsize;
compat_int_t f_flags;
compat_int_t f_spare[4];
};
#endif
#ifndef compat_ipc64_perm
struct compat_ipc64_perm {
compat_key_t key;
__compat_uid32_t uid;
__compat_gid32_t gid;
__compat_uid32_t cuid;
__compat_gid32_t cgid;
compat_mode_t mode;
unsigned char __pad1[4 - sizeof(compat_mode_t)];
compat_ushort_t seq;
compat_ushort_t __pad2;
compat_ulong_t unused1;
compat_ulong_t unused2;
};
struct compat_semid64_ds {
struct compat_ipc64_perm sem_perm;
compat_ulong_t sem_otime;
compat_ulong_t sem_otime_high;
compat_ulong_t sem_ctime;
compat_ulong_t sem_ctime_high;
compat_ulong_t sem_nsems;
compat_ulong_t __unused3;
compat_ulong_t __unused4;
};
struct compat_msqid64_ds {
struct compat_ipc64_perm msg_perm;
compat_ulong_t msg_stime;
compat_ulong_t msg_stime_high;
compat_ulong_t msg_rtime;
compat_ulong_t msg_rtime_high;
compat_ulong_t msg_ctime;
compat_ulong_t msg_ctime_high;
compat_ulong_t msg_cbytes;
compat_ulong_t msg_qnum;
compat_ulong_t msg_qbytes;
compat_pid_t msg_lspid;
compat_pid_t msg_lrpid;
compat_ulong_t __unused4;
compat_ulong_t __unused5;
};
struct compat_shmid64_ds {
struct compat_ipc64_perm shm_perm;
compat_size_t shm_segsz;
compat_ulong_t shm_atime;
compat_ulong_t shm_atime_high;
compat_ulong_t shm_dtime;
compat_ulong_t shm_dtime_high;
compat_ulong_t shm_ctime;
compat_ulong_t shm_ctime_high;
compat_pid_t shm_cpid;
compat_pid_t shm_lpid;
compat_ulong_t shm_nattch;
compat_ulong_t __unused4;
compat_ulong_t __unused5;
};
#endif
#endif #endif
...@@ -258,6 +258,37 @@ struct compat_rlimit { ...@@ -258,6 +258,37 @@ struct compat_rlimit {
compat_ulong_t rlim_max; compat_ulong_t rlim_max;
}; };
#ifdef __ARCH_NEED_COMPAT_FLOCK64_PACKED
#define __ARCH_COMPAT_FLOCK64_PACK __attribute__((packed))
#else
#define __ARCH_COMPAT_FLOCK64_PACK
#endif
struct compat_flock {
short l_type;
short l_whence;
compat_off_t l_start;
compat_off_t l_len;
#ifdef __ARCH_COMPAT_FLOCK_EXTRA_SYSID
__ARCH_COMPAT_FLOCK_EXTRA_SYSID
#endif
compat_pid_t l_pid;
#ifdef __ARCH_COMPAT_FLOCK_PAD
__ARCH_COMPAT_FLOCK_PAD
#endif
};
struct compat_flock64 {
short l_type;
short l_whence;
compat_loff_t l_start;
compat_loff_t l_len;
compat_pid_t l_pid;
#ifdef __ARCH_COMPAT_FLOCK64_PAD
__ARCH_COMPAT_FLOCK64_PAD
#endif
} __ARCH_COMPAT_FLOCK64_PACK;
struct compat_rusage { struct compat_rusage {
struct old_timeval32 ru_utime; struct old_timeval32 ru_utime;
struct old_timeval32 ru_stime; struct old_timeval32 ru_stime;
...@@ -895,6 +926,43 @@ asmlinkage long compat_sys_sigaction(int sig, ...@@ -895,6 +926,43 @@ asmlinkage long compat_sys_sigaction(int sig,
/* obsolete: net/socket.c */ /* obsolete: net/socket.c */
asmlinkage long compat_sys_socketcall(int call, u32 __user *args); asmlinkage long compat_sys_socketcall(int call, u32 __user *args);
#ifdef __ARCH_WANT_COMPAT_TRUNCATE64
asmlinkage long compat_sys_truncate64(const char __user *pathname, compat_arg_u64(len));
#endif
#ifdef __ARCH_WANT_COMPAT_FTRUNCATE64
asmlinkage long compat_sys_ftruncate64(unsigned int fd, compat_arg_u64(len));
#endif
#ifdef __ARCH_WANT_COMPAT_FALLOCATE
asmlinkage long compat_sys_fallocate(int fd, int mode, compat_arg_u64(offset),
compat_arg_u64(len));
#endif
#ifdef __ARCH_WANT_COMPAT_PREAD64
asmlinkage long compat_sys_pread64(unsigned int fd, char __user *buf, size_t count,
compat_arg_u64(pos));
#endif
#ifdef __ARCH_WANT_COMPAT_PWRITE64
asmlinkage long compat_sys_pwrite64(unsigned int fd, const char __user *buf, size_t count,
compat_arg_u64(pos));
#endif
#ifdef __ARCH_WANT_COMPAT_SYNC_FILE_RANGE
asmlinkage long compat_sys_sync_file_range(int fd, compat_arg_u64(pos),
compat_arg_u64(nbytes), unsigned int flags);
#endif
#ifdef __ARCH_WANT_COMPAT_FADVISE64_64
asmlinkage long compat_sys_fadvise64_64(int fd, compat_arg_u64(pos),
compat_arg_u64(len), int advice);
#endif
#ifdef __ARCH_WANT_COMPAT_READAHEAD
asmlinkage long compat_sys_readahead(int fd, compat_arg_u64(offset), size_t count);
#endif
#endif /* CONFIG_ARCH_HAS_SYSCALL_WRAPPER */ #endif /* CONFIG_ARCH_HAS_SYSCALL_WRAPPER */
/** /**
......
...@@ -116,13 +116,13 @@ ...@@ -116,13 +116,13 @@
#define F_GETSIG 11 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */
#endif #endif
#ifndef CONFIG_64BIT #if __BITS_PER_LONG == 32 || defined(__KERNEL__)
#ifndef F_GETLK64 #ifndef F_GETLK64
#define F_GETLK64 12 /* using 'struct flock64' */ #define F_GETLK64 12 /* using 'struct flock64' */
#define F_SETLK64 13 #define F_SETLK64 13
#define F_SETLKW64 14 #define F_SETLKW64 14
#endif #endif
#endif #endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */
#ifndef F_SETOWN_EX #ifndef F_SETOWN_EX
#define F_SETOWN_EX 15 #define F_SETOWN_EX 15
...@@ -192,25 +192,19 @@ struct f_owner_ex { ...@@ -192,25 +192,19 @@ struct f_owner_ex {
#define F_LINUX_SPECIFIC_BASE 1024 #define F_LINUX_SPECIFIC_BASE 1024
#ifndef HAVE_ARCH_STRUCT_FLOCK
#ifndef __ARCH_FLOCK_PAD
#define __ARCH_FLOCK_PAD
#endif
struct flock { struct flock {
short l_type; short l_type;
short l_whence; short l_whence;
__kernel_off_t l_start; __kernel_off_t l_start;
__kernel_off_t l_len; __kernel_off_t l_len;
__kernel_pid_t l_pid; __kernel_pid_t l_pid;
__ARCH_FLOCK_PAD #ifdef __ARCH_FLOCK_EXTRA_SYSID
}; __ARCH_FLOCK_EXTRA_SYSID
#endif #endif
#ifdef __ARCH_FLOCK_PAD
#ifndef HAVE_ARCH_STRUCT_FLOCK64 __ARCH_FLOCK_PAD
#ifndef __ARCH_FLOCK64_PAD
#define __ARCH_FLOCK64_PAD
#endif #endif
};
struct flock64 { struct flock64 {
short l_type; short l_type;
...@@ -218,8 +212,9 @@ struct flock64 { ...@@ -218,8 +212,9 @@ struct flock64 {
__kernel_loff_t l_start; __kernel_loff_t l_start;
__kernel_loff_t l_len; __kernel_loff_t l_len;
__kernel_pid_t l_pid; __kernel_pid_t l_pid;
#ifdef __ARCH_FLOCK64_PAD
__ARCH_FLOCK64_PAD __ARCH_FLOCK64_PAD
};
#endif #endif
};
#endif /* _ASM_GENERIC_FCNTL_H */ #endif /* _ASM_GENERIC_FCNTL_H */
...@@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog) ...@@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog)
/* kernel/ptrace.c */ /* kernel/ptrace.c */
#define __NR_ptrace 117 #define __NR_ptrace 117
__SYSCALL(__NR_ptrace, sys_ptrace) __SC_COMP(__NR_ptrace, sys_ptrace, compat_sys_ptrace)
/* kernel/sched/core.c */ /* kernel/sched/core.c */
#define __NR_sched_setparam 118 #define __NR_sched_setparam 118
...@@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq) ...@@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq)
#define __NR_kexec_file_load 294 #define __NR_kexec_file_load 294
__SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) __SYSCALL(__NR_kexec_file_load, sys_kexec_file_load)
/* 295 through 402 are unassigned to sync up with generic numbers, don't use */ /* 295 through 402 are unassigned to sync up with generic numbers, don't use */
#if __BITS_PER_LONG == 32 #if defined(__SYSCALL_COMPAT) || __BITS_PER_LONG == 32
#define __NR_clock_gettime64 403 #define __NR_clock_gettime64 403
__SYSCALL(__NR_clock_gettime64, sys_clock_gettime) __SYSCALL(__NR_clock_gettime64, sys_clock_gettime)
#define __NR_clock_settime64 404 #define __NR_clock_settime64 404
......
...@@ -390,6 +390,10 @@ config SYSVIPC_SYSCTL ...@@ -390,6 +390,10 @@ config SYSVIPC_SYSCTL
depends on SYSCTL depends on SYSCTL
default y default y
config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC
config POSIX_MQUEUE config POSIX_MQUEUE
bool "POSIX Message Queues" bool "POSIX Message Queues"
depends on NET depends on NET
......
...@@ -214,5 +214,16 @@ SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice) ...@@ -214,5 +214,16 @@ SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice)
return ksys_fadvise64_64(fd, offset, len, advice); return ksys_fadvise64_64(fd, offset, len, advice);
} }
#endif
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_FADVISE64_64)
COMPAT_SYSCALL_DEFINE6(fadvise64_64, int, fd, compat_arg_u64_dual(offset),
compat_arg_u64_dual(len), int, advice)
{
return ksys_fadvise64_64(fd, compat_arg_u64_glue(offset),
compat_arg_u64_glue(len), advice);
}
#endif #endif
#endif #endif
...@@ -746,6 +746,13 @@ SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count) ...@@ -746,6 +746,13 @@ SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count)
return ksys_readahead(fd, offset, count); return ksys_readahead(fd, offset, count);
} }
#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_READAHEAD)
COMPAT_SYSCALL_DEFINE4(readahead, int, fd, compat_arg_u64_dual(offset), size_t, count)
{
return ksys_readahead(fd, compat_arg_u64_glue(offset), count);
}
#endif
/** /**
* readahead_expand - Expand a readahead request * readahead_expand - Expand a readahead request
* @ractl: The request to be expanded * @ractl: The request to be expanded
......
...@@ -115,13 +115,11 @@ ...@@ -115,13 +115,11 @@
#define F_GETSIG 11 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */
#endif #endif
#ifndef CONFIG_64BIT
#ifndef F_GETLK64 #ifndef F_GETLK64
#define F_GETLK64 12 /* using 'struct flock64' */ #define F_GETLK64 12 /* using 'struct flock64' */
#define F_SETLK64 13 #define F_SETLK64 13
#define F_SETLKW64 14 #define F_SETLKW64 14
#endif #endif
#endif
#ifndef F_SETOWN_EX #ifndef F_SETOWN_EX
#define F_SETOWN_EX 15 #define F_SETOWN_EX 15
...@@ -187,25 +185,19 @@ struct f_owner_ex { ...@@ -187,25 +185,19 @@ struct f_owner_ex {
#define F_LINUX_SPECIFIC_BASE 1024 #define F_LINUX_SPECIFIC_BASE 1024
#ifndef HAVE_ARCH_STRUCT_FLOCK
#ifndef __ARCH_FLOCK_PAD
#define __ARCH_FLOCK_PAD
#endif
struct flock { struct flock {
short l_type; short l_type;
short l_whence; short l_whence;
__kernel_off_t l_start; __kernel_off_t l_start;
__kernel_off_t l_len; __kernel_off_t l_len;
__kernel_pid_t l_pid; __kernel_pid_t l_pid;
__ARCH_FLOCK_PAD #ifdef __ARCH_FLOCK_EXTRA_SYSID
}; __ARCH_FLOCK_EXTRA_SYSID
#endif #endif
#ifdef __ARCH_FLOCK_PAD
#ifndef HAVE_ARCH_STRUCT_FLOCK64 __ARCH_FLOCK_PAD
#ifndef __ARCH_FLOCK64_PAD
#define __ARCH_FLOCK64_PAD
#endif #endif
};
struct flock64 { struct flock64 {
short l_type; short l_type;
...@@ -213,8 +205,9 @@ struct flock64 { ...@@ -213,8 +205,9 @@ struct flock64 {
__kernel_loff_t l_start; __kernel_loff_t l_start;
__kernel_loff_t l_len; __kernel_loff_t l_len;
__kernel_pid_t l_pid; __kernel_pid_t l_pid;
#ifdef __ARCH_FLOCK64_PAD
__ARCH_FLOCK64_PAD __ARCH_FLOCK64_PAD
};
#endif #endif
};
#endif /* _ASM_GENERIC_FCNTL_H */ #endif /* _ASM_GENERIC_FCNTL_H */
...@@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog) ...@@ -383,7 +383,7 @@ __SYSCALL(__NR_syslog, sys_syslog)
/* kernel/ptrace.c */ /* kernel/ptrace.c */
#define __NR_ptrace 117 #define __NR_ptrace 117
__SYSCALL(__NR_ptrace, sys_ptrace) __SC_COMP(__NR_ptrace, sys_ptrace, compat_sys_ptrace)
/* kernel/sched/core.c */ /* kernel/sched/core.c */
#define __NR_sched_setparam 118 #define __NR_sched_setparam 118
...@@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq) ...@@ -779,7 +779,7 @@ __SYSCALL(__NR_rseq, sys_rseq)
#define __NR_kexec_file_load 294 #define __NR_kexec_file_load 294
__SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) __SYSCALL(__NR_kexec_file_load, sys_kexec_file_load)
/* 295 through 402 are unassigned to sync up with generic numbers, don't use */ /* 295 through 402 are unassigned to sync up with generic numbers, don't use */
#if __BITS_PER_LONG == 32 #if defined(__SYSCALL_COMPAT) || __BITS_PER_LONG == 32
#define __NR_clock_gettime64 403 #define __NR_clock_gettime64 403
__SYSCALL(__NR_clock_gettime64, sys_clock_gettime) __SYSCALL(__NR_clock_gettime64, sys_clock_gettime)
#define __NR_clock_settime64 404 #define __NR_clock_settime64 404
......
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