From: "Magnus Damm" <magnus.damm@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator
Date: Wed, 21 Nov 2007 17:16:55 +0900 [thread overview]
Message-ID: <aec7e5c30711210016u10dbcf13r6a8bb75abd3625ac@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 109 bytes --]
Hi everyone,
This adds SH support to the user space signal emulation code. Please apply.
Thanks,
/ magnus
[-- Attachment #2: qemu-cvs-20071121c-sh4-signal.patch --]
[-- Type: application/octet-stream, Size: 13185 bytes --]
--- 0001/linux-user/main.c
+++ work/linux-user/main.c 2007-11-21 16:26:16.000000000 +0900
@@ -1617,6 +1617,9 @@ void cpu_loop (CPUState *env)
env->gregs[0] = ret;
env->pc += 2;
break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
case EXCP_DEBUG:
{
int sig;
@@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env)
}
}
break;
+ case 0xa0:
+ case 0xc0:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->tea;
+ queue_signal(info.si_signo, &info);
+ break;
+
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
--- 0001/linux-user/sh4/target_signal.h
+++ work/linux-user/sh4/target_signal.h 2007-11-21 16:26:16.000000000 +0900
@@ -21,4 +21,9 @@ typedef struct target_sigaltstack {
#define TARGET_MINSIGSTKSZ 2048
#define TARGET_SIGSTKSZ 8192
+static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
+{
+ return state->gregs[15];
+}
+
#endif /* TARGET_SIGNAL_H */
--- 0001/linux-user/signal.c
+++ work/linux-user/signal.c 2007-11-21 16:36:58.000000000 +0900
@@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(t
return 0;
}
+static inline int current_exec_domain_sig(int sig)
+{
+ return /* current->exec_domain && current->exec_domain->signal_invmap
+ && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
+}
+
#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
/* from the Linux kernel */
@@ -745,11 +751,7 @@ static void setup_frame(int sig, struct
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
goto give_sigsegv;
- err |= __put_user((/*current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : */ sig),
+ err |= __put_user(current_exec_domain_sig(sig),
&frame->sig);
if (err)
goto give_sigsegv;
@@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, stru
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
goto give_sigsegv;
- err |= __put_user((/*current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : */sig),
+ err |= __put_user(current_exec_domain_sig(sig),
&frame->sig);
addr = frame_addr + offsetof(struct rt_sigframe, info);
err |= __put_user(addr, &frame->pinfo);
@@ -2406,6 +2404,320 @@ long do_rt_sigreturn(CPUState *env)
return -TARGET_ENOSYS;
}
+#elif defined(TARGET_SH4)
+
+/*
+ * code and data structures from linux kernel:
+ * include/asm-sh/sigcontext.h
+ * arch/sh/kernel/signal.c
+ */
+
+struct target_sigcontext {
+ target_ulong oldmask;
+
+ /* CPU registers */
+ target_ulong sc_gregs[16];
+ target_ulong sc_pc;
+ target_ulong sc_pr;
+ target_ulong sc_sr;
+ target_ulong sc_gbr;
+ target_ulong sc_mach;
+ target_ulong sc_macl;
+
+ /* FPU registers */
+ target_ulong sc_fpregs[16];
+ target_ulong sc_xfpregs[16];
+ unsigned int sc_fpscr;
+ unsigned int sc_fpul;
+ unsigned int sc_ownedfp;
+};
+
+struct target_sigframe
+{
+ struct target_sigcontext sc;
+ target_ulong extramask[TARGET_NSIG_WORDS-1];
+ uint16_t retcode[8];
+};
+
+
+struct target_ucontext {
+ target_ulong uc_flags;
+ struct target_ucontext *uc_link;
+ target_stack_t uc_stack;
+ struct target_sigcontext uc_mcontext;
+ target_sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+struct target_rt_sigframe
+{
+ struct target_siginfo info;
+ struct target_ucontext uc;
+ uint16_t retcode[8];
+};
+
+
+#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
+#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
+#define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */
+
+static abi_ulong get_sigframe(struct emulated_sigaction *ka,
+ unsigned long sp, size_t frame_size)
+{
+ if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+ }
+
+ return (sp - frame_size) & -8ul;
+}
+
+static int setup_sigcontext(struct target_sigcontext *sc,
+ CPUState *regs, unsigned long mask)
+{
+ int err = 0;
+
+#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
+ COPY(gregs[0]); COPY(gregs[1]);
+ COPY(gregs[2]); COPY(gregs[3]);
+ COPY(gregs[4]); COPY(gregs[5]);
+ COPY(gregs[6]); COPY(gregs[7]);
+ COPY(gregs[8]); COPY(gregs[9]);
+ COPY(gregs[10]); COPY(gregs[11]);
+ COPY(gregs[12]); COPY(gregs[13]);
+ COPY(gregs[14]); COPY(gregs[15]);
+ COPY(gbr); COPY(mach);
+ COPY(macl); COPY(pr);
+ COPY(sr); COPY(pc);
+#undef COPY
+
+ /* todo: save FPU registers here */
+
+ /* non-iBCS2 extensions.. */
+ err |= __put_user(mask, &sc->oldmask);
+
+ return err;
+}
+
+static int restore_sigcontext(struct CPUState *regs,
+ struct target_sigcontext *sc)
+{
+ unsigned int err = 0;
+
+#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
+ COPY(gregs[1]);
+ COPY(gregs[2]); COPY(gregs[3]);
+ COPY(gregs[4]); COPY(gregs[5]);
+ COPY(gregs[6]); COPY(gregs[7]);
+ COPY(gregs[8]); COPY(gregs[9]);
+ COPY(gregs[10]); COPY(gregs[11]);
+ COPY(gregs[12]); COPY(gregs[13]);
+ COPY(gregs[14]); COPY(gregs[15]);
+ COPY(gbr); COPY(mach);
+ COPY(macl); COPY(pr);
+ COPY(sr); COPY(pc);
+#undef COPY
+
+ /* todo: restore FPU registers here */
+
+ regs->tra = -1; /* disable syscall checks */
+ return err;
+}
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+ target_sigset_t *set, CPUState *regs)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+ int err = 0;
+ int signal;
+
+ frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto give_sigsegv;
+
+ signal = current_exec_domain_sig(sig);
+
+ err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+ for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+ err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa.sa_restorer;
+ } else {
+ /* Generate return code (system call to sigreturn) */
+ err |= __put_user(MOVW(7), &frame->retcode[0]);
+ err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+ err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[7]);
+ regs->pr = (unsigned long) frame->retcode;
+ }
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->gregs[15] = (unsigned long) frame;
+ regs->gregs[4] = signal; /* Arg for signal handler */
+ regs->gregs[5] = 0;
+ regs->gregs[6] = (unsigned long) &frame->sc;
+ regs->pc = (unsigned long) ka->sa._sa_handler;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sig(SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUState *regs)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+ int err = 0;
+ int signal;
+
+ frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto give_sigsegv;
+
+ signal = current_exec_domain_sig(sig);
+
+ err |= copy_siginfo_to_user(&frame->info, info);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
+ err |= __put_user((void *)target_sigaltstack_used.ss_sp,
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->gregs[15]),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(target_sigaltstack_used.ss_size,
+ &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext,
+ regs, set->sig[0]);
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa.sa_restorer;
+ } else {
+ /* Generate return code (system call to sigreturn) */
+ err |= __put_user(MOVW(7), &frame->retcode[0]);
+ err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+ err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+ err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[7]);
+ regs->pr = (unsigned long) frame->retcode;
+ }
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->gregs[15] = (unsigned long) frame;
+ regs->gregs[4] = signal; /* Arg for signal handler */
+ regs->gregs[5] = (unsigned long) &frame->info;
+ regs->gregs[6] = (unsigned long) &frame->uc;
+ regs->pc = (unsigned long) ka->sa._sa_handler;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sig(SIGSEGV);
+}
+
+long do_sigreturn(CPUState *regs)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+ target_sigset_t target_set;
+ int i;
+ int err = 0;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "do_sigreturn\n");
+#endif
+ frame_addr = regs->gregs[15];
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
+ }
+
+ if (err)
+ goto badframe;
+
+ target_to_host_sigset_internal(&blocked, &target_set);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+ if (restore_sigcontext(regs, &frame->sc))
+ goto badframe;
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return regs->gregs[0];
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return 0;
+}
+
+long do_rt_sigreturn(CPUState *regs)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "do_rt_sigreturn\n");
+#endif
+ frame_addr = regs->gregs[15];
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+ goto badframe;
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, uc.uc_stack),
+ 0, get_sp_from_cpustate(regs)) == -EFAULT)
+ goto badframe;
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return regs->gregs[0];
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return 0;
+}
+
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,
--- 0001/target-sh4/helper.c
+++ work/target-sh4/helper.c 2007-11-21 16:26:16.000000000 +0900
@@ -39,16 +39,16 @@ int cpu_sh4_handle_mmu_fault(CPUState *
int mmu_idx, int is_softmmu)
{
env->tea = address;
+ env->exception_index = 0;
switch (rw) {
case 0:
+ env->tea = address;
env->exception_index = 0x0a0;
break;
case 1:
+ env->tea = address;
env->exception_index = 0x0c0;
break;
- case 2:
- env->exception_index = 0x0a0;
- break;
}
return 1;
}
--- 0001/translate-all.c
+++ work/translate-all.c 2007-11-21 16:26:16.000000000 +0900
@@ -298,6 +298,8 @@ int cpu_restore_state(TranslationBlock *
env->hflags |= gen_opc_hflags[j];
#elif defined(TARGET_ALPHA)
env->pc = gen_opc_pc[j];
+#elif defined(TARGET_SH4)
+ env->pc = gen_opc_pc[j];
#endif
return 0;
}
next reply other threads:[~2007-11-21 8:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-21 8:16 Magnus Damm [this message]
2007-11-21 8:40 ` [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator Paul Mundt
2007-11-22 4:59 ` Magnus Damm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aec7e5c30711210016u10dbcf13r6a8bb75abd3625ac@mail.gmail.com \
--to=magnus.damm@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).