qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

signal.c (7575B)


      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 
     25 struct target_sigcontext {
     26     abi_long sc_onstack;
     27     abi_long sc_mask;
     28     abi_long sc_pc;
     29     abi_long sc_ps;
     30     abi_long sc_regs[32];
     31     abi_long sc_ownedfp;
     32     abi_long sc_fpregs[32];
     33     abi_ulong sc_fpcr;
     34     abi_ulong sc_fp_control;
     35     abi_ulong sc_reserved1;
     36     abi_ulong sc_reserved2;
     37     abi_ulong sc_ssize;
     38     abi_ulong sc_sbase;
     39     abi_ulong sc_traparg_a0;
     40     abi_ulong sc_traparg_a1;
     41     abi_ulong sc_traparg_a2;
     42     abi_ulong sc_fp_trap_pc;
     43     abi_ulong sc_fp_trigger_sum;
     44     abi_ulong sc_fp_trigger_inst;
     45 };
     46 
     47 struct target_ucontext {
     48     abi_ulong tuc_flags;
     49     abi_ulong tuc_link;
     50     abi_ulong tuc_osf_sigmask;
     51     target_stack_t tuc_stack;
     52     struct target_sigcontext tuc_mcontext;
     53     target_sigset_t tuc_sigmask;
     54 };
     55 
     56 struct target_sigframe {
     57     struct target_sigcontext sc;
     58 };
     59 
     60 struct target_rt_sigframe {
     61     target_siginfo_t info;
     62     struct target_ucontext uc;
     63 };
     64 
     65 #define INSN_MOV_R30_R16        0x47fe0410
     66 #define INSN_LDI_R0             0x201f0000
     67 #define INSN_CALLSYS            0x00000083
     68 
     69 static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
     70                              abi_ulong frame_addr, target_sigset_t *set)
     71 {
     72     int i;
     73 
     74     __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
     75     __put_user(set->sig[0], &sc->sc_mask);
     76     __put_user(env->pc, &sc->sc_pc);
     77     __put_user(8, &sc->sc_ps);
     78 
     79     for (i = 0; i < 31; ++i) {
     80         __put_user(env->ir[i], &sc->sc_regs[i]);
     81     }
     82     __put_user(0, &sc->sc_regs[31]);
     83 
     84     for (i = 0; i < 31; ++i) {
     85         __put_user(env->fir[i], &sc->sc_fpregs[i]);
     86     }
     87     __put_user(0, &sc->sc_fpregs[31]);
     88     __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
     89 
     90     __put_user(0, &sc->sc_traparg_a0); /* FIXME */
     91     __put_user(0, &sc->sc_traparg_a1); /* FIXME */
     92     __put_user(0, &sc->sc_traparg_a2); /* FIXME */
     93 }
     94 
     95 static void restore_sigcontext(CPUAlphaState *env,
     96                                struct target_sigcontext *sc)
     97 {
     98     uint64_t fpcr;
     99     int i;
    100 
    101     __get_user(env->pc, &sc->sc_pc);
    102 
    103     for (i = 0; i < 31; ++i) {
    104         __get_user(env->ir[i], &sc->sc_regs[i]);
    105     }
    106     for (i = 0; i < 31; ++i) {
    107         __get_user(env->fir[i], &sc->sc_fpregs[i]);
    108     }
    109 
    110     __get_user(fpcr, &sc->sc_fpcr);
    111     cpu_alpha_store_fpcr(env, fpcr);
    112 }
    113 
    114 static inline abi_ulong get_sigframe(struct target_sigaction *sa,
    115                                      CPUAlphaState *env,
    116                                      unsigned long framesize)
    117 {
    118     abi_ulong sp;
    119 
    120     sp = target_sigsp(get_sp_from_cpustate(env), sa);
    121 
    122     return (sp - framesize) & -32;
    123 }
    124 
    125 void setup_frame(int sig, struct target_sigaction *ka,
    126                  target_sigset_t *set, CPUAlphaState *env)
    127 {
    128     abi_ulong frame_addr, r26;
    129     struct target_sigframe *frame;
    130     int err = 0;
    131 
    132     frame_addr = get_sigframe(ka, env, sizeof(*frame));
    133     trace_user_setup_frame(env, frame_addr);
    134     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    135         goto give_sigsegv;
    136     }
    137 
    138     setup_sigcontext(&frame->sc, env, frame_addr, set);
    139 
    140     if (ka->ka_restorer) {
    141         r26 = ka->ka_restorer;
    142     } else {
    143         r26 = default_sigreturn;
    144     }
    145 
    146     unlock_user_struct(frame, frame_addr, 1);
    147 
    148     if (err) {
    149 give_sigsegv:
    150         force_sigsegv(sig);
    151         return;
    152     }
    153 
    154     env->ir[IR_RA] = r26;
    155     env->ir[IR_PV] = env->pc = ka->_sa_handler;
    156     env->ir[IR_A0] = sig;
    157     env->ir[IR_A1] = 0;
    158     env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
    159     env->ir[IR_SP] = frame_addr;
    160 }
    161 
    162 void setup_rt_frame(int sig, struct target_sigaction *ka,
    163                     target_siginfo_t *info,
    164                     target_sigset_t *set, CPUAlphaState *env)
    165 {
    166     abi_ulong frame_addr, r26;
    167     struct target_rt_sigframe *frame;
    168     int i, err = 0;
    169 
    170     frame_addr = get_sigframe(ka, env, sizeof(*frame));
    171     trace_user_setup_rt_frame(env, frame_addr);
    172     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    173         goto give_sigsegv;
    174     }
    175 
    176     tswap_siginfo(&frame->info, info);
    177 
    178     __put_user(0, &frame->uc.tuc_flags);
    179     __put_user(0, &frame->uc.tuc_link);
    180     __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
    181 
    182     target_save_altstack(&frame->uc.tuc_stack, env);
    183 
    184     setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
    185     for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
    186         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
    187     }
    188 
    189     if (ka->ka_restorer) {
    190         r26 = ka->ka_restorer;
    191     } else {
    192         r26 = default_rt_sigreturn;
    193     }
    194 
    195     if (err) {
    196 give_sigsegv:
    197         force_sigsegv(sig);
    198         return;
    199     }
    200 
    201     env->ir[IR_RA] = r26;
    202     env->ir[IR_PV] = env->pc = ka->_sa_handler;
    203     env->ir[IR_A0] = sig;
    204     env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
    205     env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
    206     env->ir[IR_SP] = frame_addr;
    207 }
    208 
    209 long do_sigreturn(CPUAlphaState *env)
    210 {
    211     struct target_sigcontext *sc;
    212     abi_ulong sc_addr = env->ir[IR_A0];
    213     target_sigset_t target_set;
    214     sigset_t set;
    215 
    216     if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
    217         goto badframe;
    218     }
    219 
    220     target_sigemptyset(&target_set);
    221     __get_user(target_set.sig[0], &sc->sc_mask);
    222 
    223     target_to_host_sigset_internal(&set, &target_set);
    224     set_sigmask(&set);
    225 
    226     restore_sigcontext(env, sc);
    227     unlock_user_struct(sc, sc_addr, 0);
    228     return -QEMU_ESIGRETURN;
    229 
    230 badframe:
    231     force_sig(TARGET_SIGSEGV);
    232     return -QEMU_ESIGRETURN;
    233 }
    234 
    235 long do_rt_sigreturn(CPUAlphaState *env)
    236 {
    237     abi_ulong frame_addr = env->ir[IR_A0];
    238     struct target_rt_sigframe *frame;
    239     sigset_t set;
    240 
    241     trace_user_do_rt_sigreturn(env, frame_addr);
    242     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
    243         goto badframe;
    244     }
    245     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
    246     set_sigmask(&set);
    247 
    248     restore_sigcontext(env, &frame->uc.tuc_mcontext);
    249     target_restore_altstack(&frame->uc.tuc_stack, env);
    250 
    251     unlock_user_struct(frame, frame_addr, 0);
    252     return -QEMU_ESIGRETURN;
    253 
    254 
    255 badframe:
    256     unlock_user_struct(frame, frame_addr, 0);
    257     force_sig(TARGET_SIGSEGV);
    258     return -QEMU_ESIGRETURN;
    259 }
    260 
    261 void setup_sigtramp(abi_ulong sigtramp_page)
    262 {
    263     uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6 * 4, 0);
    264     assert(tramp != NULL);
    265 
    266     default_sigreturn = sigtramp_page;
    267     __put_user(INSN_MOV_R30_R16, &tramp[0]);
    268     __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, &tramp[1]);
    269     __put_user(INSN_CALLSYS, &tramp[2]);
    270 
    271     default_rt_sigreturn = sigtramp_page + 3 * 4;
    272     __put_user(INSN_MOV_R30_R16, &tramp[3]);
    273     __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, &tramp[4]);
    274     __put_user(INSN_CALLSYS, &tramp[5]);
    275 
    276     unlock_user(tramp, sigtramp_page, 6 * 4);
    277 }