* [PATCH 0/8] linux-user/sparc64: Implement signals
@ 2021-04-25 15:57 Richard Henderson
2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
` (7 more replies)
0 siblings, 8 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
We were re-using sparc32 signal handling for sparc64.
In the process, clean up the altstack handling in do_*_sigreturn.
r~
Richard Henderson (8):
linux-user: Split out target_restore_altstack
linux-user: Use target_restore_altstack in all sigreturn
linux-user: Pass CPUArchState to do_sigaltstack
linux-user: Pass CPUArchState to target_restore_altstack
linux-user/sparc64: Move sparc64 code out of sparc32 signal.c
linux-user/sparc: Clean up init_thread
linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate
linux-user/sparc64: Implement signals
linux-user/qemu.h | 3 +-
linux-user/signal-common.h | 1 +
linux-user/sparc/target_cpu.h | 9 +-
linux-user/sparc/target_signal.h | 2 +
linux-user/sparc64/target_syscall.h | 14 +-
linux-user/aarch64/signal.c | 6 +-
linux-user/alpha/signal.c | 6 +-
linux-user/arm/signal.c | 9 +-
linux-user/elfload.c | 33 +-
linux-user/hexagon/signal.c | 6 +-
linux-user/hppa/signal.c | 8 +-
linux-user/i386/signal.c | 5 +-
linux-user/m68k/signal.c | 5 +-
linux-user/microblaze/signal.c | 6 +-
linux-user/mips/signal.c | 6 +-
linux-user/nios2/signal.c | 8 +-
linux-user/openrisc/signal.c | 5 +-
linux-user/ppc/signal.c | 4 +-
linux-user/riscv/signal.c | 6 +-
linux-user/s390x/signal.c | 6 +-
linux-user/sh4/signal.c | 7 +-
linux-user/signal.c | 120 ++++---
linux-user/sparc/signal.c | 280 ---------------
linux-user/sparc64/signal.c | 523 +++++++++++++++++++++++++++-
linux-user/syscall.c | 3 +-
linux-user/xtensa/signal.c | 6 +-
26 files changed, 633 insertions(+), 454 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/8] linux-user: Split out target_restore_altstack
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 15:57 ` [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn Richard Henderson
` (6 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
Create a function to match target_save_altstack.
Fix some style and unlock issues in do_sigaltstack.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/signal-common.h | 1 +
linux-user/signal.c | 115 +++++++++++++++++++++----------------
2 files changed, 66 insertions(+), 50 deletions(-)
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 1df1068552..34b963af9a 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -24,6 +24,7 @@ int on_sig_stack(unsigned long sp);
int sas_ss_flags(unsigned long sp);
abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
void target_save_altstack(target_stack_t *uss, CPUArchState *env);
+abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp);
static inline void target_sigemptyset(target_sigset_t *set)
{
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 44a5012930..306f3edec5 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -297,6 +297,50 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env)
__put_user(ts->sigaltstack_used.ss_size, &uss->ss_size);
}
+abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ size_t minstacksize = TARGET_MINSIGSTKSZ;
+ target_stack_t ss;
+
+#if defined(TARGET_PPC64)
+ /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
+ struct image_info *image = ts->info;
+ if (get_ppc64_abi(image) > 1) {
+ minstacksize = 4096;
+ }
+#endif
+
+ __get_user(ss.ss_sp, &uss->ss_sp);
+ __get_user(ss.ss_size, &uss->ss_size);
+ __get_user(ss.ss_flags, &uss->ss_flags);
+
+ if (on_sig_stack(sp)) {
+ return -TARGET_EPERM;
+ }
+
+ switch (ss.ss_flags) {
+ default:
+ return -TARGET_EINVAL;
+
+ case TARGET_SS_DISABLE:
+ ss.ss_size = 0;
+ ss.ss_sp = 0;
+ break;
+
+ case TARGET_SS_ONSTACK:
+ case 0:
+ if (ss.ss_size < minstacksize) {
+ return -TARGET_ENOMEM;
+ }
+ break;
+ }
+
+ ts->sigaltstack_used.ss_sp = ss.ss_sp;
+ ts->sigaltstack_used.ss_size = ss.ss_size;
+ return 0;
+}
+
/* siginfo conversion */
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
@@ -758,73 +802,44 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
/* compare linux/kernel/signal.c:do_sigaltstack() */
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
{
- int ret;
- struct target_sigaltstack oss;
- TaskState *ts = (TaskState *)thread_cpu->opaque;
+ target_stack_t oss, *uoss = NULL;
+ abi_long ret = -TARGET_EFAULT;
- /* XXX: test errors */
- if(uoss_addr)
- {
+ if (uoss_addr) {
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+
+ /* Verify writability now, but do not alter user memory yet. */
+ if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) {
+ goto out;
+ }
__put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp);
__put_user(ts->sigaltstack_used.ss_size, &oss.ss_size);
__put_user(sas_ss_flags(sp), &oss.ss_flags);
}
- if(uss_addr)
- {
- struct target_sigaltstack *uss;
- struct target_sigaltstack ss;
- size_t minstacksize = TARGET_MINSIGSTKSZ;
+ if (uss_addr) {
+ target_stack_t *uss;
-#if defined(TARGET_PPC64)
- /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
- struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
- if (get_ppc64_abi(image) > 1) {
- minstacksize = 4096;
- }
-#endif
-
- ret = -TARGET_EFAULT;
if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
goto out;
}
- __get_user(ss.ss_sp, &uss->ss_sp);
- __get_user(ss.ss_size, &uss->ss_size);
- __get_user(ss.ss_flags, &uss->ss_flags);
- unlock_user_struct(uss, uss_addr, 0);
-
- ret = -TARGET_EPERM;
- if (on_sig_stack(sp))
+ ret = target_restore_altstack(uss, sp);
+ if (ret) {
goto out;
-
- ret = -TARGET_EINVAL;
- if (ss.ss_flags != TARGET_SS_DISABLE
- && ss.ss_flags != TARGET_SS_ONSTACK
- && ss.ss_flags != 0)
- goto out;
-
- if (ss.ss_flags == TARGET_SS_DISABLE) {
- ss.ss_size = 0;
- ss.ss_sp = 0;
- } else {
- ret = -TARGET_ENOMEM;
- if (ss.ss_size < minstacksize) {
- goto out;
- }
}
-
- ts->sigaltstack_used.ss_sp = ss.ss_sp;
- ts->sigaltstack_used.ss_size = ss.ss_size;
}
if (uoss_addr) {
- ret = -TARGET_EFAULT;
- if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
- goto out;
+ memcpy(uoss, &oss, sizeof(oss));
+ unlock_user_struct(uoss, uoss_addr, 1);
+ uoss = NULL;
}
-
ret = 0;
-out:
+
+ out:
+ if (uoss) {
+ unlock_user_struct(uoss, uoss_addr, 0);
+ }
return ret;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 15:57 ` [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack Richard Henderson
` (5 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
Note that target_restore_altstack uses the host memory
pointer that we have already verified, so TARGET_EFAULT
is not a possible return value.
Note that using -EFAULT was a bug.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/aarch64/signal.c | 6 +-----
linux-user/alpha/signal.c | 6 +-----
linux-user/arm/signal.c | 9 ++-------
linux-user/hexagon/signal.c | 6 +-----
linux-user/hppa/signal.c | 8 +-------
linux-user/i386/signal.c | 5 +----
linux-user/m68k/signal.c | 5 +----
linux-user/microblaze/signal.c | 6 +-----
linux-user/mips/signal.c | 6 +-----
linux-user/nios2/signal.c | 8 +-------
linux-user/openrisc/signal.c | 5 +----
linux-user/ppc/signal.c | 4 +---
linux-user/riscv/signal.c | 6 +-----
linux-user/s390x/signal.c | 6 ++----
linux-user/sh4/signal.c | 7 +------
linux-user/xtensa/signal.c | 6 +-----
16 files changed, 18 insertions(+), 81 deletions(-)
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index b591790c22..2a1b7dbcdc 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -561,11 +561,7 @@ long do_rt_sigreturn(CPUARMState *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c
index 3aa4b339a4..011da0a53b 100644
--- a/linux-user/alpha/signal.c
+++ b/linux-user/alpha/signal.c
@@ -257,11 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->ir[IR_SP]) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env->ir[IR_SP]);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
index f21d1535e4..b7a772302f 100644
--- a/linux-user/arm/signal.c
+++ b/linux-user/arm/signal.c
@@ -685,11 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env,
}
}
- if (do_sigaltstack(context_addr
- + offsetof(struct target_ucontext_v2, tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- return 1;
- }
+ target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
#if 0
/* Send SIGTRAP if we're single-stepping */
@@ -773,8 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
#if 0
/* Send SIGTRAP if we're single-stepping */
diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c
index fde8dc93b7..3854eb4709 100644
--- a/linux-user/hexagon/signal.c
+++ b/linux-user/hexagon/signal.c
@@ -260,11 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
}
restore_ucontext(env, &frame->uc);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index d1a58feeb3..578874cf27 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -187,13 +187,7 @@ long do_rt_sigreturn(CPUArchState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- unlock_user_struct(frame, frame_addr, 0);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->gr[30]) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env->gr[30]);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 9320e1d472..3a0a1546a6 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -581,10 +581,7 @@ long do_rt_sigreturn(CPUX86State *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
- get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c
index 49ff87c77b..004b59fb61 100644
--- a/linux-user/m68k/signal.c
+++ b/linux-user/m68k/signal.c
@@ -400,10 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env)
if (target_rt_restore_ucontext(env, &frame->uc))
goto badframe;
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
index cf0707b556..f59a1faf47 100644
--- a/linux-user/microblaze/signal.c
+++ b/linux-user/microblaze/signal.c
@@ -209,11 +209,7 @@ long do_rt_sigreturn(CPUMBState *env)
restore_sigcontext(&frame->uc.tuc_mcontext, env);
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 455a8a229a..456fa64f41 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -368,11 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
set_sigmask(&blocked);
restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
+ target_restore_altstack(&frame->rs_uc.tuc_stack, get_sp_from_cpustate(env));
env->active_tc.PC = env->CP0_EPC;
mips_set_hflags_isa_mode_from_pc(env);
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
index 7d535065ed..751ea88811 100644
--- a/linux-user/nios2/signal.c
+++ b/linux-user/nios2/signal.c
@@ -82,9 +82,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
int *pr2)
{
int temp;
- abi_ulong off, frame_addr = env->regs[R_SP];
unsigned long *gregs = uc->tuc_mcontext.gregs;
- int err;
/* Always make any pending restarted system calls return -EINTR */
/* current->restart_block.fn = do_no_restart_syscall; */
@@ -130,11 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
__get_user(env->regs[R_RA], &gregs[23]);
__get_user(env->regs[R_SP], &gregs[28]);
- off = offsetof(struct target_rt_sigframe, uc.tuc_stack);
- err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env));
- if (err == -EFAULT) {
- return 1;
- }
+ target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
*pr2 = env->regs[2];
return 0;
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index 232ad82b98..86f94d7f76 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -158,10 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack),
- 0, frame_addr) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, frame_addr);
unlock_user_struct(frame, frame_addr, 0);
return cpu_get_gpr(env, 11);
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index b78613f7c8..79f265f82e 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -656,9 +656,7 @@ long do_rt_sigreturn(CPUPPCState *env)
if (do_setcontext(&rt_sf->uc, env, 1))
goto sigsegv;
- do_sigaltstack(rt_sf_addr
- + offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, env->gpr[1]);
+ target_restore_altstack(&rt_sf->uc.tuc_stack, env->gpr[1]);
unlock_user_struct(rt_sf, rt_sf_addr, 1);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index 67a95dbc7b..81d1129da3 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -192,11 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env)
}
restore_ucontext(env, &frame->uc);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index 7107c5fb53..73806f5472 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -307,10 +307,8 @@ long do_rt_sigreturn(CPUS390XState *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
- get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 29c1ee30e6..684f18da58 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -323,12 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
set_sigmask(&blocked);
restore_sigcontext(regs, &frame->uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(regs)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(regs));
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 590f0313ff..22ec6cdeb9 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -253,12 +253,8 @@ long do_rt_sigreturn(CPUXtensaState *env)
set_sigmask(&set);
restore_sigcontext(env, frame);
+ target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) {
- goto badframe;
- }
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
2021-04-25 15:57 ` [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
` (4 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
Now that we have exactly one call, it's easy to pass
in env instead of passing in the sp value.
Use target_save_altstack, which required env.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/qemu.h | 3 ++-
linux-user/signal.c | 11 ++++-------
linux-user/syscall.c | 3 +--
3 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 74e06e7121..3b0b6b75fe 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -432,7 +432,8 @@ int target_to_host_signal(int sig);
int host_to_target_signal(int sig);
long do_sigreturn(CPUArchState *env);
long do_rt_sigreturn(CPUArchState *env);
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
+ CPUArchState *env);
int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
abi_ulong unew_ctx, abi_long ctx_size);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 306f3edec5..83891f7c47 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -800,21 +800,18 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
/* do_sigaltstack() returns target values and errnos. */
/* compare linux/kernel/signal.c:do_sigaltstack() */
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
+ CPUArchState *env)
{
target_stack_t oss, *uoss = NULL;
abi_long ret = -TARGET_EFAULT;
if (uoss_addr) {
- TaskState *ts = (TaskState *)thread_cpu->opaque;
-
/* Verify writability now, but do not alter user memory yet. */
if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) {
goto out;
}
- __put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp);
- __put_user(ts->sigaltstack_used.ss_size, &oss.ss_size);
- __put_user(sas_ss_flags(sp), &oss.ss_flags);
+ target_save_altstack(&oss, env);
}
if (uss_addr) {
@@ -823,7 +820,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
goto out;
}
- ret = target_restore_altstack(uss, sp);
+ ret = target_restore_altstack(uss, get_sp_from_cpustate(env));
if (ret) {
goto out;
}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c7c3257f40..32a41c1387 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -11140,8 +11140,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return ret;
}
case TARGET_NR_sigaltstack:
- return do_sigaltstack(arg1, arg2,
- get_sp_from_cpustate((CPUArchState *)cpu_env));
+ return do_sigaltstack(arg1, arg2, cpu_env);
#ifdef CONFIG_SENDFILE
#ifdef TARGET_NR_sendfile
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
` (2 preceding siblings ...)
2021-04-25 15:57 ` [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 18:12 ` Warner Losh
2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
` (3 subsequent siblings)
7 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
In most cases we were already passing get_sp_from_cpustate
directly to the function. In other cases, we were passing
a local variable which already contained the same value.
In the rest of the cases, we were passing the stack pointer
out of env directly.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/signal-common.h | 2 +-
linux-user/aarch64/signal.c | 2 +-
linux-user/alpha/signal.c | 2 +-
linux-user/arm/signal.c | 4 ++--
linux-user/hexagon/signal.c | 2 +-
linux-user/hppa/signal.c | 2 +-
linux-user/i386/signal.c | 2 +-
linux-user/m68k/signal.c | 2 +-
linux-user/microblaze/signal.c | 2 +-
linux-user/mips/signal.c | 2 +-
linux-user/nios2/signal.c | 2 +-
linux-user/openrisc/signal.c | 2 +-
linux-user/ppc/signal.c | 2 +-
linux-user/riscv/signal.c | 2 +-
linux-user/s390x/signal.c | 2 +-
linux-user/sh4/signal.c | 2 +-
linux-user/signal.c | 6 +++---
linux-user/xtensa/signal.c | 2 +-
18 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 34b963af9a..ea86328b28 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -24,7 +24,7 @@ int on_sig_stack(unsigned long sp);
int sas_ss_flags(unsigned long sp);
abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
void target_save_altstack(target_stack_t *uss, CPUArchState *env);
-abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp);
+abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env);
static inline void target_sigemptyset(target_sigset_t *set)
{
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index 2a1b7dbcdc..662bcd1c4e 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -561,7 +561,7 @@ long do_rt_sigreturn(CPUARMState *env)
goto badframe;
}
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c
index 011da0a53b..1129ffeea1 100644
--- a/linux-user/alpha/signal.c
+++ b/linux-user/alpha/signal.c
@@ -257,7 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- target_restore_altstack(&frame->uc.tuc_stack, env->ir[IR_SP]);
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
index b7a772302f..32b68ee302 100644
--- a/linux-user/arm/signal.c
+++ b/linux-user/arm/signal.c
@@ -685,7 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env,
}
}
- target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&uc->tuc_stack, env);
#if 0
/* Send SIGTRAP if we're single-stepping */
@@ -769,7 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
goto badframe;
}
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
#if 0
/* Send SIGTRAP if we're single-stepping */
diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c
index 3854eb4709..85eab5e943 100644
--- a/linux-user/hexagon/signal.c
+++ b/linux-user/hexagon/signal.c
@@ -260,7 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
}
restore_ucontext(env, &frame->uc);
- target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.uc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index 578874cf27..0e266f472d 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -187,7 +187,7 @@ long do_rt_sigreturn(CPUArchState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- target_restore_altstack(&frame->uc.tuc_stack, env->gr[30]);
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 3a0a1546a6..8701774e37 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -581,7 +581,7 @@ long do_rt_sigreturn(CPUX86State *env)
goto badframe;
}
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c
index 004b59fb61..d06230655e 100644
--- a/linux-user/m68k/signal.c
+++ b/linux-user/m68k/signal.c
@@ -400,7 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env)
if (target_rt_restore_ucontext(env, &frame->uc))
goto badframe;
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
index f59a1faf47..4c483bd8c6 100644
--- a/linux-user/microblaze/signal.c
+++ b/linux-user/microblaze/signal.c
@@ -209,7 +209,7 @@ long do_rt_sigreturn(CPUMBState *env)
restore_sigcontext(&frame->uc.tuc_mcontext, env);
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 456fa64f41..e6be807a81 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -368,7 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
set_sigmask(&blocked);
restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
- target_restore_altstack(&frame->rs_uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->rs_uc.tuc_stack, env);
env->active_tc.PC = env->CP0_EPC;
mips_set_hflags_isa_mode_from_pc(env);
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
index 751ea88811..cc3872f11d 100644
--- a/linux-user/nios2/signal.c
+++ b/linux-user/nios2/signal.c
@@ -128,7 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
__get_user(env->regs[R_RA], &gregs[23]);
__get_user(env->regs[R_SP], &gregs[28]);
- target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&uc->tuc_stack, env);
*pr2 = env->regs[2];
return 0;
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index 86f94d7f76..5c5640a284 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -158,7 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- target_restore_altstack(&frame->uc.tuc_stack, frame_addr);
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return cpu_get_gpr(env, 11);
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index 79f265f82e..8e1e642807 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -656,7 +656,7 @@ long do_rt_sigreturn(CPUPPCState *env)
if (do_setcontext(&rt_sf->uc, env, 1))
goto sigsegv;
- target_restore_altstack(&rt_sf->uc.tuc_stack, env->gpr[1]);
+ target_restore_altstack(&rt_sf->uc.tuc_stack, env);
unlock_user_struct(rt_sf, rt_sf_addr, 1);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index 81d1129da3..9405c7fd9a 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -192,7 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env)
}
restore_ucontext(env, &frame->uc);
- target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.uc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index 73806f5472..b68b44ae7e 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -307,7 +307,7 @@ long do_rt_sigreturn(CPUS390XState *env)
goto badframe;
}
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 684f18da58..0451e65806 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -323,7 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
set_sigmask(&blocked);
restore_sigcontext(regs, &frame->uc.tuc_mcontext);
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(regs));
+ target_restore_altstack(&frame->uc.tuc_stack, regs);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 83891f7c47..9016896dcd 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -297,7 +297,7 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env)
__put_user(ts->sigaltstack_used.ss_size, &uss->ss_size);
}
-abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp)
+abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env)
{
TaskState *ts = (TaskState *)thread_cpu->opaque;
size_t minstacksize = TARGET_MINSIGSTKSZ;
@@ -315,7 +315,7 @@ abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp)
__get_user(ss.ss_size, &uss->ss_size);
__get_user(ss.ss_flags, &uss->ss_flags);
- if (on_sig_stack(sp)) {
+ if (on_sig_stack(get_sp_from_cpustate(env))) {
return -TARGET_EPERM;
}
@@ -820,7 +820,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
goto out;
}
- ret = target_restore_altstack(uss, get_sp_from_cpustate(env));
+ ret = target_restore_altstack(uss, env);
if (ret) {
goto out;
}
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 22ec6cdeb9..72771e1294 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -253,7 +253,7 @@ long do_rt_sigreturn(CPUXtensaState *env)
set_sigmask(&set);
restore_sigcontext(env, frame);
- target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env));
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
` (3 preceding siblings ...)
2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 18:10 ` Warner Losh
2021-04-25 15:57 ` [PATCH 6/8] linux-user/sparc: Clean up init_thread Richard Henderson
` (2 subsequent siblings)
7 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
The bulk of the code goes to sparc64/signal.c, with
TARGET_SPARC_BIAS going to target_cpu.h, as we will
shortly need this define beyond signal.c.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/sparc/target_cpu.h | 6 +
linux-user/sparc/signal.c | 280 ----------------------------------
linux-user/sparc64/signal.c | 278 +++++++++++++++++++++++++++++++++
3 files changed, 284 insertions(+), 280 deletions(-)
diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 1fa1011775..37f6a1d62b 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -20,6 +20,12 @@
#ifndef SPARC_TARGET_CPU_H
#define SPARC_TARGET_CPU_H
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+# define TARGET_STACK_BIAS 2047
+#else
+# define TARGET_STACK_BIAS 0
+#endif
+
static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
unsigned flags)
{
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index d27b7a3af7..756d983af2 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -322,283 +322,3 @@ long do_rt_sigreturn(CPUSPARCState *env)
qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
return -TARGET_ENOSYS;
}
-
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-#define SPARC_MC_TSTATE 0
-#define SPARC_MC_PC 1
-#define SPARC_MC_NPC 2
-#define SPARC_MC_Y 3
-#define SPARC_MC_G1 4
-#define SPARC_MC_G2 5
-#define SPARC_MC_G3 6
-#define SPARC_MC_G4 7
-#define SPARC_MC_G5 8
-#define SPARC_MC_G6 9
-#define SPARC_MC_G7 10
-#define SPARC_MC_O0 11
-#define SPARC_MC_O1 12
-#define SPARC_MC_O2 13
-#define SPARC_MC_O3 14
-#define SPARC_MC_O4 15
-#define SPARC_MC_O5 16
-#define SPARC_MC_O6 17
-#define SPARC_MC_O7 18
-#define SPARC_MC_NGREG 19
-
-typedef abi_ulong target_mc_greg_t;
-typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
-
-struct target_mc_fq {
- abi_ulong mcfq_addr;
- uint32_t mcfq_insn;
-};
-
-/*
- * Note the manual 16-alignment; the kernel gets this because it
- * includes a "long double qregs[16]" in the mcpu_fregs union,
- * which we can't do.
- */
-struct target_mc_fpu {
- union {
- uint32_t sregs[32];
- uint64_t dregs[32];
- //uint128_t qregs[16];
- } mcfpu_fregs;
- abi_ulong mcfpu_fsr;
- abi_ulong mcfpu_fprs;
- abi_ulong mcfpu_gsr;
- abi_ulong mcfpu_fq;
- unsigned char mcfpu_qcnt;
- unsigned char mcfpu_qentsz;
- unsigned char mcfpu_enab;
-} __attribute__((aligned(16)));
-typedef struct target_mc_fpu target_mc_fpu_t;
-
-typedef struct {
- target_mc_gregset_t mc_gregs;
- target_mc_greg_t mc_fp;
- target_mc_greg_t mc_i7;
- target_mc_fpu_t mc_fpregs;
-} target_mcontext_t;
-
-struct target_ucontext {
- abi_ulong tuc_link;
- abi_ulong tuc_flags;
- target_sigset_t tuc_sigmask;
- target_mcontext_t tuc_mcontext;
-};
-
-/* A V9 register window */
-struct target_reg_window {
- abi_ulong locals[8];
- abi_ulong ins[8];
-};
-
-#define TARGET_STACK_BIAS 2047
-
-/* {set, get}context() needed for 64-bit SparcLinux userland. */
-void sparc64_set_context(CPUSPARCState *env)
-{
- abi_ulong ucp_addr;
- struct target_ucontext *ucp;
- target_mc_gregset_t *grp;
- target_mc_fpu_t *fpup;
- abi_ulong pc, npc, tstate;
- unsigned int i;
- unsigned char fenab;
-
- ucp_addr = env->regwptr[WREG_O0];
- if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
- goto do_sigsegv;
- }
- grp = &ucp->tuc_mcontext.mc_gregs;
- __get_user(pc, &((*grp)[SPARC_MC_PC]));
- __get_user(npc, &((*grp)[SPARC_MC_NPC]));
- if ((pc | npc) & 3) {
- goto do_sigsegv;
- }
- if (env->regwptr[WREG_O1]) {
- target_sigset_t target_set;
- sigset_t set;
-
- if (TARGET_NSIG_WORDS == 1) {
- __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
- } else {
- abi_ulong *src, *dst;
- src = ucp->tuc_sigmask.sig;
- dst = target_set.sig;
- for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
- __get_user(*dst, src);
- }
- }
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
- }
- env->pc = pc;
- env->npc = npc;
- __get_user(env->y, &((*grp)[SPARC_MC_Y]));
- __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
- /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
- env->asi = (tstate >> 24) & 0xff;
- cpu_put_ccr(env, (tstate >> 32) & 0xff);
- __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
- __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
- __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
- __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
- __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
- __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
- /* Skip g7 as that's the thread register in userspace */
-
- /*
- * Note that unlike the kernel, we didn't need to mess with the
- * guest register window state to save it into a pt_regs to run
- * the kernel. So for us the guest's O regs are still in WREG_O*
- * (unlike the kernel which has put them in UREG_I* in a pt_regs)
- * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
- * need to be written back to userspace memory.
- */
- __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0]));
- __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1]));
- __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2]));
- __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3]));
- __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4]));
- __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5]));
- __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6]));
- __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7]));
-
- __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
- __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
-
- fpup = &ucp->tuc_mcontext.mc_fpregs;
-
- __get_user(fenab, &(fpup->mcfpu_enab));
- if (fenab) {
- abi_ulong fprs;
-
- /*
- * We use the FPRS from the guest only in deciding whether
- * to restore the upper, lower, or both banks of the FPU regs.
- * The kernel here writes the FPU register data into the
- * process's current_thread_info state and unconditionally
- * clears FPRS and TSTATE_PEF: this disables the FPU so that the
- * next FPU-disabled trap will copy the data out of
- * current_thread_info and into the real FPU registers.
- * QEMU doesn't need to handle lazy-FPU-state-restoring like that,
- * so we always load the data directly into the FPU registers
- * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled).
- * Note that because we (and the kernel) always write zeroes for
- * the fenab and fprs in sparc64_get_context() none of this code
- * will execute unless the guest manually constructed or changed
- * the context structure.
- */
- __get_user(fprs, &(fpup->mcfpu_fprs));
- if (fprs & FPRS_DL) {
- for (i = 0; i < 16; i++) {
- __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
- }
- }
- if (fprs & FPRS_DU) {
- for (i = 16; i < 32; i++) {
- __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
- }
- }
- __get_user(env->fsr, &(fpup->mcfpu_fsr));
- __get_user(env->gsr, &(fpup->mcfpu_gsr));
- }
- unlock_user_struct(ucp, ucp_addr, 0);
- return;
-do_sigsegv:
- unlock_user_struct(ucp, ucp_addr, 0);
- force_sig(TARGET_SIGSEGV);
-}
-
-void sparc64_get_context(CPUSPARCState *env)
-{
- abi_ulong ucp_addr;
- struct target_ucontext *ucp;
- target_mc_gregset_t *grp;
- target_mcontext_t *mcp;
- int err;
- unsigned int i;
- target_sigset_t target_set;
- sigset_t set;
-
- ucp_addr = env->regwptr[WREG_O0];
- if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
- goto do_sigsegv;
- }
-
- memset(ucp, 0, sizeof(*ucp));
-
- mcp = &ucp->tuc_mcontext;
- grp = &mcp->mc_gregs;
-
- /* Skip over the trap instruction, first. */
- env->pc = env->npc;
- env->npc += 4;
-
- /* If we're only reading the signal mask then do_sigprocmask()
- * is guaranteed not to fail, which is important because we don't
- * have any way to signal a failure or restart this operation since
- * this is not a normal syscall.
- */
- err = do_sigprocmask(0, NULL, &set);
- assert(err == 0);
- host_to_target_sigset_internal(&target_set, &set);
- if (TARGET_NSIG_WORDS == 1) {
- __put_user(target_set.sig[0],
- (abi_ulong *)&ucp->tuc_sigmask);
- } else {
- abi_ulong *src, *dst;
- src = target_set.sig;
- dst = ucp->tuc_sigmask.sig;
- for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
- __put_user(*src, dst);
- }
- }
-
- __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
- __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
- __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
- __put_user(env->y, &((*grp)[SPARC_MC_Y]));
- __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
- __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
- __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
- __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
- __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
- __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
- __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
-
- /*
- * Note that unlike the kernel, we didn't need to mess with the
- * guest register window state to save it into a pt_regs to run
- * the kernel. So for us the guest's O regs are still in WREG_O*
- * (unlike the kernel which has put them in UREG_I* in a pt_regs)
- * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
- * need to be fished out of userspace memory.
- */
- __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0]));
- __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1]));
- __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2]));
- __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3]));
- __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4]));
- __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5]));
- __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6]));
- __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7]));
-
- __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp));
- __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
-
- /*
- * We don't write out the FPU state. This matches the kernel's
- * implementation (which has the code for doing this but
- * hidden behind an "if (fenab)" where fenab is always 0).
- */
-
- unlock_user_struct(ucp, ucp_addr, 1);
- return;
-do_sigsegv:
- unlock_user_struct(ucp, ucp_addr, 1);
- force_sig(TARGET_SIGSEGV);
-}
-#endif
diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c
index 170ebac232..d27e049c2a 100644
--- a/linux-user/sparc64/signal.c
+++ b/linux-user/sparc64/signal.c
@@ -16,4 +16,282 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+
#include "../sparc/signal.c"
+
+#define SPARC_MC_TSTATE 0
+#define SPARC_MC_PC 1
+#define SPARC_MC_NPC 2
+#define SPARC_MC_Y 3
+#define SPARC_MC_G1 4
+#define SPARC_MC_G2 5
+#define SPARC_MC_G3 6
+#define SPARC_MC_G4 7
+#define SPARC_MC_G5 8
+#define SPARC_MC_G6 9
+#define SPARC_MC_G7 10
+#define SPARC_MC_O0 11
+#define SPARC_MC_O1 12
+#define SPARC_MC_O2 13
+#define SPARC_MC_O3 14
+#define SPARC_MC_O4 15
+#define SPARC_MC_O5 16
+#define SPARC_MC_O6 17
+#define SPARC_MC_O7 18
+#define SPARC_MC_NGREG 19
+
+typedef abi_ulong target_mc_greg_t;
+typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
+
+struct target_mc_fq {
+ abi_ulong mcfq_addr;
+ uint32_t mcfq_insn;
+};
+
+/*
+ * Note the manual 16-alignment; the kernel gets this because it
+ * includes a "long double qregs[16]" in the mcpu_fregs union,
+ * which we can't do.
+ */
+struct target_mc_fpu {
+ union {
+ uint32_t sregs[32];
+ uint64_t dregs[32];
+ } mcfpu_fregs;
+ abi_ulong mcfpu_fsr;
+ abi_ulong mcfpu_fprs;
+ abi_ulong mcfpu_gsr;
+ abi_ulong mcfpu_fq;
+ unsigned char mcfpu_qcnt;
+ unsigned char mcfpu_qentsz;
+ unsigned char mcfpu_enab;
+} __attribute__((aligned(16)));
+typedef struct target_mc_fpu target_mc_fpu_t;
+
+typedef struct {
+ target_mc_gregset_t mc_gregs;
+ target_mc_greg_t mc_fp;
+ target_mc_greg_t mc_i7;
+ target_mc_fpu_t mc_fpregs;
+} target_mcontext_t;
+
+struct target_ucontext {
+ abi_ulong tuc_link;
+ abi_ulong tuc_flags;
+ target_sigset_t tuc_sigmask;
+ target_mcontext_t tuc_mcontext;
+};
+
+/* A V9 register window */
+struct target_reg_window {
+ abi_ulong locals[8];
+ abi_ulong ins[8];
+};
+
+/* {set, get}context() needed for 64-bit SparcLinux userland. */
+void sparc64_set_context(CPUSPARCState *env)
+{
+ abi_ulong ucp_addr;
+ struct target_ucontext *ucp;
+ target_mc_gregset_t *grp;
+ target_mc_fpu_t *fpup;
+ abi_ulong pc, npc, tstate;
+ unsigned int i;
+ unsigned char fenab;
+
+ ucp_addr = env->regwptr[WREG_O0];
+ if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
+ goto do_sigsegv;
+ }
+ grp = &ucp->tuc_mcontext.mc_gregs;
+ __get_user(pc, &((*grp)[SPARC_MC_PC]));
+ __get_user(npc, &((*grp)[SPARC_MC_NPC]));
+ if ((pc | npc) & 3) {
+ goto do_sigsegv;
+ }
+ if (env->regwptr[WREG_O1]) {
+ target_sigset_t target_set;
+ sigset_t set;
+
+ if (TARGET_NSIG_WORDS == 1) {
+ __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
+ } else {
+ abi_ulong *src, *dst;
+ src = ucp->tuc_sigmask.sig;
+ dst = target_set.sig;
+ for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
+ __get_user(*dst, src);
+ }
+ }
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+ }
+ env->pc = pc;
+ env->npc = npc;
+ __get_user(env->y, &((*grp)[SPARC_MC_Y]));
+ __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
+ /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
+ env->asi = (tstate >> 24) & 0xff;
+ cpu_put_ccr(env, (tstate >> 32) & 0xff);
+ __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
+ __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
+ __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
+ __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
+ __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
+ __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
+ /* Skip g7 as that's the thread register in userspace */
+
+ /*
+ * Note that unlike the kernel, we didn't need to mess with the
+ * guest register window state to save it into a pt_regs to run
+ * the kernel. So for us the guest's O regs are still in WREG_O*
+ * (unlike the kernel which has put them in UREG_I* in a pt_regs)
+ * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
+ * need to be written back to userspace memory.
+ */
+ __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0]));
+ __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1]));
+ __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2]));
+ __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3]));
+ __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4]));
+ __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5]));
+ __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6]));
+ __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7]));
+
+ __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
+ __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
+
+ fpup = &ucp->tuc_mcontext.mc_fpregs;
+
+ __get_user(fenab, &(fpup->mcfpu_enab));
+ if (fenab) {
+ abi_ulong fprs;
+
+ /*
+ * We use the FPRS from the guest only in deciding whether
+ * to restore the upper, lower, or both banks of the FPU regs.
+ * The kernel here writes the FPU register data into the
+ * process's current_thread_info state and unconditionally
+ * clears FPRS and TSTATE_PEF: this disables the FPU so that the
+ * next FPU-disabled trap will copy the data out of
+ * current_thread_info and into the real FPU registers.
+ * QEMU doesn't need to handle lazy-FPU-state-restoring like that,
+ * so we always load the data directly into the FPU registers
+ * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled).
+ * Note that because we (and the kernel) always write zeroes for
+ * the fenab and fprs in sparc64_get_context() none of this code
+ * will execute unless the guest manually constructed or changed
+ * the context structure.
+ */
+ __get_user(fprs, &(fpup->mcfpu_fprs));
+ if (fprs & FPRS_DL) {
+ for (i = 0; i < 16; i++) {
+ __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
+ }
+ }
+ if (fprs & FPRS_DU) {
+ for (i = 16; i < 32; i++) {
+ __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
+ }
+ }
+ __get_user(env->fsr, &(fpup->mcfpu_fsr));
+ __get_user(env->gsr, &(fpup->mcfpu_gsr));
+ }
+ unlock_user_struct(ucp, ucp_addr, 0);
+ return;
+
+ do_sigsegv:
+ unlock_user_struct(ucp, ucp_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+}
+
+void sparc64_get_context(CPUSPARCState *env)
+{
+ abi_ulong ucp_addr;
+ struct target_ucontext *ucp;
+ target_mc_gregset_t *grp;
+ target_mcontext_t *mcp;
+ int err;
+ unsigned int i;
+ target_sigset_t target_set;
+ sigset_t set;
+
+ ucp_addr = env->regwptr[WREG_O0];
+ if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
+ goto do_sigsegv;
+ }
+
+ memset(ucp, 0, sizeof(*ucp));
+
+ mcp = &ucp->tuc_mcontext;
+ grp = &mcp->mc_gregs;
+
+ /* Skip over the trap instruction, first. */
+ env->pc = env->npc;
+ env->npc += 4;
+
+ /*
+ * If we're only reading the signal mask then do_sigprocmask()
+ * is guaranteed not to fail, which is important because we don't
+ * have any way to signal a failure or restart this operation since
+ * this is not a normal syscall.
+ */
+ err = do_sigprocmask(0, NULL, &set);
+ assert(err == 0);
+ host_to_target_sigset_internal(&target_set, &set);
+ if (TARGET_NSIG_WORDS == 1) {
+ __put_user(target_set.sig[0], (abi_ulong *)&ucp->tuc_sigmask);
+ } else {
+ abi_ulong *src, *dst;
+ src = target_set.sig;
+ dst = ucp->tuc_sigmask.sig;
+ for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
+ __put_user(*src, dst);
+ }
+ }
+
+ __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
+ __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
+ __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
+ __put_user(env->y, &((*grp)[SPARC_MC_Y]));
+ __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
+ __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
+ __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
+ __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
+ __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
+ __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
+ __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
+
+ /*
+ * Note that unlike the kernel, we didn't need to mess with the
+ * guest register window state to save it into a pt_regs to run
+ * the kernel. So for us the guest's O regs are still in WREG_O*
+ * (unlike the kernel which has put them in UREG_I* in a pt_regs)
+ * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
+ * need to be fished out of userspace memory.
+ */
+ __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0]));
+ __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1]));
+ __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2]));
+ __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3]));
+ __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4]));
+ __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5]));
+ __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6]));
+ __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7]));
+
+ __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp));
+ __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
+
+ /*
+ * We don't write out the FPU state. This matches the kernel's
+ * implementation (which has the code for doing this but
+ * hidden behind an "if (fenab)" where fenab is always 0).
+ */
+
+ unlock_user_struct(ucp, ucp_addr, 1);
+ return;
+
+ do_sigsegv:
+ unlock_user_struct(ucp, ucp_addr, 1);
+ force_sig(TARGET_SIGSEGV);
+}
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 6/8] linux-user/sparc: Clean up init_thread
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
` (4 preceding siblings ...)
2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 15:57 ` [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate Richard Henderson
2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
Share code between sparc32 and sparc64, removing a bit of pointless
difference wrt psr/tstate. Use sizeof(abi_ulong) for allocating
initial register window. Use TARGET_STACK_BIAS.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/elfload.c | 33 +++++----------------------------
1 file changed, 5 insertions(+), 28 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c6731013fd..cd8b81103f 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -663,48 +663,25 @@ static uint32_t get_elf_hwcap2(void)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_SPARCV9
-
-#define STACK_BIAS 2047
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
-#ifndef TARGET_ABI32
- regs->tstate = 0;
-#endif
- regs->pc = infop->entry;
- regs->npc = regs->pc + 4;
- regs->y = 0;
-#ifdef TARGET_ABI32
- regs->u_regs[14] = infop->start_stack - 16 * 4;
-#else
- if (personality(infop->personality) == PER_LINUX32)
- regs->u_regs[14] = infop->start_stack - 16 * 4;
- else
- regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-#endif
-}
-
#else
#define ELF_START_MMAP 0x80000000
#define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
| HWCAP_SPARC_MULDIV)
-
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_SPARC
+#endif /* TARGET_SPARC64 */
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
- regs->psr = 0;
+ /* Note that target_cpu_copy_regs does not read psr/tstate. */
regs->pc = infop->entry;
regs->npc = regs->pc + 4;
regs->y = 0;
- regs->u_regs[14] = infop->start_stack - 16 * 4;
+ regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
+ - TARGET_STACK_BIAS);
}
-
-#endif
-#endif
+#endif /* TARGET_SPARC */
#ifdef TARGET_PPC
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
` (5 preceding siblings ...)
2021-04-25 15:57 ` [PATCH 6/8] linux-user/sparc: Clean up init_thread Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
7 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
Generic code cares about the logical stack pointer, not the
physical one that has a bias applied for sparc64.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/sparc/target_cpu.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 37f6a1d62b..1f4bed50f4 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -46,6 +46,7 @@ static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
#endif
/* ??? The kernel appears to copy one stack frame to the new stack. */
/* ??? The kernel force aligns the new stack. */
+ /* Userspace provides a biased stack pointer value. */
env->regwptr[WREG_SP] = newsp;
}
@@ -83,7 +84,7 @@ static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls)
static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
{
- return state->regwptr[WREG_SP];
+ return state->regwptr[WREG_SP] + TARGET_STACK_BIAS;
}
#endif
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 8/8] linux-user/sparc64: Implement signals
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
` (6 preceding siblings ...)
2021-04-25 15:57 ` [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate Richard Henderson
@ 2021-04-25 15:57 ` Richard Henderson
2021-04-25 16:08 ` Richard Henderson
7 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 15:57 UTC (permalink / raw)
To: qemu-devel
We've been using the 32-bit sparc abi for 64-bit signals.
There's a surprising amount of difference, beginning with
the fact that 64-bit always uses rt signal frames.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/sparc/target_signal.h | 2 +
linux-user/sparc64/target_syscall.h | 14 +-
linux-user/sparc64/signal.c | 245 +++++++++++++++++++++++++++-
3 files changed, 254 insertions(+), 7 deletions(-)
diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h
index 911a3f5af5..651320ab8d 100644
--- a/linux-user/sparc/target_signal.h
+++ b/linux-user/sparc/target_signal.h
@@ -67,7 +67,9 @@ typedef struct target_sigaltstack {
#define TARGET_MINSIGSTKSZ 4096
#define TARGET_SIGSTKSZ 16384
+#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
#define TARGET_ARCH_HAS_SETUP_FRAME
+#endif
/* bit-flags */
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
diff --git a/linux-user/sparc64/target_syscall.h b/linux-user/sparc64/target_syscall.h
index 696a68b1ed..fcc71db16e 100644
--- a/linux-user/sparc64/target_syscall.h
+++ b/linux-user/sparc64/target_syscall.h
@@ -4,14 +4,16 @@
#include "../sparc/target_errno.h"
struct target_pt_regs {
- abi_ulong u_regs[16];
- abi_ulong tstate;
- abi_ulong pc;
- abi_ulong npc;
- abi_ulong y;
- abi_ulong fprs;
+ abi_ulong u_regs[16];
+ abi_ulong tstate;
+ abi_ulong pc;
+ abi_ulong npc;
+ uint32_t y;
+ uint32_t magic;
};
+#define TARGET_PT_REGS_MAGIC 0x57ac6c00
+
#define UNAME_MACHINE "sparc64"
#define UNAME_MINIMUM_RELEASE "2.6.32"
diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c
index d27e049c2a..7ba811d342 100644
--- a/linux-user/sparc64/signal.c
+++ b/linux-user/sparc64/signal.c
@@ -17,7 +17,10 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "../sparc/signal.c"
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
#define SPARC_MC_TSTATE 0
#define SPARC_MC_PC 1
@@ -295,3 +298,243 @@ void sparc64_get_context(CPUSPARCState *env)
unlock_user_struct(ucp, ucp_addr, 1);
force_sig(TARGET_SIGSEGV);
}
+
+struct target_sparc_stackf {
+ struct target_reg_window win;
+ uint64_t xargs[8];
+};
+
+struct target_siginfo_fpu_t {
+ uint64_t dregs[32];
+ uint64_t fsr;
+ uint64_t gsr;
+ uint64_t fprs;
+};
+
+struct target_sigcontext {
+ target_siginfo_t info;
+ struct target_pt_regs regs;
+ uint64_t fpu_save;
+ target_stack_t stack;
+ target_sigset_t mask;
+ uint64_t rwin_save;
+};
+
+struct target_rt_sigframe {
+ struct target_sparc_stackf ss;
+ struct target_sigcontext sc;
+ struct target_siginfo_fpu_t fpu;
+};
+
+static abi_ulong get_sigframe(struct target_sigaction *sa,
+ CPUSPARCState *env, int framesize)
+{
+ abi_ulong sp = target_sigsp(get_sp_from_cpustate(env), sa);
+ return (sp - framesize) & -16;
+}
+
+static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ __put_user(env->gregs[i], ®s->u_regs[i]);
+ }
+ for (i = 0; i < 8; i++) {
+ __put_user(env->regwptr[WREG_O0 + i], ®s->u_regs[i + 8]);
+ }
+ __put_user(sparc64_tstate(env), ®s->tstate);
+ __put_user(env->pc, ®s->pc);
+ __put_user(env->npc, ®s->npc);
+ __put_user(env->y, ®s->y);
+ __put_user(TARGET_PT_REGS_MAGIC, ®s->magic);
+}
+
+static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+{
+ uint64_t tstate;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ __get_user(env->gregs[i], ®s->u_regs[i]);
+ }
+ for (i = 0; i < 8; i++) {
+ __get_user(env->regwptr[WREG_O0 + i], ®s->u_regs[i + 8]);
+ }
+
+ __get_user(env->y, ®s->y);
+ __get_user(tstate, ®s->tstate);
+
+ /* User can only change condition codes and %asi in tstate. */
+ cpu_put_ccr(env, tstate >> 32);
+ env->asi = extract64(tstate, 24, 8);
+}
+
+static void save_fpu_state(struct target_siginfo_fpu_t *regs,
+ CPUSPARCState *env)
+{
+ int i;
+
+ /* QEMU does not lazy fpu saving. Save the entire fp register bank. */
+ for (i = 0; i < 32; ++i) {
+ __put_user(env->fpr[i].ll, ®s->dregs[i]);
+ }
+ __put_user(env->fsr, ®s->fsr);
+ __put_user(env->gsr, ®s->gsr);
+ __put_user(env->fprs, ®s->fprs);
+}
+
+static void restore_fpu_state(struct target_siginfo_fpu_t *regs,
+ CPUSPARCState *env)
+{
+ uint64_t fprs;
+ int i;
+
+ /* In case the user mucks about with FPRS, restore as directed. */
+ __get_user(fprs, ®s->fprs);
+ if (fprs & FPRS_DL) {
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->fpr[i].ll, ®s->dregs[i]);
+ }
+ }
+ if (fprs & FPRS_DU) {
+ for (i = 16; i < 32; ++i) {
+ __get_user(env->fpr[i].ll, ®s->dregs[i]);
+ }
+ }
+ __get_user(env->fsr, ®s->fsr);
+ __get_user(env->gsr, ®s->gsr);
+ env->fprs |= fprs;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUSPARCState *env)
+{
+ abi_ulong sf_addr, sp;
+ struct target_rt_sigframe *sf = NULL;
+ void *window;
+
+ sf_addr = get_sigframe(ka, env, sizeof(*sf));
+ trace_user_setup_rt_frame(env, sf_addr);
+ if (!lock_user_struct(VERIFY_WRITE, sf, sf_addr, 0)) {
+ goto do_sigsegv;
+ }
+
+ /* 2. Save the current process state */
+ save_pt_regs(&sf->sc.regs, env);
+ save_fpu_state(&sf->fpu, env);
+ __put_user(sf_addr + offsetof(struct target_rt_sigframe, fpu),
+ &sf->sc.fpu_save);
+ __put_user(0, &sf->sc.rwin_save); /* TODO: save_rwin_state */
+
+ /*
+ * Copy one register window from the top-of-stack into the signal frame.
+ * The balance of the sparc_stackf struct is for the callee --- the call
+ * abi requires the space for spilling argument registers.
+ */
+ sp = get_sp_from_cpustate(env);
+ window = lock_user(VERIFY_READ, sp, sizeof(struct target_reg_window), 1);
+ if (!window) {
+ goto do_sigsegv;
+ }
+ memcpy(sf, window, sizeof(struct target_reg_window));
+ unlock_user(window, sp, 0);
+
+ target_save_altstack(&sf->sc.stack, env);
+ for (int i = 0; i < TARGET_NSIG_WORDS; ++i) {
+ __put_user(set->sig[i], &sf->sc.mask.sig[i]);
+ }
+
+ unlock_user(sf, sf_addr, sizeof(*sf));
+
+ /* 3. signal handler back-trampoline and parameters */
+ env->regwptr[WREG_SP] = sf_addr - TARGET_STACK_BIAS;
+ env->regwptr[WREG_O0] = sig;
+ env->regwptr[WREG_O1] = sf_addr + offsetof(struct target_rt_sigframe, sc);
+ env->regwptr[WREG_O2] = sf_addr + offsetof(struct target_rt_sigframe, sc);
+
+ /* 4. return to kernel instructions */
+ env->regwptr[WREG_O7] = ka->ka_restorer;
+
+ /* 5. signal handler */
+ env->pc = ka->_sa_handler;
+ env->npc = env->pc + 4;
+ return;
+
+ do_sigsegv:
+ unlock_user(sf, sf_addr, 0);
+ force_sigsegv(sig);
+}
+
+/*
+ * __NR_sigreturn still exists for backward compatiblity,
+ * but it is set to sys_nis_syscall for sparc64.
+ */
+long do_sigreturn(CPUSPARCState *env)
+{
+ return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUSPARCState *env)
+{
+ abi_ulong sf_addr, sc_addr, tpc, tnpc, ptr;
+ struct target_sigcontext *sc = NULL;
+ sigset_t set;
+
+ sf_addr = get_sp_from_cpustate(env);
+ trace_user_do_rt_sigreturn(env, sf_addr);
+
+ if (sf_addr & 15) {
+ goto do_sigsegv;
+ }
+ sc_addr = sf_addr + offsetof(struct target_rt_sigframe, sc);
+ if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
+ goto do_sigsegv;
+ }
+
+ /* Validate SP alignment. */
+ __get_user(ptr, &sc->regs.u_regs[8 + WREG_SP]);
+ if ((ptr + TARGET_STACK_BIAS) & 7) {
+ goto do_sigsegv;
+ }
+
+ /* Validate PC and NPC alignment. */
+ __get_user(tpc, &sc->regs.pc);
+ __get_user(tnpc, &sc->regs.npc);
+ if ((tpc | tnpc) & 3) {
+ goto do_sigsegv;
+ }
+
+ restore_pt_regs(&sc->regs, env);
+
+ __get_user(ptr, &sc->fpu_save);
+ if (ptr) {
+ struct target_siginfo_fpu_t *fpu;
+ if ((ptr & 7) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) {
+ goto do_sigsegv;
+ }
+ restore_fpu_state(fpu, env);
+ unlock_user_struct(fpu, ptr, 0);
+ }
+
+ __get_user(ptr, &sc->rwin_save);
+ if (ptr) {
+ goto do_sigsegv; /* TODO: restore_rwin_state */
+ }
+
+ target_to_host_sigset(&set, &sc->mask);
+ set_sigmask(&set);
+ target_restore_altstack(&sc->stack, env);
+
+ env->pc = tpc;
+ env->npc = tnpc;
+
+ unlock_user_struct(sc, sc_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+ do_sigsegv:
+ unlock_user_struct(sc, sc_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 8/8] linux-user/sparc64: Implement signals
2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
@ 2021-04-25 16:08 ` Richard Henderson
0 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2021-04-25 16:08 UTC (permalink / raw)
To: qemu-devel
On 4/25/21 8:57 AM, Richard Henderson wrote:
> We've been using the 32-bit sparc abi for 64-bit signals.
> There's a surprising amount of difference, beginning with
> the fact that 64-bit always uses rt signal frames.
>
> Signed-off-by: Richard Henderson<richard.henderson@linaro.org>
> ---
> linux-user/sparc/target_signal.h | 2 +
> linux-user/sparc64/target_syscall.h | 14 +-
> linux-user/sparc64/signal.c | 245 +++++++++++++++++++++++++++-
> 3 files changed, 254 insertions(+), 7 deletions(-)
Ho hum. I just realized I've broken sparc32plus.
I'll have to reorg the ifdefs.
r~
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c
2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
@ 2021-04-25 18:10 ` Warner Losh
0 siblings, 0 replies; 12+ messages in thread
From: Warner Losh @ 2021-04-25 18:10 UTC (permalink / raw)
To: Richard Henderson; +Cc: QEMU Developers
[-- Attachment #1: Type: text/plain, Size: 606 bytes --]
On Sun, Apr 25, 2021 at 10:03 AM Richard Henderson <
richard.henderson@linaro.org> wrote:
> The bulk of the code goes to sparc64/signal.c, with
> TARGET_SPARC_BIAS going to target_cpu.h, as we will
> shortly need this define beyond signal.c.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/sparc/target_cpu.h | 6 +
> linux-user/sparc/signal.c | 280 ----------------------------------
> linux-user/sparc64/signal.c | 278 +++++++++++++++++++++++++++++++++
> 3 files changed, 284 insertions(+), 280 deletions(-)
>
Reviewed-by: Warner Losh <imp@bsdimp.com>
[-- Attachment #2: Type: text/html, Size: 1113 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack
2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
@ 2021-04-25 18:12 ` Warner Losh
0 siblings, 0 replies; 12+ messages in thread
From: Warner Losh @ 2021-04-25 18:12 UTC (permalink / raw)
To: Richard Henderson; +Cc: QEMU Developers
[-- Attachment #1: Type: text/plain, Size: 1275 bytes --]
On Sun, Apr 25, 2021 at 10:08 AM Richard Henderson <
richard.henderson@linaro.org> wrote:
> In most cases we were already passing get_sp_from_cpustate
> directly to the function. In other cases, we were passing
> a local variable which already contained the same value.
> In the rest of the cases, we were passing the stack pointer
> out of env directly.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/signal-common.h | 2 +-
> linux-user/aarch64/signal.c | 2 +-
> linux-user/alpha/signal.c | 2 +-
> linux-user/arm/signal.c | 4 ++--
> linux-user/hexagon/signal.c | 2 +-
> linux-user/hppa/signal.c | 2 +-
> linux-user/i386/signal.c | 2 +-
> linux-user/m68k/signal.c | 2 +-
> linux-user/microblaze/signal.c | 2 +-
> linux-user/mips/signal.c | 2 +-
> linux-user/nios2/signal.c | 2 +-
> linux-user/openrisc/signal.c | 2 +-
> linux-user/ppc/signal.c | 2 +-
> linux-user/riscv/signal.c | 2 +-
> linux-user/s390x/signal.c | 2 +-
> linux-user/sh4/signal.c | 2 +-
> linux-user/signal.c | 6 +++---
> linux-user/xtensa/signal.c | 2 +-
> 18 files changed, 21 insertions(+), 21 deletions(-)
>
Reviewed by: Warner Losh <imp@bsdimp.com>
[-- Attachment #2: Type: text/html, Size: 1896 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2021-04-25 18:15 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-25 15:57 [PATCH 0/8] linux-user/sparc64: Implement signals Richard Henderson
2021-04-25 15:57 ` [PATCH 1/8] linux-user: Split out target_restore_altstack Richard Henderson
2021-04-25 15:57 ` [PATCH 2/8] linux-user: Use target_restore_altstack in all sigreturn Richard Henderson
2021-04-25 15:57 ` [PATCH 3/8] linux-user: Pass CPUArchState to do_sigaltstack Richard Henderson
2021-04-25 15:57 ` [PATCH 4/8] linux-user: Pass CPUArchState to target_restore_altstack Richard Henderson
2021-04-25 18:12 ` Warner Losh
2021-04-25 15:57 ` [PATCH 5/8] linux-user/sparc64: Move sparc64 code out of sparc32 signal.c Richard Henderson
2021-04-25 18:10 ` Warner Losh
2021-04-25 15:57 ` [PATCH 6/8] linux-user/sparc: Clean up init_thread Richard Henderson
2021-04-25 15:57 ` [PATCH 7/8] linux-user/sparc64: Include TARGET_STACK_BIAS in get_sp_from_cpustate Richard Henderson
2021-04-25 15:57 ` [PATCH 8/8] linux-user/sparc64: Implement signals Richard Henderson
2021-04-25 16:08 ` Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).