mirror of https://github.com/xemu-project/xemu.git
s390 translator bug fixes
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJU0THzAAoJEK0ScMxN0CebpTEIAKv2k1iE/Mj5YeE6ZygepQXg iNe28daFU2XXFKv+DNS0ptPnt+M1NLbFcuyXTOhWnQnpc+Z82i2TecxgqqCMrp4f JjW56WxJR8H7Gdc6CesCigld2QNXOprniEMxZwkCy8KEZa32D22WKb9E/CHOFzeS 3+YqiYlnj52DAm8oS+hVapf0tm+qJLGfgDFEU1MJLCtAVNE5DJclguzi05//W5Go Jx0LClvED5a0rRN4vYFXHRMB9H6QTsG5/HtvYLR5wBUCk6SBcx/2domHSXYKiEfN LS1DjLYArXwjzI3Fr232po8VX3pcG0QrG71kYh9v8GXcvxDUNtQ69DV7p8ZRxZ0= =RqeH -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tg-s390-20150203' into staging s390 translator bug fixes # gpg: Signature made Tue 03 Feb 2015 20:39:15 GMT using RSA key ID 4DD0279B # gpg: Good signature from "Richard Henderson <rth7680@gmail.com>" # gpg: aka "Richard Henderson <rth@redhat.com>" # gpg: aka "Richard Henderson <rth@twiddle.net>" * remotes/rth/tags/pull-tg-s390-20150203: target-s390x: fix and optimize slb* and slbg* computation of carry/borrow flag target-s390x: support OC and NC in the EX instruction disas/s390.c: Remove unused variables target-s390x: Mark check_privileged() as !CONFIG_USER_ONLY target-s390: Implement ECAG target-s390: Implement LURA, LURAG, STURG target-s390: Fix STURA target-s390: Fix STIDP target-s390: Implement EPSW target-s390: Implement SAM specification exception Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ec6f25e788
35
disas/s390.c
35
disas/s390.c
|
@ -106,10 +106,6 @@ struct s390_opcode
|
|||
static const struct s390_opcode s390_opcodes[];
|
||||
static const int s390_num_opcodes;
|
||||
|
||||
/* A opcode format table for the .insn pseudo mnemonic. */
|
||||
static const struct s390_opcode s390_opformats[];
|
||||
static const int s390_num_opformats;
|
||||
|
||||
/* Values defined for the flags field of a struct powerpc_opcode. */
|
||||
|
||||
/* The operands table is an array of struct s390_operand. */
|
||||
|
@ -844,37 +840,6 @@ static const struct s390_operand s390_operands[] =
|
|||
#define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
|
||||
/* QEMU-END */
|
||||
|
||||
/* The opcode formats table (blueprints for .insn pseudo mnemonic). */
|
||||
|
||||
static const struct s390_opcode s390_opformats[] =
|
||||
{
|
||||
{ "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0 },
|
||||
{ "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0 },
|
||||
{ "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0 },
|
||||
{ "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0 },
|
||||
{ "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0 },
|
||||
{ "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0 },
|
||||
{ "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0 },
|
||||
{ "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0 },
|
||||
{ "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0 },
|
||||
{ "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0 },
|
||||
{ "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0 },
|
||||
{ "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3 },
|
||||
{ "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0 },
|
||||
{ "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0 },
|
||||
{ "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR,3, 0 },
|
||||
{ "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3 },
|
||||
{ "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0 },
|
||||
{ "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0 },
|
||||
{ "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3 },
|
||||
{ "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD,3, 0 },
|
||||
{ "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0 },
|
||||
{ "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD,3, 0 },
|
||||
};
|
||||
|
||||
static const int s390_num_opformats =
|
||||
sizeof (s390_opformats) / sizeof (s390_opformats[0]);
|
||||
|
||||
/* include "s390-opc.tab" generated from opcodes/s390-opc.txt rev 1.17 */
|
||||
/* The opcode table. This file was generated by s390-mkopc.
|
||||
|
||||
|
|
|
@ -179,16 +179,11 @@ static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar)
|
|||
|
||||
static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar)
|
||||
{
|
||||
/* We had borrow-in if normal subtraction isn't equal. */
|
||||
int borrow_in = ar - (a1 - a2);
|
||||
int borrow_out;
|
||||
|
||||
/* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits,
|
||||
and we must have had borrow out. */
|
||||
if (borrow_in && a2 == (uint64_t)-1) {
|
||||
borrow_out = 1;
|
||||
if (ar != a1 - a2) { /* difference means borrow-in */
|
||||
borrow_out = (a2 >= a1);
|
||||
} else {
|
||||
a2 += borrow_in;
|
||||
borrow_out = (a2 > a1);
|
||||
}
|
||||
|
||||
|
@ -285,16 +280,11 @@ static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar)
|
|||
|
||||
static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar)
|
||||
{
|
||||
/* We had borrow-in if normal subtraction isn't equal. */
|
||||
int borrow_in = ar - (a1 - a2);
|
||||
int borrow_out;
|
||||
|
||||
/* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits,
|
||||
and we must have had borrow out. */
|
||||
if (borrow_in && a2 == (uint32_t)-1) {
|
||||
borrow_out = 1;
|
||||
if (ar != a1 - a2) { /* difference means borrow-in */
|
||||
borrow_out = (a2 >= a1);
|
||||
} else {
|
||||
a2 += borrow_in;
|
||||
borrow_out = (a2 > a1);
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,9 @@ typedef struct CPUS390XState {
|
|||
|
||||
/* reset does memset(0) up to here */
|
||||
|
||||
int cpu_num;
|
||||
uint32_t cpu_num;
|
||||
uint32_t machine_type;
|
||||
|
||||
uint8_t *storage_keys;
|
||||
|
||||
uint64_t tod_offset;
|
||||
|
|
|
@ -111,5 +111,8 @@ DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64)
|
|||
DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
|
||||
DEF_HELPER_2(lra, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_2(lura, TCG_CALL_NO_WG, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(sturg, TCG_CALL_NO_WG, void, env, i64, i64)
|
||||
#endif
|
||||
|
|
|
@ -285,8 +285,12 @@
|
|||
|
||||
/* EXTRACT ACCESS */
|
||||
C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0)
|
||||
/* EXTRACT CPU ATTRIBUTE */
|
||||
C(0xeb4c, ECAG, RSY_a, GIE, 0, a2, r1, 0, ecag, 0)
|
||||
/* EXTRACT FPC */
|
||||
C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0)
|
||||
/* EXTRACT PSW */
|
||||
C(0xb98d, EPSW, RRE, Z, 0, 0, 0, 0, epsw, 0)
|
||||
|
||||
/* FIND LEFTMOST ONE */
|
||||
C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0)
|
||||
|
@ -566,6 +570,10 @@
|
|||
|
||||
/* SET ACCESS */
|
||||
C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0)
|
||||
/* SET ADDRESSING MODE */
|
||||
D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0)
|
||||
D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1)
|
||||
D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3)
|
||||
/* SET FPC */
|
||||
C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0)
|
||||
/* SET FPC AND SIGNAL */
|
||||
|
@ -733,6 +741,9 @@
|
|||
C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0)
|
||||
C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0)
|
||||
C(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0)
|
||||
/* LOAD USING REAL ADDRESS */
|
||||
C(0xb24b, LURA, RRE, Z, 0, r2, new, r1_32, lura, 0)
|
||||
C(0xb905, LURAG, RRE, Z, 0, r2, r1, 0, lurag, 0)
|
||||
/* MOVE TO PRIMARY */
|
||||
C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0)
|
||||
/* MOVE TO SECONDARY */
|
||||
|
@ -743,10 +754,6 @@
|
|||
C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0)
|
||||
/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */
|
||||
C(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0)
|
||||
/* SET ADDRESSING MODE */
|
||||
D(0x010c, SAM24, E, Z, 0, 0, 0, 0, sam, 0, 0)
|
||||
D(0x010d, SAM31, E, Z, 0, 0, 0, 0, sam, 0, 1)
|
||||
D(0x010e, SAM64, E, Z, 0, 0, 0, 0, sam, 0, 3)
|
||||
/* SET ADDRESS SPACE CONTROL FAST */
|
||||
C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0)
|
||||
/* SET CLOCK */
|
||||
|
@ -794,6 +801,7 @@
|
|||
C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0)
|
||||
/* STORE USING REAL ADDRESS */
|
||||
C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0)
|
||||
C(0xb925, STURG, RRE, Z, r1_o, r2_o, 0, 0, sturg, 0)
|
||||
/* TEST PROTECTION */
|
||||
C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0)
|
||||
|
||||
|
|
|
@ -490,10 +490,18 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
|
|||
helper_mvc(env, l, get_address(env, 0, b1, d1),
|
||||
get_address(env, 0, b2, d2));
|
||||
break;
|
||||
case 0x400:
|
||||
cc = helper_nc(env, l, get_address(env, 0, b1, d1),
|
||||
get_address(env, 0, b2, d2));
|
||||
break;
|
||||
case 0x500:
|
||||
cc = helper_clc(env, l, get_address(env, 0, b1, d1),
|
||||
get_address(env, 0, b2, d2));
|
||||
break;
|
||||
case 0x600:
|
||||
cc = helper_oc(env, l, get_address(env, 0, b1, d1),
|
||||
get_address(env, 0, b2, d2));
|
||||
break;
|
||||
case 0x700:
|
||||
cc = helper_xc(env, l, get_address(env, 0, b1, d1),
|
||||
get_address(env, 0, b2, d2));
|
||||
|
@ -1034,12 +1042,34 @@ void HELPER(ptlb)(CPUS390XState *env)
|
|||
tlb_flush(CPU(cpu), 1);
|
||||
}
|
||||
|
||||
/* load using real address */
|
||||
uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
|
||||
{
|
||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||
|
||||
return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr));
|
||||
}
|
||||
|
||||
uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
|
||||
{
|
||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||
|
||||
return ldq_phys(cs->as, get_address(env, 0, 0, addr));
|
||||
}
|
||||
|
||||
/* store using real address */
|
||||
void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
|
||||
{
|
||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||
|
||||
stw_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
|
||||
stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
|
||||
}
|
||||
|
||||
void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
|
||||
{
|
||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||
|
||||
stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
|
||||
}
|
||||
|
||||
/* load real address */
|
||||
|
|
|
@ -317,12 +317,14 @@ static inline void gen_illegal_opcode(DisasContext *s)
|
|||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
}
|
||||
|
||||
static inline void check_privileged(DisasContext *s)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static void check_privileged(DisasContext *s)
|
||||
{
|
||||
if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) {
|
||||
gen_program_exception(s, PGM_PRIVILEGED);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
|
||||
{
|
||||
|
@ -2045,12 +2047,37 @@ static ExitStatus op_ear(DisasContext *s, DisasOps *o)
|
|||
return NO_EXIT;
|
||||
}
|
||||
|
||||
static ExitStatus op_ecag(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
/* No cache information provided. */
|
||||
tcg_gen_movi_i64(o->out, -1);
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
static ExitStatus op_efpc(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc));
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
static ExitStatus op_epsw(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s->fields, r1);
|
||||
int r2 = get_field(s->fields, r2);
|
||||
TCGv_i64 t = tcg_temp_new_i64();
|
||||
|
||||
/* Note the "subsequently" in the PoO, which implies a defined result
|
||||
if r1 == r2. Thus we cannot defer these writes to an output hook. */
|
||||
tcg_gen_shri_i64(t, psw_mask, 32);
|
||||
store_reg32_i64(r1, t);
|
||||
if (r2 != 0) {
|
||||
store_reg32_i64(r2, psw_mask);
|
||||
}
|
||||
|
||||
tcg_temp_free_i64(t);
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
static ExitStatus op_ex(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
/* ??? Perhaps a better way to implement EXECUTE is to set a bit in
|
||||
|
@ -2460,6 +2487,24 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o)
|
|||
return NO_EXIT;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static ExitStatus op_lura(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
check_privileged(s);
|
||||
potential_page_fault(s);
|
||||
gen_helper_lura(o->out, cpu_env, o->in2);
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
static ExitStatus op_lurag(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
check_privileged(s);
|
||||
potential_page_fault(s);
|
||||
gen_helper_lurag(o->out, cpu_env, o->in2);
|
||||
return NO_EXIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ExitStatus op_mov2(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
o->out = o->in2;
|
||||
|
@ -2925,19 +2970,42 @@ static ExitStatus op_sacf(DisasContext *s, DisasOps *o)
|
|||
/* Addressing mode has changed, so end the block. */
|
||||
return EXIT_PC_STALE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ExitStatus op_sam(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int sam = s->insn->data;
|
||||
TCGv_i64 tsam = tcg_const_i64(sam);
|
||||
TCGv_i64 tsam;
|
||||
uint64_t mask;
|
||||
|
||||
/* Overwrite PSW_MASK_64 and PSW_MASK_32 */
|
||||
switch (sam) {
|
||||
case 0:
|
||||
mask = 0xffffff;
|
||||
break;
|
||||
case 1:
|
||||
mask = 0x7fffffff;
|
||||
break;
|
||||
default:
|
||||
mask = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bizzare but true, we check the address of the current insn for the
|
||||
specification exception, not the next to be executed. Thus the PoO
|
||||
documents that Bad Things Happen two bytes before the end. */
|
||||
if (s->pc & ~mask) {
|
||||
gen_program_exception(s, PGM_SPECIFICATION);
|
||||
return EXIT_NORETURN;
|
||||
}
|
||||
s->next_pc &= mask;
|
||||
|
||||
tsam = tcg_const_i64(sam);
|
||||
tcg_gen_deposit_i64(psw_mask, psw_mask, tsam, 31, 2);
|
||||
|
||||
tcg_temp_free_i64(tsam);
|
||||
|
||||
/* Always exit the TB, since we (may have) changed execution mode. */
|
||||
return EXIT_PC_STALE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ExitStatus op_sar(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
|
@ -3221,8 +3289,14 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o)
|
|||
|
||||
static ExitStatus op_stidp(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
check_privileged(s);
|
||||
tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num));
|
||||
tcg_gen_ld32u_i64(t1, cpu_env, offsetof(CPUS390XState, machine_type));
|
||||
tcg_gen_deposit_i64(o->out, o->out, t1, 32, 32);
|
||||
tcg_temp_free_i64(t1);
|
||||
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
|
@ -3317,6 +3391,14 @@ static ExitStatus op_stura(DisasContext *s, DisasOps *o)
|
|||
gen_helper_stura(cpu_env, o->in2, o->in1);
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
static ExitStatus op_sturg(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
check_privileged(s);
|
||||
potential_page_fault(s);
|
||||
gen_helper_sturg(cpu_env, o->in2, o->in1);
|
||||
return NO_EXIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ExitStatus op_st8(DisasContext *s, DisasOps *o)
|
||||
|
|
Loading…
Reference in New Issue