target-tilegx: Decode ill pseudo-instructions
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.5i5j@gmail.com> Message-Id: <1443243635-4886-1-git-send-email-gang.chen.5i5j@gmail.com> Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
bf0f60a61b
commit
dd8070d865
@ -3436,6 +3436,17 @@ static void gen_sigill_reg(CPUTLGState *env)
|
|||||||
queue_signal(env, info.si_signo, &info);
|
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)
|
static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
|
||||||
{
|
{
|
||||||
if (unlikely(reg >= TILEGX_R_COUNT)) {
|
if (unlikely(reg >= TILEGX_R_COUNT)) {
|
||||||
@ -3622,6 +3633,9 @@ void cpu_loop(CPUTLGState *env)
|
|||||||
case TILEGX_EXCP_OPCODE_FETCHOR4:
|
case TILEGX_EXCP_OPCODE_FETCHOR4:
|
||||||
do_fetch(env, trapnr, false);
|
do_fetch(env, trapnr, false);
|
||||||
break;
|
break;
|
||||||
|
case TILEGX_EXCP_SIGNAL:
|
||||||
|
do_signal(env);
|
||||||
|
break;
|
||||||
case TILEGX_EXCP_REG_IDN_ACCESS:
|
case TILEGX_EXCP_REG_IDN_ACCESS:
|
||||||
case TILEGX_EXCP_REG_UDN_ACCESS:
|
case TILEGX_EXCP_REG_UDN_ACCESS:
|
||||||
gen_sigill_reg(env);
|
gen_sigill_reg(env);
|
||||||
|
@ -61,6 +61,7 @@ typedef enum {
|
|||||||
TILEGX_EXCP_NONE = 0,
|
TILEGX_EXCP_NONE = 0,
|
||||||
TILEGX_EXCP_SYSCALL = 1,
|
TILEGX_EXCP_SYSCALL = 1,
|
||||||
TILEGX_EXCP_SEGV = 2,
|
TILEGX_EXCP_SEGV = 2,
|
||||||
|
TILEGX_EXCP_SIGNAL = 3,
|
||||||
TILEGX_EXCP_OPCODE_UNKNOWN = 0x101,
|
TILEGX_EXCP_OPCODE_UNKNOWN = 0x101,
|
||||||
TILEGX_EXCP_OPCODE_UNIMPLEMENTED = 0x102,
|
TILEGX_EXCP_OPCODE_UNIMPLEMENTED = 0x102,
|
||||||
TILEGX_EXCP_OPCODE_CMPEXCH = 0x103,
|
TILEGX_EXCP_OPCODE_CMPEXCH = 0x103,
|
||||||
@ -87,10 +88,12 @@ typedef struct CPUTLGState {
|
|||||||
uint64_t pc; /* Current pc */
|
uint64_t pc; /* Current pc */
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
uint64_t excaddr; /* exception address */
|
||||||
uint64_t atomic_srca; /* Arguments to atomic "exceptions" */
|
uint64_t atomic_srca; /* Arguments to atomic "exceptions" */
|
||||||
uint64_t atomic_srcb;
|
uint64_t atomic_srcb;
|
||||||
uint32_t atomic_dstr;
|
uint32_t atomic_dstr;
|
||||||
uint64_t excaddr; /* exception address */
|
uint32_t signo; /* Signal number */
|
||||||
|
uint32_t sigcode; /* Signal code */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CPU_COMMON
|
CPU_COMMON
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
#include "tcg-op.h"
|
#include "tcg-op.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
|
#include "linux-user/syscall_defs.h"
|
||||||
|
|
||||||
#include "opcode_tilegx.h"
|
#include "opcode_tilegx.h"
|
||||||
#include "spr_def_64.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);
|
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,
|
static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
|
||||||
unsigned dest, unsigned srca)
|
unsigned dest, unsigned srca, uint64_t bundle)
|
||||||
{
|
{
|
||||||
TCGv tdest, tsrca;
|
TCGv tdest, tsrca;
|
||||||
const char *mnemonic;
|
const char *mnemonic;
|
||||||
@ -458,16 +518,9 @@ static TileExcp gen_rr_opcode(DisasContext *dc, unsigned opext,
|
|||||||
mnemonic = "flushwb";
|
mnemonic = "flushwb";
|
||||||
goto done0;
|
goto done0;
|
||||||
case OE_RR_X1(ILL):
|
case OE_RR_X1(ILL):
|
||||||
if (dest == 0x1c && srca == 0x25) {
|
return gen_specill(dc, dest, srca, bundle);
|
||||||
mnemonic = "bpt";
|
|
||||||
goto done2;
|
|
||||||
}
|
|
||||||
/* Fall through */
|
|
||||||
case OE_RR_Y1(ILL):
|
case OE_RR_Y1(ILL):
|
||||||
mnemonic = "ill";
|
return gen_signal(dc, TARGET_SIGILL, TARGET_ILL_ILLOPC, "ill");
|
||||||
done2:
|
|
||||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s", mnemonic);
|
|
||||||
return TILEGX_EXCP_OPCODE_UNKNOWN;
|
|
||||||
case OE_RR_X1(MF):
|
case OE_RR_X1(MF):
|
||||||
mnemonic = "mf";
|
mnemonic = "mf";
|
||||||
goto done0;
|
goto done0;
|
||||||
@ -1909,7 +1962,7 @@ static TileExcp decode_y0(DisasContext *dc, tilegx_bundle_bits bundle)
|
|||||||
case RRR_1_OPCODE_Y0:
|
case RRR_1_OPCODE_Y0:
|
||||||
if (ext == UNARY_RRR_1_OPCODE_Y0) {
|
if (ext == UNARY_RRR_1_OPCODE_Y0) {
|
||||||
ext = get_UnaryOpcodeExtension_Y0(bundle);
|
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 */
|
/* fallthru */
|
||||||
case RRR_0_OPCODE_Y0:
|
case RRR_0_OPCODE_Y0:
|
||||||
@ -1955,7 +2008,7 @@ static TileExcp decode_y1(DisasContext *dc, tilegx_bundle_bits bundle)
|
|||||||
case RRR_1_OPCODE_Y1:
|
case RRR_1_OPCODE_Y1:
|
||||||
if (ext == UNARY_RRR_1_OPCODE_Y0) {
|
if (ext == UNARY_RRR_1_OPCODE_Y0) {
|
||||||
ext = get_UnaryOpcodeExtension_Y1(bundle);
|
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 */
|
/* fallthru */
|
||||||
case RRR_0_OPCODE_Y1:
|
case RRR_0_OPCODE_Y1:
|
||||||
@ -2057,7 +2110,7 @@ static TileExcp decode_x0(DisasContext *dc, tilegx_bundle_bits bundle)
|
|||||||
ext = get_RRROpcodeExtension_X0(bundle);
|
ext = get_RRROpcodeExtension_X0(bundle);
|
||||||
if (ext == UNARY_RRR_0_OPCODE_X0) {
|
if (ext == UNARY_RRR_0_OPCODE_X0) {
|
||||||
ext = get_UnaryOpcodeExtension_X0(bundle);
|
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);
|
srcb = get_SrcB_X0(bundle);
|
||||||
return gen_rrr_opcode(dc, OE(opc, ext, X0), dest, srca, srcb);
|
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) {
|
switch (ext) {
|
||||||
case UNARY_RRR_0_OPCODE_X1:
|
case UNARY_RRR_0_OPCODE_X1:
|
||||||
ext = get_UnaryOpcodeExtension_X1(bundle);
|
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:
|
case ST1_RRR_0_OPCODE_X1:
|
||||||
return gen_st_opcode(dc, dest, srca, srcb, MO_UB, "st1");
|
return gen_st_opcode(dc, dest, srca, srcb, MO_UB, "st1");
|
||||||
case ST2_RRR_0_OPCODE_X1:
|
case ST2_RRR_0_OPCODE_X1:
|
||||||
|
Loading…
Reference in New Issue
Block a user