All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling
@ 2009-04-22  2:32 Nathan Froyd
  2009-04-22  2:32 ` [Qemu-devel] [PATCH 1/3] target-ppc: expose cpu capability flags Nathan Froyd
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Nathan Froyd @ 2009-04-22  2:32 UTC (permalink / raw)
  To: qemu-devel

This patch series adds signal handling support for 32-bit PPC linux-user
emulation.  It requires a bit of shuffling of target-ppc code to ensure
that we know what the capabilities of our current CPU are so we know
which registers to save.

The signal handling code has been tested by an in-house NPTL
implementation for PPC linux-user emulation.  The NPTL implementation
will be coming along shortly, but the signal handling bits are useful on
their own.

-Nathan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [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; 11+ 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] 11+ 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; 11+ 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] 11+ messages in thread

* [Qemu-devel] [PATCH 3/3] linux-user: support ELF_HWCAP for PPPC
  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 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
@ 2009-04-22  2:32 ` Nathan Froyd
  2 siblings, 0 replies; 11+ messages in thread
From: Nathan Froyd @ 2009-04-22  2:32 UTC (permalink / raw)
  To: qemu-devel


Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
 linux-user/elfload.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 6de30f4..508cb37 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -300,6 +300,64 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
 #endif
 #define ELF_ARCH	EM_PPC
 
+/* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
+   See arch/powerpc/include/asm/cputable.h.  */
+enum {
+    PPC_FEATURE_32 = 0x80000000,
+    PPC_FEATURE_64 = 0x40000000,
+    PPC_FEATURE_601_INSTR = 0x20000000,
+    PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
+    PPC_FEATURE_HAS_FPU = 0x08000000,
+    PPC_FEATURE_HAS_MMU = 0x04000000,
+    PPC_FEATURE_HAS_4xxMAC = 0x02000000,
+    PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
+    PPC_FEATURE_HAS_SPE = 0x00800000,
+    PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
+    PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
+    PPC_FEATURE_NO_TB = 0x00100000,
+    PPC_FEATURE_POWER4 = 0x00080000,
+    PPC_FEATURE_POWER5 = 0x00040000,
+    PPC_FEATURE_POWER5_PLUS = 0x00020000,
+    PPC_FEATURE_CELL = 0x00010000,
+    PPC_FEATURE_BOOKE = 0x00008000,
+    PPC_FEATURE_SMT = 0x00004000,
+    PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
+    PPC_FEATURE_ARCH_2_05 = 0x00001000,
+    PPC_FEATURE_PA6T = 0x00000800,
+    PPC_FEATURE_HAS_DFP = 0x00000400,
+    PPC_FEATURE_POWER6_EXT = 0x00000200,
+    PPC_FEATURE_ARCH_2_06 = 0x00000100,
+    PPC_FEATURE_HAS_VSX = 0x00000080,
+    PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
+
+    PPC_FEATURE_TRUE_LE = 0x00000002,
+    PPC_FEATURE_PPC_LE = 0x00000001,
+};
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+    CPUState *e = thread_env;
+    uint32_t features = 0;
+
+    /* We don't have to be terribly complete here; the high points are
+       Altivec/FP/SPE support.  Anything else is just a bonus.  */
+#define GET_FEATURE(flag, feature)              \
+    do {if (e->insns_flags & flag) features |= feature; } while(0)
+    GET_FEATURE(PPC_64B, PPC_FEATURE_64);
+    GET_FEATURE(PPC_FLOAT, PPC_FEATURE_HAS_FPU);
+    GET_FEATURE(PPC_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC);
+    GET_FEATURE(PPC_SPE, PPC_FEATURE_HAS_SPE);
+    GET_FEATURE(PPC_SPE_SINGLE, PPC_FEATURE_HAS_EFP_SINGLE);
+    GET_FEATURE(PPC_SPE_DOUBLE, PPC_FEATURE_HAS_EFP_DOUBLE);
+    GET_FEATURE(PPC_BOOKE, PPC_FEATURE_BOOKE);
+    GET_FEATURE(PPC_405_MAC, PPC_FEATURE_HAS_4xxMAC);
+#undef GET_FEATURE
+
+    return features;
+}
+
 /*
  * We need to put in some extra aux table entries to tell glibc what
  * the cache block size is, so it can use the dcbz instruction safely.
-- 
1.6.0.5

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-04-22  2:32 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
@ 2009-04-23  1:22   ` malc
  2009-04-23  1:55     ` Nathan Froyd
  0 siblings, 1 reply; 11+ messages in thread
From: malc @ 2009-04-23  1:22 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Tue, 21 Apr 2009, Nathan Froyd wrote:

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

With one modification i managed to make it compile and run on my system,
but:

a) Why is it marked as second/third in the series (patch makred as
   first has different subject and touches main ppc translation engine
   and AFAICT doesn't have much to do with linux user bits)?

> 
> 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(-)
> 
[..snip..]

> +
> +/* 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
> +};

b) This clashes with PT_ (save for PT_SOFTE) values that are "leaking"
   through the headers that were previously included. To make it build
   i replaced all instances of PT_ with QPT_

[..snip..]

> +
> +    /* 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])) {

c) For the reasons i can not really understand gcc-4.4.0 says:

.../signal.c:3439: warning: large integer implicitly truncated to unsigned type
             ^^^^ That's the 0x44000002UL line.

[..snip..]

Otherwise, looks good (IOW `openssl speed sha1' is now usable)

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-04-23  1:22   ` malc
@ 2009-04-23  1:55     ` Nathan Froyd
  2009-04-23 14:44       ` malc
  0 siblings, 1 reply; 11+ messages in thread
From: Nathan Froyd @ 2009-04-23  1:55 UTC (permalink / raw)
  To: malc; +Cc: qemu-devel

On Thu, Apr 23, 2009 at 05:22:55AM +0400, malc wrote:
> On Tue, 21 Apr 2009, Nathan Froyd wrote:
> 
> > 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.
> 
> With one modification i managed to make it compile and run on my system,
> but:
> 
> a) Why is it marked as second/third in the series (patch makred as
>    first has different subject and touches main ppc translation engine
>    and AFAICT doesn't have much to do with linux user bits)?

The first patch moves the cpu capability flags to a place where
save_user_regs and restore_user_regs can get at them.  The main reason
this is necessary is to choose between altivec and spe register
save/restore, since the save area for those registers overlap.
elfload.c in the third patch also uses the cpu capability flags.  (I
suppose if QEMU ever supports VSX, those flags will come in handy in the
same place(s) as well.  Maybe decimal float, too, since IIRC FPSCR is
larger in DFP-supporting processors...)

> > +/* 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
> > +};
> 
> b) This clashes with PT_ (save for PT_SOFTE) values that are "leaking"
>    through the headers that were previously included. To make it build
>    i replaced all instances of PT_ with QPT_

Is this because you're compiling on ppc?  I'll update the patch to use
TARGET_PT_*; I like the brevity of QPT_*, but TARGET_PT_* is more inline
with linux-user conventions.

> > +    /* 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])) {
> 
> c) For the reasons i can not really understand gcc-4.4.0 says:
> 
> .../signal.c:3439: warning: large integer implicitly truncated to unsigned type
>              ^^^^ That's the 0x44000002UL line.

I got this warning too and I'm really not sure how to make it go away.
I've tried several things but none of them had any effect.

-Nathan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-04-23  1:55     ` Nathan Froyd
@ 2009-04-23 14:44       ` malc
  2009-04-23 16:11         ` Nathan Froyd
  0 siblings, 1 reply; 11+ messages in thread
From: malc @ 2009-04-23 14:44 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Wed, 22 Apr 2009, Nathan Froyd wrote:

> On Thu, Apr 23, 2009 at 05:22:55AM +0400, malc wrote:
> > On Tue, 21 Apr 2009, Nathan Froyd wrote:
> > 
> > > 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.
> > 
> > With one modification i managed to make it compile and run on my system,
> > but:
> > 
> > a) Why is it marked as second/third in the series (patch makred as
> >    first has different subject and touches main ppc translation engine
> >    and AFAICT doesn't have much to do with linux user bits)?
> 
> The first patch moves the cpu capability flags to a place where
> save_user_regs and restore_user_regs can get at them.  The main reason
> this is necessary is to choose between altivec and spe register
> save/restore, since the save area for those registers overlap.
> elfload.c in the third patch also uses the cpu capability flags.  (I
> suppose if QEMU ever supports VSX, those flags will come in handy in the
> same place(s) as well.  Maybe decimal float, too, since IIRC FPSCR is
> larger in DFP-supporting processors...)

Thing is i applied patches 2 and 3 and things just worked thus questioned
the utility of patch 1.

[..snip..]
 
> > 
> > b) This clashes with PT_ (save for PT_SOFTE) values that are "leaking"
> >    through the headers that were previously included. To make it build
> >    i replaced all instances of PT_ with QPT_
> 
> Is this because you're compiling on ppc?  I'll update the patch to use
> TARGET_PT_*; I like the brevity of QPT_*, but TARGET_PT_* is more inline
> with linux-user conventions.

I'm compiling on a ppc yes, as for TARGET_PT_, sure, will do just as fine.
 
> > > +    /* 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])) {
> > 
> > c) For the reasons i can not really understand gcc-4.4.0 says:
> > 
> > .../signal.c:3439: warning: large integer implicitly truncated to unsigned type
> >              ^^^^ That's the 0x44000002UL line.
> 
> I got this warning too and I'm really not sure how to make it go away.
> I've tried several things but none of them had any effect.

Puzzling that..

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-04-23 14:44       ` malc
@ 2009-04-23 16:11         ` Nathan Froyd
  2009-04-23 23:18           ` malc
  0 siblings, 1 reply; 11+ messages in thread
From: Nathan Froyd @ 2009-04-23 16:11 UTC (permalink / raw)
  To: malc; +Cc: qemu-devel

On Thu, Apr 23, 2009 at 06:44:39PM +0400, malc wrote:
> On Wed, 22 Apr 2009, Nathan Froyd wrote:
> > The first patch moves the cpu capability flags to a place where
> > save_user_regs and restore_user_regs can get at them.
> 
> Thing is i applied patches 2 and 3 and things just worked thus questioned
> the utility of patch 1.

I suppose this is possible, but it seems unlikely, given that patches 2
and 3 reference env->insns_flags, which is a nonexistent field if you
didn't already apply patch 1...

-Nathan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-04-23 16:11         ` Nathan Froyd
@ 2009-04-23 23:18           ` malc
  0 siblings, 0 replies; 11+ messages in thread
From: malc @ 2009-04-23 23:18 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: qemu-devel

On Thu, 23 Apr 2009, Nathan Froyd wrote:

> On Thu, Apr 23, 2009 at 06:44:39PM +0400, malc wrote:
> > On Wed, 22 Apr 2009, Nathan Froyd wrote:
> > > The first patch moves the cpu capability flags to a place where
> > > save_user_regs and restore_user_regs can get at them.
> > 
> > Thing is i applied patches 2 and 3 and things just worked thus questioned
> > the utility of patch 1.
> 
> I suppose this is possible, but it seems unlikely, given that patches 2
> and 3 reference env->insns_flags, which is a nonexistent field if you
> didn't already apply patch 1...

You are right, i only wanted to apply just 2,3 but somehow applied all.

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-05-12 19:26 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
@ 2009-05-13  2:13   ` Nathan Froyd
  0 siblings, 0 replies; 11+ messages in thread
From: Nathan Froyd @ 2009-05-13  2:13 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>
---
Remove the trailing whitespace and tabs that malc noticed.

 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..9c9c7eb 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 {
+    TARGET_PT_R0 = 0,
+    TARGET_PT_R1 = 1,
+    TARGET_PT_R2 = 2,
+    TARGET_PT_R3 = 3,
+    TARGET_PT_R4 = 4,
+    TARGET_PT_R5 = 5,
+    TARGET_PT_R6 = 6,
+    TARGET_PT_R7 = 7,
+    TARGET_PT_R8 = 8,
+    TARGET_PT_R9 = 9,
+    TARGET_PT_R10 = 10,
+    TARGET_PT_R11 = 11,
+    TARGET_PT_R12 = 12,
+    TARGET_PT_R13 = 13,
+    TARGET_PT_R14 = 14,
+    TARGET_PT_R15 = 15,
+    TARGET_PT_R16 = 16,
+    TARGET_PT_R17 = 17,
+    TARGET_PT_R18 = 18,
+    TARGET_PT_R19 = 19,
+    TARGET_PT_R20 = 20,
+    TARGET_PT_R21 = 21,
+    TARGET_PT_R22 = 22,
+    TARGET_PT_R23 = 23,
+    TARGET_PT_R24 = 24,
+    TARGET_PT_R25 = 25,
+    TARGET_PT_R26 = 26,
+    TARGET_PT_R27 = 27,
+    TARGET_PT_R28 = 28,
+    TARGET_PT_R29 = 29,
+    TARGET_PT_R30 = 30,
+    TARGET_PT_R31 = 31,
+    TARGET_PT_NIP = 32,
+    TARGET_PT_MSR = 33,
+    TARGET_PT_ORIG_R3 = 34,
+    TARGET_PT_CTR = 35,
+    TARGET_PT_LNK = 36,
+    TARGET_PT_XER = 37,
+    TARGET_PT_CCR = 38,
+    /* Yes, there are two registers with #39.  One is 64-bit only.  */
+    TARGET_PT_MQ = 39,
+    TARGET_PT_SOFTE = 39,
+    TARGET_PT_TRAP = 40,
+    TARGET_PT_DAR = 41,
+    TARGET_PT_DSISR = 42,
+    TARGET_PT_RESULT = 43,
+    TARGET_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[TARGET_PT_NIP])
+        || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __put_user(env->xer, &frame->mc_gregs[TARGET_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[TARGET_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[TARGET_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[TARGET_PT_NIP])
+        || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
+        return 1;
+    if (__get_user(ccr, &frame->mc_gregs[TARGET_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[TARGET_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] 11+ messages in thread

* [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
  2009-05-12 19:26 [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling, v2 Nathan Froyd
@ 2009-05-12 19:26 ` Nathan Froyd
  2009-05-13  2:13   ` Nathan Froyd
  0 siblings, 1 reply; 11+ messages in thread
From: Nathan Froyd @ 2009-05-12 19:26 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..d7dd3cf 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 {
+    TARGET_PT_R0 = 0,
+    TARGET_PT_R1 = 1,
+    TARGET_PT_R2 = 2,
+    TARGET_PT_R3 = 3,
+    TARGET_PT_R4 = 4,
+    TARGET_PT_R5 = 5,
+    TARGET_PT_R6 = 6,
+    TARGET_PT_R7 = 7,
+    TARGET_PT_R8 = 8,
+    TARGET_PT_R9 = 9,
+    TARGET_PT_R10 = 10,
+    TARGET_PT_R11 = 11,
+    TARGET_PT_R12 = 12,
+    TARGET_PT_R13 = 13,
+    TARGET_PT_R14 = 14,
+    TARGET_PT_R15 = 15,
+    TARGET_PT_R16 = 16,
+    TARGET_PT_R17 = 17,
+    TARGET_PT_R18 = 18,
+    TARGET_PT_R19 = 19,
+    TARGET_PT_R20 = 20,
+    TARGET_PT_R21 = 21,
+    TARGET_PT_R22 = 22,
+    TARGET_PT_R23 = 23,
+    TARGET_PT_R24 = 24,
+    TARGET_PT_R25 = 25,
+    TARGET_PT_R26 = 26,
+    TARGET_PT_R27 = 27,
+    TARGET_PT_R28 = 28,
+    TARGET_PT_R29 = 29,
+    TARGET_PT_R30 = 30,
+    TARGET_PT_R31 = 31,
+    TARGET_PT_NIP = 32,
+    TARGET_PT_MSR = 33,
+    TARGET_PT_ORIG_R3 = 34,
+    TARGET_PT_CTR = 35,
+    TARGET_PT_LNK = 36,
+    TARGET_PT_XER = 37,
+    TARGET_PT_CCR = 38,
+    /* Yes, there are two registers with #39.  One is 64-bit only.  */
+    TARGET_PT_MQ = 39,
+    TARGET_PT_SOFTE = 39,
+    TARGET_PT_TRAP = 40,
+    TARGET_PT_DAR = 41,
+    TARGET_PT_DSISR = 42,
+    TARGET_PT_RESULT = 43,
+    TARGET_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[TARGET_PT_NIP])
+        || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __put_user(env->xer, &frame->mc_gregs[TARGET_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[TARGET_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[TARGET_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[TARGET_PT_NIP])
+        || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
+        return 1;
+    if (__get_user(ccr, &frame->mc_gregs[TARGET_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[TARGET_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] 11+ messages in thread

end of thread, other threads:[~2009-05-13  2:13 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
2009-04-23  1:22   ` malc
2009-04-23  1:55     ` Nathan Froyd
2009-04-23 14:44       ` malc
2009-04-23 16:11         ` Nathan Froyd
2009-04-23 23:18           ` malc
2009-04-22  2:32 ` [Qemu-devel] [PATCH 3/3] linux-user: support ELF_HWCAP for PPPC Nathan Froyd
2009-05-12 19:26 [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling, v2 Nathan Froyd
2009-05-12 19:26 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
2009-05-13  2:13   ` Nathan Froyd

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.