qemu/linux-user/m68k/signal.c
<<
>>
Prefs
   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 {
  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
  36struct 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
  46typedef int target_greg_t;
  47#define TARGET_NGREG 18
  48typedef target_greg_t target_gregset_t[TARGET_NGREG];
  49
  50typedef struct target_fpregset {
  51    int f_fpcntl[3];
  52    int f_fpregs[8*3];
  53} target_fpregset_t;
  54
  55struct target_mcontext {
  56    int version;
  57    target_gregset_t gregs;
  58    target_fpregset_t fpregs;
  59};
  60
  61#define TARGET_MCONTEXT_VERSION 2
  62
  63struct 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
  72struct 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
  82static 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
  96static void
  97restore_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 */
 114static inline abi_ulong
 115get_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
 126void 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
 160give_sigsegv:
 161    force_sigsegv(sig);
 162}
 163
 164static 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
 182static 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
 213static 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
 234static 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
 269badframe:
 270    return 1;
 271}
 272
 273void 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
 323give_sigsegv:
 324    unlock_user_struct(frame, frame_addr, 1);
 325    force_sigsegv(sig);
 326}
 327
 328long 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
 358badframe:
 359    force_sig(TARGET_SIGSEGV);
 360    return -QEMU_ESIGRETURN;
 361}
 362
 363long 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
 386badframe:
 387    unlock_user_struct(frame, frame_addr, 0);
 388    force_sig(TARGET_SIGSEGV);
 389    return -QEMU_ESIGRETURN;
 390}
 391
 392void 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}
 411