* [PATCH 2/3] linux-user/s390x: Clean up signal.c
2021-04-28 3:32 [PATCH 0/3] linux-user/s390x: some signal fixes Richard Henderson
2021-04-28 3:32 ` [PATCH 1/3] linux-user/s390x: Fix sigframe types Richard Henderson
@ 2021-04-28 3:32 ` Richard Henderson
2021-04-28 13:56 ` David Hildenbrand
2021-04-28 3:32 ` [PATCH 3/3] linux-user/s390x: Handle vector regs in signal stack Richard Henderson
2 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2021-04-28 3:32 UTC (permalink / raw)
To: qemu-devel; +Cc: thuth, qemu-s390x, cohuck, laurent, david
The "save" routines from the kernel, which are currently
commented out, are unnecessary in qemu. We can copy from
env where the kernel needs special instructions.
Drop the return value from restore_sigregs, as it cannot fail.
Use __get_user return as input to trace, so that we properly
bswap the value for the host.
Reorder the function bodies to correspond to the kernel source.
Fix the use of host addresses where guest addresses are needed.
Drop the use of PSW_ADDR_AMODE, since we only support 64-bit.
Set psw.mask properly for the signal handler.
Use tswap_sigset in setup_rt_frame.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/s390x/signal.c | 184 ++++++++++++++++++--------------------
1 file changed, 89 insertions(+), 95 deletions(-)
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index e5bc4f0358..fb7065f243 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -32,7 +32,6 @@
#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
-#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
typedef struct {
@@ -106,23 +105,25 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
{
int i;
- //save_access_regs(current->thread.acrs); FIXME
- /* Copy a 'clean' PSW mask to the user to avoid leaking
- information about whether PER is currently on. */
+ /*
+ * Copy a 'clean' PSW mask to the user to avoid leaking
+ * information about whether PER is currently on.
+ */
__put_user(env->psw.mask, &sregs->regs.psw.mask);
__put_user(env->psw.addr, &sregs->regs.psw.addr);
+
for (i = 0; i < 16; i++) {
__put_user(env->regs[i], &sregs->regs.gprs[i]);
}
for (i = 0; i < 16; i++) {
__put_user(env->aregs[i], &sregs->regs.acrs[i]);
}
+
/*
* We have to store the fp registers to current->thread.fp_regs
* to merge them with the emulated registers.
*/
- //save_fp_regs(¤t->thread.fp_regs); FIXME
for (i = 0; i < 16; i++) {
__put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]);
}
@@ -137,120 +138,124 @@ void setup_frame(int sig, struct target_sigaction *ka,
frame_addr = get_sigframe(ka, env, sizeof(*frame));
trace_user_setup_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- __put_user(set->sig[0], &frame->sc.oldmask[0]);
-
- save_sigregs(env, &frame->sregs);
-
- __put_user((abi_ulong)(unsigned long)&frame->sregs,
- (abi_ulong *)&frame->sc.sregs);
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[14] = (unsigned long)
- ka->sa_restorer | PSW_ADDR_AMODE;
- } else {
- env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
- | PSW_ADDR_AMODE;
- __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
- (uint16_t *)(frame->retcode));
+ force_sigsegv(sig);
+ return;
}
/* Set up backchain. */
__put_user(env->regs[15], (abi_ulong *) frame);
+ /* Create struct sigcontext on the signal stack. */
+ for (int i = 0; i < ARRAY_SIZE(frame->sc.oldmask); ++i) {
+ __put_user(set->sig[i], &frame->sc.oldmask[i]);
+ }
+
+ save_sigregs(env, &frame->sregs);
+ __put_user(frame_addr + offsetof(sigframe, sregs), &frame->sc.sregs);
+
+ /* Place signal number on stack to allow backtrace from handler. */
+ __put_user(sig, &frame->signo);
+
+ /*
+ * Set up to return from userspace.
+ * If provided, use a stub already in userspace.
+ */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ env->regs[14] = ka->sa_restorer;
+ } else {
+ env->regs[14] = frame_addr + offsetof(sigframe, retcode);
+ __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
+ (uint16_t *)(frame->retcode));
+ }
+
/* Set up registers for signal handler */
env->regs[15] = frame_addr;
- env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+ /* Force default amode and default user address space control. */
+ env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY
+ | (env->psw.mask & ~PSW_MASK_ASC);
+ env->psw.addr = ka->_sa_handler;
env->regs[2] = sig; //map_signal(sig);
env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
- /* We forgot to include these in the sigcontext.
- To avoid breaking binary compatibility, they are passed as args. */
- env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
- env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
+ /*
+ * We forgot to include these in the sigcontext.
+ * To avoid breaking binary compatibility, they are passed as args.
+ */
+ env->regs[4] = 0; /* FIXME: regs->int_code & 127 */
+ env->regs[5] = 0; /* FIXME: regs->int_parm_long */
+ env->regs[6] = 0; /* FIXME: current->thread.last_break */
- /* Place signal number on stack to allow backtrace from handler. */
- __put_user(env->regs[2], &frame->signo);
unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUS390XState *env)
{
- int i;
rt_sigframe *frame;
abi_ulong frame_addr;
frame_addr = get_sigframe(ka, env, sizeof *frame);
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- tswap_siginfo(&frame->info, info);
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
- target_save_altstack(&frame->uc.tuc_stack, env);
- save_sigregs(env, &frame->uc.tuc_mcontext);
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user((abi_ulong)set->sig[i],
- (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[14] = ka->sa_restorer | PSW_ADDR_AMODE;
- } else {
- env->regs[14] = (frame_addr + offsetof(typeof(*frame), retcode))
- | PSW_ADDR_AMODE;
- __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
- (uint16_t *)(frame->retcode));
+ force_sigsegv(sig);
+ return;
}
/* Set up backchain. */
__put_user(env->regs[15], (abi_ulong *) frame);
+ /*
+ * Set up to return from userspace.
+ * If provided, use a stub already in userspace.
+ */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ env->regs[14] = ka->sa_restorer;
+ } else {
+ env->regs[14] = frame_addr + offsetof(typeof(*frame), retcode);
+ __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
+ (uint16_t *)(frame->retcode));
+ }
+
+ /* Create siginfo on the signal stack. */
+ tswap_siginfo(&frame->info, info);
+
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ save_sigregs(env, &frame->uc.tuc_mcontext);
+ tswap_sigset(&frame->uc.tuc_sigmask, set);
+
/* Set up registers for signal handler */
env->regs[15] = frame_addr;
- env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
- env->regs[2] = sig; //map_signal(sig);
+ /* Force default amode and default user address space control. */
+ env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY
+ | (env->psw.mask & ~PSW_MASK_ASC);
+ env->psw.addr = ka->_sa_handler;
+
+ env->regs[2] = sig;
env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
+ env->regs[5] = 0; /* FIXME: current->thread.last_break */
}
-static int
-restore_sigregs(CPUS390XState *env, target_sigregs *sc)
+static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
{
- int err = 0;
+ target_ulong prev_addr;
int i;
for (i = 0; i < 16; i++) {
__get_user(env->regs[i], &sc->regs.gprs[i]);
}
+ prev_addr = env->psw.addr;
__get_user(env->psw.mask, &sc->regs.psw.mask);
- trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
- (unsigned long long)env->psw.addr);
__get_user(env->psw.addr, &sc->regs.psw.addr);
- /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
+ trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr);
for (i = 0; i < 16; i++) {
__get_user(env->aregs[i], &sc->regs.acrs[i]);
@@ -258,8 +263,6 @@ restore_sigregs(CPUS390XState *env, target_sigregs *sc)
for (i = 0; i < 16; i++) {
__get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
}
-
- return err;
}
long do_sigreturn(CPUS390XState *env)
@@ -271,23 +274,21 @@ long do_sigreturn(CPUS390XState *env)
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
- __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
+ QEMU_BUILD_BUG_ON(sizeof(target_set) != sizeof(frame->sc.oldmask));
+ for (int i = 0; i < ARRAY_SIZE(frame->sc.oldmask); ++i) {
+ __get_user(target_set.sig[i], &frame->sc.oldmask[i]);
+ }
target_to_host_sigset_internal(&set, &target_set);
set_sigmask(&set); /* ~_BLOCKABLE? */
- if (restore_sigregs(env, &frame->sregs)) {
- goto badframe;
- }
+ restore_sigregs(env, &frame->sregs);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUS390XState *env)
@@ -298,23 +299,16 @@ long do_rt_sigreturn(CPUS390XState *env)
trace_user_do_rt_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
set_sigmask(&set); /* ~_BLOCKABLE? */
- if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
- goto badframe;
- }
-
target_restore_altstack(&frame->uc.tuc_stack, env);
+ restore_sigregs(env, &frame->uc.tuc_mcontext);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/3] linux-user/s390x: Handle vector regs in signal stack
2021-04-28 3:32 [PATCH 0/3] linux-user/s390x: some signal fixes Richard Henderson
2021-04-28 3:32 ` [PATCH 1/3] linux-user/s390x: Fix sigframe types Richard Henderson
2021-04-28 3:32 ` [PATCH 2/3] linux-user/s390x: Clean up signal.c Richard Henderson
@ 2021-04-28 3:32 ` Richard Henderson
2 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2021-04-28 3:32 UTC (permalink / raw)
To: qemu-devel; +Cc: thuth, qemu-s390x, cohuck, laurent, david
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/s390x/signal.c | 62 +++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index fb7065f243..57752a2a96 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -51,6 +51,12 @@ typedef struct {
target_s390_fp_regs fpregs;
} target_sigregs;
+typedef struct {
+ uint64_t vxrs_low[16];
+ uint64_t vxrs_high[16][2];
+ uint8_t reserved[128];
+} target_sigregs_ext;
+
typedef struct {
abi_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
abi_ulong sregs;
@@ -61,15 +67,20 @@ typedef struct {
target_sigcontext sc;
target_sigregs sregs;
int signo;
+ target_sigregs_ext sregs_ext;
uint8_t retcode[S390_SYSCALL_SIZE];
} sigframe;
+#define TARGET_UC_VXRS 2
+
struct target_ucontext {
abi_ulong tuc_flags;
abi_ulong tuc_link;
target_stack_t tuc_stack;
target_sigregs tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
+ target_sigset_t tuc_sigmask;
+ uint8_t reserved[128 - sizeof(target_sigset_t)];
+ target_sigregs_ext tuc_mcontext_ext;
};
typedef struct {
@@ -129,6 +140,24 @@ static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
}
}
+static void save_sigregs_ext(CPUS390XState *env, target_sigregs_ext *ext)
+{
+ int i;
+
+ /*
+ * if (MACHINE_HAS_VX) ...
+ * That said, we always allocate the stack storage and the
+ * space is always available in env.
+ */
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->vregs[i][1], &ext->vxrs_low[i]);
+ }
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->vregs[i + 16][0], &ext->vxrs_high[i][0]);
+ __put_user(env->vregs[i + 16][1], &ext->vxrs_high[i][1]);
+ }
+}
+
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUS390XState *env)
{
@@ -156,6 +185,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
/* Place signal number on stack to allow backtrace from handler. */
__put_user(sig, &frame->signo);
+ /* Create sigregs_ext on the signal stack. */
+ save_sigregs_ext(env, &frame->sregs_ext);
+
/*
* Set up to return from userspace.
* If provided, use a stub already in userspace.
@@ -196,6 +228,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
{
rt_sigframe *frame;
abi_ulong frame_addr;
+ abi_ulong uc_flags;
frame_addr = get_sigframe(ka, env, sizeof *frame);
trace_user_setup_rt_frame(env, frame_addr);
@@ -223,10 +256,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
tswap_siginfo(&frame->info, info);
/* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
+ uc_flags = 0;
+ if (s390_has_feat(S390_FEAT_VECTOR)) {
+ uc_flags |= TARGET_UC_VXRS;
+ }
+ __put_user(uc_flags, &frame->uc.tuc_flags);
__put_user(0, &frame->uc.tuc_link);
target_save_altstack(&frame->uc.tuc_stack, env);
save_sigregs(env, &frame->uc.tuc_mcontext);
+ save_sigregs_ext(env, &frame->uc.tuc_mcontext_ext);
tswap_sigset(&frame->uc.tuc_sigmask, set);
/* Set up registers for signal handler */
@@ -265,6 +303,24 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
}
}
+static void restore_sigregs_ext(CPUS390XState *env, target_sigregs_ext *ext)
+{
+ int i;
+
+ /*
+ * if (MACHINE_HAS_VX) ...
+ * That said, we always allocate the stack storage and the
+ * space is always available in env.
+ */
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->vregs[i][1], &ext->vxrs_low[i]);
+ }
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->vregs[i + 16][0], &ext->vxrs_high[i][0]);
+ __get_user(env->vregs[i + 16][1], &ext->vxrs_high[i][1]);
+ }
+}
+
long do_sigreturn(CPUS390XState *env)
{
sigframe *frame;
@@ -286,6 +342,7 @@ long do_sigreturn(CPUS390XState *env)
set_sigmask(&set); /* ~_BLOCKABLE? */
restore_sigregs(env, &frame->sregs);
+ restore_sigregs_ext(env, &frame->sregs_ext);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
@@ -308,6 +365,7 @@ long do_rt_sigreturn(CPUS390XState *env)
target_restore_altstack(&frame->uc.tuc_stack, env);
restore_sigregs(env, &frame->uc.tuc_mcontext);
+ restore_sigregs_ext(env, &frame->uc.tuc_mcontext_ext);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
--
2.25.1
^ permalink raw reply related [flat|nested] 6+ messages in thread