target/xtensa: extract test for an illegal instruction
- TB flags: add XTENSA_TBFLAG_CWOE that corresponds to the architectural CWOE state; - entry: move CWOE check from the helper to the test_ill_entry; - retw: move CWOE check from the helper to the test_ill_retw; - separate instruction disassembly loop and translation loop; save disassembly results in local array; Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
This commit is contained in:
parent
c5e4e49258
commit
0946097051
@ -217,6 +217,7 @@ enum {
|
|||||||
#define MEMCTL_IL0EN 0x1
|
#define MEMCTL_IL0EN 0x1
|
||||||
|
|
||||||
#define MAX_INSN_LENGTH 64
|
#define MAX_INSN_LENGTH 64
|
||||||
|
#define MAX_INSN_SLOTS 32
|
||||||
#define MAX_OPCODE_ARGS 16
|
#define MAX_OPCODE_ARGS 16
|
||||||
#define MAX_NAREG 64
|
#define MAX_NAREG 64
|
||||||
#define MAX_NINTERRUPT 32
|
#define MAX_NINTERRUPT 32
|
||||||
@ -347,11 +348,34 @@ typedef struct XtensaMemory {
|
|||||||
typedef struct DisasContext DisasContext;
|
typedef struct DisasContext DisasContext;
|
||||||
typedef void (*XtensaOpcodeOp)(DisasContext *dc, const uint32_t arg[],
|
typedef void (*XtensaOpcodeOp)(DisasContext *dc, const uint32_t arg[],
|
||||||
const uint32_t par[]);
|
const uint32_t par[]);
|
||||||
|
typedef bool (*XtensaOpcodeBoolTest)(DisasContext *dc,
|
||||||
|
const uint32_t arg[],
|
||||||
|
const uint32_t par[]);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
XTENSA_OP_ILL = 0x1,
|
||||||
|
XTENSA_OP_PRIVILEGED = 0x2,
|
||||||
|
XTENSA_OP_SYSCALL = 0x4,
|
||||||
|
XTENSA_OP_DEBUG_BREAK = 0x8,
|
||||||
|
|
||||||
|
XTENSA_OP_OVERFLOW = 0x10,
|
||||||
|
XTENSA_OP_UNDERFLOW = 0x20,
|
||||||
|
XTENSA_OP_ALLOCA = 0x40,
|
||||||
|
XTENSA_OP_COPROCESSOR = 0x80,
|
||||||
|
|
||||||
|
XTENSA_OP_DIVIDE_BY_ZERO = 0x100,
|
||||||
|
|
||||||
|
XTENSA_OP_CHECK_INTERRUPTS = 0x200,
|
||||||
|
XTENSA_OP_EXIT_TB_M1 = 0x400,
|
||||||
|
XTENSA_OP_EXIT_TB_0 = 0x800,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct XtensaOpcodeOps {
|
typedef struct XtensaOpcodeOps {
|
||||||
const char *name;
|
const char *name;
|
||||||
XtensaOpcodeOp translate;
|
XtensaOpcodeOp translate;
|
||||||
|
XtensaOpcodeBoolTest test_ill;
|
||||||
const uint32_t *par;
|
const uint32_t *par;
|
||||||
|
uint32_t op_flags;
|
||||||
} XtensaOpcodeOps;
|
} XtensaOpcodeOps;
|
||||||
|
|
||||||
typedef struct XtensaOpcodeTranslators {
|
typedef struct XtensaOpcodeTranslators {
|
||||||
@ -661,6 +685,7 @@ static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch)
|
|||||||
#define XTENSA_TBFLAG_WINDOW_MASK 0x18000
|
#define XTENSA_TBFLAG_WINDOW_MASK 0x18000
|
||||||
#define XTENSA_TBFLAG_WINDOW_SHIFT 15
|
#define XTENSA_TBFLAG_WINDOW_SHIFT 15
|
||||||
#define XTENSA_TBFLAG_YIELD 0x20000
|
#define XTENSA_TBFLAG_YIELD 0x20000
|
||||||
|
#define XTENSA_TBFLAG_CWOE 0x40000
|
||||||
|
|
||||||
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
|
static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
|
||||||
target_ulong *cs_base, uint32_t *flags)
|
target_ulong *cs_base, uint32_t *flags)
|
||||||
@ -698,7 +723,7 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
|
|||||||
(env->sregs[WINDOW_BASE] + 1);
|
(env->sregs[WINDOW_BASE] + 1);
|
||||||
uint32_t w = ctz32(windowstart | 0x8);
|
uint32_t w = ctz32(windowstart | 0x8);
|
||||||
|
|
||||||
*flags |= w << XTENSA_TBFLAG_WINDOW_SHIFT;
|
*flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE;
|
||||||
} else {
|
} else {
|
||||||
*flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
|
*flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT;
|
||||||
}
|
}
|
||||||
|
@ -57,12 +57,18 @@ static void init_libisa(XtensaConfig *config)
|
|||||||
{
|
{
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
unsigned opcodes;
|
unsigned opcodes;
|
||||||
|
unsigned formats;
|
||||||
|
|
||||||
config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL);
|
config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL);
|
||||||
assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH);
|
assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH);
|
||||||
opcodes = xtensa_isa_num_opcodes(config->isa);
|
opcodes = xtensa_isa_num_opcodes(config->isa);
|
||||||
|
formats = xtensa_isa_num_formats(config->isa);
|
||||||
config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes);
|
config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes);
|
||||||
|
|
||||||
|
for (i = 0; i < formats; ++i) {
|
||||||
|
assert(xtensa_format_num_slots(config->isa, i) <= MAX_INSN_SLOTS);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < opcodes; ++i) {
|
for (i = 0; i < opcodes; ++i) {
|
||||||
const char *opc_name = xtensa_opcode_name(config->isa, i);
|
const char *opc_name = xtensa_opcode_name(config->isa, i);
|
||||||
XtensaOpcodeOps *ops = NULL;
|
XtensaOpcodeOps *ops = NULL;
|
||||||
|
@ -5,6 +5,7 @@ DEF_HELPER_3(debug_exception, noreturn, env, i32, i32)
|
|||||||
|
|
||||||
DEF_HELPER_2(wsr_windowbase, void, env, i32)
|
DEF_HELPER_2(wsr_windowbase, void, env, i32)
|
||||||
DEF_HELPER_4(entry, void, env, i32, i32, i32)
|
DEF_HELPER_4(entry, void, env, i32, i32, i32)
|
||||||
|
DEF_HELPER_2(test_ill_retw, void, env, i32)
|
||||||
DEF_HELPER_2(retw, i32, env, i32)
|
DEF_HELPER_2(retw, i32, env, i32)
|
||||||
DEF_HELPER_2(rotw, void, env, i32)
|
DEF_HELPER_2(rotw, void, env, i32)
|
||||||
DEF_HELPER_3(window_check, noreturn, env, i32, i32)
|
DEF_HELPER_3(window_check, noreturn, env, i32, i32)
|
||||||
|
@ -253,22 +253,16 @@ void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v)
|
|||||||
void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
|
void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
|
||||||
{
|
{
|
||||||
int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
|
int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
|
||||||
if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
|
uint32_t windowstart = xtensa_replicate_windowstart(env) >>
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "Illegal entry instruction(pc = %08x), PS = %08x\n",
|
(env->sregs[WINDOW_BASE] + 1);
|
||||||
pc, env->sregs[PS]);
|
|
||||||
HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
|
|
||||||
} else {
|
|
||||||
uint32_t windowstart = xtensa_replicate_windowstart(env) >>
|
|
||||||
(env->sregs[WINDOW_BASE] + 1);
|
|
||||||
|
|
||||||
if (windowstart & ((1 << callinc) - 1)) {
|
if (windowstart & ((1 << callinc) - 1)) {
|
||||||
HELPER(window_check)(env, pc, callinc);
|
HELPER(window_check)(env, pc, callinc);
|
||||||
}
|
|
||||||
env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - imm;
|
|
||||||
xtensa_rotate_window(env, callinc);
|
|
||||||
env->sregs[WINDOW_START] |=
|
|
||||||
windowstart_bit(env->sregs[WINDOW_BASE], env);
|
|
||||||
}
|
}
|
||||||
|
env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - imm;
|
||||||
|
xtensa_rotate_window(env, callinc);
|
||||||
|
env->sregs[WINDOW_START] |=
|
||||||
|
windowstart_bit(env->sregs[WINDOW_BASE], env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
|
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
|
||||||
@ -298,13 +292,12 @@ void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
|
void HELPER(test_ill_retw)(CPUXtensaState *env, uint32_t pc)
|
||||||
{
|
{
|
||||||
int n = (env->regs[0] >> 30) & 0x3;
|
int n = (env->regs[0] >> 30) & 0x3;
|
||||||
int m = 0;
|
int m = 0;
|
||||||
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
|
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
|
||||||
uint32_t windowstart = env->sregs[WINDOW_START];
|
uint32_t windowstart = env->sregs[WINDOW_START];
|
||||||
uint32_t ret_pc = 0;
|
|
||||||
|
|
||||||
if (windowstart & windowstart_bit(windowbase - 1, env)) {
|
if (windowstart & windowstart_bit(windowbase - 1, env)) {
|
||||||
m = 1;
|
m = 1;
|
||||||
@ -314,33 +307,38 @@ uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
|
|||||||
m = 3;
|
m = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0 || (m != 0 && m != n) ||
|
if (n == 0 || (m != 0 && m != n)) {
|
||||||
((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
|
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "Illegal retw instruction(pc = %08x), "
|
qemu_log_mask(LOG_GUEST_ERROR, "Illegal retw instruction(pc = %08x), "
|
||||||
"PS = %08x, m = %d, n = %d\n",
|
"PS = %08x, m = %d, n = %d\n",
|
||||||
pc, env->sregs[PS], m, n);
|
pc, env->sregs[PS], m, n);
|
||||||
HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
|
HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
|
||||||
|
{
|
||||||
|
int n = (env->regs[0] >> 30) & 0x3;
|
||||||
|
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
|
||||||
|
uint32_t windowstart = env->sregs[WINDOW_START];
|
||||||
|
uint32_t ret_pc = 0;
|
||||||
|
|
||||||
|
ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
|
||||||
|
|
||||||
|
xtensa_rotate_window(env, -n);
|
||||||
|
if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
|
||||||
|
env->sregs[WINDOW_START] &= ~windowstart_bit(windowbase, env);
|
||||||
} else {
|
} else {
|
||||||
int owb = windowbase;
|
/* window underflow */
|
||||||
|
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
|
||||||
|
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
|
||||||
|
env->sregs[EPC1] = env->pc = pc;
|
||||||
|
|
||||||
ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
|
if (n == 1) {
|
||||||
|
HELPER(exception)(env, EXC_WINDOW_UNDERFLOW4);
|
||||||
xtensa_rotate_window(env, -n);
|
} else if (n == 2) {
|
||||||
if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
|
HELPER(exception)(env, EXC_WINDOW_UNDERFLOW8);
|
||||||
env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
|
} else if (n == 3) {
|
||||||
} else {
|
HELPER(exception)(env, EXC_WINDOW_UNDERFLOW12);
|
||||||
/* window underflow */
|
|
||||||
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
|
|
||||||
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
|
|
||||||
env->sregs[EPC1] = env->pc = pc;
|
|
||||||
|
|
||||||
if (n == 1) {
|
|
||||||
HELPER(exception)(env, EXC_WINDOW_UNDERFLOW4);
|
|
||||||
} else if (n == 2) {
|
|
||||||
HELPER(exception)(env, EXC_WINDOW_UNDERFLOW8);
|
|
||||||
} else if (n == 3) {
|
|
||||||
HELPER(exception)(env, EXC_WINDOW_UNDERFLOW12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret_pc;
|
return ret_pc;
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user