mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+21
-13
@@ -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 */
|
||||
|
||||
+20
-14
@@ -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 */
|
||||
|
||||
+190
-390
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
+42
-23
@@ -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 */
|
||||
|
||||
+22
-25
@@ -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 */
|
||||
|
||||
+25
-14
@@ -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 */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user