[RFC5 PATCH v6 00/21] ILP32 for ARM64

Yury Norov
2016-03-26T22:46:16Z

On Sat, Mar 26, 2016 at 09:45:53PM +0800, Zhangjian (Bamvor) wrote:
> Hi, guys

Hi,
>
> Does any body test the bigendian? We found lots of failures in be in
> our arm64 hardware. E.g. the signal issue.

I'm afraid, nobody yet. Thank you for work on it.

>
> IIUC, the signal of struct in ILP32 is align with the aarch32. If so,
> we need to revert the following patch wrote by Andrew in 2014 which
> align the kernel_sigaction of ilp32 to lp64:
> Revert "[AARCH64] Add kernel_sigaction.h for AARCH64 ILP32"
>
> And we also need to handle the uc_stack properly in kernel. After
> apply these two patches, we could fix lots of failure in bigendian.
>
> Regards
>
> Bamvor

Andrew sent me similar patches yesterday. See
https://github.com/apinski-cavium/linux (branch pin1)
https://github.com/norov/glibc.git (branch new-api)

There are also some other fixes, so my fail list is like this:
[Float tests skipped but fail too]
pipeio_1 FAIL 5
pipeio_6 FAIL 1
abort01 FAIL 2
clone02 FAIL 4
execve03 FAIL 4
fcntl17 FAIL 4
fcntl21 FAIL 4
kill11 FAIL 2
mmap16 FAIL 6
open12 FAIL 2
rename11 FAIL 2
rmdir02 FAIL 2
umount2_01 FAIL 2
umount2_02 FAIL 2
umount2_03 FAIL 2
utime06 FAIL 2
mtest06 FAIL 11

Some tests fail both on lp64 and ilp32, so it seems, it's not a
problem of ilp32 itself.

Some tests fail only when run in scenario, so I cannot reproduce it.
I suspect it's because core dump fails.

Also, Andrew told, there's an issue in unwind, and it is caused by GCC
bug, not kernel or glibc. To reproduce, run unwind from signal
handler (trigo does it). I think, at least float tests fail due to it.
Andrew is in vacation now, so he may answer longer than usual.

See Andrew's kernel signal patch:

>From b95c5250c5c869d8852886ed49e34fa11c29663e Mon Sep 17 00:00:00 2001
From: Andrew Pinski <apinski@cavium.com>
Date: Thu, 24 Mar 2016 23:10:08 -0700
Subject: [PATCH] Fix signals

Signed-off-by: Andrew Pinski <apinski@cavium.com>
Signed-off-by: Yury Norov <ynorov@caviumnetworks.com>
---
arch/arm64/include/asm/signal_common.h | 10 +----
arch/arm64/kernel/signal.c | 59 +++++++++++++++++--------
arch/arm64/kernel/signal_ilp32.c | 78 +++++++++++++++++++++++++++++++---
3 files changed, 115 insertions(+), 32 deletions(-)

diff --git a/arch/arm64/include/asm/signal_common.h b/arch/arm64/include/asm/signal_common.h
index faa82c0..402e0c4 100644
--- a/arch/arm64/include/asm/signal_common.h
+++ b/arch/arm64/include/asm/signal_common.h
@@ -23,16 +23,10 @@
#include <asm/ucontext.h>
#include <asm/fpsimd.h>

-struct sigframe {
- struct ucontext uc;
- u64 fp;
- u64 lr;
-};
-
int preserve_fpsimd_context(struct fpsimd_context __user *ctx);
int restore_fpsimd_context(struct fpsimd_context __user *ctx);
-int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set);
-int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf);
+int setup_sigcontex(struct sigcontext __user *uc_mcontext, struct pt_regs *regs);
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sf);
void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
void __user *frame, off_t sigframe_off, int usig);

diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 0648aa5..5f2faf2 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -37,6 +37,12 @@
#include <asm/signal_common.h>
#include <asm/signal_ilp32.h>

+struct sigframe {
+ struct ucontext uc;
+ u64 fp;
+ u64 lr;
+};
+
/*
* Do a signal return; undo the signal stack. These are aligned to 128-bit.
*/
@@ -92,23 +98,31 @@ int restore_fpsimd_context(struct fpsimd_context __user *ctx)
return err ? -EFAULT : 0;
}

-int restore_sigframe(struct pt_regs *regs,
+static int restore_sigframe(struct pt_regs *regs,
struct sigframe __user *sf)
{
sigset_t set;
- int i, err;
- void *aux = sf->uc.uc_mcontext.__reserved;
-
+ int err;
err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
if (err == 0)
set_current_blocked(&set);

+ err |= restore_sigcontext(regs, &sf->uc.uc_mcontext);
+ return err;
+}
+
+
+int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *uc_mcontext)
+{
+ int i, err = 0;
+ void *aux = uc_mcontext->__reserved;
+
for (i = 0; i < 31; i++)
- __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+ __get_user_error(regs->regs[i], &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);
+ __get_user_error(regs->sp, &uc_mcontext->sp, err);
+ __get_user_error(regs->pc, &uc_mcontext->pc, err);
+ __get_user_error(regs->pstate, &uc_mcontext->pstate, err);

/*
* Avoid sys_rt_sigreturn() restarting.
@@ -162,27 +176,36 @@ badframe:
return 0;
}

-int setup_sigframe(struct sigframe __user *sf,
+static int setup_sigframe(struct sigframe __user *sf,
struct pt_regs *regs, sigset_t *set)
{
- int i, err = 0;
- void *aux = sf->uc.uc_mcontext.__reserved;
- struct _aarch64_ctx *end;
+ int err = 0;

/* 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);
+ err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+ err |= setup_sigcontex (&sf->uc.uc_mcontext, regs);
+
+ return err;
+}
+
+int setup_sigcontex(struct sigcontext __user *uc_mcontext,
+ struct pt_regs *regs)
+{
+ void *aux = uc_mcontext->__reserved;
+ struct _aarch64_ctx *end;
+ int i, err = 0;

for (i = 0; i < 31; i++)
- __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+ __put_user_error(regs->regs[i], &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);
+ __put_user_error(regs->sp, &uc_mcontext->sp, err);
+ __put_user_error(regs->pc, &uc_mcontext->pc, err);
+ __put_user_error(regs->pstate, &uc_mcontext->pstate, err);

- err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+ __put_user_error(current->thread.fault_address, &uc_mcontext->fault_address, err);

if (err == 0) {
struct fpsimd_context *fpsimd_ctx =
diff --git a/arch/arm64/kernel/signal_ilp32.c b/arch/arm64/kernel/signal_ilp32.c
index 1bb0ea8..d399ed0 100644
--- a/arch/arm64/kernel/signal_ilp32.c
+++ b/arch/arm64/kernel/signal_ilp32.c
@@ -32,11 +32,76 @@
#include <asm/unistd.h>
#include <asm/ucontext.h>

+
+struct ilp32_ucontext {
+ u32 uc_flags;
+ u32 uc_link;
+ compat_stack_t uc_stack;
+ compat_sigset_t uc_sigmask;
+ /* glibc uses a 1024-bit sigset_t */
+ __u8 __unused[1024 / 8 - sizeof(compat_sigset_t)];
+ /* last for future expansion */
+ struct sigcontext uc_mcontext;
+};
+
+struct ilp32_sigframe {
+ struct ilp32_ucontext uc;
+ u64 fp;
+ u64 lr;
+};
+
struct ilp32_rt_sigframe {
struct compat_siginfo info;
- struct sigframe sig;
+ struct ilp32_sigframe sig;
};

+static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
+{
+ compat_sigset_t cset;
+
+ cset.sig[0] = set->sig[0] & 0xffffffffull;
+ cset.sig[1] = set->sig[0] >> 32;
+
+ return copy_to_user(uset, &cset, sizeof(*uset));
+}
+
+static inline int get_sigset_t(sigset_t *set,
+ const compat_sigset_t __user *uset)
+{
+ compat_sigset_t s32;
+
+ if (copy_from_user(&s32, uset, sizeof(*uset)))
+ return -EFAULT;
+
+ set->sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+ return 0;
+}
+
+static int restore_ilp32_sigframe(struct pt_regs *regs,
+ struct ilp32_sigframe __user *sf)
+{
+ sigset_t set;
+ int err;
+ err = get_sigset_t(&set, &sf->uc.uc_sigmask);
+ if (err == 0)
+ set_current_blocked(&set);
+ err |= restore_sigcontext(regs, &sf->uc.uc_mcontext);
+ return err;
+}
+
+static int setup_ilp32_sigframe(struct ilp32_sigframe __user *sf,
+ struct pt_regs *regs, sigset_t *set)
+{
+ int err = 0;
+ /* 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);
+
+ err |= put_sigset_t(&sf->uc.uc_sigmask, set);
+ err |= setup_sigcontex (&sf->uc.uc_mcontext, regs);
+ return err;
+}
+
asmlinkage long ilp32_sys_rt_sigreturn(struct pt_regs *regs)
{
struct ilp32_rt_sigframe __user *frame;
@@ -57,10 +122,10 @@ asmlinkage long ilp32_sys_rt_sigreturn(struct pt_regs *regs)
if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;

- if (restore_sigframe(regs, &frame->sig))
+ if (restore_ilp32_sigframe(regs, &frame->sig))
goto badframe;

- if (restore_altstack(&frame->sig.uc.uc_stack))
+ if (compat_restore_altstack(&frame->sig.uc.uc_stack))
goto badframe;

return regs->regs[0];
@@ -107,13 +172,14 @@ int ilp32_setup_rt_frame(int usig, struct ksignal *ksig,

if (!frame)
return 1;
+
err |= copy_siginfo_to_user32(&frame->info, &ksig->info);

__put_user_error(0, &frame->sig.uc.uc_flags, err);
- __put_user_error(NULL, &frame->sig.uc.uc_link, err);
+ __put_user_error(0, &frame->sig.uc.uc_link, err);

- err |= __save_altstack(&frame->sig.uc.uc_stack, regs->sp);
- err |= setup_sigframe(&frame->sig, regs, set);
+ err |= __compat_save_altstack(&frame->sig.uc.uc_stack, regs->sp);
+ err |= setup_ilp32_sigframe(&frame->sig, regs, set);
if (err == 0) {
setup_return(regs, &ksig->ka, frame,
offsetof(struct ilp32_rt_sigframe, sig), usig);
--
2.5.0