From: Chen Gang <gang.chen.5...@gmail.com>

Notice raise and bpt, decoding the constants embedded in the
nop addil instruction in the x0 slot.

[rth: Generalize TILEGX_EXCP_OPCODE_ILL to TILEGX_EXCP_SIGNAL.
Drop validation of signal values.]

Signed-off-by: Chen Gang <gang.chen.5...@gmail.com>
Message-Id: <1443243635-4886-1-git-send-email-gang.chen.5...@gmail.com>
Signed-off-by: Richard Henderson <r...@twiddle.net>
---
 linux-user/main.c         | 14 ++++++++
 target-tilegx/cpu.h       |  5 ++-
 target-tilegx/translate.c | 81 +++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index 6599a41..9e8b92b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3436,6 +3436,17 @@ static void gen_sigill_reg(CPUTLGState *env)
     queue_signal(env, info.si_signo, &info);
 }
 
+static void do_signal(CPUTLGState *env)
+{
+    target_siginfo_t info;
+
+    info.si_signo = env->signo;
+    info.si_errno = 0;
+    info.si_code = env->sigcode;
+    info._sifields._sigfault._addr = env->pc;
+    queue_signal(env, info.si_signo, &info);
+}
+
 static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
 {
     if (unlikely(reg >= TILEGX_R_COUNT)) {
@@ -3622,6 +3633,9 @@ void cpu_loop(CPUTLGState *env)
         case TILEGX_EXCP_OPCODE_FETCHOR4:
             do_fetch(env, trapnr, false);
             break;
+        case TILEGX_EXCP_SIGNAL:
+            do_signal(env);
+            break;
         case TILEGX_EXCP_REG_IDN_ACCESS:
         case TILEGX_EXCP_REG_UDN_ACCESS:
             gen_sigill_reg(env);
diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h
index b9f5082..023ccd4 100644
--- a/target-tilegx/cpu.h
+++ b/target-tilegx/cpu.h
@@ -61,6 +61,7 @@ typedef enum {
     TILEGX_EXCP_NONE = 0,
     TILEGX_EXCP_SYSCALL = 1,
     TILEGX_EXCP_SEGV = 2,
+    TILEGX_EXCP_SIGNAL = 3,
     TILEGX_EXCP_OPCODE_UNKNOWN = 0x101,
     TILEGX_EXCP_OPCODE_UNIMPLEMENTED = 0x102,
     TILEGX_EXCP_OPCODE_CMPEXCH = 0x103,
@@ -87,10 +88,12 @@ typedef struct CPUTLGState {
     uint64_t pc;                       /* Current pc */
 
 #if defined(CONFIG_USER_ONLY)
+    uint64_t excaddr;                  /* exception address */
     uint64_t atomic_srca;              /* Arguments to atomic "exceptions" */
     uint64_t atomic_srcb;
     uint32_t atomic_dstr;
-    uint64_t excaddr;                  /* exception address */
+    uint32_t signo;                    /* Signal number */
+    uint32_t sigcode;                  /* Signal code */
 #endif
 
     CPU_COMMON
diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c
index 3566b88..54aa71d 100644
--- a/target-tilegx/translate.c
+++ b/target-tilegx/translate.c
@@ -23,6 +23,8 @@
 #include "disas/disas.h"
 #include "tcg-op.h"
 #include "exec/cpu_ldst.h"
+#include "linux-user/syscall_defs.h"
+
 #include "opcode_tilegx.h"
 #include "spr_def_64.h"
 
@@ -429,8 +431,66 @@ static void gen_v4op(TCGv d64, TCGv a64, TCGv b64,
     tcg_temp_free_i32(bh);
 }
 
+static TileExcp gen_signal(DisasContext *dc, int signo, int sigcode,
+                           const char *mnemonic)
+{
+    TCGv_i32 t0 = tcg_const_i32(signo);
+    TCGv_i32 t1 = tcg_const_i32(sigcode);
+
+    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUTLGState, signo));
+    tcg_gen_st_i32(t1, cpu_env, offsetof(CPUTLGState, sigcode));
+
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t0);
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s", mnemonic);
+    return TILEGX_EXCP_SIGNAL;
+}
+
+static bool parse_from_addli(uint64_t bundle, int *signo, int *sigcode)
+{
+    int imm;
+
+    if ((get_Opcode_X0(bundle) != ADDLI_OPCODE_X0)
+        || (get_Dest_X0(bundle) != TILEGX_R_ZERO)
+        || (get_SrcA_X0(bundle) != TILEGX_R_ZERO)) {
+        return false;
+    }
+
+    imm = get_Imm16_X0(bundle);
+    *signo = imm & 0x3f;
+    *sigcode = (imm >> 6) & 0xf;
+
+    /* ??? The linux kernel validates both signo and the sigcode vs the
+       known max for each signal.  Don't bother here.  */
+    return true;
+}
+
+static TileExcp gen_specill(DisasContext *dc, unsigned dest, unsigned srca,
+                            uint64_t bundle)
+{
+    const char *mnemonic;
+    int signo;
+    int sigcode;
+
+    if (dest == 0x1c && srca == 0x25) {
+        signo = TARGET_SIGTRAP;
+        sigcode = TARGET_TRAP_BRKPT;
+        mnemonic = "bpt";
+    } else if (dest == 0x1d && srca == 0x25
+               && parse_from_addli(bundle, &signo, &sigcode)) {
+        mnemonic = "raise";
+    } else {
+        signo = TARGET_SIGILL;
+        sigcode = TARGET_ILL_ILLOPC;
+        mnemonic = "ill";
+    }
+
+    return gen_signal(dc, signo, sigcode, mnemonic);
+}
+
 static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
-                              unsigned dest, unsigned srca)
+                              unsigned dest, unsigned srca, uint64_t bundle)
 {
     TCGv tdest, tsrca;
     const char *mnemonic;
@@ -458,16 +518,9 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned 
opext,
         mnemonic = "flushwb";
         goto done0;
     case OE_RR_X1(ILL):
-        if (dest == 0x1c && srca == 0x25) {
-            mnemonic = "bpt";
-            goto done2;
-        }
-        /* Fall through */
+        return gen_specill(dc, dest, srca, bundle);
     case OE_RR_Y1(ILL):
-        mnemonic = "ill";
-    done2:
-        qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s", mnemonic);
-        return TILEGX_EXCP_OPCODE_UNKNOWN;
+        return gen_signal(dc, TARGET_SIGILL, TARGET_ILL_ILLOPC, "ill");
     case OE_RR_X1(MF):
         mnemonic = "mf";
         goto done0;
@@ -1909,7 +1962,7 @@ static TileExcp decode_y0(DisasContext *dc, 
tilegx_bundle_bits bundle)
     case RRR_1_OPCODE_Y0:
         if (ext == UNARY_RRR_1_OPCODE_Y0) {
             ext = get_UnaryOpcodeExtension_Y0(bundle);
-            return gen_rr_opcode(dc, OE(opc, ext, Y0), dest, srca);
+            return gen_rr_opcode(dc, OE(opc, ext, Y0), dest, srca, bundle);
         }
         /* fallthru */
     case RRR_0_OPCODE_Y0:
@@ -1955,7 +2008,7 @@ static TileExcp decode_y1(DisasContext *dc, 
tilegx_bundle_bits bundle)
     case RRR_1_OPCODE_Y1:
         if (ext == UNARY_RRR_1_OPCODE_Y0) {
             ext = get_UnaryOpcodeExtension_Y1(bundle);
-            return gen_rr_opcode(dc, OE(opc, ext, Y1), dest, srca);
+            return gen_rr_opcode(dc, OE(opc, ext, Y1), dest, srca, bundle);
         }
         /* fallthru */
     case RRR_0_OPCODE_Y1:
@@ -2057,7 +2110,7 @@ static TileExcp decode_x0(DisasContext *dc, 
tilegx_bundle_bits bundle)
         ext = get_RRROpcodeExtension_X0(bundle);
         if (ext == UNARY_RRR_0_OPCODE_X0) {
             ext = get_UnaryOpcodeExtension_X0(bundle);
-            return gen_rr_opcode(dc, OE(opc, ext, X0), dest, srca);
+            return gen_rr_opcode(dc, OE(opc, ext, X0), dest, srca, bundle);
         }
         srcb = get_SrcB_X0(bundle);
         return gen_rrr_opcode(dc, OE(opc, ext, X0), dest, srca, srcb);
@@ -2104,7 +2157,7 @@ static TileExcp decode_x1(DisasContext *dc, 
tilegx_bundle_bits bundle)
         switch (ext) {
         case UNARY_RRR_0_OPCODE_X1:
             ext = get_UnaryOpcodeExtension_X1(bundle);
-            return gen_rr_opcode(dc, OE(opc, ext, X1), dest, srca);
+            return gen_rr_opcode(dc, OE(opc, ext, X1), dest, srca, bundle);
         case ST1_RRR_0_OPCODE_X1:
             return gen_st_opcode(dc, dest, srca, srcb, MO_UB, "st1");
         case ST2_RRR_0_OPCODE_X1:
-- 
2.4.3


Reply via email to