* [Qemu-devel] [PATCH 1/3] target-ppc: expose cpu capability flags
2009-04-22 2:32 [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling Nathan Froyd
@ 2009-04-22 2:32 ` Nathan Froyd
2009-04-22 2:32 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
2009-04-22 2:32 ` [Qemu-devel] [PATCH 3/3] linux-user: support ELF_HWCAP for PPPC Nathan Froyd
2 siblings, 0 replies; 9+ messages in thread
From: Nathan Froyd @ 2009-04-22 2:32 UTC (permalink / raw)
To: qemu-devel
Do this so other pieces of code can make decisions based on the
capabilities of the CPU we're emulating.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
target-ppc/cpu.h | 139 +++++++++++++++++++++++++++++++++++++++++++
target-ppc/translate.c | 138 ------------------------------------------
target-ppc/translate_init.c | 1 +
3 files changed, 140 insertions(+), 138 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 87b3460..fe73997 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -642,6 +642,7 @@ struct CPUPPCState {
powerpc_input_t bus_model;
int bfd_mach;
uint32_t flags;
+ uint64_t insns_flags;
int error_code;
uint32_t pending_interrupts;
@@ -1319,6 +1320,144 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#define SPR_E500_SVR (0x3FF)
/*****************************************************************************/
+/* PowerPC Instructions types definitions */
+enum {
+ PPC_NONE = 0x0000000000000000ULL,
+ /* PowerPC base instructions set */
+ PPC_INSNS_BASE = 0x0000000000000001ULL,
+ /* integer operations instructions */
+#define PPC_INTEGER PPC_INSNS_BASE
+ /* flow control instructions */
+#define PPC_FLOW PPC_INSNS_BASE
+ /* virtual memory instructions */
+#define PPC_MEM PPC_INSNS_BASE
+ /* ld/st with reservation instructions */
+#define PPC_RES PPC_INSNS_BASE
+ /* spr/msr access instructions */
+#define PPC_MISC PPC_INSNS_BASE
+ /* Deprecated instruction sets */
+ /* Original POWER instruction set */
+ PPC_POWER = 0x0000000000000002ULL,
+ /* POWER2 instruction set extension */
+ PPC_POWER2 = 0x0000000000000004ULL,
+ /* Power RTC support */
+ PPC_POWER_RTC = 0x0000000000000008ULL,
+ /* Power-to-PowerPC bridge (601) */
+ PPC_POWER_BR = 0x0000000000000010ULL,
+ /* 64 bits PowerPC instruction set */
+ PPC_64B = 0x0000000000000020ULL,
+ /* New 64 bits extensions (PowerPC 2.0x) */
+ PPC_64BX = 0x0000000000000040ULL,
+ /* 64 bits hypervisor extensions */
+ PPC_64H = 0x0000000000000080ULL,
+ /* New wait instruction (PowerPC 2.0x) */
+ PPC_WAIT = 0x0000000000000100ULL,
+ /* Time base mftb instruction */
+ PPC_MFTB = 0x0000000000000200ULL,
+
+ /* Fixed-point unit extensions */
+ /* PowerPC 602 specific */
+ PPC_602_SPEC = 0x0000000000000400ULL,
+ /* isel instruction */
+ PPC_ISEL = 0x0000000000000800ULL,
+ /* popcntb instruction */
+ PPC_POPCNTB = 0x0000000000001000ULL,
+ /* string load / store */
+ PPC_STRING = 0x0000000000002000ULL,
+
+ /* Floating-point unit extensions */
+ /* Optional floating point instructions */
+ PPC_FLOAT = 0x0000000000010000ULL,
+ /* New floating-point extensions (PowerPC 2.0x) */
+ PPC_FLOAT_EXT = 0x0000000000020000ULL,
+ PPC_FLOAT_FSQRT = 0x0000000000040000ULL,
+ PPC_FLOAT_FRES = 0x0000000000080000ULL,
+ PPC_FLOAT_FRSQRTE = 0x0000000000100000ULL,
+ PPC_FLOAT_FRSQRTES = 0x0000000000200000ULL,
+ PPC_FLOAT_FSEL = 0x0000000000400000ULL,
+ PPC_FLOAT_STFIWX = 0x0000000000800000ULL,
+
+ /* Vector/SIMD extensions */
+ /* Altivec support */
+ PPC_ALTIVEC = 0x0000000001000000ULL,
+ /* PowerPC 2.03 SPE extension */
+ PPC_SPE = 0x0000000002000000ULL,
+ /* PowerPC 2.03 SPE single-precision floating-point extension */
+ PPC_SPE_SINGLE = 0x0000000004000000ULL,
+ /* PowerPC 2.03 SPE double-precision floating-point extension */
+ PPC_SPE_DOUBLE = 0x0000000008000000ULL,
+
+ /* Optional memory control instructions */
+ PPC_MEM_TLBIA = 0x0000000010000000ULL,
+ PPC_MEM_TLBIE = 0x0000000020000000ULL,
+ PPC_MEM_TLBSYNC = 0x0000000040000000ULL,
+ /* sync instruction */
+ PPC_MEM_SYNC = 0x0000000080000000ULL,
+ /* eieio instruction */
+ PPC_MEM_EIEIO = 0x0000000100000000ULL,
+
+ /* Cache control instructions */
+ PPC_CACHE = 0x0000000200000000ULL,
+ /* icbi instruction */
+ PPC_CACHE_ICBI = 0x0000000400000000ULL,
+ /* dcbz instruction with fixed cache line size */
+ PPC_CACHE_DCBZ = 0x0000000800000000ULL,
+ /* dcbz instruction with tunable cache line size */
+ PPC_CACHE_DCBZT = 0x0000001000000000ULL,
+ /* dcba instruction */
+ PPC_CACHE_DCBA = 0x0000002000000000ULL,
+ /* Freescale cache locking instructions */
+ PPC_CACHE_LOCK = 0x0000004000000000ULL,
+
+ /* MMU related extensions */
+ /* external control instructions */
+ PPC_EXTERN = 0x0000010000000000ULL,
+ /* segment register access instructions */
+ PPC_SEGMENT = 0x0000020000000000ULL,
+ /* PowerPC 6xx TLB management instructions */
+ PPC_6xx_TLB = 0x0000040000000000ULL,
+ /* PowerPC 74xx TLB management instructions */
+ PPC_74xx_TLB = 0x0000080000000000ULL,
+ /* PowerPC 40x TLB management instructions */
+ PPC_40x_TLB = 0x0000100000000000ULL,
+ /* segment register access instructions for PowerPC 64 "bridge" */
+ PPC_SEGMENT_64B = 0x0000200000000000ULL,
+ /* SLB management */
+ PPC_SLBI = 0x0000400000000000ULL,
+
+ /* Embedded PowerPC dedicated instructions */
+ PPC_WRTEE = 0x0001000000000000ULL,
+ /* PowerPC 40x exception model */
+ PPC_40x_EXCP = 0x0002000000000000ULL,
+ /* PowerPC 405 Mac instructions */
+ PPC_405_MAC = 0x0004000000000000ULL,
+ /* PowerPC 440 specific instructions */
+ PPC_440_SPEC = 0x0008000000000000ULL,
+ /* BookE (embedded) PowerPC specification */
+ PPC_BOOKE = 0x0010000000000000ULL,
+ /* mfapidi instruction */
+ PPC_MFAPIDI = 0x0020000000000000ULL,
+ /* tlbiva instruction */
+ PPC_TLBIVA = 0x0040000000000000ULL,
+ /* tlbivax instruction */
+ PPC_TLBIVAX = 0x0080000000000000ULL,
+ /* PowerPC 4xx dedicated instructions */
+ PPC_4xx_COMMON = 0x0100000000000000ULL,
+ /* PowerPC 40x ibct instructions */
+ PPC_40x_ICBT = 0x0200000000000000ULL,
+ /* rfmci is not implemented in all BookE PowerPC */
+ PPC_RFMCI = 0x0400000000000000ULL,
+ /* rfdi instruction */
+ PPC_RFDI = 0x0800000000000000ULL,
+ /* DCR accesses */
+ PPC_DCR = 0x1000000000000000ULL,
+ /* DCR extended accesse */
+ PPC_DCRX = 0x2000000000000000ULL,
+ /* user-mode DCR access, implemented in PowerPC 460 */
+ PPC_DCRUX = 0x4000000000000000ULL,
+};
+
+/*****************************************************************************/
/* Memory access type :
* may be needed for precise access rights control and precise exceptions.
*/
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 24c78d1..2cb90f0 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -457,144 +457,6 @@ static always_inline target_ulong MASK (uint32_t start, uint32_t end)
}
/*****************************************************************************/
-/* PowerPC Instructions types definitions */
-enum {
- PPC_NONE = 0x0000000000000000ULL,
- /* PowerPC base instructions set */
- PPC_INSNS_BASE = 0x0000000000000001ULL,
- /* integer operations instructions */
-#define PPC_INTEGER PPC_INSNS_BASE
- /* flow control instructions */
-#define PPC_FLOW PPC_INSNS_BASE
- /* virtual memory instructions */
-#define PPC_MEM PPC_INSNS_BASE
- /* ld/st with reservation instructions */
-#define PPC_RES PPC_INSNS_BASE
- /* spr/msr access instructions */
-#define PPC_MISC PPC_INSNS_BASE
- /* Deprecated instruction sets */
- /* Original POWER instruction set */
- PPC_POWER = 0x0000000000000002ULL,
- /* POWER2 instruction set extension */
- PPC_POWER2 = 0x0000000000000004ULL,
- /* Power RTC support */
- PPC_POWER_RTC = 0x0000000000000008ULL,
- /* Power-to-PowerPC bridge (601) */
- PPC_POWER_BR = 0x0000000000000010ULL,
- /* 64 bits PowerPC instruction set */
- PPC_64B = 0x0000000000000020ULL,
- /* New 64 bits extensions (PowerPC 2.0x) */
- PPC_64BX = 0x0000000000000040ULL,
- /* 64 bits hypervisor extensions */
- PPC_64H = 0x0000000000000080ULL,
- /* New wait instruction (PowerPC 2.0x) */
- PPC_WAIT = 0x0000000000000100ULL,
- /* Time base mftb instruction */
- PPC_MFTB = 0x0000000000000200ULL,
-
- /* Fixed-point unit extensions */
- /* PowerPC 602 specific */
- PPC_602_SPEC = 0x0000000000000400ULL,
- /* isel instruction */
- PPC_ISEL = 0x0000000000000800ULL,
- /* popcntb instruction */
- PPC_POPCNTB = 0x0000000000001000ULL,
- /* string load / store */
- PPC_STRING = 0x0000000000002000ULL,
-
- /* Floating-point unit extensions */
- /* Optional floating point instructions */
- PPC_FLOAT = 0x0000000000010000ULL,
- /* New floating-point extensions (PowerPC 2.0x) */
- PPC_FLOAT_EXT = 0x0000000000020000ULL,
- PPC_FLOAT_FSQRT = 0x0000000000040000ULL,
- PPC_FLOAT_FRES = 0x0000000000080000ULL,
- PPC_FLOAT_FRSQRTE = 0x0000000000100000ULL,
- PPC_FLOAT_FRSQRTES = 0x0000000000200000ULL,
- PPC_FLOAT_FSEL = 0x0000000000400000ULL,
- PPC_FLOAT_STFIWX = 0x0000000000800000ULL,
-
- /* Vector/SIMD extensions */
- /* Altivec support */
- PPC_ALTIVEC = 0x0000000001000000ULL,
- /* PowerPC 2.03 SPE extension */
- PPC_SPE = 0x0000000002000000ULL,
- /* PowerPC 2.03 SPE single-precision floating-point extension */
- PPC_SPE_SINGLE = 0x0000000004000000ULL,
- /* PowerPC 2.03 SPE double-precision floating-point extension */
- PPC_SPE_DOUBLE = 0x0000000008000000ULL,
-
- /* Optional memory control instructions */
- PPC_MEM_TLBIA = 0x0000000010000000ULL,
- PPC_MEM_TLBIE = 0x0000000020000000ULL,
- PPC_MEM_TLBSYNC = 0x0000000040000000ULL,
- /* sync instruction */
- PPC_MEM_SYNC = 0x0000000080000000ULL,
- /* eieio instruction */
- PPC_MEM_EIEIO = 0x0000000100000000ULL,
-
- /* Cache control instructions */
- PPC_CACHE = 0x0000000200000000ULL,
- /* icbi instruction */
- PPC_CACHE_ICBI = 0x0000000400000000ULL,
- /* dcbz instruction with fixed cache line size */
- PPC_CACHE_DCBZ = 0x0000000800000000ULL,
- /* dcbz instruction with tunable cache line size */
- PPC_CACHE_DCBZT = 0x0000001000000000ULL,
- /* dcba instruction */
- PPC_CACHE_DCBA = 0x0000002000000000ULL,
- /* Freescale cache locking instructions */
- PPC_CACHE_LOCK = 0x0000004000000000ULL,
-
- /* MMU related extensions */
- /* external control instructions */
- PPC_EXTERN = 0x0000010000000000ULL,
- /* segment register access instructions */
- PPC_SEGMENT = 0x0000020000000000ULL,
- /* PowerPC 6xx TLB management instructions */
- PPC_6xx_TLB = 0x0000040000000000ULL,
- /* PowerPC 74xx TLB management instructions */
- PPC_74xx_TLB = 0x0000080000000000ULL,
- /* PowerPC 40x TLB management instructions */
- PPC_40x_TLB = 0x0000100000000000ULL,
- /* segment register access instructions for PowerPC 64 "bridge" */
- PPC_SEGMENT_64B = 0x0000200000000000ULL,
- /* SLB management */
- PPC_SLBI = 0x0000400000000000ULL,
-
- /* Embedded PowerPC dedicated instructions */
- PPC_WRTEE = 0x0001000000000000ULL,
- /* PowerPC 40x exception model */
- PPC_40x_EXCP = 0x0002000000000000ULL,
- /* PowerPC 405 Mac instructions */
- PPC_405_MAC = 0x0004000000000000ULL,
- /* PowerPC 440 specific instructions */
- PPC_440_SPEC = 0x0008000000000000ULL,
- /* BookE (embedded) PowerPC specification */
- PPC_BOOKE = 0x0010000000000000ULL,
- /* mfapidi instruction */
- PPC_MFAPIDI = 0x0020000000000000ULL,
- /* tlbiva instruction */
- PPC_TLBIVA = 0x0040000000000000ULL,
- /* tlbivax instruction */
- PPC_TLBIVAX = 0x0080000000000000ULL,
- /* PowerPC 4xx dedicated instructions */
- PPC_4xx_COMMON = 0x0100000000000000ULL,
- /* PowerPC 40x ibct instructions */
- PPC_40x_ICBT = 0x0200000000000000ULL,
- /* rfmci is not implemented in all BookE PowerPC */
- PPC_RFMCI = 0x0400000000000000ULL,
- /* rfdi instruction */
- PPC_RFDI = 0x0800000000000000ULL,
- /* DCR accesses */
- PPC_DCR = 0x1000000000000000ULL,
- /* DCR extended accesse */
- PPC_DCRX = 0x2000000000000000ULL,
- /* user-mode DCR access, implemented in PowerPC 460 */
- PPC_DCRUX = 0x4000000000000000ULL,
-};
-
-/*****************************************************************************/
/* PowerPC instructions table */
#if HOST_LONG_BITS == 64
#define OPC_ALIGN 8
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 56d8d93..6b42fe1 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9480,6 +9480,7 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
env->mmu_model = def->mmu_model;
env->excp_model = def->excp_model;
env->bus_model = def->bus_model;
+ env->insns_flags = def->insns_flags;
env->flags = def->flags;
env->bfd_mach = def->bfd_mach;
env->check_pow = def->check_pow;
--
1.6.0.5
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
2009-04-22 2:32 [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling Nathan Froyd
2009-04-22 2:32 ` [Qemu-devel] [PATCH 1/3] target-ppc: expose cpu capability flags Nathan Froyd
@ 2009-04-22 2:32 ` Nathan Froyd
2009-04-23 1:22 ` malc
2009-04-22 2:32 ` [Qemu-devel] [PATCH 3/3] linux-user: support ELF_HWCAP for PPPC Nathan Froyd
2 siblings, 1 reply; 9+ messages in thread
From: Nathan Froyd @ 2009-04-22 2:32 UTC (permalink / raw)
To: qemu-devel
Implement setup_{,rt_}frame and do_{,rt_}sigreturn for PPC 32-bit. Use
the same TARGET_QEMU_ESIGRETURN hack as for MIPS to avoid clobbering
register state on a sigreturn.
Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
linux-user/main.c | 5 +
linux-user/ppc/syscall.h | 3 +
linux-user/signal.c | 596 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 604 insertions(+), 0 deletions(-)
diff --git a/linux-user/main.c b/linux-user/main.c
index dc39b05..9c57c17 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1461,6 +1461,11 @@ void cpu_loop(CPUPPCState *env)
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8]);
+ if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+ /* Returning from a successful sigreturn syscall.
+ Avoid corrupting register state. */
+ break;
+ }
if (ret > (uint32_t)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h
index a21d61b..d789911 100644
--- a/linux-user/ppc/syscall.h
+++ b/linux-user/ppc/syscall.h
@@ -51,6 +51,9 @@ struct target_revectored_struct {
abi_ulong __map[8]; /* 256 bits */
};
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
/*
* flags masks
*/
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 742d52a..e396f9c 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3182,6 +3182,602 @@ long do_rt_sigreturn(CPUState *env)
return -TARGET_ENOSYS;
}
+#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
+
+/* FIXME: Many of the structures are defined for both PPC and PPC64, but
+ the signal handling is different enough that we haven't implemented
+ support for PPC64 yet. Hence the restriction above.
+
+ There are various #if'd blocks for code for TARGET_PPC64. These
+ blocks should go away so that we can successfully run 32-bit and
+ 64-bit binaries on a QEMU configured for PPC64. */
+
+/* Size of dummy stack frame allocated when calling signal handler.
+ See arch/powerpc/include/asm/ptrace.h. */
+#if defined(TARGET_PPC64)
+#define SIGNAL_FRAMESIZE 128
+#else
+#define SIGNAL_FRAMESIZE 64
+#endif
+
+/* See arch/powerpc/include/asm/sigcontext.h. */
+struct target_sigcontext {
+ target_ulong _unused[4];
+ int32_t signal;
+#if defined(TARGET_PPC64)
+ int32_t pad0;
+#endif
+ target_ulong handler;
+ target_ulong oldmask;
+ target_ulong regs; /* struct pt_regs __user * */
+ /* TODO: PPC64 includes extra bits here. */
+};
+
+/* Indices for target_mcontext.mc_gregs, below.
+ See arch/powerpc/include/asm/ptrace.h for details. */
+enum {
+ PT_R0 = 0,
+ PT_R1 = 1,
+ PT_R2 = 2,
+ PT_R3 = 3,
+ PT_R4 = 4,
+ PT_R5 = 5,
+ PT_R6 = 6,
+ PT_R7 = 7,
+ PT_R8 = 8,
+ PT_R9 = 9,
+ PT_R10 = 10,
+ PT_R11 = 11,
+ PT_R12 = 12,
+ PT_R13 = 13,
+ PT_R14 = 14,
+ PT_R15 = 15,
+ PT_R16 = 16,
+ PT_R17 = 17,
+ PT_R18 = 18,
+ PT_R19 = 19,
+ PT_R20 = 20,
+ PT_R21 = 21,
+ PT_R22 = 22,
+ PT_R23 = 23,
+ PT_R24 = 24,
+ PT_R25 = 25,
+ PT_R26 = 26,
+ PT_R27 = 27,
+ PT_R28 = 28,
+ PT_R29 = 29,
+ PT_R30 = 30,
+ PT_R31 = 31,
+ PT_NIP = 32,
+ PT_MSR = 33,
+ PT_ORIG_R3 = 34,
+ PT_CTR = 35,
+ PT_LNK = 36,
+ PT_XER = 37,
+ PT_CCR = 38,
+ /* Yes, there are two registers with #39. One is 64-bit only. */
+ PT_MQ = 39,
+ PT_SOFTE = 39,
+ PT_TRAP = 40,
+ PT_DAR = 41,
+ PT_DSISR = 42,
+ PT_RESULT = 43,
+ PT_REGS_COUNT = 44
+};
+
+/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
+ on 64-bit PPC, sigcontext and mcontext are one and the same. */
+struct target_mcontext {
+ target_ulong mc_gregs[48];
+ /* Includes fpscr. */
+ uint64_t mc_fregs[33];
+ target_ulong mc_pad[2];
+ /* We need to handle Altivec and SPE at the same time, which no
+ kernel needs to do. Fortunately, the kernel defines this bit to
+ be Altivec-register-large all the time, rather than trying to
+ twiddle it based on the specific platform. */
+ union {
+ /* SPE vector registers. One extra for SPEFSCR. */
+ uint32_t spe[33];
+ /* Altivec vector registers. The packing of VSCR and VRSAVE
+ varies depending on whether we're PPC64 or not: PPC64 splits
+ them apart; PPC32 stuffs them together. */
+#if defined(TARGET_PPC64)
+#define NVRREG 34
+#else
+#define NVRREG 33
+#endif
+ ppc_avr_t altivec[NVRREG];
+#undef NVRREG
+ } mc_vregs __attribute__((__aligned__(16)));
+};
+
+struct target_ucontext {
+ target_ulong uc_flags;
+ target_ulong uc_link; /* struct ucontext __user * */
+ struct target_sigaltstack uc_stack;
+#if !defined(TARGET_PPC64)
+ int32_t uc_pad[7];
+ target_ulong uc_regs; /* struct mcontext __user *
+ points to uc_mcontext field */
+#endif
+ target_sigset_t uc_sigmask;
+#if defined(TARGET_PPC64)
+ target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
+ struct target_sigcontext uc_mcontext;
+#else
+ int32_t uc_maskext[30];
+ int32_t uc_pad2[3];
+ struct target_mcontext uc_mcontext;
+#endif
+};
+
+/* See arch/powerpc/kernel/signal_32.c. */
+struct target_sigframe {
+ struct target_sigcontext sctx;
+ struct target_mcontext mctx;
+ int32_t abigap[56];
+};
+
+struct target_rt_sigframe {
+ struct target_siginfo info;
+ struct target_ucontext uc;
+ int32_t abigap[56];
+};
+
+/* 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,
+ CPUState *env,
+ int frame_size)
+{
+ target_ulong oldsp, newsp;
+
+ oldsp = env->gpr[1];
+
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
+ (sas_ss_flags(oldsp))) {
+ oldsp = (target_sigaltstack_used.ss_sp
+ + target_sigaltstack_used.ss_size);
+ }
+
+ newsp = (oldsp - frame_size) & ~0xFUL;
+
+ return newsp;
+}
+
+static int save_user_regs(CPUState *env, struct target_mcontext *frame,
+ int sigret)
+{
+ target_ulong msr = env->msr;
+ int i;
+ target_ulong ccr = 0;
+
+ /* In general, the kernel attempts to be intelligent about what it
+ needs to save for Altivec/FP/SPE registers. We don't care that
+ much, so we just go ahead and save everything. */
+
+ /* Save general registers. */
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
+ return 1;
+ }
+ }
+ if (__put_user(env->nip, &frame->mc_gregs[PT_NIP])
+ || __put_user(env->ctr, &frame->mc_gregs[PT_CTR])
+ || __put_user(env->lr, &frame->mc_gregs[PT_LNK])
+ || __put_user(env->xer, &frame->mc_gregs[PT_XER]))
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+ ccr |= env->crf[i] << (32 - ((i + 1) * 4));
+ }
+ if (__put_user(ccr, &frame->mc_gregs[PT_CCR]))
+ return 1;
+
+ /* Save Altivec registers if necessary. */
+ if (env->insns_flags & PPC_ALTIVEC) {
+ for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+ ppc_avr_t *avr = &env->avr[i];
+ ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
+
+ if (__put_user(avr->u64[0], &vreg->u64[0]) ||
+ __put_user(avr->u64[1], &vreg->u64[1])) {
+ return 1;
+ }
+ }
+ /* Set MSR_VR in the saved MSR value to indicate that
+ frame->mc_vregs contains valid data. */
+ msr |= MSR_VR;
+ if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
+ &frame->mc_vregs.altivec[32].u32[3]))
+ return 1;
+ }
+
+ /* Save floating point registers. */
+ if (env->insns_flags & PPC_FLOAT) {
+ for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+ if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
+ return 1;
+ }
+ }
+ if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
+ return 1;
+ }
+
+ /* Save SPE registers. The kernel only saves the high half. */
+ if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
+ return 1;
+ }
+ }
+#else
+ for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+ if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
+ return 1;
+ }
+ }
+#endif
+ /* Set MSR_SPE in the saved MSR value to indicate that
+ frame->mc_vregs contains valid data. */
+ msr |= MSR_SPE;
+ if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
+ return 1;
+ }
+
+ /* Store MSR. */
+ if (__put_user(msr, &frame->mc_gregs[PT_MSR]))
+ return 1;
+
+ /* Set up the sigreturn trampoline: li r0,sigret; sc. */
+ if (sigret) {
+ if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
+ __put_user(0x44000002UL, &frame->tramp[1])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int restore_user_regs(CPUState *env,
+ struct target_mcontext *frame, int sig)
+{
+ target_ulong save_r2 = 0;
+ target_ulong msr;
+ target_ulong ccr;
+
+ int i;
+
+ if (!sig) {
+ save_r2 = env->gpr[2];
+ }
+
+ /* Restore general registers. */
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
+ return 1;
+ }
+ }
+ if (__get_user(env->nip, &frame->mc_gregs[PT_NIP])
+ || __get_user(env->ctr, &frame->mc_gregs[PT_CTR])
+ || __get_user(env->lr, &frame->mc_gregs[PT_LNK])
+ || __get_user(env->xer, &frame->mc_gregs[PT_XER]))
+ return 1;
+ if (__get_user(ccr, &frame->mc_gregs[PT_CCR]))
+ return 1;
+
+ for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+ env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
+ }
+
+ if (!sig) {
+ env->gpr[2] = save_r2;
+ }
+ /* Restore MSR. */
+ if (__get_user(msr, &frame->mc_gregs[PT_MSR]))
+ return 1;
+
+ /* If doing signal return, restore the previous little-endian mode. */
+ if (sig)
+ env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
+
+ /* Restore Altivec registers if necessary. */
+ if (env->insns_flags & PPC_ALTIVEC) {
+ for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+ ppc_avr_t *avr = &env->avr[i];
+ ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
+
+ if (__get_user(avr->u64[0], &vreg->u64[0]) ||
+ __get_user(avr->u64[1], &vreg->u64[1])) {
+ return 1;
+ }
+ }
+ /* Set MSR_VEC in the saved MSR value to indicate that
+ frame->mc_vregs contains valid data. */
+ if (__get_user(env->spr[SPR_VRSAVE],
+ (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
+ return 1;
+ }
+
+ /* Restore floating point registers. */
+ if (env->insns_flags & PPC_FLOAT) {
+ uint64_t fpscr;
+ for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+ if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
+ return 1;
+ }
+ }
+ if (__get_user(fpscr, &frame->mc_fregs[32]))
+ return 1;
+ env->fpscr = (uint32_t) fpscr;
+ }
+
+ /* Save SPE registers. The kernel only saves the high half. */
+ if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ uint32_t hi;
+
+ if (__get_user(hi, &frame->mc_vregs.spe[i])) {
+ return 1;
+ }
+ env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
+ }
+#else
+ for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+ if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
+ return 1;
+ }
+ }
+#endif
+ if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
+ return 1;
+ }
+
+ return 0;
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUState *env)
+{
+ struct target_sigframe *frame;
+ struct target_sigcontext *sc;
+ target_ulong frame_addr, newsp;
+ int err = 0;
+ int signal;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+ goto sigsegv;
+ sc = &frame->sctx;
+
+ signal = current_exec_domain_sig(sig);
+
+ err |= __put_user(h2g(ka->_sa_handler), &sc->handler);
+ err |= __put_user(set->sig[0], &sc->oldmask);
+#if defined(TARGET_PPC64)
+ err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
+#else
+ err |= __put_user(set->sig[1], &sc->_unused[3]);
+#endif
+ err |= __put_user(h2g(&frame->mctx), &sc->regs);
+ err |= __put_user(sig, &sc->signal);
+
+ /* Save user regs. */
+ err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
+
+ /* 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);
+
+ /* Turn off all fp exceptions. */
+ env->fpscr = 0;
+
+ /* Create a stack frame for the caller of the handler. */
+ newsp = frame_addr - SIGNAL_FRAMESIZE;
+ err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
+
+ if (err)
+ goto sigsegv;
+
+ /* Set up registers for signal handler. */
+ env->gpr[1] = newsp;
+ env->gpr[3] = signal;
+ env->gpr[4] = (target_ulong) h2g(sc);
+ env->nip = (target_ulong) ka->_sa_handler;
+ /* Signal handlers are entered in big-endian mode. */
+ env->msr &= ~MSR_LE;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ if (logfile)
+ fprintf (logfile, "segfaulting from setup_frame\n");
+ force_sig(SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUState *env)
+{
+ struct target_rt_sigframe *rt_sf;
+ struct target_mcontext *frame;
+ target_ulong rt_sf_addr, newsp = 0;
+ int i, err = 0;
+ int signal;
+
+ rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
+ if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
+ goto sigsegv;
+
+ signal = current_exec_domain_sig(sig);
+
+ err |= copy_siginfo_to_user(&rt_sf->info, info);
+
+ err |= __put_user(0, &rt_sf->uc.uc_flags);
+ err |= __put_user(0, &rt_sf->uc.uc_link);
+ err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
+ &rt_sf->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(env->gpr[1]),
+ &rt_sf->uc.uc_stack.ss_flags);
+ err |= __put_user(target_sigaltstack_used.ss_size,
+ &rt_sf->uc.uc_stack.ss_size);
+ err |= __put_user(h2g (&rt_sf->uc.uc_mcontext),
+ &rt_sf->uc.uc_regs);
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ err |= __put_user(set->sig[i], &rt_sf->uc.uc_sigmask.sig[i]);
+ }
+
+ frame = &rt_sf->uc.uc_mcontext;
+ err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
+
+ /* 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->tramp);
+
+ /* Turn off all fp exceptions. */
+ env->fpscr = 0;
+
+ /* Create a stack frame for the caller of the handler. */
+ newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
+ err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
+
+ if (err)
+ goto sigsegv;
+
+ /* Set up registers for signal handler. */
+ env->gpr[1] = newsp;
+ env->gpr[3] = (target_ulong) signal;
+ env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
+ env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
+ env->gpr[6] = (target_ulong) h2g(rt_sf);
+ env->nip = (target_ulong) ka->_sa_handler;
+ /* Signal handlers are entered in big-endian mode. */
+ env->msr &= ~MSR_LE;
+
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ return;
+
+sigsegv:
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ if (logfile)
+ fprintf (logfile, "segfaulting from setup_rt_frame\n");
+ force_sig(SIGSEGV);
+
+}
+
+long do_sigreturn(CPUState *env)
+{
+ struct target_sigcontext *sc = NULL;
+ struct target_mcontext *sr = NULL;
+ target_ulong sr_addr, sc_addr;
+ sigset_t blocked;
+ target_sigset_t set;
+
+ sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
+ if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
+ goto sigsegv;
+
+#if defined(TARGET_PPC64)
+ set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
+#else
+ if(__get_user(set.sig[0], &sc->oldmask) ||
+ __get_user(set.sig[1], &sc->_unused[3]))
+ goto sigsegv;
+#endif
+ target_to_host_sigset_internal(&blocked, &set);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+ if (__get_user(sr_addr, &sc->regs))
+ goto sigsegv;
+ if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
+ goto sigsegv;
+ if (restore_user_regs(env, sr, 1))
+ goto sigsegv;
+
+ unlock_user_struct(sr, sr_addr, 1);
+ unlock_user_struct(sc, sc_addr, 1);
+ return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+ unlock_user_struct(sr, sr_addr, 1);
+ unlock_user_struct(sc, sc_addr, 1);
+ if (logfile)
+ fprintf (logfile, "segfaulting from do_sigreturn\n");
+ force_sig(SIGSEGV);
+ return 0;
+}
+
+/* See arch/powerpc/kernel/signal_32.c. */
+static int do_setcontext(struct target_ucontext *ucp, CPUState *env, int sig)
+{
+ struct target_mcontext *mcp;
+ target_ulong mcp_addr;
+ sigset_t blocked;
+ target_sigset_t set;
+
+ if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, uc_sigmask),
+ sizeof (set)))
+ return 1;
+
+#if defined(TARGET_PPC64)
+ fprintf (stderr, "do_setcontext: not implemented\n");
+ return 0;
+#else
+ if (__get_user(mcp_addr, &ucp->uc_regs))
+ return 1;
+
+ if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
+ return 1;
+
+ target_to_host_sigset_internal(&blocked, &set);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+ if (restore_user_regs(env, mcp, sig))
+ goto sigsegv;
+
+ unlock_user_struct(mcp, mcp_addr, 1);
+ return 0;
+
+sigsegv:
+ unlock_user_struct(mcp, mcp_addr, 1);
+ return 1;
+#endif
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+ struct target_rt_sigframe *rt_sf = NULL;
+ target_ulong rt_sf_addr;
+
+ rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
+ if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
+ goto sigsegv;
+
+ if (do_setcontext(&rt_sf->uc, env, 1))
+ goto sigsegv;
+
+ do_sigaltstack(rt_sf_addr
+ + offsetof(struct target_rt_sigframe, uc.uc_stack),
+ 0, env->gpr[1]);
+
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ if (logfile)
+ fprintf (logfile, "segfaulting from do_rt_sigreturn\n");
+ force_sig(SIGSEGV);
+ return 0;
+}
+
#else
static void setup_frame(int sig, struct target_sigaction *ka,
--
1.6.0.5
^ permalink raw reply related [flat|nested] 9+ messages in thread