|
@@ -35,9 +35,9 @@ struct target_stack_t {
|
|
|
struct target_ucontext {
|
|
|
abi_ulong tuc_flags;
|
|
|
abi_ulong tuc_link;
|
|
|
- struct target_stack_t tuc_stack;
|
|
|
+ target_stack_t tuc_stack;
|
|
|
struct target_sigcontext tuc_mcontext;
|
|
|
- uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
|
|
|
+ target_sigset_t tuc_sigmask;
|
|
|
};
|
|
|
|
|
|
/* Signal frames. */
|
|
@@ -47,9 +47,9 @@ struct target_signal_frame {
|
|
|
uint32_t tramp[2];
|
|
|
};
|
|
|
|
|
|
-struct rt_signal_frame {
|
|
|
- siginfo_t info;
|
|
|
- ucontext_t uc;
|
|
|
+struct target_rt_sigframe {
|
|
|
+ target_siginfo_t info;
|
|
|
+ struct target_ucontext uc;
|
|
|
uint32_t tramp[2];
|
|
|
};
|
|
|
|
|
@@ -200,7 +200,55 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|
|
target_siginfo_t *info,
|
|
|
target_sigset_t *set, CPUMBState *env)
|
|
|
{
|
|
|
- qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n");
|
|
|
+ struct target_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)) {
|
|
|
+ force_sigsegv(sig);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ tswap_siginfo(&frame->info, info);
|
|
|
+
|
|
|
+ __put_user(0, &frame->uc.tuc_flags);
|
|
|
+ __put_user(0, &frame->uc.tuc_link);
|
|
|
+
|
|
|
+ target_save_altstack(&frame->uc.tuc_stack, env);
|
|
|
+ setup_sigcontext(&frame->uc.tuc_mcontext, env);
|
|
|
+
|
|
|
+ for (int i = 0; i < TARGET_NSIG_WORDS; i++) {
|
|
|
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Kernel does not use SA_RESTORER. */
|
|
|
+
|
|
|
+ /* addi r12, r0, __NR_sigreturn */
|
|
|
+ __put_user(0x31800000U | TARGET_NR_rt_sigreturn, frame->tramp + 0);
|
|
|
+ /* brki r14, 0x8 */
|
|
|
+ __put_user(0xb9cc0008U, frame->tramp + 1);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Return from sighandler will jump to the tramp.
|
|
|
+ * Negative 8 offset because return is rtsd r15, 8
|
|
|
+ */
|
|
|
+ env->regs[15] =
|
|
|
+ frame_addr + offsetof(struct target_rt_sigframe, tramp) - 8;
|
|
|
+
|
|
|
+ /* Set up registers for signal handler */
|
|
|
+ env->regs[1] = frame_addr;
|
|
|
+
|
|
|
+ /* Signal handler args: */
|
|
|
+ env->regs[5] = sig;
|
|
|
+ env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info);
|
|
|
+ env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc);
|
|
|
+
|
|
|
+ /* Offset to handle microblaze rtid r14, 0 */
|
|
|
+ env->pc = (unsigned long)ka->_sa_handler;
|
|
|
+
|
|
|
+ unlock_user_struct(frame, frame_addr, 1);
|
|
|
}
|
|
|
|
|
|
long do_sigreturn(CPUMBState *env)
|
|
@@ -239,7 +287,32 @@ badframe:
|
|
|
|
|
|
long do_rt_sigreturn(CPUMBState *env)
|
|
|
{
|
|
|
- trace_user_do_rt_sigreturn(env, 0);
|
|
|
- qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
|
|
|
- return -TARGET_ENOSYS;
|
|
|
+ struct target_rt_sigframe *frame = NULL;
|
|
|
+ abi_ulong frame_addr = env->regs[1];
|
|
|
+ sigset_t set;
|
|
|
+
|
|
|
+ trace_user_do_rt_sigreturn(env, frame_addr);
|
|
|
+
|
|
|
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
|
|
+ goto badframe;
|
|
|
+ }
|
|
|
+
|
|
|
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
|
|
+ set_sigmask(&set);
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
}
|