qemu

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

signal.c (11361B)


      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_ulong  sc_mask;
     27     abi_ulong  sc_usp;
     28     abi_ulong  sc_d0;
     29     abi_ulong  sc_d1;
     30     abi_ulong  sc_a0;
     31     abi_ulong  sc_a1;
     32     unsigned short sc_sr;
     33     abi_ulong  sc_pc;
     34 };
     35 
     36 struct target_sigframe
     37 {
     38     abi_ulong pretcode;
     39     int sig;
     40     int code;
     41     abi_ulong psc;
     42     abi_ulong extramask[TARGET_NSIG_WORDS-1];
     43     struct target_sigcontext sc;
     44 };
     45 
     46 typedef int target_greg_t;
     47 #define TARGET_NGREG 18
     48 typedef target_greg_t target_gregset_t[TARGET_NGREG];
     49 
     50 typedef struct target_fpregset {
     51     int f_fpcntl[3];
     52     int f_fpregs[8*3];
     53 } target_fpregset_t;
     54 
     55 struct target_mcontext {
     56     int version;
     57     target_gregset_t gregs;
     58     target_fpregset_t fpregs;
     59 };
     60 
     61 #define TARGET_MCONTEXT_VERSION 2
     62 
     63 struct target_ucontext {
     64     abi_ulong tuc_flags;
     65     abi_ulong tuc_link;
     66     target_stack_t tuc_stack;
     67     struct target_mcontext tuc_mcontext;
     68     abi_long tuc_filler[80];
     69     target_sigset_t tuc_sigmask;
     70 };
     71 
     72 struct target_rt_sigframe
     73 {
     74     abi_ulong pretcode;
     75     int sig;
     76     abi_ulong pinfo;
     77     abi_ulong puc;
     78     struct target_siginfo info;
     79     struct target_ucontext uc;
     80 };
     81 
     82 static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
     83                              abi_ulong mask)
     84 {
     85     uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
     86     __put_user(mask, &sc->sc_mask);
     87     __put_user(env->aregs[7], &sc->sc_usp);
     88     __put_user(env->dregs[0], &sc->sc_d0);
     89     __put_user(env->dregs[1], &sc->sc_d1);
     90     __put_user(env->aregs[0], &sc->sc_a0);
     91     __put_user(env->aregs[1], &sc->sc_a1);
     92     __put_user(sr, &sc->sc_sr);
     93     __put_user(env->pc, &sc->sc_pc);
     94 }
     95 
     96 static void
     97 restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
     98 {
     99     int temp;
    100 
    101     __get_user(env->aregs[7], &sc->sc_usp);
    102     __get_user(env->dregs[0], &sc->sc_d0);
    103     __get_user(env->dregs[1], &sc->sc_d1);
    104     __get_user(env->aregs[0], &sc->sc_a0);
    105     __get_user(env->aregs[1], &sc->sc_a1);
    106     __get_user(env->pc, &sc->sc_pc);
    107     __get_user(temp, &sc->sc_sr);
    108     cpu_m68k_set_ccr(env, temp);
    109 }
    110 
    111 /*
    112  * Determine which stack to use..
    113  */
    114 static inline abi_ulong
    115 get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
    116              size_t frame_size)
    117 {
    118     abi_ulong sp;
    119 
    120     sp = target_sigsp(get_sp_from_cpustate(regs), ka);
    121 
    122 
    123     return ((sp - frame_size) & -8UL);
    124 }
    125 
    126 void setup_frame(int sig, struct target_sigaction *ka,
    127                  target_sigset_t *set, CPUM68KState *env)
    128 {
    129     struct target_sigframe *frame;
    130     abi_ulong frame_addr;
    131     abi_ulong sc_addr;
    132     int i;
    133 
    134     frame_addr = get_sigframe(ka, env, sizeof *frame);
    135     trace_user_setup_frame(env, frame_addr);
    136     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    137         goto give_sigsegv;
    138     }
    139 
    140     __put_user(sig, &frame->sig);
    141 
    142     sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
    143     __put_user(sc_addr, &frame->psc);
    144 
    145     setup_sigcontext(&frame->sc, env, set->sig[0]);
    146 
    147     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
    148         __put_user(set->sig[i], &frame->extramask[i - 1]);
    149     }
    150 
    151     /* Set up to return from userspace.  */
    152     __put_user(default_sigreturn, &frame->pretcode);
    153 
    154     env->aregs[7] = frame_addr;
    155     env->pc = ka->_sa_handler;
    156 
    157     unlock_user_struct(frame, frame_addr, 1);
    158     return;
    159 
    160 give_sigsegv:
    161     force_sigsegv(sig);
    162 }
    163 
    164 static inline void target_rt_save_fpu_state(struct target_ucontext *uc,
    165                                            CPUM68KState *env)
    166 {
    167     int i;
    168     target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
    169 
    170     __put_user(env->fpcr, &fpregs->f_fpcntl[0]);
    171     __put_user(env->fpsr, &fpregs->f_fpcntl[1]);
    172     /* fpiar is not emulated */
    173 
    174     for (i = 0; i < 8; i++) {
    175         uint32_t high = env->fregs[i].d.high << 16;
    176         __put_user(high, &fpregs->f_fpregs[i * 3]);
    177         __put_user(env->fregs[i].d.low,
    178                    (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
    179     }
    180 }
    181 
    182 static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
    183                                            CPUM68KState *env)
    184 {
    185     target_greg_t *gregs = uc->tuc_mcontext.gregs;
    186     uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
    187 
    188     __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
    189     __put_user(env->dregs[0], &gregs[0]);
    190     __put_user(env->dregs[1], &gregs[1]);
    191     __put_user(env->dregs[2], &gregs[2]);
    192     __put_user(env->dregs[3], &gregs[3]);
    193     __put_user(env->dregs[4], &gregs[4]);
    194     __put_user(env->dregs[5], &gregs[5]);
    195     __put_user(env->dregs[6], &gregs[6]);
    196     __put_user(env->dregs[7], &gregs[7]);
    197     __put_user(env->aregs[0], &gregs[8]);
    198     __put_user(env->aregs[1], &gregs[9]);
    199     __put_user(env->aregs[2], &gregs[10]);
    200     __put_user(env->aregs[3], &gregs[11]);
    201     __put_user(env->aregs[4], &gregs[12]);
    202     __put_user(env->aregs[5], &gregs[13]);
    203     __put_user(env->aregs[6], &gregs[14]);
    204     __put_user(env->aregs[7], &gregs[15]);
    205     __put_user(env->pc, &gregs[16]);
    206     __put_user(sr, &gregs[17]);
    207 
    208     target_rt_save_fpu_state(uc, env);
    209 
    210     return 0;
    211 }
    212 
    213 static inline void target_rt_restore_fpu_state(CPUM68KState *env,
    214                                                struct target_ucontext *uc)
    215 {
    216     int i;
    217     target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
    218     uint32_t fpcr;
    219 
    220     __get_user(fpcr, &fpregs->f_fpcntl[0]);
    221     cpu_m68k_set_fpcr(env, fpcr);
    222     __get_user(env->fpsr, &fpregs->f_fpcntl[1]);
    223     /* fpiar is not emulated */
    224 
    225     for (i = 0; i < 8; i++) {
    226         uint32_t high;
    227         __get_user(high, &fpregs->f_fpregs[i * 3]);
    228         env->fregs[i].d.high = high >> 16;
    229         __get_user(env->fregs[i].d.low,
    230                    (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
    231     }
    232 }
    233 
    234 static inline int target_rt_restore_ucontext(CPUM68KState *env,
    235                                              struct target_ucontext *uc)
    236 {
    237     int temp;
    238     target_greg_t *gregs = uc->tuc_mcontext.gregs;
    239 
    240     __get_user(temp, &uc->tuc_mcontext.version);
    241     if (temp != TARGET_MCONTEXT_VERSION)
    242         goto badframe;
    243 
    244     /* restore passed registers */
    245     __get_user(env->dregs[0], &gregs[0]);
    246     __get_user(env->dregs[1], &gregs[1]);
    247     __get_user(env->dregs[2], &gregs[2]);
    248     __get_user(env->dregs[3], &gregs[3]);
    249     __get_user(env->dregs[4], &gregs[4]);
    250     __get_user(env->dregs[5], &gregs[5]);
    251     __get_user(env->dregs[6], &gregs[6]);
    252     __get_user(env->dregs[7], &gregs[7]);
    253     __get_user(env->aregs[0], &gregs[8]);
    254     __get_user(env->aregs[1], &gregs[9]);
    255     __get_user(env->aregs[2], &gregs[10]);
    256     __get_user(env->aregs[3], &gregs[11]);
    257     __get_user(env->aregs[4], &gregs[12]);
    258     __get_user(env->aregs[5], &gregs[13]);
    259     __get_user(env->aregs[6], &gregs[14]);
    260     __get_user(env->aregs[7], &gregs[15]);
    261     __get_user(env->pc, &gregs[16]);
    262     __get_user(temp, &gregs[17]);
    263     cpu_m68k_set_ccr(env, temp);
    264 
    265     target_rt_restore_fpu_state(env, uc);
    266 
    267     return 0;
    268 
    269 badframe:
    270     return 1;
    271 }
    272 
    273 void setup_rt_frame(int sig, struct target_sigaction *ka,
    274                     target_siginfo_t *info,
    275                     target_sigset_t *set, CPUM68KState *env)
    276 {
    277     struct target_rt_sigframe *frame;
    278     abi_ulong frame_addr;
    279     abi_ulong info_addr;
    280     abi_ulong uc_addr;
    281     int err = 0;
    282     int i;
    283 
    284     frame_addr = get_sigframe(ka, env, sizeof *frame);
    285     trace_user_setup_rt_frame(env, frame_addr);
    286     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    287         goto give_sigsegv;
    288     }
    289 
    290     __put_user(sig, &frame->sig);
    291 
    292     info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
    293     __put_user(info_addr, &frame->pinfo);
    294 
    295     uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
    296     __put_user(uc_addr, &frame->puc);
    297 
    298     tswap_siginfo(&frame->info, info);
    299 
    300     /* Create the ucontext */
    301 
    302     __put_user(0, &frame->uc.tuc_flags);
    303     __put_user(0, &frame->uc.tuc_link);
    304     target_save_altstack(&frame->uc.tuc_stack, env);
    305     err |= target_rt_setup_ucontext(&frame->uc, env);
    306 
    307     if (err)
    308         goto give_sigsegv;
    309 
    310     for(i = 0; i < TARGET_NSIG_WORDS; i++) {
    311         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
    312     }
    313 
    314     /* Set up to return from userspace.  */
    315     __put_user(default_rt_sigreturn, &frame->pretcode);
    316 
    317     env->aregs[7] = frame_addr;
    318     env->pc = ka->_sa_handler;
    319 
    320     unlock_user_struct(frame, frame_addr, 1);
    321     return;
    322 
    323 give_sigsegv:
    324     unlock_user_struct(frame, frame_addr, 1);
    325     force_sigsegv(sig);
    326 }
    327 
    328 long do_sigreturn(CPUM68KState *env)
    329 {
    330     struct target_sigframe *frame;
    331     abi_ulong frame_addr = env->aregs[7] - 4;
    332     target_sigset_t target_set;
    333     sigset_t set;
    334     int i;
    335 
    336     trace_user_do_sigreturn(env, frame_addr);
    337     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
    338         goto badframe;
    339 
    340     /* set blocked signals */
    341 
    342     __get_user(target_set.sig[0], &frame->sc.sc_mask);
    343 
    344     for(i = 1; i < TARGET_NSIG_WORDS; i++) {
    345         __get_user(target_set.sig[i], &frame->extramask[i - 1]);
    346     }
    347 
    348     target_to_host_sigset_internal(&set, &target_set);
    349     set_sigmask(&set);
    350 
    351     /* restore registers */
    352 
    353     restore_sigcontext(env, &frame->sc);
    354 
    355     unlock_user_struct(frame, frame_addr, 0);
    356     return -QEMU_ESIGRETURN;
    357 
    358 badframe:
    359     force_sig(TARGET_SIGSEGV);
    360     return -QEMU_ESIGRETURN;
    361 }
    362 
    363 long do_rt_sigreturn(CPUM68KState *env)
    364 {
    365     struct target_rt_sigframe *frame;
    366     abi_ulong frame_addr = env->aregs[7] - 4;
    367     sigset_t set;
    368 
    369     trace_user_do_rt_sigreturn(env, frame_addr);
    370     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
    371         goto badframe;
    372 
    373     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
    374     set_sigmask(&set);
    375 
    376     /* restore registers */
    377 
    378     if (target_rt_restore_ucontext(env, &frame->uc))
    379         goto badframe;
    380 
    381     target_restore_altstack(&frame->uc.tuc_stack, env);
    382 
    383     unlock_user_struct(frame, frame_addr, 0);
    384     return -QEMU_ESIGRETURN;
    385 
    386 badframe:
    387     unlock_user_struct(frame, frame_addr, 0);
    388     force_sig(TARGET_SIGSEGV);
    389     return -QEMU_ESIGRETURN;
    390 }
    391 
    392 void setup_sigtramp(abi_ulong sigtramp_page)
    393 {
    394     void *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 4 + 6, 0);
    395     assert(tramp != NULL);
    396 
    397     default_sigreturn = sigtramp_page;
    398 
    399     /* moveq #,d0; trap #0 */
    400     __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16), (uint32_t *)tramp);
    401 
    402     default_rt_sigreturn = sigtramp_page + 4;
    403 
    404     /* moveq #,d0; notb d0; trap #0 */
    405     __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
    406                (uint32_t *)(tramp + 4));
    407     __put_user(0x4e40, (uint16_t *)(tramp + 8));
    408 
    409     unlock_user(tramp, sigtramp_page, 4 + 6);
    410 }