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, | ... | ... |