mirror of https://github.com/xemu-project/xemu.git
Pull request linux-user 20211004
Move signal trampolines to new page -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmFasLkSHGxhdXJlbnRA dml2aWVyLmV1AAoJEPMMOL0/L7483WwP/jqpk4ZRV8aOzGH6CMEiGzzHl2PdzshO lx7LWTgcB74SWohsTKlTviSQj0lc2iVC3LsZ+yFUiVU9kPpWFhtdzbxyvnfm1hyM pR80Zc3Paod+Jb9x8eTn0iT/ccP1ySFAoK4TJCuDBfV6lMThmRmBEebAKxc4ZGCk pXRxvk1wSIwykPD4Wp7cmSqYJLn2ajMkCn3g+/SWUJ4HMKkEYZMRsB51nl8SrBa4 /UPdeOaQrtjRY1veOsjmJ16xWyy1YtpDfo41ymST6HDo9yfik/0orX6tvjQhQo4g SP6a6Lp528ePa6JacIhs9r7HWMWTm+AhDWjk+N+WS2zp0jMJXF8/0p0NYDYHzH9V eRx6zOcDkxfxV2KlQ8fOd8Kmj2d/leORcVOpZpWV3sS3G1/80LyTzeT4kkbRXrzw /ujZyPGGy6GX2VQkvA05NPH7Sy/Uv1Oqr7wkCeHQVbvMghjwNAdeIbTQ2hBWJp/D S0pw7XS41ktIKYH5ui1EYaRKTIQ0gh5ecbO1CySpVZvgqTOoK2ps0H+nZtgiLySC yukNVIkbdODqgeBi19kitqP2eJHIq/SRFp4WTBRgSla4mMorVnfrvDreW6my/aC+ yK+YVbCYx4vWB7yOWL5SLvb1DcQIqyKeJdN7W3LtkkiBXqUxlb6Dmmr6wrCCOCfP qCuRrc/MvzfO =59lT -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/vivier/tags/linux-user-for-6.2-pull-request' into staging Pull request linux-user 20211004 Move signal trampolines to new page # gpg: Signature made Mon 04 Oct 2021 12:43:53 AM PDT # gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C # gpg: issuer "laurent@vivier.eu" # gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full] # gpg: aka "Laurent Vivier <laurent@vivier.eu>" [full] # gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full] * remotes/vivier/tags/linux-user-for-6.2-pull-request: (26 commits) tests/tcg/multiarch: Re-enable signals test for most guests linux-user: Remove default for TARGET_ARCH_HAS_SIGTRAMP_PAGE linux-user/xtensa: Implement setup_sigtramp linux-user/sparc: Implement setup_sigtramp linux-user/sh4: Implement setup_sigtramp linux-user/s390x: Implement setup_sigtramp linux-user/riscv: Implement setup_sigtramp linux-user/ppc: Implement setup_sigtramp linux-user/ppc: Simplify encode_trampoline linux-user/openrisc: Implement setup_sigtramp linux-user/nios2: Document non-use of setup_sigtramp linux-user/mips: Implement setup_sigtramp linux-user/mips: Tidy install_sigtramp linux-user/microblaze: Implement setup_sigtramp linux-user/m68k: Implement setup_sigtramp linux-user/x86_64: Raise SIGSEGV if SA_RESTORER not set linux-user/i386: Implement setup_sigtramp linux-user/hppa: Document non-use of setup_sigtramp linux-user/hexagon: Implement setup_sigtramp linux-user/cris: Implement setup_sigtramp ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
e7ab658478
|
@ -109,7 +109,6 @@ struct target_rt_sigframe {
|
|||
struct target_rt_frame_record {
|
||||
uint64_t fp;
|
||||
uint64_t lr;
|
||||
uint32_t tramp[2];
|
||||
};
|
||||
|
||||
static void target_setup_general_frame(struct target_rt_sigframe *sf,
|
||||
|
@ -461,9 +460,9 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
|||
layout.total_size = MAX(layout.total_size,
|
||||
sizeof(struct target_rt_sigframe));
|
||||
|
||||
/* Reserve space for the return code. On a real system this would
|
||||
* be within the VDSO. So, despite the name this is not a "real"
|
||||
* record within the frame.
|
||||
/*
|
||||
* Reserve space for the standard frame unwind pair: fp, lr.
|
||||
* Despite the name this is not a "real" record within the frame.
|
||||
*/
|
||||
fr_ofs = layout.total_size;
|
||||
layout.total_size += sizeof(struct target_rt_frame_record);
|
||||
|
@ -496,15 +495,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
|||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
return_addr = ka->sa_restorer;
|
||||
} else {
|
||||
/*
|
||||
* mov x8,#__NR_rt_sigreturn; svc #0
|
||||
* Since these are instructions they need to be put as little-endian
|
||||
* regardless of target default or current CPU endianness.
|
||||
*/
|
||||
__put_user_e(0xd2801168, &fr->tramp[0], le);
|
||||
__put_user_e(0xd4000001, &fr->tramp[1], le);
|
||||
return_addr = frame_addr + fr_ofs
|
||||
+ offsetof(struct target_rt_frame_record, tramp);
|
||||
return_addr = default_rt_sigreturn;
|
||||
}
|
||||
env->xregs[0] = usig;
|
||||
env->xregs[29] = frame_addr + fr_ofs;
|
||||
|
@ -577,3 +568,20 @@ long do_sigreturn(CPUARMState *env)
|
|||
{
|
||||
return do_rt_sigreturn(env);
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
/*
|
||||
* mov x8,#__NR_rt_sigreturn; svc #0
|
||||
* Since these are instructions they need to be put as little-endian
|
||||
* regardless of target default or current CPU endianness.
|
||||
*/
|
||||
__put_user_e(0xd2801168, &tramp[0], le);
|
||||
__put_user_e(0xd4000001, &tramp[1], le);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page;
|
||||
unlock_user(tramp, sigtramp_page, 8);
|
||||
}
|
||||
|
|
|
@ -25,4 +25,6 @@ typedef struct target_sigaltstack {
|
|||
#define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* AARCH64_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -55,13 +55,11 @@ struct target_ucontext {
|
|||
|
||||
struct target_sigframe {
|
||||
struct target_sigcontext sc;
|
||||
unsigned int retcode[3];
|
||||
};
|
||||
|
||||
struct target_rt_sigframe {
|
||||
target_siginfo_t info;
|
||||
struct target_ucontext uc;
|
||||
unsigned int retcode[3];
|
||||
};
|
||||
|
||||
#define INSN_MOV_R30_R16 0x47fe0410
|
||||
|
@ -142,12 +140,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->ka_restorer) {
|
||||
r26 = ka->ka_restorer;
|
||||
} else {
|
||||
__put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
|
||||
__put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
|
||||
&frame->retcode[1]);
|
||||
__put_user(INSN_CALLSYS, &frame->retcode[2]);
|
||||
/* imb() */
|
||||
r26 = frame_addr + offsetof(struct target_sigframe, retcode);
|
||||
r26 = default_sigreturn;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
|
@ -196,12 +189,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->ka_restorer) {
|
||||
r26 = ka->ka_restorer;
|
||||
} else {
|
||||
__put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
|
||||
__put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
|
||||
&frame->retcode[1]);
|
||||
__put_user(INSN_CALLSYS, &frame->retcode[2]);
|
||||
/* imb(); */
|
||||
r26 = frame_addr + offsetof(struct target_rt_sigframe, retcode);
|
||||
r26 = default_rt_sigreturn;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
|
@ -269,3 +257,21 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6 * 4, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
__put_user(INSN_MOV_R30_R16, &tramp[0]);
|
||||
__put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, &tramp[1]);
|
||||
__put_user(INSN_CALLSYS, &tramp[2]);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 3 * 4;
|
||||
__put_user(INSN_MOV_R30_R16, &tramp[3]);
|
||||
__put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, &tramp[4]);
|
||||
__put_user(INSN_CALLSYS, &tramp[5]);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 6 * 4);
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_KA_RESTORER
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
/* bit-flags */
|
||||
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
|
||||
|
|
|
@ -46,15 +46,7 @@ struct target_sigcontext {
|
|||
abi_ulong fault_address;
|
||||
};
|
||||
|
||||
struct target_ucontext_v1 {
|
||||
abi_ulong tuc_flags;
|
||||
abi_ulong tuc_link;
|
||||
target_stack_t tuc_stack;
|
||||
struct target_sigcontext tuc_mcontext;
|
||||
target_sigset_t tuc_sigmask; /* mask last for extensibility */
|
||||
};
|
||||
|
||||
struct target_ucontext_v2 {
|
||||
struct target_ucontext {
|
||||
abi_ulong tuc_flags;
|
||||
abi_ulong tuc_link;
|
||||
target_stack_t tuc_stack;
|
||||
|
@ -98,68 +90,30 @@ struct target_iwmmxt_sigframe {
|
|||
#define TARGET_VFP_MAGIC 0x56465001
|
||||
#define TARGET_IWMMXT_MAGIC 0x12ef842a
|
||||
|
||||
struct sigframe_v1
|
||||
struct sigframe
|
||||
{
|
||||
struct target_sigcontext sc;
|
||||
abi_ulong extramask[TARGET_NSIG_WORDS-1];
|
||||
struct target_ucontext uc;
|
||||
abi_ulong retcode[4];
|
||||
};
|
||||
|
||||
struct sigframe_v2
|
||||
{
|
||||
struct target_ucontext_v2 uc;
|
||||
abi_ulong retcode[4];
|
||||
};
|
||||
|
||||
struct rt_sigframe_v1
|
||||
{
|
||||
abi_ulong pinfo;
|
||||
abi_ulong puc;
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext_v1 uc;
|
||||
abi_ulong retcode[4];
|
||||
};
|
||||
|
||||
struct rt_sigframe_v2
|
||||
struct rt_sigframe
|
||||
{
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext_v2 uc;
|
||||
abi_ulong retcode[4];
|
||||
struct sigframe sig;
|
||||
};
|
||||
|
||||
static abi_ptr sigreturn_fdpic_tramp;
|
||||
|
||||
/*
|
||||
* For ARM syscalls, we encode the syscall number into the instruction.
|
||||
* Up to 3 words of 'retcode' in the sigframe are code,
|
||||
* with retcode[3] being used by fdpic for the function descriptor.
|
||||
* This code is not actually executed, but is retained for ABI compat.
|
||||
*
|
||||
* We will create a table of 8 retcode variants in the sigtramp page.
|
||||
* Let each table entry use 3 words.
|
||||
*/
|
||||
#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
|
||||
#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
|
||||
|
||||
/*
|
||||
* For Thumb syscalls, we pass the syscall number via r7. We therefore
|
||||
* need two 16-bit instructions.
|
||||
*/
|
||||
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
|
||||
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
|
||||
|
||||
static const abi_ulong retcodes[4] = {
|
||||
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
|
||||
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
|
||||
};
|
||||
|
||||
/*
|
||||
* Stub needed to make sure the FD register (r9) contains the right
|
||||
* value.
|
||||
*/
|
||||
static const unsigned long sigreturn_fdpic_codes[3] = {
|
||||
0xe59fc004, /* ldr r12, [pc, #4] to read function descriptor */
|
||||
0xe59c9004, /* ldr r9, [r12, #4] to setup GOT */
|
||||
0xe59cf000 /* ldr pc, [r12] to jump into restorer */
|
||||
};
|
||||
|
||||
static const unsigned long sigreturn_fdpic_thumb_codes[3] = {
|
||||
0xc008f8df, /* ldr r12, [pc, #8] to read function descriptor */
|
||||
0x9004f8dc, /* ldr r9, [r12, #4] to setup GOT */
|
||||
0xf000f8dc /* ldr pc, [r12] to jump into restorer */
|
||||
};
|
||||
#define RETCODE_WORDS 3
|
||||
#define RETCODE_BYTES (RETCODE_WORDS * 4)
|
||||
|
||||
static inline int valid_user_regs(CPUARMState *regs)
|
||||
{
|
||||
|
@ -207,15 +161,15 @@ get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
|
|||
}
|
||||
|
||||
static int
|
||||
setup_return(CPUARMState *env, struct target_sigaction *ka,
|
||||
abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
|
||||
setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
|
||||
struct sigframe *frame, abi_ulong sp_addr)
|
||||
{
|
||||
abi_ulong handler = 0;
|
||||
abi_ulong handler_fdpic_GOT = 0;
|
||||
abi_ulong retcode;
|
||||
|
||||
int thumb;
|
||||
int thumb, retcode_idx;
|
||||
int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
|
||||
bool copy_retcode;
|
||||
|
||||
if (is_fdpic) {
|
||||
/* In FDPIC mode, ka->_sa_handler points to a function
|
||||
|
@ -232,6 +186,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
|
|||
}
|
||||
|
||||
thumb = handler & 1;
|
||||
retcode_idx = thumb + (ka->sa_flags & TARGET_SA_SIGINFO ? 2 : 0);
|
||||
|
||||
uint32_t cpsr = cpsr_read(env);
|
||||
|
||||
|
@ -249,44 +204,29 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
|
|||
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
if (is_fdpic) {
|
||||
/* For FDPIC we ensure that the restorer is called with a
|
||||
* correct r9 value. For that we need to write code on
|
||||
* the stack that sets r9 and jumps back to restorer
|
||||
* value.
|
||||
*/
|
||||
if (thumb) {
|
||||
__put_user(sigreturn_fdpic_thumb_codes[0], rc);
|
||||
__put_user(sigreturn_fdpic_thumb_codes[1], rc + 1);
|
||||
__put_user(sigreturn_fdpic_thumb_codes[2], rc + 2);
|
||||
__put_user((abi_ulong)ka->sa_restorer, rc + 3);
|
||||
} else {
|
||||
__put_user(sigreturn_fdpic_codes[0], rc);
|
||||
__put_user(sigreturn_fdpic_codes[1], rc + 1);
|
||||
__put_user(sigreturn_fdpic_codes[2], rc + 2);
|
||||
__put_user((abi_ulong)ka->sa_restorer, rc + 3);
|
||||
}
|
||||
|
||||
retcode = rc_addr + thumb;
|
||||
__put_user((abi_ulong)ka->sa_restorer, &frame->retcode[3]);
|
||||
retcode = (sigreturn_fdpic_tramp +
|
||||
retcode_idx * RETCODE_BYTES + thumb);
|
||||
copy_retcode = true;
|
||||
} else {
|
||||
retcode = ka->sa_restorer;
|
||||
copy_retcode = false;
|
||||
}
|
||||
} else {
|
||||
unsigned int idx = thumb;
|
||||
retcode = default_sigreturn + retcode_idx * RETCODE_BYTES + thumb;
|
||||
copy_retcode = true;
|
||||
}
|
||||
|
||||
if (ka->sa_flags & TARGET_SA_SIGINFO) {
|
||||
idx += 2;
|
||||
}
|
||||
|
||||
__put_user(retcodes[idx], rc);
|
||||
|
||||
retcode = rc_addr + thumb;
|
||||
/* Copy the code to the stack slot for ABI compatibility. */
|
||||
if (copy_retcode) {
|
||||
memcpy(frame->retcode, g2h_untagged(retcode & ~1), RETCODE_BYTES);
|
||||
}
|
||||
|
||||
env->regs[0] = usig;
|
||||
if (is_fdpic) {
|
||||
env->regs[9] = handler_fdpic_GOT;
|
||||
}
|
||||
env->regs[13] = frame_addr;
|
||||
env->regs[13] = sp_addr;
|
||||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
cpsr_write(env, cpsr, CPSR_IT | CPSR_T | CPSR_E, CPSRWriteByInstr);
|
||||
|
@ -294,7 +234,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
|
||||
static abi_ulong *setup_sigframe_vfp(abi_ulong *regspace, CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
struct target_vfp_sigframe *vfpframe;
|
||||
|
@ -311,8 +251,7 @@ static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
|
|||
return (abi_ulong*)(vfpframe+1);
|
||||
}
|
||||
|
||||
static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
|
||||
CPUARMState *env)
|
||||
static abi_ulong *setup_sigframe_iwmmxt(abi_ulong *regspace, CPUARMState *env)
|
||||
{
|
||||
int i;
|
||||
struct target_iwmmxt_sigframe *iwmmxtframe;
|
||||
|
@ -331,15 +270,15 @@ static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
|
|||
return (abi_ulong*)(iwmmxtframe+1);
|
||||
}
|
||||
|
||||
static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
|
||||
target_sigset_t *set, CPUARMState *env)
|
||||
static void setup_sigframe(struct target_ucontext *uc,
|
||||
target_sigset_t *set, CPUARMState *env)
|
||||
{
|
||||
struct target_sigaltstack stack;
|
||||
int i;
|
||||
abi_ulong *regspace;
|
||||
|
||||
/* Clear all the bits of the ucontext we don't use. */
|
||||
memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
|
||||
memset(uc, 0, offsetof(struct target_ucontext, tuc_mcontext));
|
||||
|
||||
memset(&stack, 0, sizeof(stack));
|
||||
target_save_altstack(&stack, env);
|
||||
|
@ -349,10 +288,10 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
|
|||
/* Save coprocessor signal frame. */
|
||||
regspace = uc->tuc_regspace;
|
||||
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
|
||||
regspace = setup_sigframe_v2_vfp(regspace, env);
|
||||
regspace = setup_sigframe_vfp(regspace, env);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
||||
regspace = setup_sigframe_v2_iwmmxt(regspace, env);
|
||||
regspace = setup_sigframe_iwmmxt(regspace, env);
|
||||
}
|
||||
|
||||
/* Write terminating magic word */
|
||||
|
@ -363,148 +302,23 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
|
|||
}
|
||||
}
|
||||
|
||||
/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
|
||||
static void setup_frame_v1(int usig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUARMState *regs)
|
||||
{
|
||||
struct sigframe_v1 *frame;
|
||||
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
|
||||
int i;
|
||||
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
setup_sigcontext(&frame->sc, regs, set->sig[0]);
|
||||
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
__put_user(set->sig[i], &frame->extramask[i - 1]);
|
||||
}
|
||||
|
||||
if (setup_return(regs, ka, frame->retcode, frame_addr, usig,
|
||||
frame_addr + offsetof(struct sigframe_v1, retcode))) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
sigsegv:
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
force_sigsegv(usig);
|
||||
}
|
||||
|
||||
static void setup_frame_v2(int usig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUARMState *regs)
|
||||
{
|
||||
struct sigframe_v2 *frame;
|
||||
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
setup_sigframe_v2(&frame->uc, set, regs);
|
||||
|
||||
if (setup_return(regs, ka, frame->retcode, frame_addr, usig,
|
||||
frame_addr + offsetof(struct sigframe_v2, retcode))) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
sigsegv:
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
force_sigsegv(usig);
|
||||
}
|
||||
|
||||
void setup_frame(int usig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUARMState *regs)
|
||||
{
|
||||
if (get_osversion() >= 0x020612) {
|
||||
setup_frame_v2(usig, ka, set, regs);
|
||||
} else {
|
||||
setup_frame_v1(usig, ka, set, regs);
|
||||
}
|
||||
}
|
||||
struct sigframe *frame;
|
||||
abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
|
||||
static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUARMState *env)
|
||||
{
|
||||
struct rt_sigframe_v1 *frame;
|
||||
abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
|
||||
struct target_sigaltstack stack;
|
||||
int i;
|
||||
abi_ulong info_addr, uc_addr;
|
||||
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
trace_user_setup_frame(regs, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
|
||||
__put_user(info_addr, &frame->pinfo);
|
||||
uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
|
||||
__put_user(uc_addr, &frame->puc);
|
||||
tswap_siginfo(&frame->info, info);
|
||||
setup_sigframe(&frame->uc, set, regs);
|
||||
|
||||
/* Clear all the bits of the ucontext we don't use. */
|
||||
memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
|
||||
|
||||
memset(&stack, 0, sizeof(stack));
|
||||
target_save_altstack(&stack, env);
|
||||
memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
|
||||
|
||||
setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
|
||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
||||
}
|
||||
|
||||
if (setup_return(env, ka, frame->retcode, frame_addr, usig,
|
||||
frame_addr + offsetof(struct rt_sigframe_v1, retcode))) {
|
||||
if (setup_return(regs, ka, usig, frame, frame_addr)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
env->regs[1] = info_addr;
|
||||
env->regs[2] = uc_addr;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
sigsegv:
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
force_sigsegv(usig);
|
||||
}
|
||||
|
||||
static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUARMState *env)
|
||||
{
|
||||
struct rt_sigframe_v2 *frame;
|
||||
abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
|
||||
abi_ulong info_addr, uc_addr;
|
||||
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
|
||||
uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
|
||||
tswap_siginfo(&frame->info, info);
|
||||
|
||||
setup_sigframe_v2(&frame->uc, set, env);
|
||||
|
||||
if (setup_return(env, ka, frame->retcode, frame_addr, usig,
|
||||
frame_addr + offsetof(struct rt_sigframe_v2, retcode))) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
env->regs[1] = info_addr;
|
||||
env->regs[2] = uc_addr;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
sigsegv:
|
||||
|
@ -516,11 +330,33 @@ void setup_rt_frame(int usig, struct target_sigaction *ka,
|
|||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUARMState *env)
|
||||
{
|
||||
if (get_osversion() >= 0x020612) {
|
||||
setup_rt_frame_v2(usig, ka, info, set, env);
|
||||
} else {
|
||||
setup_rt_frame_v1(usig, ka, info, set, env);
|
||||
struct rt_sigframe *frame;
|
||||
abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
|
||||
abi_ulong info_addr, uc_addr;
|
||||
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
info_addr = frame_addr + offsetof(struct rt_sigframe, info);
|
||||
uc_addr = frame_addr + offsetof(struct rt_sigframe, sig.uc);
|
||||
tswap_siginfo(&frame->info, info);
|
||||
|
||||
setup_sigframe(&frame->sig.uc, set, env);
|
||||
|
||||
if (setup_return(env, ka, usig, &frame->sig, frame_addr)) {
|
||||
goto sigsegv;
|
||||
}
|
||||
|
||||
env->regs[1] = info_addr;
|
||||
env->regs[2] = uc_addr;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
sigsegv:
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
force_sigsegv(usig);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -553,55 +389,7 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
|
|||
return err;
|
||||
}
|
||||
|
||||
static long do_sigreturn_v1(CPUARMState *env)
|
||||
{
|
||||
abi_ulong frame_addr;
|
||||
struct sigframe_v1 *frame = NULL;
|
||||
target_sigset_t set;
|
||||
sigset_t host_set;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
* then 'sp' should be word aligned here. If it's
|
||||
* not, then the user is trying to mess with us.
|
||||
*/
|
||||
frame_addr = env->regs[13];
|
||||
trace_user_do_sigreturn(env, frame_addr);
|
||||
if (frame_addr & 7) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
__get_user(set.sig[0], &frame->sc.oldmask);
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
__get_user(set.sig[i], &frame->extramask[i - 1]);
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&host_set, &set);
|
||||
set_sigmask(&host_set);
|
||||
|
||||
if (restore_sigcontext(env, &frame->sc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
if (ptrace_cancel_bpt(current))
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
#endif
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
|
||||
static abi_ulong *restore_sigframe_vfp(CPUARMState *env, abi_ulong *regspace)
|
||||
{
|
||||
int i;
|
||||
abi_ulong magic, sz;
|
||||
|
@ -631,8 +419,8 @@ static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
|
|||
return (abi_ulong*)(vfpframe + 1);
|
||||
}
|
||||
|
||||
static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
|
||||
abi_ulong *regspace)
|
||||
static abi_ulong *restore_sigframe_iwmmxt(CPUARMState *env,
|
||||
abi_ulong *regspace)
|
||||
{
|
||||
int i;
|
||||
abi_ulong magic, sz;
|
||||
|
@ -656,9 +444,9 @@ static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
|
|||
return (abi_ulong*)(iwmmxtframe + 1);
|
||||
}
|
||||
|
||||
static int do_sigframe_return_v2(CPUARMState *env,
|
||||
target_ulong context_addr,
|
||||
struct target_ucontext_v2 *uc)
|
||||
static int do_sigframe_return(CPUARMState *env,
|
||||
target_ulong context_addr,
|
||||
struct target_ucontext *uc)
|
||||
{
|
||||
sigset_t host_set;
|
||||
abi_ulong *regspace;
|
||||
|
@ -666,19 +454,20 @@ static int do_sigframe_return_v2(CPUARMState *env,
|
|||
target_to_host_sigset(&host_set, &uc->tuc_sigmask);
|
||||
set_sigmask(&host_set);
|
||||
|
||||
if (restore_sigcontext(env, &uc->tuc_mcontext))
|
||||
if (restore_sigcontext(env, &uc->tuc_mcontext)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Restore coprocessor signal frame */
|
||||
regspace = uc->tuc_regspace;
|
||||
if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
|
||||
regspace = restore_sigframe_v2_vfp(env, regspace);
|
||||
regspace = restore_sigframe_vfp(env, regspace);
|
||||
if (!regspace) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
||||
regspace = restore_sigframe_v2_iwmmxt(env, regspace);
|
||||
regspace = restore_sigframe_iwmmxt(env, regspace);
|
||||
if (!regspace) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -695,10 +484,10 @@ static int do_sigframe_return_v2(CPUARMState *env,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long do_sigreturn_v2(CPUARMState *env)
|
||||
long do_sigreturn(CPUARMState *env)
|
||||
{
|
||||
abi_ulong frame_addr;
|
||||
struct sigframe_v2 *frame = NULL;
|
||||
struct sigframe *frame = NULL;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
|
@ -715,99 +504,9 @@ static long do_sigreturn_v2(CPUARMState *env)
|
|||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigframe_return_v2(env,
|
||||
frame_addr
|
||||
+ offsetof(struct sigframe_v2, uc),
|
||||
&frame->uc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUARMState *env)
|
||||
{
|
||||
if (get_osversion() >= 0x020612) {
|
||||
return do_sigreturn_v2(env);
|
||||
} else {
|
||||
return do_sigreturn_v1(env);
|
||||
}
|
||||
}
|
||||
|
||||
static long do_rt_sigreturn_v1(CPUARMState *env)
|
||||
{
|
||||
abi_ulong frame_addr;
|
||||
struct rt_sigframe_v1 *frame = NULL;
|
||||
sigset_t host_set;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
* then 'sp' should be word aligned here. If it's
|
||||
* not, then the user is trying to mess with us.
|
||||
*/
|
||||
frame_addr = env->regs[13];
|
||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
if (frame_addr & 7) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
|
||||
set_sigmask(&host_set);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_restore_altstack(&frame->uc.tuc_stack, env);
|
||||
|
||||
#if 0
|
||||
/* Send SIGTRAP if we're single-stepping */
|
||||
if (ptrace_cancel_bpt(current))
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
#endif
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
static long do_rt_sigreturn_v2(CPUARMState *env)
|
||||
{
|
||||
abi_ulong frame_addr;
|
||||
struct rt_sigframe_v2 *frame = NULL;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
* then 'sp' should be word aligned here. If it's
|
||||
* not, then the user is trying to mess with us.
|
||||
*/
|
||||
frame_addr = env->regs[13];
|
||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
if (frame_addr & 7) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigframe_return_v2(env,
|
||||
frame_addr
|
||||
+ offsetof(struct rt_sigframe_v2, uc),
|
||||
&frame->uc)) {
|
||||
if (do_sigframe_return(env,
|
||||
frame_addr + offsetof(struct sigframe, uc),
|
||||
&frame->uc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
|
@ -822,9 +521,110 @@ badframe:
|
|||
|
||||
long do_rt_sigreturn(CPUARMState *env)
|
||||
{
|
||||
if (get_osversion() >= 0x020612) {
|
||||
return do_rt_sigreturn_v2(env);
|
||||
} else {
|
||||
return do_rt_sigreturn_v1(env);
|
||||
abi_ulong frame_addr;
|
||||
struct rt_sigframe *frame = NULL;
|
||||
|
||||
/*
|
||||
* Since we stacked the signal on a 64-bit boundary,
|
||||
* then 'sp' should be word aligned here. If it's
|
||||
* not, then the user is trying to mess with us.
|
||||
*/
|
||||
frame_addr = env->regs[13];
|
||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
if (frame_addr & 7) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
if (do_sigframe_return(env,
|
||||
frame_addr + offsetof(struct rt_sigframe, sig.uc),
|
||||
&frame->sig.uc)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
* EABI syscalls pass the number via r7.
|
||||
* Note that the kernel still adds the OABI syscall number to the trap,
|
||||
* presumably for backward ABI compatibility with unwinders.
|
||||
*/
|
||||
#define ARM_MOV_R7_IMM(X) (0xe3a07000 | (X))
|
||||
#define ARM_SWI_SYS(X) (0xef000000 | (X) | ARM_SYSCALL_BASE)
|
||||
|
||||
#define THUMB_MOVS_R7_IMM(X) (0x2700 | (X))
|
||||
#define THUMB_SWI_SYS 0xdf00
|
||||
|
||||
static void write_arm_sigreturn(uint32_t *rc, int syscall)
|
||||
{
|
||||
__put_user(ARM_MOV_R7_IMM(syscall), rc);
|
||||
__put_user(ARM_SWI_SYS(syscall), rc + 1);
|
||||
/* Wrote 8 of 12 bytes */
|
||||
}
|
||||
|
||||
static void write_thm_sigreturn(uint32_t *rc, int syscall)
|
||||
{
|
||||
__put_user(THUMB_SWI_SYS << 16 | THUMB_MOVS_R7_IMM(syscall), rc);
|
||||
/* Wrote 4 of 12 bytes */
|
||||
}
|
||||
|
||||
/*
|
||||
* Stub needed to make sure the FD register (r9) contains the right value.
|
||||
* Use the same instruction sequence as the kernel.
|
||||
*/
|
||||
static void write_arm_fdpic_sigreturn(uint32_t *rc, int ofs)
|
||||
{
|
||||
assert(ofs <= 0xfff);
|
||||
__put_user(0xe59d3000 | ofs, rc + 0); /* ldr r3, [sp, #ofs] */
|
||||
__put_user(0xe8930908, rc + 1); /* ldm r3, { r3, r9 } */
|
||||
__put_user(0xe12fff13, rc + 2); /* bx r3 */
|
||||
/* Wrote 12 of 12 bytes */
|
||||
}
|
||||
|
||||
static void write_thm_fdpic_sigreturn(void *vrc, int ofs)
|
||||
{
|
||||
uint16_t *rc = vrc;
|
||||
|
||||
assert((ofs & ~0x3fc) == 0);
|
||||
__put_user(0x9b00 | (ofs >> 2), rc + 0); /* ldr r3, [sp, #ofs] */
|
||||
__put_user(0xcb0c, rc + 1); /* ldm r3, { r2, r3 } */
|
||||
__put_user(0x4699, rc + 2); /* mov r9, r3 */
|
||||
__put_user(0x4710, rc + 3); /* bx r2 */
|
||||
/* Wrote 8 of 12 bytes */
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t total_size = 8 * RETCODE_BYTES;
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, total_size, 0);
|
||||
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
write_arm_sigreturn(&tramp[0 * RETCODE_WORDS], TARGET_NR_sigreturn);
|
||||
write_thm_sigreturn(&tramp[1 * RETCODE_WORDS], TARGET_NR_sigreturn);
|
||||
write_arm_sigreturn(&tramp[2 * RETCODE_WORDS], TARGET_NR_rt_sigreturn);
|
||||
write_thm_sigreturn(&tramp[3 * RETCODE_WORDS], TARGET_NR_rt_sigreturn);
|
||||
|
||||
sigreturn_fdpic_tramp = sigtramp_page + 4 * RETCODE_BYTES;
|
||||
write_arm_fdpic_sigreturn(tramp + 4 * RETCODE_WORDS,
|
||||
offsetof(struct sigframe, retcode[3]));
|
||||
write_thm_fdpic_sigreturn(tramp + 5 * RETCODE_WORDS,
|
||||
offsetof(struct sigframe, retcode[3]));
|
||||
write_arm_fdpic_sigreturn(tramp + 6 * RETCODE_WORDS,
|
||||
offsetof(struct rt_sigframe, sig.retcode[3]));
|
||||
write_thm_fdpic_sigreturn(tramp + 7 * RETCODE_WORDS,
|
||||
offsetof(struct rt_sigframe, sig.retcode[3]));
|
||||
|
||||
unlock_user(tramp, sigtramp_page, total_size);
|
||||
}
|
||||
|
|
|
@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
|
|||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* ARM_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -97,6 +97,14 @@ static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
|
|||
return sp - framesize;
|
||||
}
|
||||
|
||||
static void setup_sigreturn(uint16_t *retcode)
|
||||
{
|
||||
/* This is movu.w __NR_sigreturn, r9; break 13; */
|
||||
__put_user(0x9c5f, retcode + 0);
|
||||
__put_user(TARGET_NR_sigreturn, retcode + 1);
|
||||
__put_user(0xe93d, retcode + 2);
|
||||
}
|
||||
|
||||
void setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUCRISState *env)
|
||||
{
|
||||
|
@ -112,14 +120,8 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
/*
|
||||
* The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
|
||||
* use this trampoline anymore but it sets it up for GDB.
|
||||
* In QEMU, using the trampoline simplifies things a bit so we use it.
|
||||
*
|
||||
* This is movu.w __NR_sigreturn, r9; break 13;
|
||||
*/
|
||||
__put_user(0x9c5f, frame->retcode+0);
|
||||
__put_user(TARGET_NR_sigreturn,
|
||||
frame->retcode + 1);
|
||||
__put_user(0xe93d, frame->retcode + 2);
|
||||
setup_sigreturn(frame->retcode);
|
||||
|
||||
/* Save the mask. */
|
||||
__put_user(set->sig[0], &frame->sc.oldmask);
|
||||
|
@ -135,7 +137,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
env->regs[10] = sig;
|
||||
env->pc = (unsigned long) ka->_sa_handler;
|
||||
/* Link SRP so the guest returns through the trampoline. */
|
||||
env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
|
||||
env->pregs[PR_SRP] = default_sigreturn;
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
|
@ -187,3 +189,14 @@ long do_rt_sigreturn(CPUCRISState *env)
|
|||
qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
setup_sigreturn(tramp);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 6);
|
||||
}
|
||||
|
|
|
@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
|
|||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* CRIS_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "qemu.h"
|
||||
#include "user-internals.h"
|
||||
#include "signal-common.h"
|
||||
#include "loader.h"
|
||||
#include "user-mmap.h"
|
||||
#include "disas/disas.h"
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include "qemu/units.h"
|
||||
#include "qemu/selfmap.h"
|
||||
#include "qapi/error.h"
|
||||
#include "target_signal.h"
|
||||
|
||||
#ifdef _ARCH_PPC64
|
||||
#undef ARCH_DLINFO
|
||||
|
@ -3249,6 +3251,18 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: load a vdso, which would also contain the signal trampolines.
|
||||
* Otherwise, allocate a private page to hold them.
|
||||
*/
|
||||
if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
|
||||
abi_ulong tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
setup_sigtramp(tramp_page);
|
||||
target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
|
||||
}
|
||||
|
||||
bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
|
||||
info, (elf_interpreter ? &interp_info : NULL));
|
||||
info->start_stack = bprm->p;
|
||||
|
|
|
@ -162,6 +162,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
setup_ucontext(&frame->uc, env, set);
|
||||
tswap_siginfo(&frame->info, info);
|
||||
/*
|
||||
* The on-stack signal trampoline is no longer executed;
|
||||
* however, the libgcc signal frame unwinding code checks
|
||||
* for the presence of these two numeric magic values.
|
||||
*/
|
||||
install_sigtramp(frame->tramp);
|
||||
|
||||
env->gpr[HEX_REG_PC] = ka->_sa_handler;
|
||||
|
@ -171,8 +176,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
frame_addr + offsetof(struct target_rt_sigframe, info);
|
||||
env->gpr[HEX_REG_R02] =
|
||||
frame_addr + offsetof(struct target_rt_sigframe, uc);
|
||||
env->gpr[HEX_REG_LR] =
|
||||
frame_addr + offsetof(struct target_rt_sigframe, tramp);
|
||||
env->gpr[HEX_REG_LR] = default_rt_sigreturn;
|
||||
|
||||
return;
|
||||
|
||||
|
@ -271,3 +275,14 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 4 * 2, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page;
|
||||
install_sigtramp(tramp);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 4 * 2);
|
||||
}
|
||||
|
|
|
@ -31,4 +31,6 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
||||
|
|
|
@ -71,4 +71,18 @@ typedef struct target_sigaltstack {
|
|||
/* mask for all SS_xxx flags */
|
||||
#define TARGET_SS_FLAG_BITS TARGET_SS_AUTODISARM
|
||||
|
||||
/*
|
||||
* We cannot use a bare sigtramp page for hppa-linux.
|
||||
*
|
||||
* Unlike other guests where we use the instructions at PC to validate
|
||||
* an offset from SP, the hppa libgcc signal frame fallback unwinding uses
|
||||
* the PC address itself to find the frame. This is due to the fact that
|
||||
* the hppa grows the stack upward, and the frame is of unknown size.
|
||||
*
|
||||
* TODO: We should be able to use a VDSO to address this, by providing
|
||||
* proper unwind info for the sigtramp code, at which point the fallback
|
||||
* unwinder will not be used.
|
||||
*/
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
|
||||
#endif /* HPPA_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -310,6 +310,22 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
|
|||
}
|
||||
|
||||
#ifndef TARGET_X86_64
|
||||
static void install_sigtramp(void *tramp)
|
||||
{
|
||||
/* This is popl %eax ; movl $syscall,%eax ; int $0x80 */
|
||||
__put_user(0xb858, (uint16_t *)(tramp + 0));
|
||||
__put_user(TARGET_NR_sigreturn, (int32_t *)(tramp + 2));
|
||||
__put_user(0x80cd, (uint16_t *)(tramp + 6));
|
||||
}
|
||||
|
||||
static void install_rt_sigtramp(void *tramp)
|
||||
{
|
||||
/* This is movl $syscall,%eax ; int $0x80 */
|
||||
__put_user(0xb8, (uint8_t *)(tramp + 0));
|
||||
__put_user(TARGET_NR_rt_sigreturn, (int32_t *)(tramp + 1));
|
||||
__put_user(0x80cd, (uint16_t *)(tramp + 5));
|
||||
}
|
||||
|
||||
/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
|
||||
void setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUX86State *env)
|
||||
|
@ -338,16 +354,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
__put_user(ka->sa_restorer, &frame->pretcode);
|
||||
} else {
|
||||
uint16_t val16;
|
||||
abi_ulong retcode_addr;
|
||||
retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
|
||||
__put_user(retcode_addr, &frame->pretcode);
|
||||
/* This is popl %eax ; movl $,%eax ; int $0x80 */
|
||||
val16 = 0xb858;
|
||||
__put_user(val16, (uint16_t *)(frame->retcode+0));
|
||||
__put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
|
||||
val16 = 0x80cd;
|
||||
__put_user(val16, (uint16_t *)(frame->retcode+6));
|
||||
/* This is no longer used, but is retained for ABI compatibility. */
|
||||
install_sigtramp(frame->retcode);
|
||||
__put_user(default_sigreturn, &frame->pretcode);
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
|
@ -412,24 +421,18 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
#ifndef TARGET_X86_64
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
__put_user(ka->sa_restorer, &frame->pretcode);
|
||||
} else {
|
||||
uint16_t val16;
|
||||
addr = frame_addr + offsetof(struct rt_sigframe, retcode);
|
||||
__put_user(addr, &frame->pretcode);
|
||||
/* This is movl $,%eax ; int $0x80 */
|
||||
__put_user(0xb8, (char *)(frame->retcode+0));
|
||||
__put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
|
||||
val16 = 0x80cd;
|
||||
__put_user(val16, (uint16_t *)(frame->retcode+5));
|
||||
}
|
||||
#ifdef TARGET_X86_64
|
||||
/* For x86_64, SA_RESTORER is required ABI. */
|
||||
goto give_sigsegv;
|
||||
#else
|
||||
/* XXX: Would be slightly better to return -EFAULT here if test fails
|
||||
assert(ka->sa_flags & TARGET_SA_RESTORER); */
|
||||
__put_user(ka->sa_restorer, &frame->pretcode);
|
||||
/* This is no longer used, but is retained for ABI compatibility. */
|
||||
install_rt_sigtramp(frame->retcode);
|
||||
__put_user(default_rt_sigreturn, &frame->pretcode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
env->regs[R_ESP] = frame_addr;
|
||||
|
@ -592,3 +595,19 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
#ifndef TARGET_X86_64
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
install_sigtramp(tramp);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 8;
|
||||
install_rt_sigtramp(tramp + 8);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 2 * 8);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
|
|||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* I386_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -39,7 +39,6 @@ struct target_sigframe
|
|||
int sig;
|
||||
int code;
|
||||
abi_ulong psc;
|
||||
char retcode[8];
|
||||
abi_ulong extramask[TARGET_NSIG_WORDS-1];
|
||||
struct target_sigcontext sc;
|
||||
};
|
||||
|
@ -76,7 +75,6 @@ struct target_rt_sigframe
|
|||
int sig;
|
||||
abi_ulong pinfo;
|
||||
abi_ulong puc;
|
||||
char retcode[8];
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
};
|
||||
|
@ -130,7 +128,6 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
{
|
||||
struct target_sigframe *frame;
|
||||
abi_ulong frame_addr;
|
||||
abi_ulong retcode_addr;
|
||||
abi_ulong sc_addr;
|
||||
int i;
|
||||
|
||||
|
@ -152,16 +149,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
}
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
|
||||
retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
|
||||
__put_user(retcode_addr, &frame->pretcode);
|
||||
|
||||
/* moveq #,d0; trap #0 */
|
||||
|
||||
__put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
|
||||
(uint32_t *)(frame->retcode));
|
||||
|
||||
/* Set up to return from userspace */
|
||||
__put_user(default_sigreturn, &frame->pretcode);
|
||||
|
||||
env->aregs[7] = frame_addr;
|
||||
env->pc = ka->_sa_handler;
|
||||
|
@ -288,7 +276,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
{
|
||||
struct target_rt_sigframe *frame;
|
||||
abi_ulong frame_addr;
|
||||
abi_ulong retcode_addr;
|
||||
abi_ulong info_addr;
|
||||
abi_ulong uc_addr;
|
||||
int err = 0;
|
||||
|
@ -325,17 +312,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
}
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
|
||||
retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
|
||||
__put_user(retcode_addr, &frame->pretcode);
|
||||
|
||||
/* moveq #,d0; notb d0; trap #0 */
|
||||
|
||||
__put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
|
||||
(uint32_t *)(frame->retcode + 0));
|
||||
__put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
|
||||
|
||||
/* Set up to return from userspace */
|
||||
__put_user(default_rt_sigreturn, &frame->pretcode);
|
||||
|
||||
env->aregs[7] = frame_addr;
|
||||
env->pc = ka->_sa_handler;
|
||||
|
@ -411,3 +388,23 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
void *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 4 + 6, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
|
||||
/* moveq #,d0; trap #0 */
|
||||
__put_user(0x70004e40 + (TARGET_NR_sigreturn << 16), (uint32_t *)tramp);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 4;
|
||||
|
||||
/* moveq #,d0; notb d0; trap #0 */
|
||||
__put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
|
||||
(uint32_t *)(tramp + 4));
|
||||
__put_user(0x4e40, (uint16_t *)(tramp + 8));
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 4 + 6);
|
||||
}
|
||||
|
|
|
@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
|
|||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* M68K_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -161,17 +161,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
/* Kernel does not use SA_RESTORER. */
|
||||
|
||||
/* addi r12, r0, __NR_sigreturn */
|
||||
__put_user(0x31800000U | TARGET_NR_rt_sigreturn, frame->tramp + 0);
|
||||
/* brki r14, 0x8 */
|
||||
__put_user(0xb9cc0008U, frame->tramp + 1);
|
||||
|
||||
/*
|
||||
* Return from sighandler will jump to the tramp.
|
||||
* Negative 8 offset because return is rtsd r15, 8
|
||||
*/
|
||||
env->regs[15] =
|
||||
frame_addr + offsetof(struct target_rt_sigframe, tramp) - 8;
|
||||
env->regs[15] = default_rt_sigreturn - 8;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
env->regs[1] = frame_addr;
|
||||
|
@ -220,3 +214,19 @@ long do_rt_sigreturn(CPUMBState *env)
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
/*
|
||||
* addi r12, r0, __NR_rt_sigreturn
|
||||
* brki r14, 0x8
|
||||
*/
|
||||
__put_user(0x31800000U | TARGET_NR_rt_sigreturn, tramp);
|
||||
__put_user(0xb9cc0008U, tramp + 1);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page;
|
||||
unlock_user(tramp, sigtramp_page, 8);
|
||||
}
|
||||
|
|
|
@ -21,4 +21,6 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* MICROBLAZE_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -87,10 +87,8 @@ struct target_rt_sigframe {
|
|||
};
|
||||
|
||||
/* Install trampoline to jump back from signal handler */
|
||||
static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
|
||||
static void install_sigtramp(uint32_t *tramp, unsigned int syscall)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* Set up the return code ...
|
||||
*
|
||||
|
@ -100,7 +98,6 @@ static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
|
|||
|
||||
__put_user(0x24020000 + syscall, tramp + 0);
|
||||
__put_user(0x0000000c , tramp + 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void setup_sigcontext(CPUMIPSState *regs,
|
||||
|
@ -212,8 +209,6 @@ void setup_frame(int sig, struct target_sigaction * ka,
|
|||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
|
||||
|
||||
setup_sigcontext(regs, &frame->sf_sc);
|
||||
|
||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||
|
@ -234,7 +229,7 @@ void setup_frame(int sig, struct target_sigaction * ka,
|
|||
regs->active_tc.gpr[ 5] = 0;
|
||||
regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
|
||||
regs->active_tc.gpr[29] = frame_addr;
|
||||
regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
|
||||
regs->active_tc.gpr[31] = default_sigreturn;
|
||||
/* The original kernel code sets CP0_EPC to the handler
|
||||
* since it returns to userland using eret
|
||||
* we cannot do this here, and we must set PC directly */
|
||||
|
@ -308,8 +303,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
|
||||
|
||||
tswap_siginfo(&frame->rs_info, info);
|
||||
|
||||
__put_user(0, &frame->rs_uc.tuc_flags);
|
||||
|
@ -338,11 +331,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
env->active_tc.gpr[ 6] = frame_addr
|
||||
+ offsetof(struct target_rt_sigframe, rs_uc);
|
||||
env->active_tc.gpr[29] = frame_addr;
|
||||
env->active_tc.gpr[31] = frame_addr
|
||||
+ offsetof(struct target_rt_sigframe, rs_code);
|
||||
/* The original kernel code sets CP0_EPC to the handler
|
||||
* since it returns to userland using eret
|
||||
* we cannot do this here, and we must set PC directly */
|
||||
env->active_tc.gpr[31] = default_rt_sigreturn;
|
||||
|
||||
/*
|
||||
* The original kernel code sets CP0_EPC to the handler
|
||||
* since it returns to userland using eret
|
||||
* we cannot do this here, and we must set PC directly
|
||||
*/
|
||||
env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
|
||||
mips_set_hflags_isa_mode_from_pc(env);
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
|
@ -382,3 +377,19 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
#ifdef TARGET_ARCH_HAS_SETUP_FRAME
|
||||
default_sigreturn = sigtramp_page;
|
||||
install_sigtramp(tramp, TARGET_NR_sigreturn);
|
||||
#endif
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 8;
|
||||
install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 2 * 8);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ typedef struct target_sigaltstack {
|
|||
/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#endif
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
/* bit-flags */
|
||||
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
|
||||
|
|
|
@ -76,4 +76,6 @@ typedef struct target_sigaltstack {
|
|||
/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#endif
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* MIPS64_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -19,4 +19,7 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
/* Nios2 uses a fixed address on the kuser page for sigreturn. */
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
|
||||
#endif /* NIOS2_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -38,7 +38,6 @@ typedef struct target_ucontext {
|
|||
typedef struct target_rt_sigframe {
|
||||
struct target_siginfo info;
|
||||
target_ucontext uc;
|
||||
uint32_t retcode[4]; /* trampoline code */
|
||||
} target_rt_sigframe;
|
||||
|
||||
static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc)
|
||||
|
@ -116,14 +115,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
|
||||
}
|
||||
|
||||
/* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */
|
||||
__put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0);
|
||||
__put_user(0x20000001, frame->retcode + 1);
|
||||
__put_user(0x15000000, frame->retcode + 2);
|
||||
__put_user(0x15000000, frame->retcode + 3);
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode));
|
||||
cpu_set_gpr(env, 9, default_rt_sigreturn);
|
||||
cpu_set_gpr(env, 3, sig);
|
||||
cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info));
|
||||
cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc));
|
||||
|
@ -169,3 +162,16 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
/* This is l.ori r11,r0,__NR_sigreturn; l.sys 1 */
|
||||
__put_user(0xa9600000 | TARGET_NR_rt_sigreturn, tramp + 0);
|
||||
__put_user(0x20000001, tramp + 1);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page;
|
||||
unlock_user(tramp, sigtramp_page, 8);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,6 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* OPENRISC_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -203,9 +203,6 @@ struct target_func_ptr {
|
|||
|
||||
#endif
|
||||
|
||||
/* We use the mc_pad field for the signal return trampoline. */
|
||||
#define tramp mc_pad
|
||||
|
||||
/* See arch/powerpc/kernel/signal.c. */
|
||||
static target_ulong get_sigframe(struct target_sigaction *ka,
|
||||
CPUPPCState *env,
|
||||
|
@ -309,10 +306,8 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
|
|||
static void encode_trampoline(int sigret, uint32_t *tramp)
|
||||
{
|
||||
/* Set up the sigreturn trampoline: li r0,sigret; sc. */
|
||||
if (sigret) {
|
||||
__put_user(0x38000000 | sigret, &tramp[0]);
|
||||
__put_user(0x44000002, &tramp[1]);
|
||||
}
|
||||
__put_user(0x38000000 | sigret, &tramp[0]);
|
||||
__put_user(0x44000002, &tramp[1]);
|
||||
}
|
||||
|
||||
static void restore_user_regs(CPUPPCState *env,
|
||||
|
@ -438,12 +433,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
/* Save user regs. */
|
||||
save_user_regs(env, &frame->mctx);
|
||||
|
||||
/* Construct the trampoline code on the stack. */
|
||||
encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
|
||||
|
||||
/* The kernel checks for the presence of a VDSO here. We don't
|
||||
emulate a vdso, so use a sigreturn system call. */
|
||||
env->lr = (target_ulong) h2g(frame->mctx.tramp);
|
||||
env->lr = default_sigreturn;
|
||||
|
||||
/* Turn off all fp exceptions. */
|
||||
env->fpscr = 0;
|
||||
|
@ -479,7 +469,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
target_sigset_t *set, CPUPPCState *env)
|
||||
{
|
||||
struct target_rt_sigframe *rt_sf;
|
||||
uint32_t *trampptr = 0;
|
||||
struct target_mcontext *mctx = 0;
|
||||
target_ulong rt_sf_addr, newsp = 0;
|
||||
int i, err = 0;
|
||||
|
@ -509,22 +498,17 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
#if defined(TARGET_PPC64)
|
||||
mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
|
||||
trampptr = &rt_sf->trampoline[0];
|
||||
|
||||
sc = &rt_sf->uc.tuc_sigcontext;
|
||||
__put_user(h2g(mctx), &sc->regs);
|
||||
__put_user(sig, &sc->signal);
|
||||
#else
|
||||
mctx = &rt_sf->uc.tuc_mcontext;
|
||||
trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
|
||||
#endif
|
||||
|
||||
save_user_regs(env, mctx);
|
||||
encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
|
||||
|
||||
/* The kernel checks for the presence of a VDSO here. We don't
|
||||
emulate a vdso, so use a sigreturn system call. */
|
||||
env->lr = (target_ulong) h2g(trampptr);
|
||||
env->lr = default_rt_sigreturn;
|
||||
|
||||
/* Turn off all fp exceptions. */
|
||||
env->fpscr = 0;
|
||||
|
@ -722,3 +706,19 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
#ifdef TARGET_ARCH_HAS_SETUP_FRAME
|
||||
default_sigreturn = sigtramp_page;
|
||||
encode_trampoline(TARGET_NR_sigreturn, tramp + 0);
|
||||
#endif
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 8;
|
||||
encode_trampoline(TARGET_NR_rt_sigreturn, tramp + 2);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 2 * 8);
|
||||
}
|
||||
|
|
|
@ -24,4 +24,6 @@ typedef struct target_sigaltstack {
|
|||
#if !defined(TARGET_PPC64)
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#endif
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* PPC_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -47,7 +47,6 @@ struct target_ucontext {
|
|||
};
|
||||
|
||||
struct target_rt_sigframe {
|
||||
uint32_t tramp[2]; /* not in kernel, which uses VDSO instead */
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
};
|
||||
|
@ -105,12 +104,6 @@ static void setup_ucontext(struct target_ucontext *uc,
|
|||
setup_sigcontext(&uc->uc_mcontext, env);
|
||||
}
|
||||
|
||||
static inline void install_sigtramp(uint32_t *tramp)
|
||||
{
|
||||
__put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
|
||||
__put_user(0x00000073, tramp + 1); /* ecall */
|
||||
}
|
||||
|
||||
void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPURISCVState *env)
|
||||
|
@ -127,14 +120,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
|
||||
setup_ucontext(&frame->uc, env, set);
|
||||
tswap_siginfo(&frame->info, info);
|
||||
install_sigtramp(frame->tramp);
|
||||
|
||||
env->pc = ka->_sa_handler;
|
||||
env->gpr[xSP] = frame_addr;
|
||||
env->gpr[xA0] = sig;
|
||||
env->gpr[xA1] = frame_addr + offsetof(struct target_rt_sigframe, info);
|
||||
env->gpr[xA2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
|
||||
env->gpr[xRA] = frame_addr + offsetof(struct target_rt_sigframe, tramp);
|
||||
env->gpr[xRA] = default_rt_sigreturn;
|
||||
|
||||
return;
|
||||
|
||||
|
@ -203,3 +195,15 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
__put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
|
||||
__put_user(0x00000073, tramp + 1); /* ecall */
|
||||
|
||||
default_rt_sigreturn = sigtramp_page;
|
||||
unlock_user(tramp, sigtramp_page, 8);
|
||||
}
|
||||
|
|
|
@ -15,4 +15,6 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* RISCV_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -68,7 +68,6 @@ typedef struct {
|
|||
target_sigregs sregs;
|
||||
int signo;
|
||||
target_sigregs_ext sregs_ext;
|
||||
uint16_t retcode;
|
||||
} sigframe;
|
||||
|
||||
#define TARGET_UC_VXRS 2
|
||||
|
@ -85,7 +84,6 @@ struct target_ucontext {
|
|||
|
||||
typedef struct {
|
||||
uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
|
||||
uint16_t retcode;
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
} rt_sigframe;
|
||||
|
@ -209,9 +207,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
restorer = ka->sa_restorer;
|
||||
} else {
|
||||
restorer = frame_addr + offsetof(sigframe, retcode);
|
||||
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
|
||||
&frame->retcode);
|
||||
restorer = default_sigreturn;
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
|
@ -262,9 +258,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
restorer = ka->sa_restorer;
|
||||
} else {
|
||||
restorer = frame_addr + offsetof(typeof(*frame), retcode);
|
||||
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
|
||||
&frame->retcode);
|
||||
restorer = default_rt_sigreturn;
|
||||
}
|
||||
|
||||
/* Create siginfo on the signal stack. */
|
||||
|
@ -405,3 +399,17 @@ long do_rt_sigreturn(CPUS390XState *env)
|
|||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 + 2, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, &tramp[0]);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 2;
|
||||
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, &tramp[1]);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 2 + 2);
|
||||
}
|
||||
|
|
|
@ -19,4 +19,6 @@ typedef struct target_sigaltstack {
|
|||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* S390X_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -52,7 +52,6 @@ struct target_sigframe
|
|||
{
|
||||
struct target_sigcontext sc;
|
||||
target_ulong extramask[TARGET_NSIG_WORDS-1];
|
||||
uint16_t retcode[3];
|
||||
};
|
||||
|
||||
|
||||
|
@ -68,7 +67,6 @@ struct target_rt_sigframe
|
|||
{
|
||||
struct target_siginfo info;
|
||||
struct target_ucontext uc;
|
||||
uint16_t retcode[3];
|
||||
};
|
||||
|
||||
|
||||
|
@ -190,15 +188,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
regs->pr = (unsigned long) ka->sa_restorer;
|
||||
regs->pr = ka->sa_restorer;
|
||||
} else {
|
||||
/* Generate return code (system call to sigreturn) */
|
||||
abi_ulong retcode_addr = frame_addr +
|
||||
offsetof(struct target_sigframe, retcode);
|
||||
__put_user(MOVW(2), &frame->retcode[0]);
|
||||
__put_user(TRAP_NOARG, &frame->retcode[1]);
|
||||
__put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
|
||||
regs->pr = (unsigned long) retcode_addr;
|
||||
regs->pr = default_sigreturn;
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
|
@ -248,15 +240,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
/* Set up to return from userspace. If provided, use a stub
|
||||
already in userspace. */
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
regs->pr = (unsigned long) ka->sa_restorer;
|
||||
regs->pr = ka->sa_restorer;
|
||||
} else {
|
||||
/* Generate return code (system call to sigreturn) */
|
||||
abi_ulong retcode_addr = frame_addr +
|
||||
offsetof(struct target_rt_sigframe, retcode);
|
||||
__put_user(MOVW(2), &frame->retcode[0]);
|
||||
__put_user(TRAP_NOARG, &frame->retcode[1]);
|
||||
__put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
|
||||
regs->pr = (unsigned long) retcode_addr;
|
||||
regs->pr = default_rt_sigreturn;
|
||||
}
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
|
@ -334,3 +320,21 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 6, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
__put_user(MOVW(2), &tramp[0]);
|
||||
__put_user(TRAP_NOARG, &tramp[1]);
|
||||
__put_user(TARGET_NR_sigreturn, &tramp[2]);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 6;
|
||||
__put_user(MOVW(2), &tramp[3]);
|
||||
__put_user(TRAP_NOARG, &tramp[4]);
|
||||
__put_user(TARGET_NR_rt_sigreturn, &tramp[5]);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 2 * 6);
|
||||
}
|
||||
|
|
|
@ -22,4 +22,6 @@ typedef struct target_sigaltstack {
|
|||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif /* SH4_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
#ifndef SIGNAL_COMMON_H
|
||||
#define SIGNAL_COMMON_H
|
||||
|
||||
/* Fallback addresses into sigtramp page. */
|
||||
extern abi_ulong default_sigreturn;
|
||||
extern abi_ulong default_rt_sigreturn;
|
||||
|
||||
void setup_sigtramp(abi_ulong tramp_page);
|
||||
|
||||
int on_sig_stack(unsigned long sp);
|
||||
int sas_ss_flags(unsigned long sp);
|
||||
abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
|
||||
|
|
|
@ -35,6 +35,9 @@ static struct target_sigaction sigact_table[TARGET_NSIG];
|
|||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc);
|
||||
|
||||
/* Fallback addresses into sigtramp page. */
|
||||
abi_ulong default_sigreturn;
|
||||
abi_ulong default_rt_sigreturn;
|
||||
|
||||
/*
|
||||
* System includes define _NSIG as SIGRTMAX + 1,
|
||||
|
|
|
@ -242,6 +242,12 @@ static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
|
|||
}
|
||||
|
||||
#ifdef TARGET_ARCH_HAS_SETUP_FRAME
|
||||
static void install_sigtramp(uint32_t *tramp, int syscall)
|
||||
{
|
||||
__put_user(0x82102000u + syscall, &tramp[0]); /* mov syscall, %g1 */
|
||||
__put_user(0x91d02010u, &tramp[1]); /* t 0x10 */
|
||||
}
|
||||
|
||||
void setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUSPARCState *env)
|
||||
{
|
||||
|
@ -291,13 +297,9 @@ void setup_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->ka_restorer) {
|
||||
env->regwptr[WREG_O7] = ka->ka_restorer;
|
||||
} else {
|
||||
env->regwptr[WREG_O7] = sf_addr +
|
||||
offsetof(struct target_signal_frame, insns) - 2 * 4;
|
||||
|
||||
/* mov __NR_sigreturn, %g1 */
|
||||
__put_user(0x821020d8u, &sf->insns[0]);
|
||||
/* t 0x10 */
|
||||
__put_user(0x91d02010u, &sf->insns[1]);
|
||||
/* Not used, but retain for ABI compatibility. */
|
||||
install_sigtramp(sf->insns, TARGET_NR_sigreturn);
|
||||
env->regwptr[WREG_O7] = default_sigreturn;
|
||||
}
|
||||
unlock_user(sf, sf_addr, sf_size);
|
||||
}
|
||||
|
@ -358,13 +360,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->ka_restorer) {
|
||||
env->regwptr[WREG_O7] = ka->ka_restorer;
|
||||
} else {
|
||||
env->regwptr[WREG_O7] =
|
||||
sf_addr + offsetof(struct target_rt_signal_frame, insns) - 2 * 4;
|
||||
|
||||
/* mov __NR_rt_sigreturn, %g1 */
|
||||
__put_user(0x82102065u, &sf->insns[0]);
|
||||
/* t 0x10 */
|
||||
__put_user(0x91d02010u, &sf->insns[1]);
|
||||
/* Not used, but retain for ABI compatibility. */
|
||||
install_sigtramp(sf->insns, TARGET_NR_rt_sigreturn);
|
||||
env->regwptr[WREG_O7] = default_rt_sigreturn;
|
||||
}
|
||||
#else
|
||||
env->regwptr[WREG_O7] = ka->ka_restorer;
|
||||
|
@ -775,4 +773,18 @@ do_sigsegv:
|
|||
unlock_user_struct(ucp, ucp_addr, 1);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
}
|
||||
#else
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_sigreturn = sigtramp_page;
|
||||
install_sigtramp(tramp, TARGET_NR_sigreturn);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page + 8;
|
||||
install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
|
||||
|
||||
unlock_user(tramp, sigtramp_page, 2 * 8);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -69,6 +69,10 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#ifdef TARGET_ABI32
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
#else
|
||||
/* For sparc64, use of KA_RESTORER is mandatory. */
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
#endif
|
||||
|
||||
/* bit-flags */
|
||||
|
|
|
@ -21,4 +21,7 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
/* For x86_64, use of SA_RESTORER is mandatory. */
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
|
||||
#endif /* X86_64_TARGET_SIGNAL_H */
|
||||
|
|
|
@ -128,6 +128,29 @@ static int setup_sigcontext(struct target_rt_sigframe *frame,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void install_sigtramp(uint8_t *tramp)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
|
||||
__put_user(0x22, &tramp[0]);
|
||||
__put_user(0x0a, &tramp[1]);
|
||||
__put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
|
||||
/* Generate instruction: SYSCALL */
|
||||
__put_user(0x00, &tramp[3]);
|
||||
__put_user(0x05, &tramp[4]);
|
||||
__put_user(0x00, &tramp[5]);
|
||||
#else
|
||||
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
|
||||
__put_user(0x22, &tramp[0]);
|
||||
__put_user(0xa0, &tramp[1]);
|
||||
__put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
|
||||
/* Generate instruction: SYSCALL */
|
||||
__put_user(0x00, &tramp[3]);
|
||||
__put_user(0x50, &tramp[4]);
|
||||
__put_user(0x00, &tramp[5]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUXtensaState *env)
|
||||
|
@ -164,26 +187,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
ra = ka->sa_restorer;
|
||||
} else {
|
||||
ra = frame_addr + offsetof(struct target_rt_sigframe, retcode);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
|
||||
__put_user(0x22, &frame->retcode[0]);
|
||||
__put_user(0x0a, &frame->retcode[1]);
|
||||
__put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
|
||||
/* Generate instruction: SYSCALL */
|
||||
__put_user(0x00, &frame->retcode[3]);
|
||||
__put_user(0x05, &frame->retcode[4]);
|
||||
__put_user(0x00, &frame->retcode[5]);
|
||||
#else
|
||||
/* Generate instruction: MOVI a2, __NR_rt_sigreturn */
|
||||
__put_user(0x22, &frame->retcode[0]);
|
||||
__put_user(0xa0, &frame->retcode[1]);
|
||||
__put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
|
||||
/* Generate instruction: SYSCALL */
|
||||
__put_user(0x00, &frame->retcode[3]);
|
||||
__put_user(0x50, &frame->retcode[4]);
|
||||
__put_user(0x00, &frame->retcode[5]);
|
||||
#endif
|
||||
/* Not used, but retain for ABI compatibility. */
|
||||
install_sigtramp(frame->retcode);
|
||||
ra = default_rt_sigreturn;
|
||||
}
|
||||
memset(env->regs, 0, sizeof(env->regs));
|
||||
env->pc = ka->_sa_handler;
|
||||
|
@ -264,3 +270,13 @@ badframe:
|
|||
force_sig(TARGET_SIGSEGV);
|
||||
return -TARGET_QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
void setup_sigtramp(abi_ulong sigtramp_page)
|
||||
{
|
||||
uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
|
||||
assert(tramp != NULL);
|
||||
|
||||
default_rt_sigreturn = sigtramp_page;
|
||||
install_sigtramp(tramp);
|
||||
unlock_user(tramp, sigtramp_page, 6);
|
||||
}
|
||||
|
|
|
@ -20,4 +20,6 @@ typedef struct target_sigaltstack {
|
|||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,3 +5,10 @@
|
|||
# On parisc Linux supports 4K/16K/64K (but currently only 4k works)
|
||||
EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-16384 run-test-mmap-65536
|
||||
|
||||
# This triggers failures for hppa-linux about 1% of the time
|
||||
# HPPA is the odd target that can't use the sigtramp page;
|
||||
# it requires the full vdso with dwarf2 unwind info.
|
||||
run-signals: signals
|
||||
$(call skip-test, $<, "BROKEN awaiting vdso support")
|
||||
run-plugin-signals-with-%:
|
||||
$(call skip-test, $<, "BROKEN awaiting vdso support")
|
||||
|
|
|
@ -65,9 +65,6 @@ run-plugin-%-with-libinsn.so:
|
|||
-d plugin -D $*-with-libinsn.so.pout $*, \
|
||||
"$* (inline) on $(TARGET_NAME)")
|
||||
|
||||
run-plugin-signals-with-libinsn.so:
|
||||
$(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support")
|
||||
|
||||
# Update TESTS
|
||||
I386_TESTS:=$(filter-out $(SKIP_I386_TESTS), $(ALL_X86_TESTS))
|
||||
TESTS=$(MULTIARCH_TESTS) $(I386_TESTS)
|
||||
|
|
|
@ -32,14 +32,6 @@ threadcount: LDFLAGS+=-lpthread
|
|||
|
||||
signals: LDFLAGS+=-lrt -lpthread
|
||||
|
||||
# This triggers failures on s390x hosts about 4% of the time
|
||||
# This triggers failures for hppa-linux about 1% of the time
|
||||
run-signals: signals
|
||||
$(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support")
|
||||
|
||||
run-plugin-signals-with-%:
|
||||
$(call skip-test, $<, "BROKEN awaiting sigframe clean-ups and vdso support")
|
||||
|
||||
# We define the runner for test-mmap after the individual
|
||||
# architectures have defined their supported pages sizes. If no
|
||||
# additional page sizes are defined we only run the default test.
|
||||
|
|
|
@ -5,3 +5,10 @@
|
|||
|
||||
# On sh Linux supports 4k, 8k, 16k and 64k pages (but only 4k currently works)
|
||||
EXTRA_RUNS+=run-test-mmap-4096 # run-test-mmap-8192 run-test-mmap-16384 run-test-mmap-65536
|
||||
|
||||
# This triggers failures for sh4-linux about 10% of the time.
|
||||
# Random SIGSEGV at unpredictable guest address, cause unknown.
|
||||
run-signals: signals
|
||||
$(call skip-test, $<, "BROKEN")
|
||||
run-plugin-signals-with-%:
|
||||
$(call skip-test, $<, "BROKEN")
|
||||
|
|
Loading…
Reference in New Issue