Commit bcd4933a23f1dbdb5b5546b81f3305ebcb13c9c0
Committed by
malc
1 parent
c29b735c
linux-user: ppc signal handling
Implement setup_{,rt_}frame and do_{,rt_}sigreturn for PPC 32-bit. Use the same TARGET_QEMU_ESIGRETURN hack as for MIPS to avoid clobbering register state on a sigreturn. Signed-off-by: Nathan Froyd <froydnj@codesourcery.com> Signed-off-by: malc <av1474@comtv.ru>
Showing
3 changed files
with
604 additions
and
0 deletions
linux-user/main.c
... | ... | @@ -1461,6 +1461,11 @@ void cpu_loop(CPUPPCState *env) |
1461 | 1461 | ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], |
1462 | 1462 | env->gpr[5], env->gpr[6], env->gpr[7], |
1463 | 1463 | env->gpr[8]); |
1464 | + if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) { | |
1465 | + /* Returning from a successful sigreturn syscall. | |
1466 | + Avoid corrupting register state. */ | |
1467 | + break; | |
1468 | + } | |
1464 | 1469 | if (ret > (uint32_t)(-515)) { |
1465 | 1470 | env->crf[0] |= 0x1; |
1466 | 1471 | ret = -ret; | ... | ... |
linux-user/ppc/syscall.h
linux-user/signal.c
... | ... | @@ -3182,6 +3182,602 @@ long do_rt_sigreturn(CPUState *env) |
3182 | 3182 | return -TARGET_ENOSYS; |
3183 | 3183 | } |
3184 | 3184 | |
3185 | +#elif defined(TARGET_PPC) && !defined(TARGET_PPC64) | |
3186 | + | |
3187 | +/* FIXME: Many of the structures are defined for both PPC and PPC64, but | |
3188 | + the signal handling is different enough that we haven't implemented | |
3189 | + support for PPC64 yet. Hence the restriction above. | |
3190 | + | |
3191 | + There are various #if'd blocks for code for TARGET_PPC64. These | |
3192 | + blocks should go away so that we can successfully run 32-bit and | |
3193 | + 64-bit binaries on a QEMU configured for PPC64. */ | |
3194 | + | |
3195 | +/* Size of dummy stack frame allocated when calling signal handler. | |
3196 | + See arch/powerpc/include/asm/ptrace.h. */ | |
3197 | +#if defined(TARGET_PPC64) | |
3198 | +#define SIGNAL_FRAMESIZE 128 | |
3199 | +#else | |
3200 | +#define SIGNAL_FRAMESIZE 64 | |
3201 | +#endif | |
3202 | + | |
3203 | +/* See arch/powerpc/include/asm/sigcontext.h. */ | |
3204 | +struct target_sigcontext { | |
3205 | + target_ulong _unused[4]; | |
3206 | + int32_t signal; | |
3207 | +#if defined(TARGET_PPC64) | |
3208 | + int32_t pad0; | |
3209 | +#endif | |
3210 | + target_ulong handler; | |
3211 | + target_ulong oldmask; | |
3212 | + target_ulong regs; /* struct pt_regs __user * */ | |
3213 | + /* TODO: PPC64 includes extra bits here. */ | |
3214 | +}; | |
3215 | + | |
3216 | +/* Indices for target_mcontext.mc_gregs, below. | |
3217 | + See arch/powerpc/include/asm/ptrace.h for details. */ | |
3218 | +enum { | |
3219 | + TARGET_PT_R0 = 0, | |
3220 | + TARGET_PT_R1 = 1, | |
3221 | + TARGET_PT_R2 = 2, | |
3222 | + TARGET_PT_R3 = 3, | |
3223 | + TARGET_PT_R4 = 4, | |
3224 | + TARGET_PT_R5 = 5, | |
3225 | + TARGET_PT_R6 = 6, | |
3226 | + TARGET_PT_R7 = 7, | |
3227 | + TARGET_PT_R8 = 8, | |
3228 | + TARGET_PT_R9 = 9, | |
3229 | + TARGET_PT_R10 = 10, | |
3230 | + TARGET_PT_R11 = 11, | |
3231 | + TARGET_PT_R12 = 12, | |
3232 | + TARGET_PT_R13 = 13, | |
3233 | + TARGET_PT_R14 = 14, | |
3234 | + TARGET_PT_R15 = 15, | |
3235 | + TARGET_PT_R16 = 16, | |
3236 | + TARGET_PT_R17 = 17, | |
3237 | + TARGET_PT_R18 = 18, | |
3238 | + TARGET_PT_R19 = 19, | |
3239 | + TARGET_PT_R20 = 20, | |
3240 | + TARGET_PT_R21 = 21, | |
3241 | + TARGET_PT_R22 = 22, | |
3242 | + TARGET_PT_R23 = 23, | |
3243 | + TARGET_PT_R24 = 24, | |
3244 | + TARGET_PT_R25 = 25, | |
3245 | + TARGET_PT_R26 = 26, | |
3246 | + TARGET_PT_R27 = 27, | |
3247 | + TARGET_PT_R28 = 28, | |
3248 | + TARGET_PT_R29 = 29, | |
3249 | + TARGET_PT_R30 = 30, | |
3250 | + TARGET_PT_R31 = 31, | |
3251 | + TARGET_PT_NIP = 32, | |
3252 | + TARGET_PT_MSR = 33, | |
3253 | + TARGET_PT_ORIG_R3 = 34, | |
3254 | + TARGET_PT_CTR = 35, | |
3255 | + TARGET_PT_LNK = 36, | |
3256 | + TARGET_PT_XER = 37, | |
3257 | + TARGET_PT_CCR = 38, | |
3258 | + /* Yes, there are two registers with #39. One is 64-bit only. */ | |
3259 | + TARGET_PT_MQ = 39, | |
3260 | + TARGET_PT_SOFTE = 39, | |
3261 | + TARGET_PT_TRAP = 40, | |
3262 | + TARGET_PT_DAR = 41, | |
3263 | + TARGET_PT_DSISR = 42, | |
3264 | + TARGET_PT_RESULT = 43, | |
3265 | + TARGET_PT_REGS_COUNT = 44 | |
3266 | +}; | |
3267 | + | |
3268 | +/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC; | |
3269 | + on 64-bit PPC, sigcontext and mcontext are one and the same. */ | |
3270 | +struct target_mcontext { | |
3271 | + target_ulong mc_gregs[48]; | |
3272 | + /* Includes fpscr. */ | |
3273 | + uint64_t mc_fregs[33]; | |
3274 | + target_ulong mc_pad[2]; | |
3275 | + /* We need to handle Altivec and SPE at the same time, which no | |
3276 | + kernel needs to do. Fortunately, the kernel defines this bit to | |
3277 | + be Altivec-register-large all the time, rather than trying to | |
3278 | + twiddle it based on the specific platform. */ | |
3279 | + union { | |
3280 | + /* SPE vector registers. One extra for SPEFSCR. */ | |
3281 | + uint32_t spe[33]; | |
3282 | + /* Altivec vector registers. The packing of VSCR and VRSAVE | |
3283 | + varies depending on whether we're PPC64 or not: PPC64 splits | |
3284 | + them apart; PPC32 stuffs them together. */ | |
3285 | +#if defined(TARGET_PPC64) | |
3286 | +#define NVRREG 34 | |
3287 | +#else | |
3288 | +#define NVRREG 33 | |
3289 | +#endif | |
3290 | + ppc_avr_t altivec[NVRREG]; | |
3291 | +#undef NVRREG | |
3292 | + } mc_vregs __attribute__((__aligned__(16))); | |
3293 | +}; | |
3294 | + | |
3295 | +struct target_ucontext { | |
3296 | + target_ulong uc_flags; | |
3297 | + target_ulong uc_link; /* struct ucontext __user * */ | |
3298 | + struct target_sigaltstack uc_stack; | |
3299 | +#if !defined(TARGET_PPC64) | |
3300 | + int32_t uc_pad[7]; | |
3301 | + target_ulong uc_regs; /* struct mcontext __user * | |
3302 | + points to uc_mcontext field */ | |
3303 | +#endif | |
3304 | + target_sigset_t uc_sigmask; | |
3305 | +#if defined(TARGET_PPC64) | |
3306 | + target_sigset_t unused[15]; /* Allow for uc_sigmask growth */ | |
3307 | + struct target_sigcontext uc_mcontext; | |
3308 | +#else | |
3309 | + int32_t uc_maskext[30]; | |
3310 | + int32_t uc_pad2[3]; | |
3311 | + struct target_mcontext uc_mcontext; | |
3312 | +#endif | |
3313 | +}; | |
3314 | + | |
3315 | +/* See arch/powerpc/kernel/signal_32.c. */ | |
3316 | +struct target_sigframe { | |
3317 | + struct target_sigcontext sctx; | |
3318 | + struct target_mcontext mctx; | |
3319 | + int32_t abigap[56]; | |
3320 | +}; | |
3321 | + | |
3322 | +struct target_rt_sigframe { | |
3323 | + struct target_siginfo info; | |
3324 | + struct target_ucontext uc; | |
3325 | + int32_t abigap[56]; | |
3326 | +}; | |
3327 | + | |
3328 | +/* We use the mc_pad field for the signal return trampoline. */ | |
3329 | +#define tramp mc_pad | |
3330 | + | |
3331 | +/* See arch/powerpc/kernel/signal.c. */ | |
3332 | +static target_ulong get_sigframe(struct target_sigaction *ka, | |
3333 | + CPUState *env, | |
3334 | + int frame_size) | |
3335 | +{ | |
3336 | + target_ulong oldsp, newsp; | |
3337 | + | |
3338 | + oldsp = env->gpr[1]; | |
3339 | + | |
3340 | + if ((ka->sa_flags & TARGET_SA_ONSTACK) && | |
3341 | + (sas_ss_flags(oldsp))) { | |
3342 | + oldsp = (target_sigaltstack_used.ss_sp | |
3343 | + + target_sigaltstack_used.ss_size); | |
3344 | + } | |
3345 | + | |
3346 | + newsp = (oldsp - frame_size) & ~0xFUL; | |
3347 | + | |
3348 | + return newsp; | |
3349 | +} | |
3350 | + | |
3351 | +static int save_user_regs(CPUState *env, struct target_mcontext *frame, | |
3352 | + int sigret) | |
3353 | +{ | |
3354 | + target_ulong msr = env->msr; | |
3355 | + int i; | |
3356 | + target_ulong ccr = 0; | |
3357 | + | |
3358 | + /* In general, the kernel attempts to be intelligent about what it | |
3359 | + needs to save for Altivec/FP/SPE registers. We don't care that | |
3360 | + much, so we just go ahead and save everything. */ | |
3361 | + | |
3362 | + /* Save general registers. */ | |
3363 | + for (i = 0; i < ARRAY_SIZE(env->gpr); i++) { | |
3364 | + if (__put_user(env->gpr[i], &frame->mc_gregs[i])) { | |
3365 | + return 1; | |
3366 | + } | |
3367 | + } | |
3368 | + if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]) | |
3369 | + || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]) | |
3370 | + || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]) | |
3371 | + || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER])) | |
3372 | + return 1; | |
3373 | + | |
3374 | + for (i = 0; i < ARRAY_SIZE(env->crf); i++) { | |
3375 | + ccr |= env->crf[i] << (32 - ((i + 1) * 4)); | |
3376 | + } | |
3377 | + if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR])) | |
3378 | + return 1; | |
3379 | + | |
3380 | + /* Save Altivec registers if necessary. */ | |
3381 | + if (env->insns_flags & PPC_ALTIVEC) { | |
3382 | + for (i = 0; i < ARRAY_SIZE(env->avr); i++) { | |
3383 | + ppc_avr_t *avr = &env->avr[i]; | |
3384 | + ppc_avr_t *vreg = &frame->mc_vregs.altivec[i]; | |
3385 | + | |
3386 | + if (__put_user(avr->u64[0], &vreg->u64[0]) || | |
3387 | + __put_user(avr->u64[1], &vreg->u64[1])) { | |
3388 | + return 1; | |
3389 | + } | |
3390 | + } | |
3391 | + /* Set MSR_VR in the saved MSR value to indicate that | |
3392 | + frame->mc_vregs contains valid data. */ | |
3393 | + msr |= MSR_VR; | |
3394 | + if (__put_user((uint32_t)env->spr[SPR_VRSAVE], | |
3395 | + &frame->mc_vregs.altivec[32].u32[3])) | |
3396 | + return 1; | |
3397 | + } | |
3398 | + | |
3399 | + /* Save floating point registers. */ | |
3400 | + if (env->insns_flags & PPC_FLOAT) { | |
3401 | + for (i = 0; i < ARRAY_SIZE(env->fpr); i++) { | |
3402 | + if (__put_user(env->fpr[i], &frame->mc_fregs[i])) { | |
3403 | + return 1; | |
3404 | + } | |
3405 | + } | |
3406 | + if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32])) | |
3407 | + return 1; | |
3408 | + } | |
3409 | + | |
3410 | + /* Save SPE registers. The kernel only saves the high half. */ | |
3411 | + if (env->insns_flags & PPC_SPE) { | |
3412 | +#if defined(TARGET_PPC64) | |
3413 | + for (i = 0; i < ARRAY_SIZE(env->gpr); i++) { | |
3414 | + if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) { | |
3415 | + return 1; | |
3416 | + } | |
3417 | + } | |
3418 | +#else | |
3419 | + for (i = 0; i < ARRAY_SIZE(env->gprh); i++) { | |
3420 | + if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) { | |
3421 | + return 1; | |
3422 | + } | |
3423 | + } | |
3424 | +#endif | |
3425 | + /* Set MSR_SPE in the saved MSR value to indicate that | |
3426 | + frame->mc_vregs contains valid data. */ | |
3427 | + msr |= MSR_SPE; | |
3428 | + if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32])) | |
3429 | + return 1; | |
3430 | + } | |
3431 | + | |
3432 | + /* Store MSR. */ | |
3433 | + if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR])) | |
3434 | + return 1; | |
3435 | + | |
3436 | + /* Set up the sigreturn trampoline: li r0,sigret; sc. */ | |
3437 | + if (sigret) { | |
3438 | + if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) || | |
3439 | + __put_user(0x44000002UL, &frame->tramp[1])) { | |
3440 | + return 1; | |
3441 | + } | |
3442 | + } | |
3443 | + | |
3444 | + return 0; | |
3445 | +} | |
3446 | + | |
3447 | +static int restore_user_regs(CPUState *env, | |
3448 | + struct target_mcontext *frame, int sig) | |
3449 | +{ | |
3450 | + target_ulong save_r2 = 0; | |
3451 | + target_ulong msr; | |
3452 | + target_ulong ccr; | |
3453 | + | |
3454 | + int i; | |
3455 | + | |
3456 | + if (!sig) { | |
3457 | + save_r2 = env->gpr[2]; | |
3458 | + } | |
3459 | + | |
3460 | + /* Restore general registers. */ | |
3461 | + for (i = 0; i < ARRAY_SIZE(env->gpr); i++) { | |
3462 | + if (__get_user(env->gpr[i], &frame->mc_gregs[i])) { | |
3463 | + return 1; | |
3464 | + } | |
3465 | + } | |
3466 | + if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]) | |
3467 | + || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]) | |
3468 | + || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]) | |
3469 | + || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER])) | |
3470 | + return 1; | |
3471 | + if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR])) | |
3472 | + return 1; | |
3473 | + | |
3474 | + for (i = 0; i < ARRAY_SIZE(env->crf); i++) { | |
3475 | + env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf; | |
3476 | + } | |
3477 | + | |
3478 | + if (!sig) { | |
3479 | + env->gpr[2] = save_r2; | |
3480 | + } | |
3481 | + /* Restore MSR. */ | |
3482 | + if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR])) | |
3483 | + return 1; | |
3484 | + | |
3485 | + /* If doing signal return, restore the previous little-endian mode. */ | |
3486 | + if (sig) | |
3487 | + env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE); | |
3488 | + | |
3489 | + /* Restore Altivec registers if necessary. */ | |
3490 | + if (env->insns_flags & PPC_ALTIVEC) { | |
3491 | + for (i = 0; i < ARRAY_SIZE(env->avr); i++) { | |
3492 | + ppc_avr_t *avr = &env->avr[i]; | |
3493 | + ppc_avr_t *vreg = &frame->mc_vregs.altivec[i]; | |
3494 | + | |
3495 | + if (__get_user(avr->u64[0], &vreg->u64[0]) || | |
3496 | + __get_user(avr->u64[1], &vreg->u64[1])) { | |
3497 | + return 1; | |
3498 | + } | |
3499 | + } | |
3500 | + /* Set MSR_VEC in the saved MSR value to indicate that | |
3501 | + frame->mc_vregs contains valid data. */ | |
3502 | + if (__get_user(env->spr[SPR_VRSAVE], | |
3503 | + (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]))) | |
3504 | + return 1; | |
3505 | + } | |
3506 | + | |
3507 | + /* Restore floating point registers. */ | |
3508 | + if (env->insns_flags & PPC_FLOAT) { | |
3509 | + uint64_t fpscr; | |
3510 | + for (i = 0; i < ARRAY_SIZE(env->fpr); i++) { | |
3511 | + if (__get_user(env->fpr[i], &frame->mc_fregs[i])) { | |
3512 | + return 1; | |
3513 | + } | |
3514 | + } | |
3515 | + if (__get_user(fpscr, &frame->mc_fregs[32])) | |
3516 | + return 1; | |
3517 | + env->fpscr = (uint32_t) fpscr; | |
3518 | + } | |
3519 | + | |
3520 | + /* Save SPE registers. The kernel only saves the high half. */ | |
3521 | + if (env->insns_flags & PPC_SPE) { | |
3522 | +#if defined(TARGET_PPC64) | |
3523 | + for (i = 0; i < ARRAY_SIZE(env->gpr); i++) { | |
3524 | + uint32_t hi; | |
3525 | + | |
3526 | + if (__get_user(hi, &frame->mc_vregs.spe[i])) { | |
3527 | + return 1; | |
3528 | + } | |
3529 | + env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]); | |
3530 | + } | |
3531 | +#else | |
3532 | + for (i = 0; i < ARRAY_SIZE(env->gprh); i++) { | |
3533 | + if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) { | |
3534 | + return 1; | |
3535 | + } | |
3536 | + } | |
3537 | +#endif | |
3538 | + if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32])) | |
3539 | + return 1; | |
3540 | + } | |
3541 | + | |
3542 | + return 0; | |
3543 | +} | |
3544 | + | |
3545 | +static void setup_frame(int sig, struct target_sigaction *ka, | |
3546 | + target_sigset_t *set, CPUState *env) | |
3547 | +{ | |
3548 | + struct target_sigframe *frame; | |
3549 | + struct target_sigcontext *sc; | |
3550 | + target_ulong frame_addr, newsp; | |
3551 | + int err = 0; | |
3552 | + int signal; | |
3553 | + | |
3554 | + frame_addr = get_sigframe(ka, env, sizeof(*frame)); | |
3555 | + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) | |
3556 | + goto sigsegv; | |
3557 | + sc = &frame->sctx; | |
3558 | + | |
3559 | + signal = current_exec_domain_sig(sig); | |
3560 | + | |
3561 | + err |= __put_user(h2g(ka->_sa_handler), &sc->handler); | |
3562 | + err |= __put_user(set->sig[0], &sc->oldmask); | |
3563 | +#if defined(TARGET_PPC64) | |
3564 | + err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]); | |
3565 | +#else | |
3566 | + err |= __put_user(set->sig[1], &sc->_unused[3]); | |
3567 | +#endif | |
3568 | + err |= __put_user(h2g(&frame->mctx), &sc->regs); | |
3569 | + err |= __put_user(sig, &sc->signal); | |
3570 | + | |
3571 | + /* Save user regs. */ | |
3572 | + err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn); | |
3573 | + | |
3574 | + /* The kernel checks for the presence of a VDSO here. We don't | |
3575 | + emulate a vdso, so use a sigreturn system call. */ | |
3576 | + env->lr = (target_ulong) h2g(frame->mctx.tramp); | |
3577 | + | |
3578 | + /* Turn off all fp exceptions. */ | |
3579 | + env->fpscr = 0; | |
3580 | + | |
3581 | + /* Create a stack frame for the caller of the handler. */ | |
3582 | + newsp = frame_addr - SIGNAL_FRAMESIZE; | |
3583 | + err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp); | |
3584 | + | |
3585 | + if (err) | |
3586 | + goto sigsegv; | |
3587 | + | |
3588 | + /* Set up registers for signal handler. */ | |
3589 | + env->gpr[1] = newsp; | |
3590 | + env->gpr[3] = signal; | |
3591 | + env->gpr[4] = (target_ulong) h2g(sc); | |
3592 | + env->nip = (target_ulong) ka->_sa_handler; | |
3593 | + /* Signal handlers are entered in big-endian mode. */ | |
3594 | + env->msr &= ~MSR_LE; | |
3595 | + | |
3596 | + unlock_user_struct(frame, frame_addr, 1); | |
3597 | + return; | |
3598 | + | |
3599 | +sigsegv: | |
3600 | + unlock_user_struct(frame, frame_addr, 1); | |
3601 | + if (logfile) | |
3602 | + fprintf (logfile, "segfaulting from setup_frame\n"); | |
3603 | + force_sig(SIGSEGV); | |
3604 | +} | |
3605 | + | |
3606 | +static void setup_rt_frame(int sig, struct target_sigaction *ka, | |
3607 | + target_siginfo_t *info, | |
3608 | + target_sigset_t *set, CPUState *env) | |
3609 | +{ | |
3610 | + struct target_rt_sigframe *rt_sf; | |
3611 | + struct target_mcontext *frame; | |
3612 | + target_ulong rt_sf_addr, newsp = 0; | |
3613 | + int i, err = 0; | |
3614 | + int signal; | |
3615 | + | |
3616 | + rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf)); | |
3617 | + if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1)) | |
3618 | + goto sigsegv; | |
3619 | + | |
3620 | + signal = current_exec_domain_sig(sig); | |
3621 | + | |
3622 | + err |= copy_siginfo_to_user(&rt_sf->info, info); | |
3623 | + | |
3624 | + err |= __put_user(0, &rt_sf->uc.uc_flags); | |
3625 | + err |= __put_user(0, &rt_sf->uc.uc_link); | |
3626 | + err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp, | |
3627 | + &rt_sf->uc.uc_stack.ss_sp); | |
3628 | + err |= __put_user(sas_ss_flags(env->gpr[1]), | |
3629 | + &rt_sf->uc.uc_stack.ss_flags); | |
3630 | + err |= __put_user(target_sigaltstack_used.ss_size, | |
3631 | + &rt_sf->uc.uc_stack.ss_size); | |
3632 | + err |= __put_user(h2g (&rt_sf->uc.uc_mcontext), | |
3633 | + &rt_sf->uc.uc_regs); | |
3634 | + for(i = 0; i < TARGET_NSIG_WORDS; i++) { | |
3635 | + err |= __put_user(set->sig[i], &rt_sf->uc.uc_sigmask.sig[i]); | |
3636 | + } | |
3637 | + | |
3638 | + frame = &rt_sf->uc.uc_mcontext; | |
3639 | + err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn); | |
3640 | + | |
3641 | + /* The kernel checks for the presence of a VDSO here. We don't | |
3642 | + emulate a vdso, so use a sigreturn system call. */ | |
3643 | + env->lr = (target_ulong) h2g(frame->tramp); | |
3644 | + | |
3645 | + /* Turn off all fp exceptions. */ | |
3646 | + env->fpscr = 0; | |
3647 | + | |
3648 | + /* Create a stack frame for the caller of the handler. */ | |
3649 | + newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16); | |
3650 | + err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp); | |
3651 | + | |
3652 | + if (err) | |
3653 | + goto sigsegv; | |
3654 | + | |
3655 | + /* Set up registers for signal handler. */ | |
3656 | + env->gpr[1] = newsp; | |
3657 | + env->gpr[3] = (target_ulong) signal; | |
3658 | + env->gpr[4] = (target_ulong) h2g(&rt_sf->info); | |
3659 | + env->gpr[5] = (target_ulong) h2g(&rt_sf->uc); | |
3660 | + env->gpr[6] = (target_ulong) h2g(rt_sf); | |
3661 | + env->nip = (target_ulong) ka->_sa_handler; | |
3662 | + /* Signal handlers are entered in big-endian mode. */ | |
3663 | + env->msr &= ~MSR_LE; | |
3664 | + | |
3665 | + unlock_user_struct(rt_sf, rt_sf_addr, 1); | |
3666 | + return; | |
3667 | + | |
3668 | +sigsegv: | |
3669 | + unlock_user_struct(rt_sf, rt_sf_addr, 1); | |
3670 | + if (logfile) | |
3671 | + fprintf (logfile, "segfaulting from setup_rt_frame\n"); | |
3672 | + force_sig(SIGSEGV); | |
3673 | + | |
3674 | +} | |
3675 | + | |
3676 | +long do_sigreturn(CPUState *env) | |
3677 | +{ | |
3678 | + struct target_sigcontext *sc = NULL; | |
3679 | + struct target_mcontext *sr = NULL; | |
3680 | + target_ulong sr_addr, sc_addr; | |
3681 | + sigset_t blocked; | |
3682 | + target_sigset_t set; | |
3683 | + | |
3684 | + sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE; | |
3685 | + if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) | |
3686 | + goto sigsegv; | |
3687 | + | |
3688 | +#if defined(TARGET_PPC64) | |
3689 | + set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32); | |
3690 | +#else | |
3691 | + if(__get_user(set.sig[0], &sc->oldmask) || | |
3692 | + __get_user(set.sig[1], &sc->_unused[3])) | |
3693 | + goto sigsegv; | |
3694 | +#endif | |
3695 | + target_to_host_sigset_internal(&blocked, &set); | |
3696 | + sigprocmask(SIG_SETMASK, &blocked, NULL); | |
3697 | + | |
3698 | + if (__get_user(sr_addr, &sc->regs)) | |
3699 | + goto sigsegv; | |
3700 | + if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1)) | |
3701 | + goto sigsegv; | |
3702 | + if (restore_user_regs(env, sr, 1)) | |
3703 | + goto sigsegv; | |
3704 | + | |
3705 | + unlock_user_struct(sr, sr_addr, 1); | |
3706 | + unlock_user_struct(sc, sc_addr, 1); | |
3707 | + return -TARGET_QEMU_ESIGRETURN; | |
3708 | + | |
3709 | +sigsegv: | |
3710 | + unlock_user_struct(sr, sr_addr, 1); | |
3711 | + unlock_user_struct(sc, sc_addr, 1); | |
3712 | + if (logfile) | |
3713 | + fprintf (logfile, "segfaulting from do_sigreturn\n"); | |
3714 | + force_sig(SIGSEGV); | |
3715 | + return 0; | |
3716 | +} | |
3717 | + | |
3718 | +/* See arch/powerpc/kernel/signal_32.c. */ | |
3719 | +static int do_setcontext(struct target_ucontext *ucp, CPUState *env, int sig) | |
3720 | +{ | |
3721 | + struct target_mcontext *mcp; | |
3722 | + target_ulong mcp_addr; | |
3723 | + sigset_t blocked; | |
3724 | + target_sigset_t set; | |
3725 | + | |
3726 | + if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, uc_sigmask), | |
3727 | + sizeof (set))) | |
3728 | + return 1; | |
3729 | + | |
3730 | +#if defined(TARGET_PPC64) | |
3731 | + fprintf (stderr, "do_setcontext: not implemented\n"); | |
3732 | + return 0; | |
3733 | +#else | |
3734 | + if (__get_user(mcp_addr, &ucp->uc_regs)) | |
3735 | + return 1; | |
3736 | + | |
3737 | + if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1)) | |
3738 | + return 1; | |
3739 | + | |
3740 | + target_to_host_sigset_internal(&blocked, &set); | |
3741 | + sigprocmask(SIG_SETMASK, &blocked, NULL); | |
3742 | + if (restore_user_regs(env, mcp, sig)) | |
3743 | + goto sigsegv; | |
3744 | + | |
3745 | + unlock_user_struct(mcp, mcp_addr, 1); | |
3746 | + return 0; | |
3747 | + | |
3748 | +sigsegv: | |
3749 | + unlock_user_struct(mcp, mcp_addr, 1); | |
3750 | + return 1; | |
3751 | +#endif | |
3752 | +} | |
3753 | + | |
3754 | +long do_rt_sigreturn(CPUState *env) | |
3755 | +{ | |
3756 | + struct target_rt_sigframe *rt_sf = NULL; | |
3757 | + target_ulong rt_sf_addr; | |
3758 | + | |
3759 | + rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16; | |
3760 | + if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1)) | |
3761 | + goto sigsegv; | |
3762 | + | |
3763 | + if (do_setcontext(&rt_sf->uc, env, 1)) | |
3764 | + goto sigsegv; | |
3765 | + | |
3766 | + do_sigaltstack(rt_sf_addr | |
3767 | + + offsetof(struct target_rt_sigframe, uc.uc_stack), | |
3768 | + 0, env->gpr[1]); | |
3769 | + | |
3770 | + unlock_user_struct(rt_sf, rt_sf_addr, 1); | |
3771 | + return -TARGET_QEMU_ESIGRETURN; | |
3772 | + | |
3773 | +sigsegv: | |
3774 | + unlock_user_struct(rt_sf, rt_sf_addr, 1); | |
3775 | + if (logfile) | |
3776 | + fprintf (logfile, "segfaulting from do_rt_sigreturn\n"); | |
3777 | + force_sig(SIGSEGV); | |
3778 | + return 0; | |
3779 | +} | |
3780 | + | |
3185 | 3781 | #else |
3186 | 3782 | |
3187 | 3783 | static void setup_frame(int sig, struct target_sigaction *ka, | ... | ... |