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>
master
Peter Maydell 2015-02-03 21:37:16 +00:00
commit ec6f25e788
7 changed files with 140 additions and 60 deletions

View File

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

View File

@ -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);
}

View File

@ -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;

View File

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

View File

@ -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)

View File

@ -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 */

View File

@ -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)