qemu
194 строки · 6.1 Кб
1/*
2* Emulation of Linux signals
3*
4* Copyright (c) 2003 Fabrice Bellard
5*
6* This program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2 of the License, or
9* (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program; if not, see <http://www.gnu.org/licenses/>.
18*/
19#include "qemu/osdep.h"20#include "qemu.h"21#include "user-internals.h"22#include "signal-common.h"23#include "linux-user/trace.h"24
25struct target_sigcontext {26struct target_pt_regs regs; /* needs to be first */27uint32_t oldmask;28uint32_t usp; /* usp before stacking this gunk on it */29};30
31/* Signal frames. */
32struct target_signal_frame {33struct target_sigcontext sc;34uint32_t extramask[TARGET_NSIG_WORDS - 1];35uint16_t retcode[4]; /* Trampoline code. */36};37
38static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)39{
40__put_user(env->regs[0], &sc->regs.r0);41__put_user(env->regs[1], &sc->regs.r1);42__put_user(env->regs[2], &sc->regs.r2);43__put_user(env->regs[3], &sc->regs.r3);44__put_user(env->regs[4], &sc->regs.r4);45__put_user(env->regs[5], &sc->regs.r5);46__put_user(env->regs[6], &sc->regs.r6);47__put_user(env->regs[7], &sc->regs.r7);48__put_user(env->regs[8], &sc->regs.r8);49__put_user(env->regs[9], &sc->regs.r9);50__put_user(env->regs[10], &sc->regs.r10);51__put_user(env->regs[11], &sc->regs.r11);52__put_user(env->regs[12], &sc->regs.r12);53__put_user(env->regs[13], &sc->regs.r13);54__put_user(env->regs[14], &sc->usp);55__put_user(env->regs[15], &sc->regs.acr);56__put_user(env->pregs[PR_MOF], &sc->regs.mof);57__put_user(env->pregs[PR_SRP], &sc->regs.srp);58__put_user(env->pc, &sc->regs.erp);59}
60
61static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)62{
63__get_user(env->regs[0], &sc->regs.r0);64__get_user(env->regs[1], &sc->regs.r1);65__get_user(env->regs[2], &sc->regs.r2);66__get_user(env->regs[3], &sc->regs.r3);67__get_user(env->regs[4], &sc->regs.r4);68__get_user(env->regs[5], &sc->regs.r5);69__get_user(env->regs[6], &sc->regs.r6);70__get_user(env->regs[7], &sc->regs.r7);71__get_user(env->regs[8], &sc->regs.r8);72__get_user(env->regs[9], &sc->regs.r9);73__get_user(env->regs[10], &sc->regs.r10);74__get_user(env->regs[11], &sc->regs.r11);75__get_user(env->regs[12], &sc->regs.r12);76__get_user(env->regs[13], &sc->regs.r13);77__get_user(env->regs[14], &sc->usp);78__get_user(env->regs[15], &sc->regs.acr);79__get_user(env->pregs[PR_MOF], &sc->regs.mof);80__get_user(env->pregs[PR_SRP], &sc->regs.srp);81__get_user(env->pc, &sc->regs.erp);82}
83
84static abi_ulong get_sigframe(CPUCRISState *env, int framesize)85{
86abi_ulong sp;87/* Align the stack downwards to 4. */88sp = (env->regs[R_SP] & ~3);89return sp - framesize;90}
91
92static void setup_sigreturn(uint16_t *retcode)93{
94/* This is movu.w __NR_sigreturn, r9; break 13; */95__put_user(0x9c5f, retcode + 0);96__put_user(TARGET_NR_sigreturn, retcode + 1);97__put_user(0xe93d, retcode + 2);98}
99
100void setup_frame(int sig, struct target_sigaction *ka,101target_sigset_t *set, CPUCRISState *env)102{
103struct target_signal_frame *frame;104abi_ulong frame_addr;105int i;106
107frame_addr = get_sigframe(env, sizeof *frame);108trace_user_setup_frame(env, frame_addr);109if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))110goto badframe;111
112/*113* The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
114* use this trampoline anymore but it sets it up for GDB.
115*/
116setup_sigreturn(frame->retcode);117
118/* Save the mask. */119__put_user(set->sig[0], &frame->sc.oldmask);120
121for(i = 1; i < TARGET_NSIG_WORDS; i++) {122__put_user(set->sig[i], &frame->extramask[i - 1]);123}124
125setup_sigcontext(&frame->sc, env);126
127/* Move the stack and setup the arguments for the handler. */128env->regs[R_SP] = frame_addr;129env->regs[10] = sig;130env->pc = (unsigned long) ka->_sa_handler;131/* Link SRP so the guest returns through the trampoline. */132env->pregs[PR_SRP] = default_sigreturn;133
134unlock_user_struct(frame, frame_addr, 1);135return;136badframe:137force_sigsegv(sig);138}
139
140void setup_rt_frame(int sig, struct target_sigaction *ka,141target_siginfo_t *info,142target_sigset_t *set, CPUCRISState *env)143{
144qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n");145}
146
147long do_sigreturn(CPUCRISState *env)148{
149struct target_signal_frame *frame;150abi_ulong frame_addr;151target_sigset_t target_set;152sigset_t set;153int i;154
155frame_addr = env->regs[R_SP];156trace_user_do_sigreturn(env, frame_addr);157/* Make sure the guest isn't playing games. */158if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {159goto badframe;160}161
162/* Restore blocked signals */163__get_user(target_set.sig[0], &frame->sc.oldmask);164for(i = 1; i < TARGET_NSIG_WORDS; i++) {165__get_user(target_set.sig[i], &frame->extramask[i - 1]);166}167target_to_host_sigset_internal(&set, &target_set);168set_sigmask(&set);169
170restore_sigcontext(&frame->sc, env);171unlock_user_struct(frame, frame_addr, 0);172return -QEMU_ESIGRETURN;173badframe:174force_sig(TARGET_SIGSEGV);175return -QEMU_ESIGRETURN;176}
177
178long do_rt_sigreturn(CPUCRISState *env)179{
180trace_user_do_rt_sigreturn(env, 0);181qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");182return -TARGET_ENOSYS;183}
184
185void setup_sigtramp(abi_ulong sigtramp_page)186{
187uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);188assert(tramp != NULL);189
190default_sigreturn = sigtramp_page;191setup_sigreturn(tramp);192
193unlock_user(tramp, sigtramp_page, 6);194}
195