Revision 6049f4f8 linux-user/signal.c
b/linux-user/signal.c | ||
---|---|---|
4410 | 4410 |
return 0; |
4411 | 4411 |
} |
4412 | 4412 |
|
4413 |
#elif defined(TARGET_ALPHA) |
|
4414 |
|
|
4415 |
struct target_sigcontext { |
|
4416 |
abi_long sc_onstack; |
|
4417 |
abi_long sc_mask; |
|
4418 |
abi_long sc_pc; |
|
4419 |
abi_long sc_ps; |
|
4420 |
abi_long sc_regs[32]; |
|
4421 |
abi_long sc_ownedfp; |
|
4422 |
abi_long sc_fpregs[32]; |
|
4423 |
abi_ulong sc_fpcr; |
|
4424 |
abi_ulong sc_fp_control; |
|
4425 |
abi_ulong sc_reserved1; |
|
4426 |
abi_ulong sc_reserved2; |
|
4427 |
abi_ulong sc_ssize; |
|
4428 |
abi_ulong sc_sbase; |
|
4429 |
abi_ulong sc_traparg_a0; |
|
4430 |
abi_ulong sc_traparg_a1; |
|
4431 |
abi_ulong sc_traparg_a2; |
|
4432 |
abi_ulong sc_fp_trap_pc; |
|
4433 |
abi_ulong sc_fp_trigger_sum; |
|
4434 |
abi_ulong sc_fp_trigger_inst; |
|
4435 |
}; |
|
4436 |
|
|
4437 |
struct target_ucontext { |
|
4438 |
abi_ulong uc_flags; |
|
4439 |
abi_ulong uc_link; |
|
4440 |
abi_ulong uc_osf_sigmask; |
|
4441 |
target_stack_t uc_stack; |
|
4442 |
struct target_sigcontext uc_mcontext; |
|
4443 |
target_sigset_t uc_sigmask; |
|
4444 |
}; |
|
4445 |
|
|
4446 |
struct target_sigframe { |
|
4447 |
struct target_sigcontext sc; |
|
4448 |
unsigned int retcode[3]; |
|
4449 |
}; |
|
4450 |
|
|
4451 |
struct target_rt_sigframe { |
|
4452 |
target_siginfo_t info; |
|
4453 |
struct target_ucontext uc; |
|
4454 |
unsigned int retcode[3]; |
|
4455 |
}; |
|
4456 |
|
|
4457 |
#define INSN_MOV_R30_R16 0x47fe0410 |
|
4458 |
#define INSN_LDI_R0 0x201f0000 |
|
4459 |
#define INSN_CALLSYS 0x00000083 |
|
4460 |
|
|
4461 |
static int setup_sigcontext(struct target_sigcontext *sc, CPUState *env, |
|
4462 |
abi_ulong frame_addr, target_sigset_t *set) |
|
4463 |
{ |
|
4464 |
int i, err = 0; |
|
4465 |
|
|
4466 |
err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); |
|
4467 |
err |= __put_user(set->sig[0], &sc->sc_mask); |
|
4468 |
err |= __put_user(env->pc, &sc->sc_pc); |
|
4469 |
err |= __put_user(8, &sc->sc_ps); |
|
4470 |
|
|
4471 |
for (i = 0; i < 31; ++i) { |
|
4472 |
err |= __put_user(env->ir[i], &sc->sc_regs[i]); |
|
4473 |
} |
|
4474 |
err |= __put_user(0, &sc->sc_regs[31]); |
|
4475 |
|
|
4476 |
for (i = 0; i < 31; ++i) { |
|
4477 |
err |= __put_user(env->fir[i], &sc->sc_fpregs[i]); |
|
4478 |
} |
|
4479 |
err |= __put_user(0, &sc->sc_fpregs[31]); |
|
4480 |
err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr); |
|
4481 |
|
|
4482 |
err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */ |
|
4483 |
err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */ |
|
4484 |
err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */ |
|
4485 |
|
|
4486 |
return err; |
|
4487 |
} |
|
4488 |
|
|
4489 |
static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc) |
|
4490 |
{ |
|
4491 |
uint64_t fpcr; |
|
4492 |
int i, err = 0; |
|
4493 |
|
|
4494 |
err |= __get_user(env->pc, &sc->sc_pc); |
|
4495 |
|
|
4496 |
for (i = 0; i < 31; ++i) { |
|
4497 |
err |= __get_user(env->ir[i], &sc->sc_regs[i]); |
|
4498 |
} |
|
4499 |
for (i = 0; i < 31; ++i) { |
|
4500 |
err |= __get_user(env->fir[i], &sc->sc_fpregs[i]); |
|
4501 |
} |
|
4502 |
|
|
4503 |
err |= __get_user(fpcr, &sc->sc_fpcr); |
|
4504 |
cpu_alpha_store_fpcr(env, fpcr); |
|
4505 |
|
|
4506 |
return err; |
|
4507 |
} |
|
4508 |
|
|
4509 |
static inline abi_ulong get_sigframe(struct target_sigaction *sa, |
|
4510 |
CPUState *env, unsigned long framesize) |
|
4511 |
{ |
|
4512 |
abi_ulong sp = env->ir[IR_SP]; |
|
4513 |
|
|
4514 |
/* This is the X/Open sanctioned signal stack switching. */ |
|
4515 |
if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { |
|
4516 |
sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; |
|
4517 |
} |
|
4518 |
return (sp - framesize) & -32; |
|
4519 |
} |
|
4520 |
|
|
4521 |
static void setup_frame(int sig, struct target_sigaction *ka, |
|
4522 |
target_sigset_t *set, CPUState *env) |
|
4523 |
{ |
|
4524 |
abi_ulong frame_addr, r26; |
|
4525 |
struct target_sigframe *frame; |
|
4526 |
int err = 0; |
|
4527 |
|
|
4528 |
frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
|
4529 |
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { |
|
4530 |
goto give_sigsegv; |
|
4531 |
} |
|
4532 |
|
|
4533 |
err |= setup_sigcontext(&frame->sc, env, frame_addr, set); |
|
4534 |
|
|
4535 |
if (ka->sa_restorer) { |
|
4536 |
r26 = ka->sa_restorer; |
|
4537 |
} else { |
|
4538 |
err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); |
|
4539 |
err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, |
|
4540 |
&frame->retcode[1]); |
|
4541 |
err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); |
|
4542 |
/* imb() */ |
|
4543 |
r26 = frame_addr; |
|
4544 |
} |
|
4545 |
|
|
4546 |
unlock_user_struct(frame, frame_addr, 1); |
|
4547 |
|
|
4548 |
if (err) { |
|
4549 |
give_sigsegv: |
|
4550 |
if (sig == TARGET_SIGSEGV) { |
|
4551 |
ka->_sa_handler = TARGET_SIG_DFL; |
|
4552 |
} |
|
4553 |
force_sig(TARGET_SIGSEGV); |
|
4554 |
} |
|
4555 |
|
|
4556 |
env->ir[IR_RA] = r26; |
|
4557 |
env->ir[IR_PV] = env->pc = ka->_sa_handler; |
|
4558 |
env->ir[IR_A0] = sig; |
|
4559 |
env->ir[IR_A1] = 0; |
|
4560 |
env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc); |
|
4561 |
env->ir[IR_SP] = frame_addr; |
|
4562 |
} |
|
4563 |
|
|
4564 |
static void setup_rt_frame(int sig, struct target_sigaction *ka, |
|
4565 |
target_siginfo_t *info, |
|
4566 |
target_sigset_t *set, CPUState *env) |
|
4567 |
{ |
|
4568 |
abi_ulong frame_addr, r26; |
|
4569 |
struct target_rt_sigframe *frame; |
|
4570 |
int i, err = 0; |
|
4571 |
|
|
4572 |
frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
|
4573 |
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { |
|
4574 |
goto give_sigsegv; |
|
4575 |
} |
|
4576 |
|
|
4577 |
err |= copy_siginfo_to_user(&frame->info, info); |
|
4578 |
|
|
4579 |
err |= __put_user(0, &frame->uc.uc_flags); |
|
4580 |
err |= __put_user(0, &frame->uc.uc_link); |
|
4581 |
err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); |
|
4582 |
err |= __put_user(target_sigaltstack_used.ss_sp, |
|
4583 |
&frame->uc.uc_stack.ss_sp); |
|
4584 |
err |= __put_user(sas_ss_flags(env->ir[IR_SP]), |
|
4585 |
&frame->uc.uc_stack.ss_flags); |
|
4586 |
err |= __put_user(target_sigaltstack_used.ss_size, |
|
4587 |
&frame->uc.uc_stack.ss_size); |
|
4588 |
err |= setup_sigcontext(&frame->uc.uc_mcontext, env, frame_addr, set); |
|
4589 |
for (i = 0; i < TARGET_NSIG_WORDS; ++i) { |
|
4590 |
err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); |
|
4591 |
} |
|
4592 |
|
|
4593 |
if (ka->sa_restorer) { |
|
4594 |
r26 = ka->sa_restorer; |
|
4595 |
} else { |
|
4596 |
err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); |
|
4597 |
err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, |
|
4598 |
&frame->retcode[1]); |
|
4599 |
err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); |
|
4600 |
/* imb(); */ |
|
4601 |
r26 = frame_addr; |
|
4602 |
} |
|
4603 |
|
|
4604 |
if (err) { |
|
4605 |
give_sigsegv: |
|
4606 |
if (sig == TARGET_SIGSEGV) { |
|
4607 |
ka->_sa_handler = TARGET_SIG_DFL; |
|
4608 |
} |
|
4609 |
force_sig(TARGET_SIGSEGV); |
|
4610 |
} |
|
4611 |
|
|
4612 |
env->ir[IR_RA] = r26; |
|
4613 |
env->ir[IR_PV] = env->pc = ka->_sa_handler; |
|
4614 |
env->ir[IR_A0] = sig; |
|
4615 |
env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); |
|
4616 |
env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); |
|
4617 |
env->ir[IR_SP] = frame_addr; |
|
4618 |
} |
|
4619 |
|
|
4620 |
long do_sigreturn(CPUState *env) |
|
4621 |
{ |
|
4622 |
struct target_sigcontext *sc; |
|
4623 |
abi_ulong sc_addr = env->ir[IR_A0]; |
|
4624 |
target_sigset_t target_set; |
|
4625 |
sigset_t set; |
|
4626 |
|
|
4627 |
if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { |
|
4628 |
goto badframe; |
|
4629 |
} |
|
4630 |
|
|
4631 |
target_sigemptyset(&target_set); |
|
4632 |
if (__get_user(target_set.sig[0], &sc->sc_mask)) { |
|
4633 |
goto badframe; |
|
4634 |
} |
|
4635 |
|
|
4636 |
target_to_host_sigset_internal(&set, &target_set); |
|
4637 |
sigprocmask(SIG_SETMASK, &set, NULL); |
|
4638 |
|
|
4639 |
if (restore_sigcontext(env, sc)) { |
|
4640 |
goto badframe; |
|
4641 |
} |
|
4642 |
unlock_user_struct(sc, sc_addr, 0); |
|
4643 |
return env->ir[IR_V0]; |
|
4644 |
|
|
4645 |
badframe: |
|
4646 |
unlock_user_struct(sc, sc_addr, 0); |
|
4647 |
force_sig(TARGET_SIGSEGV); |
|
4648 |
} |
|
4649 |
|
|
4650 |
long do_rt_sigreturn(CPUState *env) |
|
4651 |
{ |
|
4652 |
abi_ulong frame_addr = env->ir[IR_A0]; |
|
4653 |
struct target_rt_sigframe *frame; |
|
4654 |
sigset_t set; |
|
4655 |
|
|
4656 |
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { |
|
4657 |
goto badframe; |
|
4658 |
} |
|
4659 |
target_to_host_sigset(&set, &frame->uc.uc_sigmask); |
|
4660 |
sigprocmask(SIG_SETMASK, &set, NULL); |
|
4661 |
|
|
4662 |
if (restore_sigcontext(env, &frame->uc.uc_mcontext)) { |
|
4663 |
goto badframe; |
|
4664 |
} |
|
4665 |
if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, |
|
4666 |
uc.uc_stack), |
|
4667 |
0, env->ir[IR_SP]) == -EFAULT) { |
|
4668 |
goto badframe; |
|
4669 |
} |
|
4670 |
|
|
4671 |
unlock_user_struct(frame, frame_addr, 0); |
|
4672 |
return env->ir[IR_V0]; |
|
4673 |
|
|
4674 |
|
|
4675 |
badframe: |
|
4676 |
unlock_user_struct(frame, frame_addr, 0); |
|
4677 |
force_sig(TARGET_SIGSEGV); |
|
4678 |
} |
|
4679 |
|
|
4413 | 4680 |
#else |
4414 | 4681 |
|
4415 | 4682 |
static void setup_frame(int sig, struct target_sigaction *ka, |
Also available in: Unified diff