Right now CONFIG_COMPAT means enabling AARCH32 support in the ARM64 traget, which we want to split out so we can it to mean any 32bit ABI support instead.
---
arch/arm64/Kconfig | 6 +++++-
arch/arm64/include/asm/compat.h | 32 ++++++++++++++++++++++++++++----
arch/arm64/include/asm/elf.h | 19 ++++++++++++++-----
arch/arm64/include/asm/fpsimd.h | 2 +-
arch/arm64/include/asm/hwcap.h | 3 ++-
arch/arm64/include/asm/memory.h | 6 +++---
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/include/asm/ptrace.h | 2 +-
arch/arm64/include/asm/stat.h | 2 +-
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/entry.S | 6 +++---
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/hw_breakpoint.c | 6 +++---
arch/arm64/kernel/process.c | 6 +++---
arch/arm64/kernel/ptrace.c | 28 ++++++++++++++--------------
arch/arm64/kernel/signal.c | 4 ++--
arch/arm64/kernel/traps.c | 4 ++--
arch/arm64/kernel/vdso.c | 6 +++---
arch/arm64/mm/fault.c | 1 +
arch/arm64/mm/mmap.c | 1 +
20 files changed, 90 insertions(+), 50 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index ae323a4..cc64df5 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -247,9 +247,13 @@ menu "Userspace binary formats"
source "fs/Kconfig.binfmt"
config COMPAT
+ def_bool y
+ depends on ARM64_AARCH32
+ select COMPAT_BINFMT_ELF
+
+config ARM64_AARCH32
bool "Kernel support for 32-bit EL0"
depends on !ARM64_64K_PAGES
- select COMPAT_BINFMT_ELF
select HAVE_UID16
select OLD_SIGSUSPEND3
select COMPAT_OLD_SIGACTION
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 899af80..5ab2676 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -279,28 +279,52 @@ struct compat_shmid64_ds {
compat_ulong_t __unused5;
};
-static inline int is_compat_task(void)
+#if defined(CONFIG_ARM64_AARCH32)
+static inline int is_aarch32_task(void)
{
return test_thread_flag(TIF_32BIT);
}
-static inline int is_compat_thread(struct thread_info *thread)
+static inline int is_aarch32_thread(struct thread_info *thread)
{
return test_ti_thread_flag(thread, TIF_32BIT);
}
+#else
+static inline int is_aarch32_task(void)
+{
+ return 0;
+}
+
+static inline int is_aarch32_thread(struct thread_info *thread)
+{
+ return 0;
+}
+#endif
+
#else /* !CONFIG_COMPAT */
-static inline int is_compat_task(void)
+static inline int is_aarch32_task(void)
{
return 0;
}
-static inline int is_compat_thread(struct thread_info *thread)
+static inline int is_aarch32_thread(struct thread_info *thread)
{
return 0;
}
#endif /* CONFIG_COMPAT */
+
+static inline int is_compat_task(void)
+{
+ return is_aarch32_task();
+}
+
+static inline int is_compat_thread(struct thread_info *thread)
+{
+ return is_aarch32_thread(thread);
+}
+
#endif /* __KERNEL__ */
#endif /* __ASM_COMPAT_H */
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index e7fa87f..0a89e94 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -153,24 +153,33 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 / 3))
+#ifdef CONFIG_ARM64_AARCH32
/* AArch32 registers. */
#define COMPAT_ELF_NGREG 18
-typedef unsigned int compat_elf_greg_t;
-typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
+typedef unsigned int compat_a32_elf_greg_t;
+typedef compat_a32_elf_greg_t compat_a32_elf_gregset_t[COMPAT_ELF_NGREG];
/* AArch32 EABI. */
#define EF_ARM_EABI_MASK 0xff000000
-#define compat_elf_check_arch(x) (((x)->e_machine == EM_ARM) && \
+#define compat_elf_a32_check_arch(x) (((x)->e_machine == EM_ARM) && \
((x)->e_flags & EF_ARM_EABI_MASK))
-#define compat_start_thread compat_start_thread
-#define COMPAT_SET_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
+#define COMPAT_SET_A32_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
#define COMPAT_ARCH_DLINFO
+
extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
int uses_interp);
#define compat_arch_setup_additional_pages \
aarch32_setup_vectors_page
+typedef compat_a32_elf_greg_t compat_elf_greg_t;
+typedef compat_a32_elf_gregset_t compat_elf_gregset_t;
+#endif
+
+#define compat_elf_check_arch(x) compat_elf_a32_check_arch(x)
+#define COMPAT_SET_PERSONALITY(ex) COMPAT_SET_A32_PERSONALITY(x)
+#define compat_start_thread compat_start_thread
+
#endif /* CONFIG_COMPAT */
#endif
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index c43b4ac..1924290 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -39,7 +39,7 @@ struct fpsimd_state {
};
};
-#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+#if defined(__KERNEL__) && defined(CONFIG_ARM64_AARCH32)
/* Masks for extracting the FPSR and FPCR from the FPSCR */
#define VFP_FPSCR_STAT_MASK 0xf800009f
#define VFP_FPSCR_CTRL_MASK 0x07f79f00
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 6d4482f..d189728 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -37,12 +37,13 @@
* instruction set this cpu supports.
*/
#define ELF_HWCAP (elf_hwcap)
-#define COMPAT_ELF_HWCAP (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
+#define COMPAT_ELF_A32_HWCAP (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
extern unsigned int elf_hwcap;
+#define COMPAT_ELF_HWCAP COMPAT_ELF_A32_HWCAP
#endif
#endif
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 20925bc..4a644a5 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -49,11 +49,11 @@
#ifdef CONFIG_COMPAT
#define TASK_SIZE_32 UL(0x100000000)
-#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
+#define TASK_SIZE (is_compat_task() ? \
TASK_SIZE_32 : TASK_SIZE_64)
#else
-#define TASK_SIZE TASK_SIZE_64
-#endif /* CONFIG_COMPAT */
+#define TASK_SIZE TASK_SIZE_64
+#endif
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index ab239b2..9f0cbcd 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -38,7 +38,7 @@
#define STACK_TOP_MAX TASK_SIZE_64
#ifdef CONFIG_COMPAT
#define AARCH32_VECTORS_BASE 0xffff0000
-#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
+#define STACK_TOP (is_compat_task() ? \
AARCH32_VECTORS_BASE : STACK_TOP_MAX)
#else
#define STACK_TOP STACK_TOP_MAX
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 0dacbbf..832a4d8 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -107,7 +107,7 @@ struct pt_regs {
#define arch_has_single_step() (1)
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
#define compat_thumb_mode(regs) \
(((regs)->pstate & COMPAT_PSR_T_BIT))
#else
diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
index 15e3559..989128a 100644
--- a/arch/arm64/include/asm/stat.h
+++ b/arch/arm64/include/asm/stat.h
@@ -18,7 +18,7 @@
#include <uapi/asm/stat.h>
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
#include <asm/compat.h>
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7b4b564..e23efb7 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -11,7 +11,7 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o psci.o
-arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
+arm64-obj-$(CONFIG_ARM64_AARCH32) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o smp_psci.o
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 3881fd1..28cf5c7 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -167,7 +167,7 @@ ENTRY(vectors)
ventry el0_fiq_invalid // FIQ 64-bit EL0
ventry el0_error_invalid // Error 64-bit EL0
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
ventry el0_sync_compat // Synchronous 32-bit EL0
ventry el0_irq_compat // IRQ 32-bit EL0
ventry el0_fiq_invalid_compat // FIQ 32-bit EL0
@@ -207,7 +207,7 @@ el0_error_invalid:
inv_entry 0, BAD_ERROR
ENDPROC(el0_error_invalid)
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
el0_fiq_invalid_compat:
inv_entry 0, BAD_FIQ, 32
ENDPROC(el0_fiq_invalid_compat)
@@ -371,7 +371,7 @@ el0_sync:
b.ge el0_dbg
b el0_inv
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
.align 6
el0_sync_compat:
kernel_entry 0, 32
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 7090c12..ad6a33a 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -188,7 +188,7 @@ ENTRY(el2_setup)
mov x0, #0x33ff
msr cptr_el2, x0 // Disable copro. traps to EL2
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
msr hstr_el2, xzr // Disable CP15 traps to EL2
#endif
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index 329218c..fbaad0d 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -392,7 +392,7 @@ static int arch_build_bp_info(struct perf_event *bp)
* Watchpoints can be of length 1, 2, 4 or 8 bytes.
*/
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
- if (is_compat_task()) {
+ if (is_aarch32_task()) {
if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
info->ctrl.len != ARM_BREAKPOINT_LEN_4)
return -EINVAL;
@@ -449,7 +449,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
* AArch32 tasks expect some simple alignment fixups, so emulate
* that here.
*/
- if (is_compat_task()) {
+ if (is_aarch32_task()) {
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7;
else
@@ -636,7 +636,7 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,
info = counter_arch_bp(wp);
/* AArch32 watchpoints are either 4 or 8 bytes aligned. */
- if (is_compat_task()) {
+ if (is_aarch32_task()) {
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7;
else
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 57fb55c..8845c2d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -202,7 +202,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
if (likely(!(p->flags & PF_KTHREAD))) {
*childregs = *current_pt_regs();
childregs->regs[0] = 0;
- if (is_compat_thread(task_thread_info(p))) {
+ if (is_aarch32_thread(task_thread_info(p))) {
if (stack_start)
childregs->compat_sp = stack_start;
} else {
@@ -243,12 +243,12 @@ static void tls_thread_switch(struct task_struct *next)
{
unsigned long tpidr, tpidrro;
- if (!is_compat_task()) {
+ if (!is_aarch32_task()) {
asm("mrs %0, tpidr_el0" : "=r" (tpidr));
current->thread.tp_value = tpidr;
}
- if (is_compat_thread(task_thread_info(next))) {
+ if (is_aarch32_thread(task_thread_info(next))) {
tpidr = 0;
tpidrro = next->thread.tp_value;
} else {
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index fecdbf7..4805581 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -69,10 +69,10 @@ static void ptrace_hbptriggered(struct perf_event *bp,
.si_addr = (void __user *)(bkpt->trigger),
};
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
int i;
- if (!is_compat_task())
+ if (!is_aarch32_task())
goto send_sig;
for (i = 0; i < ARM_MAX_BRP; ++i) {
@@ -609,7 +609,7 @@ static const struct user_regset_view user_aarch64_view = {
.regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
};
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
#include <linux/compat.h>
enum compat_regset {
@@ -775,8 +775,8 @@ static const struct user_regset aarch32_regsets[] = {
[REGSET_COMPAT_GPR] = {
.core_note_type = NT_PRSTATUS,
.n = COMPAT_ELF_NGREG,
- .size = sizeof(compat_elf_greg_t),
- .align = sizeof(compat_elf_greg_t),
+ .size = sizeof(compat_a32_elf_greg_t),
+ .align = sizeof(compat_a32_elf_greg_t),
.get = compat_gpr_get,
.set = compat_gpr_set
},
@@ -809,7 +809,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
tmp = tsk->mm->start_data;
else if (off == COMPAT_PT_TEXT_END_ADDR)
tmp = tsk->mm->end_code;
- else if (off < sizeof(compat_elf_gregset_t))
+ else if (off < sizeof(compat_a32_elf_gregset_t))
return copy_regset_to_user(tsk, &user_aarch32_view,
REGSET_COMPAT_GPR, off,
sizeof(compat_ulong_t), ret);
@@ -829,7 +829,7 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
if (off & 3 || off >= COMPAT_USER_SZ)
return -EIO;
- if (off >= sizeof(compat_elf_gregset_t))
+ if (off >= sizeof(compat_a32_elf_gregset_t))
return 0;
ret = copy_regset_from_user(tsk, &user_aarch32_view,
@@ -989,7 +989,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
ret = copy_regset_to_user(child,
&user_aarch32_view,
REGSET_COMPAT_GPR,
- 0, sizeof(compat_elf_gregset_t),
+ 0, sizeof(compat_a32_elf_gregset_t),
datap);
break;
@@ -997,7 +997,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
ret = copy_regset_from_user(child,
&user_aarch32_view,
REGSET_COMPAT_GPR,
- 0, sizeof(compat_elf_gregset_t),
+ 0, sizeof(compat_a32_elf_gregset_t),
datap);
break;
@@ -1045,12 +1045,12 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
return ret;
}
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_ARM64_AARCH32 */
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
-#ifdef CONFIG_COMPAT
- if (is_compat_thread(task_thread_info(task)))
+#ifdef CONFIG_ARM64_AARCH32
+ if (is_aarch32_thread(task_thread_info(task)))
return &user_aarch32_view;
#endif
return &user_aarch64_view;
@@ -1069,7 +1069,7 @@ asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return regs->syscallno;
- if (is_compat_task()) {
+ if (is_aarch32_task()) {
/* AArch32 uses ip (r12) for scratch */
saved_reg = regs->regs[12];
regs->regs[12] = dir;
@@ -1087,7 +1087,7 @@ asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
else if (tracehook_report_syscall_entry(regs))
regs->syscallno = ~0UL;
- if (is_compat_task())
+ if (is_aarch32_task())
regs->regs[12] = saved_reg;
else
regs->regs[7] = saved_reg;
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 890a591..3fbd848 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -268,7 +268,7 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
static void setup_restart_syscall(struct pt_regs *regs)
{
- if (is_compat_task())
+ if (is_aarch32_task())
compat_setup_restart_syscall(regs);
else
regs->regs[8] = __NR_restart_syscall;
@@ -295,7 +295,7 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
/*
* Set up the stack frame
*/
- if (is_compat_task()) {
+ if (is_aarch32_task()) {
if (ka->sa.sa_flags & SA_SIGINFO)
ret = compat_setup_rt_frame(usig, ka, info, oldset,
regs);
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 7ffaddd..0bc28fa 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -285,9 +285,9 @@ long compat_arm_syscall(struct pt_regs *regs);
asmlinkage long do_ni_syscall(struct pt_regs *regs)
{
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
long ret;
- if (is_compat_task()) {
+ if (is_aarch32_task()) {
ret = compat_arm_syscall(regs);
if (ret != -ENOSYS)
return ret;
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 6a389dc..b5605ac 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -49,7 +49,7 @@ static union {
} vdso_data_store __page_aligned_data;
struct vdso_data *vdso_data = &vdso_data_store.data;
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
/*
* Create and map the vectors page for AArch32 tasks.
*/
@@ -99,7 +99,7 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
return ret;
}
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_ARM64_AARCH32 */
static int __init vdso_init(void)
{
@@ -191,7 +191,7 @@ const char *arch_vma_name(struct vm_area_struct *vma)
* it conflicting with the vectors base.
*/
if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) {
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
if (vma->vm_start == AARCH32_VECTORS_BASE)
return "[vectors]";
#endif
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 6c8ba25..428658e 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -35,6 +35,7 @@
#include <asm/system_misc.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include <asm/compat.h>
static const char *fault_name(unsigned int esr);
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 8ed6cb1..29eb82a 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -28,6 +28,7 @@
#include <linux/random.h>
#include <asm/cputype.h>
+#include <asm/compat.h>
/*
* Leave enough space between the mmap area and the stack to honour ulimit in
--
1.7.2.5
Since the ILP32 ABI uses similar signal code as the LP64 ABI, it makes sense to reuse rather
than copy the same code.
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/kernel/signal.c | 170 +-------------------------------------------
1 files changed, 1 insertions(+), 169 deletions(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 3fbd848..d97a0c0 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -95,176 +95,8 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
return err ? -EFAULT : 0;
}
-static int restore_sigframe(struct pt_regs *regs,
- struct rt_sigframe __user *sf)
-{
- sigset_t set;
- int i, err;
- struct aux_context __user *aux =
- (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
-
- err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
- if (err == 0)
- set_current_blocked(&set);
-
- for (i = 0; i < 31; i++)
- __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
- err);
- __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
- __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
- __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
-
- /*
- * Avoid sys_rt_sigreturn() restarting.
- */
- regs->syscallno = ~0UL;
-
- err |= !valid_user_regs(®s->user_regs);
-
- if (err == 0)
- err |= restore_fpsimd_context(&aux->fpsimd);
-
- return err;
-}
-
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
-{
- struct rt_sigframe __user *frame;
-
- /* Always make any pending restarted system calls return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
- /*
- * Since we stacked the signal on a 128-bit boundary, then 'sp' should
- * be word aligned here.
- */
- if (regs->sp & 15)
- goto badframe;
-
- frame = (struct rt_sigframe __user *)regs->sp;
-
- if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
- goto badframe;
-
- if (restore_sigframe(regs, frame))
- goto badframe;
-
- if (restore_altstack(&frame->uc.uc_stack))
- goto badframe;
-
- return regs->regs[0];
-
-badframe:
- if (show_unhandled_signals)
- pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
- current->comm, task_pid_nr(current), __func__,
- regs->pc, regs->sp);
- force_sig(SIGSEGV, current);
- return 0;
-}
-
-static int setup_sigframe(struct rt_sigframe __user *sf,
- struct pt_regs *regs, sigset_t *set)
-{
- int i, err = 0;
- struct aux_context __user *aux =
- (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
-
- /* set up the stack frame for unwinding */
- __put_user_error(regs->regs[29], &sf->fp, err);
- __put_user_error(regs->regs[30], &sf->lr, err);
-
- for (i = 0; i < 31; i++)
- __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
- err);
- __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
- __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
- __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
-
- __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
-
- err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
-
- if (err == 0)
- err |= preserve_fpsimd_context(&aux->fpsimd);
-
- /* set the "end" magic */
- __put_user_error(0, &aux->end.magic, err);
- __put_user_error(0, &aux->end.size, err);
+#include "signal_template.c"
- return err;
-}
-
-static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka,
- struct pt_regs *regs)
-{
- unsigned long sp, sp_top;
- struct rt_sigframe __user *frame;
-
- sp = sp_top = regs->sp;
-
- /*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
- sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
-
- sp = (sp - sizeof(struct rt_sigframe)) & ~15;
- frame = (struct rt_sigframe __user *)sp;
-
- /*
- * Check that we can actually write to the signal frame.
- */
- if (!access_ok(VERIFY_WRITE, frame, sp_top - sp))
- frame = NULL;
-
- return frame;
-}
-
-static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
- void __user *frame, int usig)
-{
- __sigrestore_t sigtramp;
-
- regs->regs[0] = usig;
- regs->sp = (unsigned long)frame;
- regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
- regs->pc = (unsigned long)ka->sa.sa_handler;
-
- if (ka->sa.sa_flags & SA_RESTORER)
- sigtramp = ka->sa.sa_restorer;
- else
- sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
-
- regs->regs[30] = (unsigned long)sigtramp;
-}
-
-static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *set, struct pt_regs *regs)
-{
- struct rt_sigframe __user *frame;
- int err = 0;
-
- frame = get_sigframe(ka, regs);
- if (!frame)
- return 1;
-
- __put_user_error(0, &frame->uc.uc_flags, err);
- __put_user_error(NULL, &frame->uc.uc_link, err);
-
- err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
- err |= setup_sigframe(frame, regs, set);
- if (err == 0) {
- setup_return(regs, ka, frame, usig);
- if (ka->sa.sa_flags & SA_SIGINFO) {
- err |= copy_siginfo_to_user(&frame->info, info);
- regs->regs[1] = (unsigned long)&frame->info;
- regs->regs[2] = (unsigned long)&frame->uc;
- }
- }
-
- return err;
-}
static void setup_restart_syscall(struct pt_regs *regs)
{
--
1.7.2.5
Hi,
The ILP32 ABI in ARM64 uses a slightly different pselect from either the compat or even the native LP64 ABI. We would want to reuse some of the code path that are used as the size of the timespec is the same, so this patch exports poll_select_copy_remaining from fs/select.c and renames the copy in fs/compat.c to make sure that it is not being used.
Signed-off-by: Andrew Pinski <[email protected]>
---
fs/compat.c | 8 ++++----
fs/select.c | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/fs/compat.c b/fs/compat.c
index 6af20de..298e3e1 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1088,7 +1088,7 @@ COMPAT_SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, fla
#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
-static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
+static int compat_poll_select_copy_remaining(struct timespec *end_time, void __user *p,
int timeval, int ret)
{
struct timespec ts;
@@ -1307,7 +1307,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
}
ret = compat_core_sys_select(n, inp, outp, exp, to);
- ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);
+ ret = compat_poll_select_copy_remaining(&end_time, tvp, 1, ret);
return ret;
}
@@ -1362,7 +1362,7 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
}
ret = compat_core_sys_select(n, inp, outp, exp, to);
- ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
+ ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret);
if (ret == -ERESTARTNOHAND) {
/*
@@ -1448,7 +1448,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
+ ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret);
return ret;
}
diff --git a/fs/select.c b/fs/select.c
index 35d4adc7..aef2c10 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -287,8 +287,8 @@ int poll_select_set_timeout(struct timespec *to, long sec, long nsec)
return 0;
}
-static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
- int timeval, int ret)
+int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
+ int timeval, int ret)
{
struct timespec rts;
struct timeval rtv;
--
1.7.2.5
The signal code for ILP32 uses one extra function from signal32.c; it does not make sense to enable the whole signal32.c code so we move the function which was being used to signal.c.
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/kernel/signal.c | 85 ++++++++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/signal32.c | 81 ----------------------------------------
2 files changed, 85 insertions(+), 81 deletions(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index d97a0c0..5986b7f 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -249,3 +249,88 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
tracehook_notify_resume(regs);
}
}
+
+
+#ifdef CONFIG_COMPAT
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
+{
+ int err;
+
+ if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please be sure
+ * this code is fixed accordingly.
+ * It should never copy any pad contained in the structure
+ * to avoid security leaks, but must copy the generic
+ * 3 ints plus the relevant union member.
+ * This routine must convert siginfo from 64bit to 32bit as well
+ * at the same time.
+ */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ if (from->si_code < 0)
+ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
+ SI_PAD_SIZE);
+ else switch (from->si_code & __SI_MASK) {
+ case __SI_KILL:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_TIMER:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr,
+ &to->si_ptr);
+ break;
+ case __SI_POLL:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_FAULT:
+ err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
+ &to->si_addr);
+#ifdef BUS_MCEERR_AO
+ /*
+ * Other callers might not initialize the si_lsb field,
+ * so check explicitely for the right codes here.
+ */
+ if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+ err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
+#endif
+ break;
+ case __SI_CHLD:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_status, &to->si_status);
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ break;
+ case __SI_RT: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ: /* But this is */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
+ break;
+ default: /* this is just in case for now ... */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ }
+ return err;
+}
+
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+ memset(to, 0, sizeof *to);
+
+ if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
+ copy_from_user(to->_sifields._pad,
+ from->_sifields._pad, SI_PAD_SIZE))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index e393174..dadcb6c 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -150,87 +150,6 @@ static inline int get_sigset_t(sigset_t *set,
return 0;
}
-int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- * this code is fixed accordingly.
- * It should never copy any pad contained in the structure
- * to avoid security leaks, but must copy the generic
- * 3 ints plus the relevant union member.
- * This routine must convert siginfo from 64bit to 32bit as well
- * at the same time.
- */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
- SI_PAD_SIZE);
- else switch (from->si_code & __SI_MASK) {
- case __SI_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case __SI_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr,
- &to->si_ptr);
- break;
- case __SI_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case __SI_FAULT:
- err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
- &to->si_addr);
-#ifdef BUS_MCEERR_AO
- /*
- * Other callers might not initialize the si_lsb field,
- * so check explicitely for the right codes here.
- */
- if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
- err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
-#endif
- break;
- case __SI_CHLD:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_status, &to->si_status);
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- break;
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ: /* But this is */
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
- break;
- default: /* this is just in case for now ... */
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- }
- return err;
-}
-
-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- memset(to, 0, sizeof *to);
-
- if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
- copy_from_user(to->_sifields._pad,
- from->_sifields._pad, SI_PAD_SIZE))
- return -EFAULT;
-
- return 0;
-}
-
/*
* VFP save/restore code.
*/
--
1.7.2.5
This patch adds full support of the ABI to the ARM64 target.
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/Kconfig | 11 +-
arch/arm64/include/asm/Kbuild | 1 -
arch/arm64/include/asm/compat.h | 72 ++++++-
arch/arm64/include/asm/elf.h | 71 ++++++--
arch/arm64/include/asm/hwcap.h | 2 +-
arch/arm64/include/asm/memory.h | 4 +-
arch/arm64/include/asm/processor.h | 12 --
arch/arm64/include/asm/stat.h | 6 +-
arch/arm64/include/asm/syscalls.h | 3 +
arch/arm64/include/asm/thread_info.h | 1 +
arch/arm64/include/asm/unistd.h | 10 +-
arch/arm64/include/asm/vdso.h | 4 +
arch/arm64/include/uapi/asm/bitsperlong.h | 7 +-
arch/arm64/include/uapi/asm/posix_types.h | 12 ++
arch/arm64/include/uapi/asm/siginfo.h | 6 +
arch/arm64/kernel/Makefile | 7 +
arch/arm64/kernel/entry.S | 20 ++-
arch/arm64/kernel/process.c | 18 ++
arch/arm64/kernel/ptrace.c | 38 ++++-
arch/arm64/kernel/signal.c | 43 ++++-
arch/arm64/kernel/signal_template.c | 193 ++++++++++++++++++
arch/arm64/kernel/signalilp32.c | 30 +++
arch/arm64/kernel/sys_ilp32.c | 274 ++++++++++++++++++++++++++
arch/arm64/kernel/vdso.c | 81 ++++++++-
arch/arm64/kernel/vdsoilp32/.gitignore | 2 +
arch/arm64/kernel/vdsoilp32/Makefile | 72 +++++++
arch/arm64/kernel/vdsoilp32/vdso_ilp32.lds.S | 100 ++++++++++
arch/arm64/kernel/vdsoilp32/vdsoilp32.S | 33 +++
arch/arm64/mm/init.c | 1 +
29 files changed, 1076 insertions(+), 58 deletions(-)
create mode 100644 arch/arm64/include/uapi/asm/posix_types.h
create mode 100644 arch/arm64/kernel/signal_template.c
create mode 100644 arch/arm64/kernel/signalilp32.c
create mode 100644 arch/arm64/kernel/sys_ilp32.c
create mode 100644 arch/arm64/kernel/vdsoilp32/.gitignore
create mode 100644 arch/arm64/kernel/vdsoilp32/Makefile
create mode 100644 arch/arm64/kernel/vdsoilp32/vdso_ilp32.lds.S
create mode 100644 arch/arm64/kernel/vdsoilp32/vdsoilp32.S
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cc64df5..7fdc994 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
config COMPAT
def_bool y
- depends on ARM64_AARCH32
+ depends on ARM64_AARCH32 || ARM64_ILP32
select COMPAT_BINFMT_ELF
config ARM64_AARCH32
@@ -263,7 +263,14 @@ config ARM64_AARCH32
the user helper functions, VFP support and the ptrace interface are
handled appropriately by the kernel.
- If you want to execute 32-bit userspace applications, say Y.
+ If you want to execute Aarch32 userspace applications, say Y.
+
+config ARM64_ILP32
+ bool "Kernel support for ILP32"
+ help
+ This option enables support for AArch64 ILP32 user space. These are
+ 64-bit binaries using 32-bit quantities for addressing and certain
+ data that would normally be 64-bit.
config SYSVIPC_COMPAT
def_bool y
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 79a642d..902aef9 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -28,7 +28,6 @@ generic-y += mutex.h
generic-y += pci.h
generic-y += percpu.h
generic-y += poll.h
-generic-y += posix_types.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 5ab2676..91bcf13 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -62,6 +62,8 @@ typedef u32 compat_ulong_t;
typedef u64 compat_u64;
typedef u32 compat_uptr_t;
+typedef s64 ilp32_clock_t;
+
struct compat_timespec {
compat_time_t tv_sec;
s32 tv_nsec;
@@ -180,6 +182,15 @@ typedef struct compat_siginfo {
compat_clock_t _stime;
} _sigchld;
+ /* SIGCHLD (ILP32 version) */
+ struct {
+ compat_pid_t _pid; /* which child */
+ __compat_uid32_t _uid; /* sender's uid */
+ int _status; /* exit code */
+ ilp32_clock_t _utime;
+ ilp32_clock_t _stime;
+ } _sigchld_ilp32;
+
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
compat_uptr_t _addr; /* faulting insn/memory ref. */
@@ -214,12 +225,15 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
return (u32)(unsigned long)uptr;
}
-#define compat_user_stack_pointer() (current_pt_regs()->compat_sp)
+#define COMPAT_USE_64BIT_TIME is_ilp32_task()
+
+/* AARCH64 ILP32 vs AARCH32 differences. */
+#define compat_user_stack_pointer() \
+ (is_ilp32_task() \
+ ? current_user_stack_pointer() \
+ : current_pt_regs()->compat_sp)
+
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
- return (void __user *)compat_user_stack_pointer() - len;
-}
struct compat_ipc64_perm {
compat_key_t key;
@@ -279,7 +293,7 @@ struct compat_shmid64_ds {
compat_ulong_t __unused5;
};
-#if defined(CONFIG_ARM64_AARCH32)
+#ifdef CONFIG_ARM64_AARCH32
static inline int is_aarch32_task(void)
{
return test_thread_flag(TIF_32BIT);
@@ -289,7 +303,9 @@ static inline int is_aarch32_thread(struct thread_info *thread)
{
return test_ti_thread_flag(thread, TIF_32BIT);
}
+
#else
+
static inline int is_aarch32_task(void)
{
return 0;
@@ -299,8 +315,36 @@ static inline int is_aarch32_thread(struct thread_info *thread)
{
return 0;
}
-#endif
+#endif /* CONFIG_ARM64_AARCH32 */
+
+#ifdef CONFIG_ARM64_ILP32
+static inline int is_ilp32_task(void)
+{
+ return test_thread_flag(TIF_32BIT_AARCH64);
+}
+
+static inline int is_ilp32_thread(struct thread_info *thread)
+{
+ return test_ti_thread_flag(thread, TIF_32BIT_AARCH64);
+}
+
+#else
+
+static inline int is_ilp32_task(void)
+{
+ return 0;
+}
+static inline int is_ilp32_thread(struct thread_info *thread)
+{
+ return 0;
+}
+#endif /* CONFIG_ARM64_ILP32 */
+
+static inline void __user *arch_compat_alloc_user_space(long len)
+{
+ return (void __user *)compat_user_stack_pointer() - len;
+}
#else /* !CONFIG_COMPAT */
@@ -308,22 +352,28 @@ static inline int is_aarch32_task(void)
{
return 0;
}
-
static inline int is_aarch32_thread(struct thread_info *thread)
{
return 0;
}
-
+static inline int is_ilp32_task(void)
+{
+ return 0;
+}
+static inline int is_ilp32_thread(struct thread_info *thread)
+{
+ return 0;
+}
#endif /* CONFIG_COMPAT */
static inline int is_compat_task(void)
{
- return is_aarch32_task();
+ return is_aarch32_task() || is_ilp32_task();
}
static inline int is_compat_thread(struct thread_info *thread)
{
- return is_aarch32_thread(thread);
+ return is_aarch32_thread(thread) || is_ilp32_thread(thread);
}
#endif /* __KERNEL__ */
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 0a89e94..7b07b52 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -122,13 +122,15 @@ extern unsigned long randomize_et_dyn(unsigned long base);
*/
#define ELF_PLAT_INIT(_r, load_addr) (_r)->regs[0] = 0
-#define SET_PERSONALITY(ex) clear_thread_flag(TIF_32BIT);
+#define SET_PERSONALITY(ex) do { \
+ clear_thread_flag(TIF_32BIT); \
+ clear_thread_flag(TIF_32BIT_AARCH64); \
+ } while (0)
-#define ARCH_DLINFO \
-do { \
- NEW_AUX_ENT(AT_SYSINFO_EHDR, \
- (elf_addr_t)current->mm->context.vdso); \
-} while (0)
+#define ARCH_DLINFO do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (elf_addr_t)current->mm->context.vdso); \
+ } while (0)
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
struct linux_binprm;
@@ -165,20 +167,65 @@ typedef compat_a32_elf_greg_t compat_a32_elf_gregset_t[COMPAT_ELF_NGREG];
((x)->e_flags & EF_ARM_EABI_MASK))
#define COMPAT_SET_A32_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
-#define COMPAT_ARCH_DLINFO
extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
int uses_interp);
#define compat_arch_setup_additional_pages \
aarch32_setup_vectors_page
-typedef compat_a32_elf_greg_t compat_elf_greg_t;
-typedef compat_a32_elf_gregset_t compat_elf_gregset_t;
+extern void compat_start_thread(struct pt_regs *regs, unsigned long pc,
+ unsigned long sp);
+#define compat_start_thread compat_start_thread
+
+#else
+#define COMPAT_SET_A32_PERSONALITY(ex) do {} while (0)
+#define compat_elf_a32_check_arch(x) (0)
#endif
-#define compat_elf_check_arch(x) compat_elf_a32_check_arch(x)
-#define COMPAT_SET_PERSONALITY(ex) COMPAT_SET_A32_PERSONALITY(x)
-#define compat_start_thread compat_start_thread
+#ifdef CONFIG_ARM64_ILP32
+#define COMPAT_SET_ILP32_PERSONALITY(ex) do { \
+ set_thread_flag(TIF_32BIT_AARCH64); \
+ clear_thread_flag(TIF_32BIT); \
+ } while (0)
+
+#define compat_elf_ilp32_check_arch(x) ((x)->e_machine == EM_AARCH64)
+
+#define ARCH_DLINFO_ILP32 do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (elf_addr_t)(long)current->mm->context.vdso); \
+ } while (0)
+
+typedef unsigned long compat_elf_greg_t;
+typedef compat_elf_greg_t compat_elf_gregset_t[32+2];
+#define PR_REG_SIZE(S) (is_aarch32_task() ? 72 : 272)
+#define PRSTATUS_SIZE(S) (is_aarch32_task() ? 124 : (is_ilp32_task() ? 352 : 392))
+#define SET_PR_FPVALID(S, V) \
+ (void)(*(int *) (((void *) &((S)->pr_reg)) + PR_REG_SIZE((S)->pr_reg)) = (V));
+
+#else
+#define compat_elf_ilp32_check_arch(x) 0
+#define ARCH_DLINFO_ILP32 do {} while (0)
+
+typedef compat_a32_elf_greg_t compat_elf_greg_t;
+typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
+#define COMPAT_SET_ILP32_PERSONALITY(x) do {} while (0)
+
+#endif /* CONFIG_ARM64_ILP32 */
+
+#define COMPAT_ARCH_DLINFO do { \
+ if (is_ilp32_task()) \
+ ARCH_DLINFO_ILP32; \
+ } while (0)
+
+#define compat_elf_check_arch(x) (compat_elf_a32_check_arch(x) || compat_elf_ilp32_check_arch(x))
+#define COMPAT_SET_PERSONALITY(ex) do { \
+ if (compat_elf_ilp32_check_arch(&(ex))) \
+ COMPAT_SET_ILP32_PERSONALITY((ex)); \
+ else \
+ COMPAT_SET_A32_PERSONALITY((ex)); \
+ } while (0)
+
+
#endif /* CONFIG_COMPAT */
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index d189728..581398f 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -44,6 +44,6 @@
COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
extern unsigned int elf_hwcap;
-#define COMPAT_ELF_HWCAP COMPAT_ELF_A32_HWCAP
+#define COMPAT_ELF_HWCAP (is_aarch32_task() ? COMPAT_ELF_A32_HWCAP : elf_hwcap)
#endif
#endif
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 4a644a5..720515c 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -52,8 +52,8 @@
#define TASK_SIZE (is_compat_task() ? \
TASK_SIZE_32 : TASK_SIZE_64)
#else
-#define TASK_SIZE TASK_SIZE_64
-#endif
+#define TASK_SIZE TASK_SIZE_64
+#endif /* CONFIG_COMPAT */
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 9f0cbcd..fd7a439 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -99,18 +99,6 @@ static inline void start_thread(struct pt_regs *regs, unsigned long pc,
regs->sp = sp;
}
-#ifdef CONFIG_COMPAT
-static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
- unsigned long sp)
-{
- start_thread_common(regs, pc);
- regs->pstate = COMPAT_PSR_MODE_USR;
- if (pc & 1)
- regs->pstate |= COMPAT_PSR_T_BIT;
- regs->compat_sp = sp;
-}
-#endif
-
/* Forward declaration, a strange C thing */
struct task_struct;
diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
index 989128a..f2e0d3c 100644
--- a/arch/arm64/include/asm/stat.h
+++ b/arch/arm64/include/asm/stat.h
@@ -18,9 +18,11 @@
#include <uapi/asm/stat.h>
-#ifdef CONFIG_ARM64_AARCH32
-
+#ifdef CONFIG_COMPAT
#include <asm/compat.h>
+#endif
+
+#ifdef CONFIG_ARM64_AARCH32
/*
* struct stat64 is needed for compat tasks only. Its definition is different
diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h
index 48fe7c6..ef6dfdc 100644
--- a/arch/arm64/include/asm/syscalls.h
+++ b/arch/arm64/include/asm/syscalls.h
@@ -24,6 +24,9 @@
* System call wrappers implemented in kernel/entry.S.
*/
asmlinkage long sys_rt_sigreturn_wrapper(void);
+#ifdef CONFIG_ARM64_ILP32
+asmlinkage long sys_ilp32_rt_sigreturn_wrapper(void);
+#endif
#include <asm-generic/syscalls.h>
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 23a3c47..18ecdca 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -114,6 +114,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SINGLESTEP 21
#define TIF_32BIT 22 /* 32bit process */
#define TIF_SWITCH_MM 23 /* deferred switch_mm */
+#define TIF_32BIT_AARCH64 24 /* 32 bit process on AArch64(ILP32) */
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 82ce217..33cd2fd 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,18 +13,22 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_ARM64_AARCH32
#define __ARCH_WANT_COMPAT_STAT64
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE
#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
#endif
+
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_COMPAT_SYS_SENDFILE
+#endif
+
#define __ARCH_WANT_SYS_CLONE
#include <uapi/asm/unistd.h>
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 839ce00..84050c6 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -29,6 +29,10 @@
#include <generated/vdso-offsets.h>
+#ifdef CONFIG_ARM64_ILP32
+#include <generated/vdso-ilp32-offsets.h>
+#endif
+
#define VDSO_SYMBOL(base, name) \
({ \
(void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \
diff --git a/arch/arm64/include/uapi/asm/bitsperlong.h b/arch/arm64/include/uapi/asm/bitsperlong.h
index fce9c29..3d35762 100644
--- a/arch/arm64/include/uapi/asm/bitsperlong.h
+++ b/arch/arm64/include/uapi/asm/bitsperlong.h
@@ -16,7 +16,12 @@
#ifndef __ASM_BITSPERLONG_H
#define __ASM_BITSPERLONG_H
-#define __BITS_PER_LONG 64
+
+#ifdef __LP64__
+# define __BITS_PER_LONG 64
+#else
+# define __BITS_PER_LONG 32
+#endif
#include <asm-generic/bitsperlong.h>
diff --git a/arch/arm64/include/uapi/asm/posix_types.h b/arch/arm64/include/uapi/asm/posix_types.h
new file mode 100644
index 0000000..53b15e6
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/posix_types.h
@@ -0,0 +1,12 @@
+#ifndef __ASM_POSIX_TYPES_H
+#define __ASM_POSIX_TYPES_H
+
+#ifndef __LP64__ /* ILP32 */
+typedef long long __kernel_long_t;
+typedef unsigned long long __kernel_ulong_t;
+#define __kernel_long_t __kernel_long_t
+#endif
+
+#include <asm-generic/posix_types.h>
+
+#endif /* __ASM_POSIX_TYPES_H */
diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
index 5a74a08..297fb4f 100644
--- a/arch/arm64/include/uapi/asm/siginfo.h
+++ b/arch/arm64/include/uapi/asm/siginfo.h
@@ -16,7 +16,13 @@
#ifndef __ASM_SIGINFO_H
#define __ASM_SIGINFO_H
+#ifdef __LP64__
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#else /* ILP32 */
+typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
+#define __ARCH_SI_CLOCK_T __kernel_si_clock_t
+#define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
+#endif
#include <asm-generic/siginfo.h>
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index e23efb7..432a71d 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -13,6 +13,7 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
arm64-obj-$(CONFIG_ARM64_AARCH32) += sys32.o kuser32.o signal32.o \
sys_compat.o
+arm64-obj-$(CONFIG_ARM64_ILP32) += sys_ilp32.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o smp_psci.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
@@ -20,6 +21,7 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += $(arm64-obj-y) vdso/
+obj-$(CONFIG_ARM64_ILP32) += vdsoilp32/
obj-m += $(arm64-obj-m)
head-y := head.o
extra-y := $(head-y) vmlinux.lds
@@ -27,3 +29,8 @@ extra-y := $(head-y) vmlinux.lds
# vDSO - this must be built first to generate the symbol offsets
$(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h
$(obj)/vdso/vdso-offsets.h: $(obj)/vdso
+
+ifeq ($(CONFIG_ARM64_ILP32),y)
+$(call objectify,$(arm64-obj-y)): $(obj)/vdsoilp32/vdso-ilp32-offsets.h
+$(obj)/vdsoilp32/vdso-ilp32-offsets.h: $(obj)/vdsoilp32
+endif
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 28cf5c7..548ecc6 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -633,9 +633,14 @@ ENDPROC(ret_from_fork)
*/
.align 6
el0_svc:
- adrp stbl, sys_call_table // load syscall table pointer
uxtw scno, w8 // syscall number in w8
mov sc_nr, #__NR_syscalls
+#ifdef CONFIG_ARM64_ILP32
+ get_thread_info tsk
+ ldr x16, [tsk, #TI_FLAGS]
+ tbnz x16, #TIF_32BIT_AARCH64, el0_ilp32_svc // We are using ILP32
+#endif
+ adrp stbl, sys_call_table // load syscall table pointer
el0_svc_naked: // compat entry point
stp x0, scno, [sp, #S_ORIG_X0] // save the original x0 and syscall number
disable_step x16
@@ -656,6 +661,12 @@ ni_sys:
b do_ni_syscall
ENDPROC(el0_svc)
+#ifdef CONFIG_ARM64_ILP32
+el0_ilp32_svc:
+ adrp stbl, sys_ilp32_call_table // load syscall table pointer
+ b el0_svc_naked
+#endif
+
/*
* This is the really slow path. We're going to be doing context
* switches, and waiting for our parent to respond.
@@ -691,5 +702,12 @@ ENTRY(sys_rt_sigreturn_wrapper)
b sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn_wrapper)
+#ifdef CONFIG_ARM64_ILP32
+ENTRY(sys_ilp32_rt_sigreturn_wrapper)
+ mov x0, sp
+ b sys_ilp32_rt_sigreturn
+ENDPROC(sys_ilp32_rt_sigreturn_wrapper)
+#endif
+
ENTRY(handle_arch_irq)
.quad 0
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 8845c2d..233c591 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -329,3 +329,21 @@ unsigned long randomize_et_dyn(unsigned long base)
{
return randomize_base(base);
}
+
+#ifdef CONFIG_ARM64_AARCH32
+void compat_start_thread(struct pt_regs *regs, unsigned long pc,
+ unsigned long sp)
+{
+ if (is_ilp32_task()) {
+ start_thread(regs, pc, sp);
+ return;
+ }
+
+ start_thread_common(regs, pc);
+ regs->pstate = COMPAT_PSR_MODE_USR;
+ if (pc & 1)
+ regs->pstate |= COMPAT_PSR_T_BIT;
+ regs->compat_sp = sp;
+}
+#endif
+
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 4805581..956f18c 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -609,8 +609,11 @@ static const struct user_regset_view user_aarch64_view = {
.regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
};
-#ifdef CONFIG_ARM64_AARCH32
+#ifdef CONFIG_COMPAT
#include <linux/compat.h>
+#endif
+
+#ifdef CONFIG_ARM64_AARCH32
enum compat_regset {
REGSET_COMPAT_GPR,
@@ -968,8 +971,9 @@ static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num,
}
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
-long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
- compat_ulong_t caddr, compat_ulong_t cdata)
+
+static long compat_arch_aarch32_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
{
unsigned long addr = caddr;
unsigned long data = cdata;
@@ -1047,6 +1051,34 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
}
#endif /* CONFIG_ARM64_AARCH32 */
+#ifdef CONFIG_ARM64_ILP32
+static long compat_arch_ilp32_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
+{
+ return compat_ptrace_request(child, request, caddr, cdata);
+}
+#endif /* CONFIG_ARM64_ILP32 */
+
+#ifdef CONFIG_COMPAT
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
+{
+
+#ifdef CONFIG_ARM64_ILP32
+ if (is_ilp32_task())
+ return compat_arch_ilp32_ptrace(child, request, caddr, cdata);
+#endif
+
+#ifdef CONFIG_ARM64_AARCH32
+ if (is_aarch32_task())
+ return compat_arch_aarch32_ptrace(child, request, caddr, cdata);
+#endif
+
+ panic("Calling compat_arch_ptrace without being ilp32 or aarch32 task.");
+}
+
+#endif
+
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
#ifdef CONFIG_ARM64_AARCH32
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 5986b7f..5278415 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -45,6 +45,29 @@ struct rt_sigframe {
u64 lr;
};
+#ifdef CONFIG_COMPAT
+
+struct ucontext_ilp32 {
+ compat_ulong_t uc_flags;
+ compat_uptr_t uc_link; /* struct ucontext* */
+ compat_stack_t uc_stack;
+ compat_sigset_t uc_sigmask;
+ /* glibc uses a 1024-bit sigset_t */
+ __u8 __unused[1024 / 8 - sizeof(sigset_t)];
+ /* last for future expansion */
+ struct sigcontext uc_mcontext;
+};
+
+struct rt_sigframe_ilp32 {
+ struct compat_siginfo info;
+ struct ucontext_ilp32 uc;
+ u64 fp;
+ u64 lr;
+};
+
+#endif
+
+
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{
struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state;
@@ -96,7 +119,7 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
}
#include "signal_template.c"
-
+#include "signalilp32.c"
static void setup_restart_syscall(struct pt_regs *regs)
{
@@ -133,9 +156,13 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
regs);
else
ret = compat_setup_frame(usig, ka, oldset, regs);
- } else {
- ret = setup_rt_frame(usig, ka, info, oldset, regs);
}
+#ifdef CONFIG_ARM64_ILP32
+ else if (is_ilp32_thread(thread))
+ ret = setup_rt_frame_ilp32(usig, ka, info, oldset, regs);
+#endif
+ else
+ ret = setup_rt_frame(usig, ka, info, oldset, regs);
/*
* Check that the resulting registers are actually sane.
@@ -255,6 +282,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
int err;
+ bool ilp32 = is_ilp32_task();
if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
return -EFAULT;
@@ -304,8 +332,13 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_status, &to->si_status);
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
+ if (!ilp32) {
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ } else {
+ err |= __put_user(from->si_utime, &to->_sifields._sigchld_ilp32._utime);
+ err |= __put_user(from->si_stime, &to->_sifields._sigchld_ilp32._stime);
+ }
break;
case __SI_RT: /* This is not generated by the kernel as of now. */
case __SI_MESGQ: /* But this is */
diff --git a/arch/arm64/kernel/signal_template.c b/arch/arm64/kernel/signal_template.c
new file mode 100644
index 0000000..ceec598
--- /dev/null
+++ b/arch/arm64/kernel/signal_template.c
@@ -0,0 +1,193 @@
+/*
+ * Based on arch/arm/kernel/signal.c
+ *
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static int restore_sigframe(struct pt_regs *regs,
+ struct rt_sigframe __user *sf)
+{
+ sigset_t set;
+ int i, err;
+ struct aux_context __user *aux =
+ (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
+
+ err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
+ if (err == 0)
+ set_current_blocked(&set);
+
+ for (i = 0; i < 31; i++)
+ __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+ err);
+ __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
+ __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
+ __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
+
+ /*
+ * Avoid sys_rt_sigreturn() restarting.
+ */
+ regs->syscallno = ~0UL;
+
+ err |= !valid_user_regs(®s->user_regs);
+
+ if (err == 0)
+ err |= restore_fpsimd_context(&aux->fpsimd);
+
+ return err;
+}
+
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe __user *frame;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ /*
+ * Since we stacked the signal on a 128-bit boundary, then 'sp' should
+ * be word aligned here.
+ */
+ if (regs->sp & 15)
+ goto badframe;
+
+ frame = (struct rt_sigframe __user *)regs->sp;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+
+ if (restore_sigframe(regs, frame))
+ goto badframe;
+
+ if (restore_altstack(&frame->uc.uc_stack))
+ goto badframe;
+
+ return regs->regs[0];
+
+badframe:
+ if (show_unhandled_signals)
+ pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
+ current->comm, task_pid_nr(current), __func__,
+ regs->pc, regs->sp);
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+static int setup_sigframe(struct rt_sigframe __user *sf,
+ struct pt_regs *regs, sigset_t *set)
+{
+ int i, err = 0;
+ struct aux_context __user *aux =
+ (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
+
+ /* set up the stack frame for unwinding */
+ __put_user_error(regs->regs[29], &sf->fp, err);
+ __put_user_error(regs->regs[30], &sf->lr, err);
+
+ for (i = 0; i < 31; i++)
+ __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+ err);
+ __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
+ __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
+ __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
+
+ __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
+
+ err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+
+ if (err == 0)
+ err |= preserve_fpsimd_context(&aux->fpsimd);
+
+ /* set the "end" magic */
+ __put_user_error(0, &aux->end.magic, err);
+ __put_user_error(0, &aux->end.size, err);
+
+ return err;
+}
+
+static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka,
+ struct pt_regs *regs)
+{
+ unsigned long sp, sp_top;
+ struct rt_sigframe __user *frame;
+
+ sp = sp_top = regs->sp;
+
+ /*
+ * This is the X/Open sanctioned signal stack switching.
+ */
+ if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
+ sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
+
+ sp = (sp - sizeof(struct rt_sigframe)) & ~15;
+ frame = (struct rt_sigframe __user *)sp;
+
+ /*
+ * Check that we can actually write to the signal frame.
+ */
+ if (!access_ok(VERIFY_WRITE, frame, sp_top - sp))
+ frame = NULL;
+
+ return frame;
+}
+
+static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+ void __user *frame, int usig)
+{
+ __sigrestore_t sigtramp;
+
+ regs->regs[0] = usig;
+ regs->sp = (unsigned long)frame;
+ regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
+ regs->pc = (unsigned long)ka->sa.sa_handler;
+
+ if (ka->sa.sa_flags & SA_RESTORER)
+ sigtramp = ka->sa.sa_restorer;
+ else
+#ifdef ilp32
+ sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp_ilp32);
+#else
+ sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
+#endif
+
+ regs->regs[30] = (unsigned long)sigtramp;
+}
+
+static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct rt_sigframe __user *frame;
+ int err = 0;
+
+ frame = get_sigframe(ka, regs);
+ if (!frame)
+ return 1;
+
+ __put_user_error(0, &frame->uc.uc_flags, err);
+ __put_user_error(0, &frame->uc.uc_link, err);
+
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
+ err |= setup_sigframe(frame, regs, set);
+ if (err == 0) {
+ setup_return(regs, ka, frame, usig);
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ err |= copy_siginfo_to_user(&frame->info, info);
+ regs->regs[1] = (unsigned long)&frame->info;
+ regs->regs[2] = (unsigned long)&frame->uc;
+ }
+ }
+
+ return err;
+}
diff --git a/arch/arm64/kernel/signalilp32.c b/arch/arm64/kernel/signalilp32.c
new file mode 100644
index 0000000..607f8ec
--- /dev/null
+++ b/arch/arm64/kernel/signalilp32.c
@@ -0,0 +1,30 @@
+
+#ifdef CONFIG_ARM64_ILP32
+
+#define rt_sigframe rt_sigframe_ilp32
+#define restore_sigframe restore_sigframe_ilp32
+#define sys_rt_sigreturn sys_ilp32_rt_sigreturn
+#define restore_altstack compat_restore_altstack
+#define setup_sigframe setup_sigframe_ilp32
+#define get_sigframe get_sigframe_ilp32
+#define setup_return setup_return_ilp32
+#define setup_rt_frame setup_rt_frame_ilp32
+#define __save_altstack __compat_save_altstack
+#define copy_siginfo_to_user copy_siginfo_to_user32
+#define ilp32
+
+#include "signal_template.c"
+
+#undef rt_sigframe
+#undef restore_sigframe
+#undef sys_rt_sigreturn
+#undef restore_altstack
+#undef setup_sigframe
+#undef get_sigframe
+#undef setup_return
+#undef setup_rt_frame
+#undef __save_altstack
+#undef copy_siginfo_to_user
+#undef ilp32
+
+#endif
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
new file mode 100644
index 0000000..ada52c8
--- /dev/null
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -0,0 +1,274 @@
+/*
+ * AArch64- ILP32 specific system calls implementation
+ *
+ * Copyright (C) 2013 Cavium Inc.
+ * Author: Andrew Pinski <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Adjust unistd.h to provide 32-bit numbers and functions. */
+#define __SYSCALL_COMPAT
+
+#include <linux/compat.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/statfs.h>
+
+/*
+ * Wrappers to pass the pt_regs argument.
+ */
+#define compat_sys_rt_sigreturn sys_ilp32_rt_sigreturn_wrapper
+
+#include <asm/syscalls.h>
+
+#ifndef __AARCH64EB__
+#define __LONG_LONG_PAIR(HI, LO) LO, HI
+#else
+#define __LONG_LONG_PAIR(HI, LO) HI, LO
+#endif
+
+/* These system calls all split their 64bit arguments into high/low parts. */
+#define compat_sys_ftruncate64 ilp32_ftruncate64
+#define compat_sys_truncate64 ilp32_truncate64
+#define compat_sys_pread64 ilp32_pread64
+#define compat_sys_pwrite64 ilp32_pwrite64
+#define compat_sys_sync_file_range ilp32_sync_file_range
+#define compat_sys_readahead ilp32_readahead
+#define compat_sys_statfs64 ilp32_statfs64
+#define compat_sys_fstatfs64 ilp32_fstatfs64
+#define compat_sys_fallocate ilp32_fallocate
+#define compat_sys_fadvise64_64 ilp32_fadvise64_64
+
+#define sys_mmap2 sys_mmap_pgoff
+/* Since time_t is the 64bits. */
+#define compat_sys_gettimeofday sys_gettimeofday
+#define compat_sys_settimeofday sys_settimeofday
+#define compat_sys_wait4 sys_wait4
+#define compat_sys_times sys_times
+#define compat_sys_setitimer sys_setitimer
+#define compat_sys_getitimer sys_getitimer
+#define compat_sys_nanosleep sys_nanosleep
+#define compat_sys_clock_nanosleep sys_clock_nanosleep
+#define compat_sys_ppoll sys_ppoll
+#define sys_fstatat64 sys_newfstatat
+#define sys_fstat64 sys_newfstat
+#define compat_sys_sched_rr_get_interval sys_sched_rr_get_interval
+#define compat_sys_utimensat sys_utimensat
+#define compat_sys_timerfd_settime sys_timerfd_settime
+#define compat_sys_timerfd_gettime sys_timerfd_gettime
+#define compat_sys_io_getevents sys_io_getevents
+#define compat_sys_epoll_pwait sys_epoll_pwait
+
+#define compat_sys_timer_create sys_timer_create
+#define compat_sys_timer_gettime sys_timer_gettime
+#define compat_sys_timer_settime sys_timer_settime
+#define compat_sys_clock_settime sys_clock_settime
+#define compat_sys_clock_gettime sys_clock_gettime
+#define compat_sys_clock_getres sys_clock_getres
+
+#define compat_sys_getrusage sys_getrusage
+
+/* Since timex is the same as the non-comat one */
+#define compat_sys_adjtimex sys_adjtimex
+#define compat_sys_clock_adjtime sys_clock_adjtime
+
+/* Since mq_attr is the same as the non-compat one */
+#define compat_sys_mq_timedsend sys_mq_timedsend
+#define compat_sys_mq_timedreceive sys_mq_timedreceive
+#define compat_sys_mq_getsetattr sys_mq_getsetattr
+#define compat_sys_mq_open sys_mq_open
+
+#define compat_sys_msgctl sys_msgctl
+#define compat_sys_semctl sys_semctl
+#define compat_sys_shmctl sys_shmctl
+
+#define sys_ptrace compat_sys_ptrace
+
+/* pselect is special as we have both compat ulong and native timespec. */
+#define compat_sys_pselect6 ilp32_sys_pselect6
+
+asmlinkage long ilp32_statfs64(const char __user *pathname, compat_size_t sz,
+ struct statfs __user *buf)
+{
+ int error;
+ if (sz != sizeof(*buf))
+ return -EINVAL;
+ error = sys_statfs(pathname, buf);
+ return error;
+}
+
+asmlinkage long ilp32_fstatfs64(unsigned int fd, compat_size_t sz, struct statfs __user *buf)
+{
+ int error;
+ if (sz != sizeof(*buf))
+ return -EINVAL;
+ error = sys_fstatfs(fd, buf);
+ return error;
+}
+
+asmlinkage long ilp32_fallocate(int fd, int mode, __LONG_LONG_PAIR(u32 offset_hi, u32 offset_lo),
+ __LONG_LONG_PAIR(u32 len_hi, u32 len_lo))
+{
+ return sys_fallocate(fd, mode, ((loff_t)offset_hi << 32) | offset_lo,
+ ((loff_t)len_hi << 32) | len_lo);
+}
+
+asmlinkage long ilp32_fadvise64_64(int fd,
+ __LONG_LONG_PAIR(unsigned long offhi, unsigned long offlo),
+ __LONG_LONG_PAIR(unsigned long lenhi, unsigned long lenlo),
+ int advice)
+{
+ return sys_fadvise64_64(fd,
+ (offhi << 32) | offlo,
+ (lenhi << 32) | lenlo,
+ advice);
+}
+
+asmlinkage int ilp32_truncate64(const char __user *path,
+ __LONG_LONG_PAIR(unsigned long high, unsigned long low))
+{
+ return sys_truncate(path, (high << 32) | low);
+}
+
+asmlinkage int ilp32_ftruncate64(unsigned int fd, __LONG_LONG_PAIR(unsigned long high,
+ unsigned long low))
+{
+ return sys_ftruncate(fd, (high << 32) | low);
+}
+
+compat_ssize_t ilp32_pread64(unsigned int fd, char __user *ubuf, compat_size_t count,
+ u32 reg6, __LONG_LONG_PAIR(u32 poshi, u32 poslo))
+{
+ return sys_pread64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
+}
+
+compat_ssize_t ilp32_pwrite64(unsigned int fd, const char __user *ubuf, compat_size_t count,
+ u32 reg6, __LONG_LONG_PAIR(u32 poshi, u32 poslo))
+{
+ return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
+}
+
+asmlinkage long ilp32_sync_file_range(int fd,
+ __LONG_LONG_PAIR(unsigned offset_hi, unsigned offset_lo),
+ __LONG_LONG_PAIR(unsigned nbytes_hi, unsigned nbytes_lo),
+ unsigned int flags)
+{
+ loff_t offset = ((loff_t)offset_hi << 32) | offset_lo;
+ loff_t nbytes = ((loff_t)nbytes_hi << 32) | nbytes_lo;
+
+ return sys_sync_file_range(fd, offset, nbytes, flags);
+}
+
+compat_ssize_t ilp32_readahead(int fd, u32 r4, __LONG_LONG_PAIR(u32 offhi, u32 offlo), u32 count)
+{
+ return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count);
+}
+
+/*
+ * This is a virtual copy of sys_select from fs/select.c and probably
+ * should be compared to it from time to time
+ */
+
+extern int compat_core_sys_select(int n, compat_ulong_t __user *inp,
+ compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+ struct timespec *end_time);
+
+extern int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
+ int timeval, int ret);
+
+static long do_compat_pselect(int n, compat_ulong_t __user *inp,
+ compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+ struct timespec __user *tsp, sigset_t __user *sigmask,
+ compat_size_t sigsetsize)
+{
+ sigset_t ksigmask, sigsaved;
+ struct timespec ts, end_time, *to = NULL;
+ int ret;
+
+ if (tsp) {
+ if (copy_from_user(&ts, tsp, sizeof(ts)))
+ return -EFAULT;
+
+ to = &end_time;
+ if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
+ return -EINVAL;
+ }
+
+ if (sigmask) {
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+ return -EFAULT;
+
+ sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
+ sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+ }
+
+ ret = compat_core_sys_select(n, inp, outp, exp, to);
+ ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
+
+ if (ret == -ERESTARTNOHAND) {
+ /*
+ * Don't restore the signal mask yet. Let do_signal() deliver
+ * the signal on the way back to userspace, before the signal
+ * mask is restored.
+ */
+ if (sigmask) {
+ memcpy(¤t->saved_sigmask, &sigsaved,
+ sizeof(sigsaved));
+ set_restore_sigmask();
+ }
+ } else if (sigmask)
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
+ return ret;
+}
+
+asmlinkage long ilp32_sys_pselect6(int n, compat_ulong_t __user *inp,
+ compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+ struct timespec __user *tsp, void __user *sig)
+{
+ compat_size_t sigsetsize = 0;
+ compat_uptr_t up = 0;
+
+ if (sig) {
+ if (!access_ok(VERIFY_READ, sig,
+ sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
+ __get_user(up, (compat_uptr_t __user *)sig) ||
+ __get_user(sigsetsize,
+ (compat_size_t __user *)(sig+sizeof(up))))
+ return -EFAULT;
+ }
+ return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
+ sigsetsize);
+}
+
+
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) [nr] = sym,
+
+/*
+ * The sys_call_table array must be 4K aligned to be accessible from
+ * kernel/entry.S.
+ */
+void *sys_ilp32_call_table[__NR_syscalls] __aligned(4096) = {
+ [0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index b5605ac..a7b1c8d 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -40,6 +40,12 @@ extern char vdso_start, vdso_end;
static unsigned long vdso_pages;
static struct page **vdso_pagelist;
+#ifdef CONFIG_ARM64_ILP32
+extern char vdsoilp32_start, vdsoilp32_end;
+static unsigned long vdsoilp32_pages;
+static struct page **vdsoilp32_pagelist;
+#endif
+
/*
* The vDSO data page.
*/
@@ -87,6 +93,11 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
unsigned long addr = AARCH32_VECTORS_BASE;
int ret;
+#ifdef CONFIG_ARM64_ILP32
+ if (is_ilp32_task())
+ return arch_setup_additional_pages(bprm, uses_interp);
+#endif
+
down_write(&mm->mmap_sem);
current->mm->context.vdso = (void *)addr;
@@ -101,6 +112,59 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
}
#endif /* CONFIG_ARM64_AARCH32 */
+#ifdef CONFIG_ARM64_ILP32
+static int __init vdso_init_ilp32(void)
+{
+ struct page *pg;
+ char *vbase;
+ int i, ret = 0;
+
+ vdsoilp32_pages = (&vdsoilp32_end - &vdsoilp32_start) >> PAGE_SHIFT;
+ pr_info("vdsoilp32: %ld pages (%ld code, %ld data) at base %p\n",
+ vdsoilp32_pages + 1, vdsoilp32_pages, 1L, &vdsoilp32_start);
+
+ /* Allocate the vDSO pagelist, plus a page for the data. */
+ vdsoilp32_pagelist = kzalloc(sizeof(struct page *) * (vdsoilp32_pages + 1),
+ GFP_KERNEL);
+ if (vdsoilp32_pagelist == NULL) {
+ pr_err("Failed to allocate vDSO_ilp32 pagelist!\n");
+ return -ENOMEM;
+ }
+
+ /* Grab the vDSO code pages. */
+ for (i = 0; i < vdsoilp32_pages; i++) {
+ pg = virt_to_page(&vdsoilp32_start + i*PAGE_SIZE);
+ ClearPageReserved(pg);
+ get_page(pg);
+ vdsoilp32_pagelist[i] = pg;
+ }
+
+ /* Sanity check the shared object header. */
+ vbase = vmap(vdsoilp32_pagelist, 1, 0, PAGE_KERNEL);
+ if (vbase == NULL) {
+ pr_err("Failed to map vDSO pagelist!\n");
+ return -ENOMEM;
+ } else if (memcmp(vbase, "\177ELF", 4)) {
+ pr_err("vDSO is not a valid ELF object!\n");
+ ret = -EINVAL;
+ goto unmap;
+ }
+
+ /* Grab the vDSO data page. */
+ pg = virt_to_page(vdso_data);
+ get_page(pg);
+ vdsoilp32_pagelist[i] = pg;
+
+unmap:
+ vunmap(vbase);
+ return ret;
+
+}
+
+arch_initcall(vdso_init_ilp32);
+
+#endif /* CONFIG_ARM64_ILP32 */
+
static int __init vdso_init(void)
{
struct page *pg;
@@ -155,9 +219,17 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
struct mm_struct *mm = current->mm;
unsigned long vdso_base, vdso_mapping_len;
int ret;
+ unsigned long pages;
+ struct page **pagelist;
/* Be sure to map the data page */
- vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
+ pages = vdso_pages;
+#ifdef CONFIG_ARM64_ILP32
+ if (is_ilp32_task())
+ pages = vdsoilp32_pages;
+#endif
+ vdso_mapping_len = (pages + 1) << PAGE_SHIFT;
+
down_write(&mm->mmap_sem);
vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
@@ -167,10 +239,15 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
}
mm->context.vdso = (void *)vdso_base;
+ pagelist = vdso_pagelist;
+#ifdef CONFIG_ARM64_ILP32
+ if (is_ilp32_task())
+ pagelist = vdsoilp32_pagelist;
+#endif
ret = install_special_mapping(mm, vdso_base, vdso_mapping_len,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- vdso_pagelist);
+ pagelist);
if (ret) {
mm->context.vdso = NULL;
goto up_fail;
diff --git a/arch/arm64/kernel/vdsoilp32/.gitignore b/arch/arm64/kernel/vdsoilp32/.gitignore
new file mode 100644
index 0000000..618c4dd
--- /dev/null
+++ b/arch/arm64/kernel/vdsoilp32/.gitignore
@@ -0,0 +1,2 @@
+vdso_ilp32.lds
+vdso-ilp32-offsets.h
diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
new file mode 100644
index 0000000..ec93f3f
--- /dev/null
+++ b/arch/arm64/kernel/vdsoilp32/Makefile
@@ -0,0 +1,72 @@
+#
+# Building a vDSO image for AArch64.
+#
+# Author: Will Deacon <[email protected]>
+# Heavily based on the vDSO Makefiles for other archs.
+#
+
+obj-vdso_ilp32 := gettimeofday_ilp32.o note_ilp32.o sigreturn_ilp32.o
+
+# Build rules
+targets := $(obj-vdso_ilp32) vdso_ilp32.so vdso_ilp32.so.dbg
+obj-vdso_ilp32 := $(addprefix $(obj)/, $(obj-vdso_ilp32))
+
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
+ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+
+obj-y += vdsoilp32.o
+extra-y += vdso_ilp32.lds vdso-ilp32-offsets.h
+CPPFLAGS_vdso_ilp32.lds += -P -C -U$(ARCH) -mabi=ilp32
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+
+# Force dependency (incbin is bad)
+$(obj)/vdsoilp32.o : $(obj)/vdso_ilp32.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso_ilp32.so.dbg: $(src)/vdso_ilp32.lds $(obj-vdso_ilp32)
+ $(call if_changed,vdsoilp32ld)
+
+# 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-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+define cmd_vdsosym
+ $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ && \
+ cp $@ include/generated/
+endef
+
+$(obj)/vdso-ilp32-offsets.h: $(obj)/vdso_ilp32.so.dbg FORCE
+ $(call if_changed,vdsosym)
+
+# Assembly rules for the .S files
+$(obj)/gettimeofday_ilp32.o: $(src)/../vdso/gettimeofday.S
+ $(call if_changed_dep,vdsoilp32as)
+
+$(obj)/note_ilp32.o: $(src)/../vdso/note.S
+ $(call if_changed_dep,vdsoilp32as)
+
+$(obj)/sigreturn_ilp32.o: $(src)/../vdso/sigreturn.S
+ $(call if_changed_dep,vdsoilp32as)
+
+# Actual build commands
+quiet_cmd_vdsoilp32ld = VDSOILP32L $@
+ cmd_vdsoilp32ld = $(CC) $(c_flags) -mabi=ilp32 -Wl,-T $^ -o $@
+quiet_cmd_vdsoilp32as = VDSOILP32A $@
+ cmd_vdsoilp32as = $(CC) $(a_flags) -mabi=ilp32 -c -o $@ $<
+
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+ cmd_vdso_install = cp $(obj)/[email protected] $(MODLIB)/vdso/$@
+
+vdso_ilp32.so: $(obj)/vdso_ilp32.so.dbg
+ @mkdir -p $(MODLIB)/vdso
+ $(call cmd,vdso_install)
+
+vdso_install: vdso_ilp32.so
diff --git a/arch/arm64/kernel/vdsoilp32/vdso_ilp32.lds.S b/arch/arm64/kernel/vdsoilp32/vdso_ilp32.lds.S
new file mode 100644
index 0000000..a9eb665
--- /dev/null
+++ b/arch/arm64/kernel/vdsoilp32/vdso_ilp32.lds.S
@@ -0,0 +1,100 @@
+/*
+ * GNU linker script for the VDSO library.
+*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+/*OUTPUT_FORMAT("elf32-littleaarch64", "elf32-bigaarch64", "elf32-littleaarch64")
+OUTPUT_ARCH(aarch64)
+*/
+SECTIONS
+{
+ . = VDSO_LBASE + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ . = ALIGN(16);
+
+ .text : { *(.text*) } :text =0xd503201f
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+ _end = .;
+ PROVIDE(end = .);
+
+ . = ALIGN(PAGE_SIZE);
+ PROVIDE(_vdso_data = .);
+
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.data .data.* .gnu.linkonce.d.* .sdata*)
+ *(.bss .sbss .dynbss .dynsbss)
+ }
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.6.39 {
+ global:
+ __kernel_rt_sigreturn;
+ __kernel_gettimeofday;
+ __kernel_clock_gettime;
+ __kernel_clock_getres;
+ local: *;
+ };
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp_ilp32 = __kernel_rt_sigreturn;
diff --git a/arch/arm64/kernel/vdsoilp32/vdsoilp32.S b/arch/arm64/kernel/vdsoilp32/vdsoilp32.S
new file mode 100644
index 0000000..68329fa
--- /dev/null
+++ b/arch/arm64/kernel/vdsoilp32/vdsoilp32.S
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+ __PAGE_ALIGNED_DATA
+
+ .globl vdsoilp32_start, vdsoilp32_end
+ .balign PAGE_SIZE
+vdsoilp32_start:
+ .incbin "arch/arm64/kernel/vdsoilp32/vdso_ilp32.so"
+ .balign PAGE_SIZE
+vdsoilp32_end:
+
+ .previous
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 67e8d7c..17b9c39 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -35,6 +35,7 @@
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/sizes.h>
+#include <asm/compat.h>
#include <asm/tlb.h>
#include "mm.h"
--
1.7.2.5
On Mon, Sep 9, 2013 at 2:32 PM, Andrew Pinski <[email protected]> wrote:
> Since the ILP32 ABI uses similar signal code as the LP64 ABI, it makes sense to reuse rather
> than copy the same code.
I just noticed that signal_template.c was not part of this patch but
it is included with patch number 5.
Thanks,
Andrew Pinski
>
>
> Signed-off-by: Andrew Pinski <[email protected]>
> ---
> arch/arm64/kernel/signal.c | 170 +-------------------------------------------
> 1 files changed, 1 insertions(+), 169 deletions(-)
>
> diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
> index 3fbd848..d97a0c0 100644
> --- a/arch/arm64/kernel/signal.c
> +++ b/arch/arm64/kernel/signal.c
> @@ -95,176 +95,8 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
> return err ? -EFAULT : 0;
> }
>
> -static int restore_sigframe(struct pt_regs *regs,
> - struct rt_sigframe __user *sf)
> -{
> - sigset_t set;
> - int i, err;
> - struct aux_context __user *aux =
> - (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
> -
> - err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
> - if (err == 0)
> - set_current_blocked(&set);
> -
> - for (i = 0; i < 31; i++)
> - __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
> - err);
> - __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
> - __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
> - __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
> -
> - /*
> - * Avoid sys_rt_sigreturn() restarting.
> - */
> - regs->syscallno = ~0UL;
> -
> - err |= !valid_user_regs(®s->user_regs);
> -
> - if (err == 0)
> - err |= restore_fpsimd_context(&aux->fpsimd);
> -
> - return err;
> -}
> -
> -asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
> -{
> - struct rt_sigframe __user *frame;
> -
> - /* Always make any pending restarted system calls return -EINTR */
> - current_thread_info()->restart_block.fn = do_no_restart_syscall;
> -
> - /*
> - * Since we stacked the signal on a 128-bit boundary, then 'sp' should
> - * be word aligned here.
> - */
> - if (regs->sp & 15)
> - goto badframe;
> -
> - frame = (struct rt_sigframe __user *)regs->sp;
> -
> - if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
> - goto badframe;
> -
> - if (restore_sigframe(regs, frame))
> - goto badframe;
> -
> - if (restore_altstack(&frame->uc.uc_stack))
> - goto badframe;
> -
> - return regs->regs[0];
> -
> -badframe:
> - if (show_unhandled_signals)
> - pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
> - current->comm, task_pid_nr(current), __func__,
> - regs->pc, regs->sp);
> - force_sig(SIGSEGV, current);
> - return 0;
> -}
> -
> -static int setup_sigframe(struct rt_sigframe __user *sf,
> - struct pt_regs *regs, sigset_t *set)
> -{
> - int i, err = 0;
> - struct aux_context __user *aux =
> - (struct aux_context __user *)sf->uc.uc_mcontext.__reserved;
> -
> - /* set up the stack frame for unwinding */
> - __put_user_error(regs->regs[29], &sf->fp, err);
> - __put_user_error(regs->regs[30], &sf->lr, err);
> -
> - for (i = 0; i < 31; i++)
> - __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
> - err);
> - __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
> - __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
> - __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
> -
> - __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
> -
> - err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
> -
> - if (err == 0)
> - err |= preserve_fpsimd_context(&aux->fpsimd);
> -
> - /* set the "end" magic */
> - __put_user_error(0, &aux->end.magic, err);
> - __put_user_error(0, &aux->end.size, err);
> +#include "signal_template.c"
>
> - return err;
> -}
> -
> -static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka,
> - struct pt_regs *regs)
> -{
> - unsigned long sp, sp_top;
> - struct rt_sigframe __user *frame;
> -
> - sp = sp_top = regs->sp;
> -
> - /*
> - * This is the X/Open sanctioned signal stack switching.
> - */
> - if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
> - sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
> -
> - sp = (sp - sizeof(struct rt_sigframe)) & ~15;
> - frame = (struct rt_sigframe __user *)sp;
> -
> - /*
> - * Check that we can actually write to the signal frame.
> - */
> - if (!access_ok(VERIFY_WRITE, frame, sp_top - sp))
> - frame = NULL;
> -
> - return frame;
> -}
> -
> -static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
> - void __user *frame, int usig)
> -{
> - __sigrestore_t sigtramp;
> -
> - regs->regs[0] = usig;
> - regs->sp = (unsigned long)frame;
> - regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
> - regs->pc = (unsigned long)ka->sa.sa_handler;
> -
> - if (ka->sa.sa_flags & SA_RESTORER)
> - sigtramp = ka->sa.sa_restorer;
> - else
> - sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
> -
> - regs->regs[30] = (unsigned long)sigtramp;
> -}
> -
> -static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
> - sigset_t *set, struct pt_regs *regs)
> -{
> - struct rt_sigframe __user *frame;
> - int err = 0;
> -
> - frame = get_sigframe(ka, regs);
> - if (!frame)
> - return 1;
> -
> - __put_user_error(0, &frame->uc.uc_flags, err);
> - __put_user_error(NULL, &frame->uc.uc_link, err);
> -
> - err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
> - err |= setup_sigframe(frame, regs, set);
> - if (err == 0) {
> - setup_return(regs, ka, frame, usig);
> - if (ka->sa.sa_flags & SA_SIGINFO) {
> - err |= copy_siginfo_to_user(&frame->info, info);
> - regs->regs[1] = (unsigned long)&frame->info;
> - regs->regs[2] = (unsigned long)&frame->uc;
> - }
> - }
> -
> - return err;
> -}
>
> static void setup_restart_syscall(struct pt_regs *regs)
> {
> --
> 1.7.2.5
>
On 09/09/2013 02:38 PM, Andrew Pinski wrote:
> On Mon, Sep 9, 2013 at 2:32 PM, Andrew Pinski <[email protected]> wrote:
>> Since the ILP32 ABI uses similar signal code as the LP64 ABI, it makes sense to reuse rather
>> than copy the same code.
>
> I just noticed that signal_template.c was not part of this patch but
> it is included with patch number 5.
>
At a minimum, the patch set should be respun so that it builds, runs and
has no unusable Kconfig options at all intermediate points in the set.
You could also consider splitting out cosmetic changes unrelated to the
meat of a change to a separate patches.
David Daney
Hi Andrew,
On Mon, Sep 09, 2013 at 10:32:55PM +0100, Andrew Pinski wrote:
> Right now CONFIG_COMPAT means enabling AARCH32 support in the ARM64 traget, which we want to split out so we can it to mean any 32bit ABI support instead.
First, there are some coding style and patch format issues. Please pass
the patches through checkpatch.pl.
Also, I would like to see a cover letter giving an overview of the ABI
changes needed for arm64 ILP32 and better, longer patch description. At
a first look, you would think that this simply changes CONFIG_COMPAT to
CONFIG_ARM64_AARCH32 but you have other changes like compat_elf_greg_t
types.
More comments below.
> --- a/arch/arm64/include/asm/compat.h
> +++ b/arch/arm64/include/asm/compat.h
> @@ -279,28 +279,52 @@ struct compat_shmid64_ds {
> compat_ulong_t __unused5;
> };
>
> -static inline int is_compat_task(void)
> +#if defined(CONFIG_ARM64_AARCH32)
> +static inline int is_aarch32_task(void)
> {
> return test_thread_flag(TIF_32BIT);
> }
>
> -static inline int is_compat_thread(struct thread_info *thread)
> +static inline int is_aarch32_thread(struct thread_info *thread)
> {
> return test_ti_thread_flag(thread, TIF_32BIT);
> }
> +#else
> +static inline int is_aarch32_task(void)
> +{
> + return 0;
> +}
> +
> +static inline int is_aarch32_thread(struct thread_info *thread)
> +{
> + return 0;
> +}
> +#endif
> +
>
> #else /* !CONFIG_COMPAT */
Is the comment still correct here?
> -static inline int is_compat_task(void)
> +static inline int is_aarch32_task(void)
> {
> return 0;
> }
>
> -static inline int is_compat_thread(struct thread_info *thread)
> +static inline int is_aarch32_thread(struct thread_info *thread)
> {
> return 0;
> }
>
> #endif /* CONFIG_COMPAT */
Same here.
> diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> index e7fa87f..0a89e94 100644
> --- a/arch/arm64/include/asm/elf.h
> +++ b/arch/arm64/include/asm/elf.h
> @@ -153,24 +153,33 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
>
> #define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 / 3))
>
> +#ifdef CONFIG_ARM64_AARCH32
> /* AArch32 registers. */
> #define COMPAT_ELF_NGREG 18
> -typedef unsigned int compat_elf_greg_t;
> -typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
> +typedef unsigned int compat_a32_elf_greg_t;
> +typedef compat_a32_elf_greg_t compat_a32_elf_gregset_t[COMPAT_ELF_NGREG];
I'm not sure we need to bother placing typedefs under #ifdef. I'll have
to see how this file is modified in later patches.
>
> /* AArch32 EABI. */
> #define EF_ARM_EABI_MASK 0xff000000
> -#define compat_elf_check_arch(x) (((x)->e_machine == EM_ARM) && \
> +#define compat_elf_a32_check_arch(x) (((x)->e_machine == EM_ARM) && \
> ((x)->e_flags & EF_ARM_EABI_MASK))
>
> -#define compat_start_thread compat_start_thread
> -#define COMPAT_SET_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
> +#define COMPAT_SET_A32_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
> #define COMPAT_ARCH_DLINFO
> +
> extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
> int uses_interp);
> #define compat_arch_setup_additional_pages \
> aarch32_setup_vectors_page
>
> +typedef compat_a32_elf_greg_t compat_elf_greg_t;
> +typedef compat_a32_elf_gregset_t compat_elf_gregset_t;
> +#endif
> +
> +#define compat_elf_check_arch(x) compat_elf_a32_check_arch(x)
> +#define COMPAT_SET_PERSONALITY(ex) COMPAT_SET_A32_PERSONALITY(x)
> +#define compat_start_thread compat_start_thread
> +
> #endif /* CONFIG_COMPAT */
Mismatched comment?
> diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
> index 20925bc..4a644a5 100644
> --- a/arch/arm64/include/asm/memory.h
> +++ b/arch/arm64/include/asm/memory.h
> @@ -49,11 +49,11 @@
>
> #ifdef CONFIG_COMPAT
> #define TASK_SIZE_32 UL(0x100000000)
> -#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
> +#define TASK_SIZE (is_compat_task() ? \
> TASK_SIZE_32 : TASK_SIZE_64)
Does this file also need to include compat.h?
> --- a/arch/arm64/include/asm/processor.h
> +++ b/arch/arm64/include/asm/processor.h
> @@ -38,7 +38,7 @@
> #define STACK_TOP_MAX TASK_SIZE_64
> #ifdef CONFIG_COMPAT
> #define AARCH32_VECTORS_BASE 0xffff0000
> -#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
> +#define STACK_TOP (is_compat_task() ? \
> AARCH32_VECTORS_BASE : STACK_TOP_MAX)
Same here.
> --- a/arch/arm64/include/asm/ptrace.h
> +++ b/arch/arm64/include/asm/ptrace.h
> @@ -107,7 +107,7 @@ struct pt_regs {
>
> #define arch_has_single_step() (1)
>
> -#ifdef CONFIG_COMPAT
> +#ifdef CONFIG_ARM64_AARCH32
> #define compat_thumb_mode(regs) \
> (((regs)->pstate & COMPAT_PSR_T_BIT))
Maybe for consistency it could be worth changing to
compat_a32_thumb_mode(), if the aim is to use compat_ prefix for ILP32
as well (I'll see in the rest of the patches).
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -35,6 +35,7 @@
> #include <asm/system_misc.h>
> #include <asm/pgtable.h>
> #include <asm/tlbflush.h>
> +#include <asm/compat.h>
>
> static const char *fault_name(unsigned int esr);
>
> diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
> index 8ed6cb1..29eb82a 100644
> --- a/arch/arm64/mm/mmap.c
> +++ b/arch/arm64/mm/mmap.c
> @@ -28,6 +28,7 @@
> #include <linux/random.h>
>
> #include <asm/cputype.h>
> +#include <asm/compat.h>
So you added these includes because one was missing in memory.h?
--
Catalin
On Mon, Sep 09, 2013 at 10:32:56PM +0100, Andrew Pinski wrote:
> Since the ILP32 ABI uses similar signal code as the LP64 ABI, it makes sense to reuse rather
> than copy the same code.
At a first look, I don't really like this part. I'll comment more on the
last patch.
--
Catalin
On Mon, Sep 09, 2013 at 10:32:57PM +0100, Andrew Pinski wrote:
> The ILP32 ABI in ARM64 uses a slightly different pselect from either
> the compat or even the native LP64 ABI. We would want to reuse some
> of the code path that are used as the size of the timespec is the
> same, so this patch exports poll_select_copy_remaining from
> fs/select.c and renames the copy in fs/compat.c to make sure that it
> is not being used.
>
> Signed-off-by: Andrew Pinski <[email protected]>
I think this patch has to wait until we review the ILP32 ABI for arm64.
When I looked at this some time ago I thought we can just use the native
arm64 pselect6 and ppoll. Once we agree that's not possible we can push
this patch. On its own it doesn't have much value.
--
Catalin
On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
> This patch adds full support of the ABI to the ARM64 target.
This description is too short. Please describe what the ABI is, what are
the commonalities with AArch64 and AArch32, what other non-obvious
things had to be done (like __kernel_long_t being long long). Split this
patch into multiple patches like base syscall handling, signal handling,
pselect6/ppoll, vdso etc. It's too much to review at once.
On top of these, I would really like to see
Documentation/arm64/ilp32.txt describing the ABI.
I would also like to know (you can state this in the cover letter) the
level of testing for all 3 types of ABI. I'm worried that at least this
patch breaks the current compat ABI (has LTP reported anything?).
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index cc64df5..7fdc994 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
>
> config COMPAT
> def_bool y
> - depends on ARM64_AARCH32
> + depends on ARM64_AARCH32 || ARM64_ILP32
> select COMPAT_BINFMT_ELF
>
> config ARM64_AARCH32
> @@ -263,7 +263,14 @@ config ARM64_AARCH32
> the user helper functions, VFP support and the ptrace interface are
> handled appropriately by the kernel.
>
> - If you want to execute 32-bit userspace applications, say Y.
> + If you want to execute Aarch32 userspace applications, say Y.
> +
> +config ARM64_ILP32
> + bool "Kernel support for ILP32"
> + help
> + This option enables support for AArch64 ILP32 user space. These are
> + 64-bit binaries using 32-bit quantities for addressing and certain
> + data that would normally be 64-bit.
You could be even more precise by mentioning that longs and pointers are
32-bit, together with the derived types.
> diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
> index 5ab2676..91bcf13 100644
> --- a/arch/arm64/include/asm/compat.h
> +++ b/arch/arm64/include/asm/compat.h
> @@ -62,6 +62,8 @@ typedef u32 compat_ulong_t;
> typedef u64 compat_u64;
> typedef u32 compat_uptr_t;
>
> +typedef s64 ilp32_clock_t;
> +
> struct compat_timespec {
> compat_time_t tv_sec;
> s32 tv_nsec;
> @@ -180,6 +182,15 @@ typedef struct compat_siginfo {
> compat_clock_t _stime;
> } _sigchld;
>
> + /* SIGCHLD (ILP32 version) */
> + struct {
> + compat_pid_t _pid; /* which child */
> + __compat_uid32_t _uid; /* sender's uid */
> + int _status; /* exit code */
> + ilp32_clock_t _utime;
> + ilp32_clock_t _stime;
> + } _sigchld_ilp32;
This *breaks* the compat_siginfo alignment. ilp32_clock_t is 64-bit
which forces the _sigchld_ilp32 to be 64-bit which makes the preamble 16
instead of 12 bytes. This ilp32_clock_t needs
__attribute__((aligned(4))).
The other approach I've been looking at is just using the native siginfo
instead of the compat one for ILP32. But this requires wider debate
(cc'ed Arnd if he has time).
Basically if you use the current siginfo in the ILP32 context with
__kernel_clock_t being 64-bit you end up with a structure that doesn't
match any of the native or compat siginfo. This is because we have some
pointers which will turn into 32-bit values in ILP32:
void __user *sival_ptr; /* accessed via si_ptr */
void __user *_addr; /* accessed via si_addr */
void __user *_call_addr; /* accessed via si_call_addr */
We also have __ARCH_SI_BAND_T defined as long.
AFAICT, Linux only does a put_user() on these and never reads them from
user space. This means that we can add the right padding on either side
of these pointers (for endianness reasons) and Linux would write 0 as
the top part of a 64-bit pointer (since the user address is restricted
to 32-bit anyway). User ILP32 would only access the corresponding
pointer as a 32-bit value and ignore the padding.
It's easier to explain with some code (untested):
diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
index 5a74a08..e3848be 100644
--- a/arch/arm64/include/uapi/asm/siginfo.h
+++ b/arch/arm64/include/uapi/asm/siginfo.h
@@ -18,6 +18,13 @@
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#ifndef __LP64__ /* ILP32 */
+#define __ARCH_SI_BAND_T long long
+#define VOID_USER_PTR(x) \
+ void __user *x __attribute__((aligned(8))); \
+ char _pad[4]
+#endif
+
#include <asm-generic/siginfo.h>
#endif
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index ba5be7f..9c50257 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -4,9 +4,13 @@
#include <linux/compiler.h>
#include <linux/types.h>
+#ifndef VOID_USER_PTR
+#define VOID_USER_PTR(x) void __user *x
+#endif
+
typedef union sigval {
int sival_int;
- void __user *sival_ptr;
+ VOID_USER_PTR(sival_ptr);
} sigval_t;
/*
@@ -86,7 +90,7 @@ typedef struct siginfo {
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
- void __user *_addr; /* faulting insn/memory ref. */
+ VOID_USER_PTR(_addr); /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
int _trapno; /* TRAP # which caused the signal */
#endif
@@ -101,7 +105,7 @@ typedef struct siginfo {
/* SIGSYS */
struct {
- void __user *_call_addr; /* calling user insn */
+ VOID_USER_PTR(_call_addr); /* calling user insn */
int _syscall; /* triggering system call number */
unsigned int _arch; /* AUDIT_ARCH_* of syscall */
} _sigsys;
__LP64__ is always defined for AArch64 (kernel and native applications).
ILP32 user would not get this symbol and compat use a separate
compat_siginfo anyway.
I'm not entirely sure about defining __ARCH_SI_BAND_T to long long but
as it also seems to be just written by the kernel, we can use some
padding as for the void __user *.
So, I'm looking for feedback on this proposal.
> diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
> index 989128a..f2e0d3c 100644
> --- a/arch/arm64/include/asm/stat.h
> +++ b/arch/arm64/include/asm/stat.h
> @@ -18,9 +18,11 @@
>
> #include <uapi/asm/stat.h>
>
> -#ifdef CONFIG_ARM64_AARCH32
> -
> +#ifdef CONFIG_COMPAT
> #include <asm/compat.h>
> +#endif
Doesn't asm/compat.h have guards already? Do you get a conflict with
is_compat_task()?
> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
> index 5a74a08..297fb4f 100644
> --- a/arch/arm64/include/uapi/asm/siginfo.h
> +++ b/arch/arm64/include/uapi/asm/siginfo.h
> @@ -16,7 +16,13 @@
> #ifndef __ASM_SIGINFO_H
> #define __ASM_SIGINFO_H
>
> +#ifdef __LP64__
> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
> +#else /* ILP32 */
> +typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
> +#define __ARCH_SI_CLOCK_T __kernel_si_clock_t
> +#define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
> +#endif
This could go away if we manage to use the native siginfo.
> --- /dev/null
> +++ b/arch/arm64/kernel/signalilp32.c
> @@ -0,0 +1,30 @@
> +
> +#ifdef CONFIG_ARM64_ILP32
> +
> +#define rt_sigframe rt_sigframe_ilp32
Can we have the same native rt_sigframe (if we go for the native
siginfo)? ucontext is an arm64 structure, so we can add padding for
pointers and long.
> --- /dev/null
> +++ b/arch/arm64/kernel/sys_ilp32.c
> @@ -0,0 +1,274 @@
> +/*
> + * AArch64- ILP32 specific system calls implementation
> + *
> + * Copyright (C) 2013 Cavium Inc.
> + * Author: Andrew Pinski <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/* Adjust unistd.h to provide 32-bit numbers and functions. */
> +#define __SYSCALL_COMPAT
No. We need to use as many native syscalls as possible and only define
those absolutely necessary. In my investigation, I only ended up needing
these:
#define sys_ioctl compat_sys_ioctl
#define sys_readv compat_sys_readv
#define sys_writev compat_sys_writev
#define sys_preadv compat_sys_preadv64
#define sys_pwritev compat_sys_pwritev64
#define sys_vmsplice compat_sys_vmsplice
#define sys_waitid compat_sys_waitid
#define sys_set_robust_list compat_sys_set_robust_list
#define sys_get_robust_list compat_sys_get_robust_list
#define sys_kexec_load compat_sys_kexec_load
#define sys_timer_create compat_sys_timer_create
#define sys_ptrace compat_sys_ptrace
#define sys_sigaltstack compat_sys_sigaltstack
#define sys_rt_sigaction compat_sys_rt_sigaction
#define sys_rt_sigpending compat_sys_rt_sigpending
#define sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
#define sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
#define sys_rt_sigreturn compat_sys_rt_sigreturn_wrapper
#define sys_mq_notify compat_sys_mq_notify
#define sys_recvfrom compat_sys_recvfrom
#define sys_setsockopt compat_sys_setsockopt
#define sys_getsockopt compat_sys_getsockopt
#define sys_sendmsg compat_sys_sendmsg
#define sys_recvmsg compat_sys_recvmsg
#define sys_execve compat_sys_execve
#define sys_move_pages compat_sys_move_pages
#define sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
#define sys_recvmmsg compat_sys_recvmmsg
#define sys_sendmmsg compat_sys_sendmmsg
#define sys_process_vm_readv compat_sys_process_vm_readv
#define sys_process_vm_writev compat_sys_process_vm_writev
> diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
> new file mode 100644
> index 0000000..ec93f3f
> --- /dev/null
> +++ b/arch/arm64/kernel/vdsoilp32/Makefile
Could we not keep vdso in the same directory?
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 67e8d7c..17b9c39 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -35,6 +35,7 @@
> #include <asm/sections.h>
> #include <asm/setup.h>
> #include <asm/sizes.h>
> +#include <asm/compat.h>
> #include <asm/tlb.h>
Same issue, other header files doesn't include what is necessary.
--
Catalin
On Wed, Sep 11, 2013 at 4:09 AM, Catalin Marinas
<[email protected]> wrote:
> On Mon, Sep 09, 2013 at 10:32:57PM +0100, Andrew Pinski wrote:
>> The ILP32 ABI in ARM64 uses a slightly different pselect from either
>> the compat or even the native LP64 ABI. We would want to reuse some
>> of the code path that are used as the size of the timespec is the
>> same, so this patch exports poll_select_copy_remaining from
>> fs/select.c and renames the copy in fs/compat.c to make sure that it
>> is not being used.
>>
>> Signed-off-by: Andrew Pinski <[email protected]>
>
> I think this patch has to wait until we review the ILP32 ABI for arm64.
> When I looked at this some time ago I thought we can just use the native
> arm64 pselect6 and ppoll. Once we agree that's not possible we can push
> this patch. On its own it doesn't have much value.
Since fd_set is defined by XPG4.2 to be a struct of an array of
"long"'s, we cannot change the definition in user space.
I tried using the native ppoll/pselect for the ABI first. It worked
for little-endian just fine but failed hard when big-endian.
If we only care about little-endian arm64 at this point, I can remove
this part of the patch and keep it for when we (Cavium) submits the
big-endian patches.
Thanks,
Andrew Pinski
>
> --
> Catalin
On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
<[email protected]> wrote:
> On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
>> This patch adds full support of the ABI to the ARM64 target.
>
> This description is too short. Please describe what the ABI is, what are
> the commonalities with AArch64 and AArch32, what other non-obvious
> things had to be done (like __kernel_long_t being long long). Split this
> patch into multiple patches like base syscall handling, signal handling,
> pselect6/ppoll, vdso etc. It's too much to review at once.
Ok. I will do so after my vacation next week.
>
> On top of these, I would really like to see
> Documentation/arm64/ilp32.txt describing the ABI.
No other target does not, not even x86_64 for x32.
>
> I would also like to know (you can state this in the cover letter) the
> level of testing for all 3 types of ABI. I'm worried that at least this
> patch breaks the current compat ABI (has LTP reported anything?).
We did test LTP on an earlier version of this patch for all three
ABIs, I will make sure that the next version I send out is tested on
all three ABIs also. We also tested ILP32/LP64 on big-endian at the
same time which we will continue to do (I should push for our team
here to push out the big-endian patches).
>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index cc64df5..7fdc994 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
>>
>> config COMPAT
>> def_bool y
>> - depends on ARM64_AARCH32
>> + depends on ARM64_AARCH32 || ARM64_ILP32
>> select COMPAT_BINFMT_ELF
>>
>> config ARM64_AARCH32
>> @@ -263,7 +263,14 @@ config ARM64_AARCH32
>> the user helper functions, VFP support and the ptrace interface are
>> handled appropriately by the kernel.
>>
>> - If you want to execute 32-bit userspace applications, say Y.
>> + If you want to execute Aarch32 userspace applications, say Y.
>> +
>> +config ARM64_ILP32
>> + bool "Kernel support for ILP32"
>> + help
>> + This option enables support for AArch64 ILP32 user space. These are
>> + 64-bit binaries using 32-bit quantities for addressing and certain
>> + data that would normally be 64-bit.
>
> You could be even more precise by mentioning that longs and pointers are
> 32-bit, together with the derived types.
I copied this from the MIPS64 n32 description in Kconfig. But I will
make it more explicit.
>
>> diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
>> index 5ab2676..91bcf13 100644
>> --- a/arch/arm64/include/asm/compat.h
>> +++ b/arch/arm64/include/asm/compat.h
>> @@ -62,6 +62,8 @@ typedef u32 compat_ulong_t;
>> typedef u64 compat_u64;
>> typedef u32 compat_uptr_t;
>>
>> +typedef s64 ilp32_clock_t;
>> +
>> struct compat_timespec {
>> compat_time_t tv_sec;
>> s32 tv_nsec;
>> @@ -180,6 +182,15 @@ typedef struct compat_siginfo {
>> compat_clock_t _stime;
>> } _sigchld;
>>
>> + /* SIGCHLD (ILP32 version) */
>> + struct {
>> + compat_pid_t _pid; /* which child */
>> + __compat_uid32_t _uid; /* sender's uid */
>> + int _status; /* exit code */
>> + ilp32_clock_t _utime;
>> + ilp32_clock_t _stime;
>> + } _sigchld_ilp32;
>
> This *breaks* the compat_siginfo alignment. ilp32_clock_t is 64-bit
> which forces the _sigchld_ilp32 to be 64-bit which makes the preamble 16
> instead of 12 bytes. This ilp32_clock_t needs
> __attribute__((aligned(4))).
I will check on this.
>
> The other approach I've been looking at is just using the native siginfo
> instead of the compat one for ILP32. But this requires wider debate
> (cc'ed Arnd if he has time).
This is not useful and as you shown can be very messy and even worse
when it comes taking into account big and little-endian. Even x32
does not do that.
>
> Basically if you use the current siginfo in the ILP32 context with
> __kernel_clock_t being 64-bit you end up with a structure that doesn't
> match any of the native or compat siginfo. This is because we have some
> pointers which will turn into 32-bit values in ILP32:
>
> void __user *sival_ptr; /* accessed via si_ptr */
> void __user *_addr; /* accessed via si_addr */
> void __user *_call_addr; /* accessed via si_call_addr */
>
> We also have __ARCH_SI_BAND_T defined as long.
I had first thought about this and even started to implement it but I
found the glibc and the kernel messier than it was already.
>
> AFAICT, Linux only does a put_user() on these and never reads them from
> user space. This means that we can add the right padding on either side
> of these pointers (for endianness reasons) and Linux would write 0 as
> the top part of a 64-bit pointer (since the user address is restricted
> to 32-bit anyway). User ILP32 would only access the corresponding
> pointer as a 32-bit value and ignore the padding.
And I am not a fan of changing the generic UAPI files just so it is no
longer generic like you are doing.
>
> It's easier to explain with some code (untested):
>
> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
> index 5a74a08..e3848be 100644
> --- a/arch/arm64/include/uapi/asm/siginfo.h
> +++ b/arch/arm64/include/uapi/asm/siginfo.h
> @@ -18,6 +18,13 @@
>
> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
>
> +#ifndef __LP64__ /* ILP32 */
> +#define __ARCH_SI_BAND_T long long
> +#define VOID_USER_PTR(x) \
> + void __user *x __attribute__((aligned(8))); \
> + char _pad[4]
> +#endif
> +
> #include <asm-generic/siginfo.h>
>
> #endif
> diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
> index ba5be7f..9c50257 100644
> --- a/include/uapi/asm-generic/siginfo.h
> +++ b/include/uapi/asm-generic/siginfo.h
> @@ -4,9 +4,13 @@
> #include <linux/compiler.h>
> #include <linux/types.h>
>
> +#ifndef VOID_USER_PTR
> +#define VOID_USER_PTR(x) void __user *x
> +#endif
> +
> typedef union sigval {
> int sival_int;
> - void __user *sival_ptr;
> + VOID_USER_PTR(sival_ptr);
> } sigval_t;
>
> /*
> @@ -86,7 +90,7 @@ typedef struct siginfo {
>
> /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
> struct {
> - void __user *_addr; /* faulting insn/memory ref. */
> + VOID_USER_PTR(_addr); /* faulting insn/memory ref. */
> #ifdef __ARCH_SI_TRAPNO
> int _trapno; /* TRAP # which caused the signal */
> #endif
> @@ -101,7 +105,7 @@ typedef struct siginfo {
>
> /* SIGSYS */
> struct {
> - void __user *_call_addr; /* calling user insn */
> + VOID_USER_PTR(_call_addr); /* calling user insn */
> int _syscall; /* triggering system call number */
> unsigned int _arch; /* AUDIT_ARCH_* of syscall */
> } _sigsys;
>
>
> __LP64__ is always defined for AArch64 (kernel and native applications).
> ILP32 user would not get this symbol and compat use a separate
> compat_siginfo anyway.
>
> I'm not entirely sure about defining __ARCH_SI_BAND_T to long long but
> as it also seems to be just written by the kernel, we can use some
> padding as for the void __user *.
>
>
> So, I'm looking for feedback on this proposal.
As I mentioned before even x32 does not do that and it is very messy
to make sure things get zero'd on the glibc and kernel sides.
>
>> diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
>> index 989128a..f2e0d3c 100644
>> --- a/arch/arm64/include/asm/stat.h
>> +++ b/arch/arm64/include/asm/stat.h
>> @@ -18,9 +18,11 @@
>>
>> #include <uapi/asm/stat.h>
>>
>> -#ifdef CONFIG_ARM64_AARCH32
>> -
>> +#ifdef CONFIG_COMPAT
>> #include <asm/compat.h>
>> +#endif
>
> Doesn't asm/compat.h have guards already? Do you get a conflict with
> is_compat_task()?
The guard was there already, I am just changing it back to be under
CONFIG_COMPAT from when I added CONFIG_ARM64_AARCH32. When I submit
the next version of the set of patches, this change will be done
correctly in the patch which adds CONFIG_ARM64_AARCH32.
>
>> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
>> index 5a74a08..297fb4f 100644
>> --- a/arch/arm64/include/uapi/asm/siginfo.h
>> +++ b/arch/arm64/include/uapi/asm/siginfo.h
>> @@ -16,7 +16,13 @@
>> #ifndef __ASM_SIGINFO_H
>> #define __ASM_SIGINFO_H
>>
>> +#ifdef __LP64__
>> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
>> +#else /* ILP32 */
>> +typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
>> +#define __ARCH_SI_CLOCK_T __kernel_si_clock_t
>> +#define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
>> +#endif
>
> This could go away if we manage to use the native siginfo.
See above why I think this is a bad thing and even worse since even
x32 did not do that already; it was the last added ABI like ILP32 to
the kernel.
>
>> --- /dev/null
>> +++ b/arch/arm64/kernel/signalilp32.c
>> @@ -0,0 +1,30 @@
>> +
>> +#ifdef CONFIG_ARM64_ILP32
>> +
>> +#define rt_sigframe rt_sigframe_ilp32
>
> Can we have the same native rt_sigframe (if we go for the native
> siginfo)? ucontext is an arm64 structure, so we can add padding for
> pointers and long.
No again this is messy due to the zeroing of the values. As I
mentioned, I started to implement that but it got messy and there was
no right way of having the headers be sane.
>
>> --- /dev/null
>> +++ b/arch/arm64/kernel/sys_ilp32.c
>> @@ -0,0 +1,274 @@
>> +/*
>> + * AArch64- ILP32 specific system calls implementation
>> + *
>> + * Copyright (C) 2013 Cavium Inc.
>> + * Author: Andrew Pinski <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +/* Adjust unistd.h to provide 32-bit numbers and functions. */
>> +#define __SYSCALL_COMPAT
>
> No. We need to use as many native syscalls as possible and only define
> those absolutely necessary. In my investigation, I only ended up needing
> these:
No using __SYSCALL_COMPAT is the correct thing to do and then only
reverting back what is needed.
The main reason is due to using the generic support inside glibc already.
>
> #define sys_ioctl compat_sys_ioctl
> #define sys_readv compat_sys_readv
> #define sys_writev compat_sys_writev
> #define sys_preadv compat_sys_preadv64
> #define sys_pwritev compat_sys_pwritev64
> #define sys_vmsplice compat_sys_vmsplice
> #define sys_waitid compat_sys_waitid
> #define sys_set_robust_list compat_sys_set_robust_list
> #define sys_get_robust_list compat_sys_get_robust_list
> #define sys_kexec_load compat_sys_kexec_load
> #define sys_timer_create compat_sys_timer_create
> #define sys_ptrace compat_sys_ptrace
> #define sys_sigaltstack compat_sys_sigaltstack
> #define sys_rt_sigaction compat_sys_rt_sigaction
> #define sys_rt_sigpending compat_sys_rt_sigpending
> #define sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
> #define sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
> #define sys_rt_sigreturn compat_sys_rt_sigreturn_wrapper
> #define sys_mq_notify compat_sys_mq_notify
> #define sys_recvfrom compat_sys_recvfrom
> #define sys_setsockopt compat_sys_setsockopt
> #define sys_getsockopt compat_sys_getsockopt
> #define sys_sendmsg compat_sys_sendmsg
> #define sys_recvmsg compat_sys_recvmsg
> #define sys_execve compat_sys_execve
> #define sys_move_pages compat_sys_move_pages
> #define sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
> #define sys_recvmmsg compat_sys_recvmmsg
> #define sys_sendmmsg compat_sys_sendmmsg
> #define sys_process_vm_readv compat_sys_process_vm_readv
> #define sys_process_vm_writev compat_sys_process_vm_writev
You even forgot compat_sys_openat (where O_LARGEFILE differences does
make a difference).
>
>> diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
>> new file mode 100644
>> index 0000000..ec93f3f
>> --- /dev/null
>> +++ b/arch/arm64/kernel/vdsoilp32/Makefile
>
> Could we not keep vdso in the same directory?
I started out that way but "make clean ARCH=arm64" did not clean the
vdso files all the time.
>
>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>> index 67e8d7c..17b9c39 100644
>> --- a/arch/arm64/mm/init.c
>> +++ b/arch/arm64/mm/init.c
>> @@ -35,6 +35,7 @@
>> #include <asm/sections.h>
>> #include <asm/setup.h>
>> #include <asm/sizes.h>
>> +#include <asm/compat.h>
>> #include <asm/tlb.h>
>
> Same issue, other header files doesn't include what is necessary.
I will double check these but I think it was a fall out due to my
change that I had originally did for asm/stat.h .
Thanks,
Andrew Pinski
On Fri, Sep 13, 2013 at 07:18:48AM +0100, Andrew Pinski wrote:
> On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
> <[email protected]> wrote:
> > On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
> >> This patch adds full support of the ABI to the ARM64 target.
> >
> > This description is too short. Please describe what the ABI is, what are
> > the commonalities with AArch64 and AArch32, what other non-obvious
> > things had to be done (like __kernel_long_t being long long). Split this
> > patch into multiple patches like base syscall handling, signal handling,
> > pselect6/ppoll, vdso etc. It's too much to review at once.
>
> Ok. I will do so after my vacation next week.
>
> >
> > On top of these, I would really like to see
> > Documentation/arm64/ilp32.txt describing the ABI.
>
> No other target does not, not even x86_64 for x32.
Well, I'm sure they wouldn't mind if you submitted documentation for them
too.
> > I would also like to know (you can state this in the cover letter) the
> > level of testing for all 3 types of ABI. I'm worried that at least this
> > patch breaks the current compat ABI (has LTP reported anything?).
>
> We did test LTP on an earlier version of this patch for all three
> ABIs, I will make sure that the next version I send out is tested on
> all three ABIs also. We also tested ILP32/LP64 on big-endian at the
> same time which we will continue to do (I should push for our team
> here to push out the big-endian patches).
We also have some BE patches internally, but obviously they just target LP64
and AArch32 compat. I'd hope to get these out shortly (the current issue is
extensive testing, since we don't have much of a BE userspace).
> >> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> >> index cc64df5..7fdc994 100644
> >> --- a/arch/arm64/Kconfig
> >> +++ b/arch/arm64/Kconfig
> >> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
> >>
> >> config COMPAT
> >> def_bool y
> >> - depends on ARM64_AARCH32
> >> + depends on ARM64_AARCH32 || ARM64_ILP32
> >> select COMPAT_BINFMT_ELF
> >>
> >> config ARM64_AARCH32
(nitpick) We used to have an option like this, called
CONFIG_AARCH32_EMULATION, which I think is clearer than CONFIG_ARM64_AARCH32.
> >> diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
> >> new file mode 100644
> >> index 0000000..ec93f3f
> >> --- /dev/null
> >> +++ b/arch/arm64/kernel/vdsoilp32/Makefile
> >
> > Could we not keep vdso in the same directory?
>
> I started out that way but "make clean ARCH=arm64" did not clean the
> vdso files all the time.
Can you elaborate please? I'd much rather we fix broken make rules instead
of botching around the issue by creating new directories.
Will
On Wed, Sep 11, 2013 at 10:00:14PM +0100, Andrew Pinski wrote:
> On Wed, Sep 11, 2013 at 4:09 AM, Catalin Marinas
> <[email protected]> wrote:
> > On Mon, Sep 09, 2013 at 10:32:57PM +0100, Andrew Pinski wrote:
> >> The ILP32 ABI in ARM64 uses a slightly different pselect from either
> >> the compat or even the native LP64 ABI. We would want to reuse some
> >> of the code path that are used as the size of the timespec is the
> >> same, so this patch exports poll_select_copy_remaining from
> >> fs/select.c and renames the copy in fs/compat.c to make sure that it
> >> is not being used.
> >>
> >> Signed-off-by: Andrew Pinski <[email protected]>
> >
> > I think this patch has to wait until we review the ILP32 ABI for arm64.
> > When I looked at this some time ago I thought we can just use the native
> > arm64 pselect6 and ppoll. Once we agree that's not possible we can push
> > this patch. On its own it doesn't have much value.
>
> Since fd_set is defined by XPG4.2 to be a struct of an array of
> "long"'s, we cannot change the definition in user space.
>
> I tried using the native ppoll/pselect for the ABI first. It worked
> for little-endian just fine but failed hard when big-endian.
> If we only care about little-endian arm64 at this point, I can remove
> this part of the patch and keep it for when we (Cavium) submits the
> big-endian patches.
I see the issue now. I think for the initial set of patches we can
assume little endian. We need a lot more testing, at least for AArch32
mode (we can kick off some tests here once these patches get closer to
merging).
--
Catalin
On Fri, Sep 13, 2013 at 10:47:12AM +0100, Will Deacon wrote:
> On Fri, Sep 13, 2013 at 07:18:48AM +0100, Andrew Pinski wrote:
> > On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
> > <[email protected]> wrote:
> > > On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
> > >> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > >> index cc64df5..7fdc994 100644
> > >> --- a/arch/arm64/Kconfig
> > >> +++ b/arch/arm64/Kconfig
> > >> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
> > >>
> > >> config COMPAT
> > >> def_bool y
> > >> - depends on ARM64_AARCH32
> > >> + depends on ARM64_AARCH32 || ARM64_ILP32
> > >> select COMPAT_BINFMT_ELF
> > >>
> > >> config ARM64_AARCH32
>
> (nitpick) We used to have an option like this, called
> CONFIG_AARCH32_EMULATION, which I think is clearer than CONFIG_ARM64_AARCH32.
I think avoiding "EMULATION" is better, we don't actually emulate the
instruction set ;).
--
Catalin
On Fri, Sep 13, 2013 at 10:57:40AM +0100, Catalin Marinas wrote:
> On Fri, Sep 13, 2013 at 10:47:12AM +0100, Will Deacon wrote:
> > On Fri, Sep 13, 2013 at 07:18:48AM +0100, Andrew Pinski wrote:
> > > On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
> > > <[email protected]> wrote:
> > > > On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
> > > >> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > > >> index cc64df5..7fdc994 100644
> > > >> --- a/arch/arm64/Kconfig
> > > >> +++ b/arch/arm64/Kconfig
> > > >> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
> > > >>
> > > >> config COMPAT
> > > >> def_bool y
> > > >> - depends on ARM64_AARCH32
> > > >> + depends on ARM64_AARCH32 || ARM64_ILP32
> > > >> select COMPAT_BINFMT_ELF
> > > >>
> > > >> config ARM64_AARCH32
> >
> > (nitpick) We used to have an option like this, called
> > CONFIG_AARCH32_EMULATION, which I think is clearer than CONFIG_ARM64_AARCH32.
>
> I think avoiding "EMULATION" is better, we don't actually emulate the
> instruction set ;).
Bah, you suggest something better then!
Will
On Fri, Sep 13, 2013 at 07:18:48AM +0100, Andrew Pinski wrote:
> On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
> <[email protected]> wrote:
> > On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
> >
> > On top of these, I would really like to see
> > Documentation/arm64/ilp32.txt describing the ABI.
>
> No other target does not, not even x86_64 for x32.
That's not really a good argument.
> > The other approach I've been looking at is just using the native siginfo
> > instead of the compat one for ILP32. But this requires wider debate
> > (cc'ed Arnd if he has time).
>
> This is not useful and as you shown can be very messy and even worse
> when it comes taking into account big and little-endian. Even x32
> does not do that.
Well, please don't bring the "x32 does not do that" argument. It doesn't
mean we shouldn't investigate better ways. Initially x32 got the siginfo
members alignment wrong and they ended up __ARCH_SI_CLOCK_T and
__ARCH_SI_ATTRIBUTES, changing the generic uapi files.
> > Basically if you use the current siginfo in the ILP32 context with
> > __kernel_clock_t being 64-bit you end up with a structure that doesn't
> > match any of the native or compat siginfo. This is because we have some
> > pointers which will turn into 32-bit values in ILP32:
> >
> > void __user *sival_ptr; /* accessed via si_ptr */
> > void __user *_addr; /* accessed via si_addr */
> > void __user *_call_addr; /* accessed via si_call_addr */
> >
> > We also have __ARCH_SI_BAND_T defined as long.
>
> I had first thought about this and even started to implement it but I
> found the glibc and the kernel messier than it was already.
The kernel part wasn't bad IMO (of course, needs ack from generic
headers maintainer). I can't talk about glibc but wouldn't it just
access these members explicitly?
> > AFAICT, Linux only does a put_user() on these and never reads them from
> > user space. This means that we can add the right padding on either side
> > of these pointers (for endianness reasons) and Linux would write 0 as
> > the top part of a 64-bit pointer (since the user address is restricted
> > to 32-bit anyway). User ILP32 would only access the corresponding
> > pointer as a 32-bit value and ignore the padding.
>
> And I am not a fan of changing the generic UAPI files just so it is no
> longer generic like you are doing.
As I said above, x32 did that already and your are doing similar things
for __ARCH_SI_CLOCK_T.
> > So, I'm looking for feedback on this proposal.
>
> As I mentioned before even x32 does not do that and it is very messy
> to make sure things get zero'd on the glibc and kernel sides.
(not the x32 argument again)
On the kernel side, they get zeroed automatically because the kernel
assumes it is a 64-bit address for user space, which is restricted to
32-bit only. Are these members ever read back by the kernel? That's
where glibc zeroing would be needed (and I wouldn't like it either).
> >> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
> >> index 5a74a08..297fb4f 100644
> >> --- a/arch/arm64/include/uapi/asm/siginfo.h
> >> +++ b/arch/arm64/include/uapi/asm/siginfo.h
> >> @@ -16,7 +16,13 @@
> >> #ifndef __ASM_SIGINFO_H
> >> #define __ASM_SIGINFO_H
> >>
> >> +#ifdef __LP64__
> >> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
> >> +#else /* ILP32 */
> >> +typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
> >> +#define __ARCH_SI_CLOCK_T __kernel_si_clock_t
> >> +#define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
> >> +#endif
> >
> > This could go away if we manage to use the native siginfo.
>
> See above why I think this is a bad thing and even worse since even
> x32 did not do that already; it was the last added ABI like ILP32 to
> the kernel.
The x32 thing is becoming the central theme.
> >> --- /dev/null
> >> +++ b/arch/arm64/kernel/sys_ilp32.c
> >> @@ -0,0 +1,274 @@
> >> +/*
> >> + * AArch64- ILP32 specific system calls implementation
> >> + *
> >> + * Copyright (C) 2013 Cavium Inc.
> >> + * Author: Andrew Pinski <[email protected]>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +/* Adjust unistd.h to provide 32-bit numbers and functions. */
> >> +#define __SYSCALL_COMPAT
> >
> > No. We need to use as many native syscalls as possible and only define
> > those absolutely necessary. In my investigation, I only ended up needing
> > these:
>
> No using __SYSCALL_COMPAT is the correct thing to do and then only
> reverting back what is needed.
I _disagree_. "Even x32 does not to that". Some past discussions:
http://thread.gmane.org/gmane.linux.kernel/1184913
> > #define sys_ioctl compat_sys_ioctl
> > #define sys_readv compat_sys_readv
> > #define sys_writev compat_sys_writev
> > #define sys_preadv compat_sys_preadv64
> > #define sys_pwritev compat_sys_pwritev64
> > #define sys_vmsplice compat_sys_vmsplice
> > #define sys_waitid compat_sys_waitid
> > #define sys_set_robust_list compat_sys_set_robust_list
> > #define sys_get_robust_list compat_sys_get_robust_list
> > #define sys_kexec_load compat_sys_kexec_load
> > #define sys_timer_create compat_sys_timer_create
> > #define sys_ptrace compat_sys_ptrace
> > #define sys_sigaltstack compat_sys_sigaltstack
> > #define sys_rt_sigaction compat_sys_rt_sigaction
> > #define sys_rt_sigpending compat_sys_rt_sigpending
> > #define sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
> > #define sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
> > #define sys_rt_sigreturn compat_sys_rt_sigreturn_wrapper
> > #define sys_mq_notify compat_sys_mq_notify
> > #define sys_recvfrom compat_sys_recvfrom
> > #define sys_setsockopt compat_sys_setsockopt
> > #define sys_getsockopt compat_sys_getsockopt
> > #define sys_sendmsg compat_sys_sendmsg
> > #define sys_recvmsg compat_sys_recvmsg
> > #define sys_execve compat_sys_execve
> > #define sys_move_pages compat_sys_move_pages
> > #define sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
> > #define sys_recvmmsg compat_sys_recvmmsg
> > #define sys_sendmmsg compat_sys_sendmmsg
> > #define sys_process_vm_readv compat_sys_process_vm_readv
> > #define sys_process_vm_writev compat_sys_process_vm_writev
>
> You even forgot compat_sys_openat (where O_LARGEFILE differences does
> make a difference).
Just read the above thread. "Even x32 does not do that".
> >> diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
> >> new file mode 100644
> >> index 0000000..ec93f3f
> >> --- /dev/null
> >> +++ b/arch/arm64/kernel/vdsoilp32/Makefile
> >
> > Could we not keep vdso in the same directory?
>
> I started out that way but "make clean ARCH=arm64" did not clean the
> vdso files all the time.
I'll leave vdso comments to Will.
--
Catalin
On Fri, Sep 13, 2013 at 11:04:53AM +0100, Will Deacon wrote:
> On Fri, Sep 13, 2013 at 10:57:40AM +0100, Catalin Marinas wrote:
> > On Fri, Sep 13, 2013 at 10:47:12AM +0100, Will Deacon wrote:
> > > On Fri, Sep 13, 2013 at 07:18:48AM +0100, Andrew Pinski wrote:
> > > > On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
> > > > <[email protected]> wrote:
> > > > > On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
> > > > >> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > > > >> index cc64df5..7fdc994 100644
> > > > >> --- a/arch/arm64/Kconfig
> > > > >> +++ b/arch/arm64/Kconfig
> > > > >> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
> > > > >>
> > > > >> config COMPAT
> > > > >> def_bool y
> > > > >> - depends on ARM64_AARCH32
> > > > >> + depends on ARM64_AARCH32 || ARM64_ILP32
> > > > >> select COMPAT_BINFMT_ELF
> > > > >>
> > > > >> config ARM64_AARCH32
> > >
> > > (nitpick) We used to have an option like this, called
> > > CONFIG_AARCH32_EMULATION, which I think is clearer than CONFIG_ARM64_AARCH32.
> >
> > I think avoiding "EMULATION" is better, we don't actually emulate the
> > instruction set ;).
>
> Bah, you suggest something better then!
CONFIG_AARCH32_EL0.
--
Catalin
On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
<[email protected]> wrote:
> On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
>> This patch adds full support of the ABI to the ARM64 target.
>
> This description is too short. Please describe what the ABI is, what are
> the commonalities with AArch64 and AArch32, what other non-obvious
> things had to be done (like __kernel_long_t being long long). Split this
> patch into multiple patches like base syscall handling, signal handling,
> pselect6/ppoll, vdso etc. It's too much to review at once.
I will try to do this.
>
> On top of these, I would really like to see
> Documentation/arm64/ilp32.txt describing the ABI.
Ok, I will add some documentation.
>
> I would also like to know (you can state this in the cover letter) the
> level of testing for all 3 types of ABI. I'm worried that at least this
> patch breaks the current compat ABI (has LTP reported anything?).
When I submit the next version, I will cover this in my cover letter.
>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index cc64df5..7fdc994 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -248,7 +248,7 @@ source "fs/Kconfig.binfmt"
>>
>> config COMPAT
>> def_bool y
>> - depends on ARM64_AARCH32
>> + depends on ARM64_AARCH32 || ARM64_ILP32
>> select COMPAT_BINFMT_ELF
>>
>> config ARM64_AARCH32
>> @@ -263,7 +263,14 @@ config ARM64_AARCH32
>> the user helper functions, VFP support and the ptrace interface are
>> handled appropriately by the kernel.
>>
>> - If you want to execute 32-bit userspace applications, say Y.
>> + If you want to execute Aarch32 userspace applications, say Y.
>> +
>> +config ARM64_ILP32
>> + bool "Kernel support for ILP32"
>> + help
>> + This option enables support for AArch64 ILP32 user space. These are
>> + 64-bit binaries using 32-bit quantities for addressing and certain
>> + data that would normally be 64-bit.
>
> You could be even more precise by mentioning that longs and pointers are
> 32-bit, together with the derived types.
Will fix this as mentioned before.
>
>> diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
>> index 5ab2676..91bcf13 100644
>> --- a/arch/arm64/include/asm/compat.h
>> +++ b/arch/arm64/include/asm/compat.h
>> @@ -62,6 +62,8 @@ typedef u32 compat_ulong_t;
>> typedef u64 compat_u64;
>> typedef u32 compat_uptr_t;
>>
>> +typedef s64 ilp32_clock_t;
>> +
>> struct compat_timespec {
>> compat_time_t tv_sec;
>> s32 tv_nsec;
>> @@ -180,6 +182,15 @@ typedef struct compat_siginfo {
>> compat_clock_t _stime;
>> } _sigchld;
>>
>> + /* SIGCHLD (ILP32 version) */
>> + struct {
>> + compat_pid_t _pid; /* which child */
>> + __compat_uid32_t _uid; /* sender's uid */
>> + int _status; /* exit code */
>> + ilp32_clock_t _utime;
>> + ilp32_clock_t _stime;
>> + } _sigchld_ilp32;
>
> This *breaks* the compat_siginfo alignment. ilp32_clock_t is 64-bit
> which forces the _sigchld_ilp32 to be 64-bit which makes the preamble 16
> instead of 12 bytes. This ilp32_clock_t needs
> __attribute__((aligned(4))).
Will fix this.
>
> The other approach I've been looking at is just using the native siginfo
> instead of the compat one for ILP32. But this requires wider debate
> (cc'ed Arnd if he has time).
I will try to do this though it will take a week to get how much I can
do with siginfo as the glibc side can be a pain to work with. The
kernel is cleaner here since it is always 64bit.
>
> Basically if you use the current siginfo in the ILP32 context with
> __kernel_clock_t being 64-bit you end up with a structure that doesn't
> match any of the native or compat siginfo. This is because we have some
> pointers which will turn into 32-bit values in ILP32:
>
> void __user *sival_ptr; /* accessed via si_ptr */
> void __user *_addr; /* accessed via si_addr */
> void __user *_call_addr; /* accessed via si_call_addr */
>
> We also have __ARCH_SI_BAND_T defined as long.
This has to stay long as POSIX defines it as a long type as mentioned
in the header file. I will use an anonymous union/struct to get the
correct definition for ilp32. I have to also fix the ptrace interface
after I do this.
>
> AFAICT, Linux only does a put_user() on these and never reads them from
> user space. This means that we can add the right padding on either side
> of these pointers (for endianness reasons) and Linux would write 0 as
> the top part of a 64-bit pointer (since the user address is restricted
> to 32-bit anyway). User ILP32 would only access the corresponding
> pointer as a 32-bit value and ignore the padding.
>
> It's easier to explain with some code (untested):
>
> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
> index 5a74a08..e3848be 100644
> --- a/arch/arm64/include/uapi/asm/siginfo.h
> +++ b/arch/arm64/include/uapi/asm/siginfo.h
> @@ -18,6 +18,13 @@
>
> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
>
> +#ifndef __LP64__ /* ILP32 */
> +#define __ARCH_SI_BAND_T long long
> +#define VOID_USER_PTR(x) \
> + void __user *x __attribute__((aligned(8))); \
> + char _pad[4]
> +#endif
> +
> #include <asm-generic/siginfo.h>
>
> #endif
> diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
> index ba5be7f..9c50257 100644
> --- a/include/uapi/asm-generic/siginfo.h
> +++ b/include/uapi/asm-generic/siginfo.h
> @@ -4,9 +4,13 @@
> #include <linux/compiler.h>
> #include <linux/types.h>
>
> +#ifndef VOID_USER_PTR
> +#define VOID_USER_PTR(x) void __user *x
> +#endif
> +
> typedef union sigval {
> int sival_int;
> - void __user *sival_ptr;
> + VOID_USER_PTR(sival_ptr);
> } sigval_t;
>
> /*
> @@ -86,7 +90,7 @@ typedef struct siginfo {
>
> /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
> struct {
> - void __user *_addr; /* faulting insn/memory ref. */
> + VOID_USER_PTR(_addr); /* faulting insn/memory ref. */
> #ifdef __ARCH_SI_TRAPNO
> int _trapno; /* TRAP # which caused the signal */
> #endif
> @@ -101,7 +105,7 @@ typedef struct siginfo {
>
> /* SIGSYS */
> struct {
> - void __user *_call_addr; /* calling user insn */
> + VOID_USER_PTR(_call_addr); /* calling user insn */
> int _syscall; /* triggering system call number */
> unsigned int _arch; /* AUDIT_ARCH_* of syscall */
> } _sigsys;
>
>
> __LP64__ is always defined for AArch64 (kernel and native applications).
> ILP32 user would not get this symbol and compat use a separate
> compat_siginfo anyway.
>
> I'm not entirely sure about defining __ARCH_SI_BAND_T to long long but
> as it also seems to be just written by the kernel, we can use some
> padding as for the void __user *.
POSIX defines it as long as mentioned above. I don't think we want
ILP32 to violate POSIX here if we can not help it.
>
>
> So, I'm looking for feedback on this proposal.
>
>> diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
>> index 989128a..f2e0d3c 100644
>> --- a/arch/arm64/include/asm/stat.h
>> +++ b/arch/arm64/include/asm/stat.h
>> @@ -18,9 +18,11 @@
>>
>> #include <uapi/asm/stat.h>
>>
>> -#ifdef CONFIG_ARM64_AARCH32
>> -
>> +#ifdef CONFIG_COMPAT
>> #include <asm/compat.h>
>> +#endif
>
> Doesn't asm/compat.h have guards already? Do you get a conflict with
> is_compat_task()?
This was due to the order of the patches were applied and I did not
notice the breakage until after I finished the last one. I will fix
this so it is correctly done before I submit the next version of the
patches.
>
>> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
>> index 5a74a08..297fb4f 100644
>> --- a/arch/arm64/include/uapi/asm/siginfo.h
>> +++ b/arch/arm64/include/uapi/asm/siginfo.h
>> @@ -16,7 +16,13 @@
>> #ifndef __ASM_SIGINFO_H
>> #define __ASM_SIGINFO_H
>>
>> +#ifdef __LP64__
>> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
>> +#else /* ILP32 */
>> +typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
>> +#define __ARCH_SI_CLOCK_T __kernel_si_clock_t
>> +#define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
>> +#endif
>
> This could go away if we manage to use the native siginfo.
Yes I agree.
>
>> --- /dev/null
>> +++ b/arch/arm64/kernel/signalilp32.c
>> @@ -0,0 +1,30 @@
>> +
>> +#ifdef CONFIG_ARM64_ILP32
>> +
>> +#define rt_sigframe rt_sigframe_ilp32
>
> Can we have the same native rt_sigframe (if we go for the native
> siginfo)? ucontext is an arm64 structure, so we can add padding for
> pointers and long.
This one is a little harder at least in glibc itself. I tried a few
times but I always failed due to not having that much experience with
the code there but I will try one more time.
>
>> --- /dev/null
>> +++ b/arch/arm64/kernel/sys_ilp32.c
>> @@ -0,0 +1,274 @@
>> +/*
>> + * AArch64- ILP32 specific system calls implementation
>> + *
>> + * Copyright (C) 2013 Cavium Inc.
>> + * Author: Andrew Pinski <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +/* Adjust unistd.h to provide 32-bit numbers and functions. */
>> +#define __SYSCALL_COMPAT
>
> No. We need to use as many native syscalls as possible and only define
> those absolutely necessary. In my investigation, I only ended up needing
> these:
>
> #define sys_ioctl compat_sys_ioctl
> #define sys_readv compat_sys_readv
> #define sys_writev compat_sys_writev
> #define sys_preadv compat_sys_preadv64
> #define sys_pwritev compat_sys_pwritev64
> #define sys_vmsplice compat_sys_vmsplice
> #define sys_waitid compat_sys_waitid
> #define sys_set_robust_list compat_sys_set_robust_list
> #define sys_get_robust_list compat_sys_get_robust_list
> #define sys_kexec_load compat_sys_kexec_load
> #define sys_timer_create compat_sys_timer_create
> #define sys_ptrace compat_sys_ptrace
> #define sys_sigaltstack compat_sys_sigaltstack
> #define sys_rt_sigaction compat_sys_rt_sigaction
> #define sys_rt_sigpending compat_sys_rt_sigpending
> #define sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
> #define sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
> #define sys_rt_sigreturn compat_sys_rt_sigreturn_wrapper
> #define sys_mq_notify compat_sys_mq_notify
> #define sys_recvfrom compat_sys_recvfrom
> #define sys_setsockopt compat_sys_setsockopt
> #define sys_getsockopt compat_sys_getsockopt
> #define sys_sendmsg compat_sys_sendmsg
> #define sys_recvmsg compat_sys_recvmsg
> #define sys_execve compat_sys_execve
> #define sys_move_pages compat_sys_move_pages
> #define sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
> #define sys_recvmmsg compat_sys_recvmmsg
> #define sys_sendmmsg compat_sys_sendmmsg
> #define sys_process_vm_readv compat_sys_process_vm_readv
> #define sys_process_vm_writev compat_sys_process_vm_writev
Here is some additional ones I can up with after understanding this
code better:\
/* Pointer in struct */
#define sys_mount compat_sys_mount
/* NUMA */
/* unsigned long bitmaps */
#define sys_get_mempolicy compat_sys_get_mempolicy
#define sys_set_mempolicy compat_sys_set_mempolicy
#define sys_mbind compat_sys_mbind
/* array of pointers */
/* unsigned long bitmaps */
#define sys_migrate_pages compat_sys_migrate_pages
/* Scheduler */
/* unsigned long bitmaps */
#define sys_sched_setaffinity compat_sys_sched_setaffinity
#define sys_sched_getaffinity compat_sys_sched_getaffinity
/* iov usage */
#define sys_keyctl compat_sys_keyctl
/* aio */
/* Pointer to Pointer */
#define sys_io_setup compat_sys_io_setup
/* Array of pointers */
#define sys_io_submit compat_sys_io_submit
--- CUT ----
I added a couple of comments on why the ones listed above are needed.
Also I don't think ilp32 needs its own sys_ptrace rather than using
the compat one.
>
>> diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
>> new file mode 100644
>> index 0000000..ec93f3f
>> --- /dev/null
>> +++ b/arch/arm64/kernel/vdsoilp32/Makefile
>
> Could we not keep vdso in the same directory?
>
>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>> index 67e8d7c..17b9c39 100644
>> --- a/arch/arm64/mm/init.c
>> +++ b/arch/arm64/mm/init.c
>> @@ -35,6 +35,7 @@
>> #include <asm/sections.h>
>> #include <asm/setup.h>
>> #include <asm/sizes.h>
>> +#include <asm/compat.h>
>> #include <asm/tlb.h>
>
> Same issue, other header files doesn't include what is necessary.
>
> --
> Catalin
On Fri, Sep 13, 2013 at 5:12 AM, Catalin Marinas
<[email protected]> wrote:
> On Fri, Sep 13, 2013 at 07:18:48AM +0100, Andrew Pinski wrote:
>> On Wed, Sep 11, 2013 at 7:32 AM, Catalin Marinas
>> <[email protected]> wrote:
>> > On Mon, Sep 09, 2013 at 10:32:59PM +0100, Andrew Pinski wrote:
>> >
>> > On top of these, I would really like to see
>> > Documentation/arm64/ilp32.txt describing the ABI.
>>
>> No other target does not, not even x86_64 for x32.
>
> That's not really a good argument.
>
>> > The other approach I've been looking at is just using the native siginfo
>> > instead of the compat one for ILP32. But this requires wider debate
>> > (cc'ed Arnd if he has time).
>>
>> This is not useful and as you shown can be very messy and even worse
>> when it comes taking into account big and little-endian. Even x32
>> does not do that.
>
> Well, please don't bring the "x32 does not do that" argument. It doesn't
> mean we shouldn't investigate better ways. Initially x32 got the siginfo
> members alignment wrong and they ended up __ARCH_SI_CLOCK_T and
> __ARCH_SI_ATTRIBUTES, changing the generic uapi files.
>
>> > Basically if you use the current siginfo in the ILP32 context with
>> > __kernel_clock_t being 64-bit you end up with a structure that doesn't
>> > match any of the native or compat siginfo. This is because we have some
>> > pointers which will turn into 32-bit values in ILP32:
>> >
>> > void __user *sival_ptr; /* accessed via si_ptr */
>> > void __user *_addr; /* accessed via si_addr */
>> > void __user *_call_addr; /* accessed via si_call_addr */
>> >
>> > We also have __ARCH_SI_BAND_T defined as long.
>>
>> I had first thought about this and even started to implement it but I
>> found the glibc and the kernel messier than it was already.
>
> The kernel part wasn't bad IMO (of course, needs ack from generic
> headers maintainer). I can't talk about glibc but wouldn't it just
> access these members explicitly?
>
>> > AFAICT, Linux only does a put_user() on these and never reads them from
>> > user space. This means that we can add the right padding on either side
>> > of these pointers (for endianness reasons) and Linux would write 0 as
>> > the top part of a 64-bit pointer (since the user address is restricted
>> > to 32-bit anyway). User ILP32 would only access the corresponding
>> > pointer as a 32-bit value and ignore the padding.
This is not true for sigevent which is defined to include "union
sigval" by the POSIX standard. sigval is also included in siginfo so
it needs to be using 64bit pointers here. The padding issue does come
into play for some syscalls (mq_notify and timer_create). They both
would need a special wrapper syscall to correctly zero fill the upper
bits of that union. Would it be ok for those two system calls to have
a wapper?
The rest is correct we only write to those fields and never read from them.
Thanks,
Andrew Pinski
>>
>> And I am not a fan of changing the generic UAPI files just so it is no
>> longer generic like you are doing.
>
> As I said above, x32 did that already and your are doing similar things
> for __ARCH_SI_CLOCK_T.
>
>> > So, I'm looking for feedback on this proposal.
>>
>> As I mentioned before even x32 does not do that and it is very messy
>> to make sure things get zero'd on the glibc and kernel sides.
>
> (not the x32 argument again)
>
> On the kernel side, they get zeroed automatically because the kernel
> assumes it is a 64-bit address for user space, which is restricted to
> 32-bit only. Are these members ever read back by the kernel? That's
> where glibc zeroing would be needed (and I wouldn't like it either).
>
>> >> diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
>> >> index 5a74a08..297fb4f 100644
>> >> --- a/arch/arm64/include/uapi/asm/siginfo.h
>> >> +++ b/arch/arm64/include/uapi/asm/siginfo.h
>> >> @@ -16,7 +16,13 @@
>> >> #ifndef __ASM_SIGINFO_H
>> >> #define __ASM_SIGINFO_H
>> >>
>> >> +#ifdef __LP64__
>> >> #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
>> >> +#else /* ILP32 */
>> >> +typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
>> >> +#define __ARCH_SI_CLOCK_T __kernel_si_clock_t
>> >> +#define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
>> >> +#endif
>> >
>> > This could go away if we manage to use the native siginfo.
>>
>> See above why I think this is a bad thing and even worse since even
>> x32 did not do that already; it was the last added ABI like ILP32 to
>> the kernel.
>
> The x32 thing is becoming the central theme.
>
>> >> --- /dev/null
>> >> +++ b/arch/arm64/kernel/sys_ilp32.c
>> >> @@ -0,0 +1,274 @@
>> >> +/*
>> >> + * AArch64- ILP32 specific system calls implementation
>> >> + *
>> >> + * Copyright (C) 2013 Cavium Inc.
>> >> + * Author: Andrew Pinski <[email protected]>
>> >> + *
>> >> + * This program is free software; you can redistribute it and/or modify
>> >> + * it under the terms of the GNU General Public License version 2 as
>> >> + * published by the Free Software Foundation.
>> >> + *
>> >> + * This program is distributed in the hope that it will be useful,
>> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> >> + * GNU General Public License for more details.
>> >> + *
>> >> + * You should have received a copy of the GNU General Public License
>> >> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> >> + */
>> >> +
>> >> +/* Adjust unistd.h to provide 32-bit numbers and functions. */
>> >> +#define __SYSCALL_COMPAT
>> >
>> > No. We need to use as many native syscalls as possible and only define
>> > those absolutely necessary. In my investigation, I only ended up needing
>> > these:
>>
>> No using __SYSCALL_COMPAT is the correct thing to do and then only
>> reverting back what is needed.
>
> I _disagree_. "Even x32 does not to that". Some past discussions:
>
> http://thread.gmane.org/gmane.linux.kernel/1184913
>
>> > #define sys_ioctl compat_sys_ioctl
>> > #define sys_readv compat_sys_readv
>> > #define sys_writev compat_sys_writev
>> > #define sys_preadv compat_sys_preadv64
>> > #define sys_pwritev compat_sys_pwritev64
>> > #define sys_vmsplice compat_sys_vmsplice
>> > #define sys_waitid compat_sys_waitid
>> > #define sys_set_robust_list compat_sys_set_robust_list
>> > #define sys_get_robust_list compat_sys_get_robust_list
>> > #define sys_kexec_load compat_sys_kexec_load
>> > #define sys_timer_create compat_sys_timer_create
>> > #define sys_ptrace compat_sys_ptrace
>> > #define sys_sigaltstack compat_sys_sigaltstack
>> > #define sys_rt_sigaction compat_sys_rt_sigaction
>> > #define sys_rt_sigpending compat_sys_rt_sigpending
>> > #define sys_rt_sigtimedwait compat_sys_rt_sigtimedwait
>> > #define sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
>> > #define sys_rt_sigreturn compat_sys_rt_sigreturn_wrapper
>> > #define sys_mq_notify compat_sys_mq_notify
>> > #define sys_recvfrom compat_sys_recvfrom
>> > #define sys_setsockopt compat_sys_setsockopt
>> > #define sys_getsockopt compat_sys_getsockopt
>> > #define sys_sendmsg compat_sys_sendmsg
>> > #define sys_recvmsg compat_sys_recvmsg
>> > #define sys_execve compat_sys_execve
>> > #define sys_move_pages compat_sys_move_pages
>> > #define sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
>> > #define sys_recvmmsg compat_sys_recvmmsg
>> > #define sys_sendmmsg compat_sys_sendmmsg
>> > #define sys_process_vm_readv compat_sys_process_vm_readv
>> > #define sys_process_vm_writev compat_sys_process_vm_writev
>>
>> You even forgot compat_sys_openat (where O_LARGEFILE differences does
>> make a difference).
>
> Just read the above thread. "Even x32 does not do that".
>
>> >> diff --git a/arch/arm64/kernel/vdsoilp32/Makefile b/arch/arm64/kernel/vdsoilp32/Makefile
>> >> new file mode 100644
>> >> index 0000000..ec93f3f
>> >> --- /dev/null
>> >> +++ b/arch/arm64/kernel/vdsoilp32/Makefile
>> >
>> > Could we not keep vdso in the same directory?
>>
>> I started out that way but "make clean ARCH=arm64" did not clean the
>> vdso files all the time.
>
> I'll leave vdso comments to Will.
>
> --
> Catalin