diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-02-03 21:37:16 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-02-03 21:37:16 +0000 |
commit | ec6f25e788ef57ce1e9f734984ef8885172fd9e2 (patch) | |
tree | 281a31124534d9676f9700037848d613da32a797 /target-s390x | |
parent | 007c99fd0fb4e0f0579872bb71f5de99b5943dc2 (diff) | |
parent | 9ef1473693a1400a903567489d3122fc9511765d (diff) |
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>
Diffstat (limited to 'target-s390x')
-rw-r--r-- | target-s390x/cc_helper.c | 18 | ||||
-rw-r--r-- | target-s390x/cpu.h | 4 | ||||
-rw-r--r-- | target-s390x/helper.h | 3 | ||||
-rw-r--r-- | target-s390x/insn-data.def | 16 | ||||
-rw-r--r-- | target-s390x/mem_helper.c | 32 | ||||
-rw-r--r-- | target-s390x/translate.c | 92 |
6 files changed, 140 insertions, 25 deletions
diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 373eb176a1..00bc883a8a 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -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); } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index c123b6f023..2e2554c4b3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -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; diff --git a/target-s390x/helper.h b/target-s390x/helper.h index faebfd96aa..8d2c8596bb 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -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 diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4d2feb6977..8d8e47e0bf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -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) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 5a55de86a1..d67b345ad1 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -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 */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index ab01bc004e..8b36eca718 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -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 */ - tcg_gen_deposit_i64(psw_mask, psw_mask, tsam, 31, 2); + 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) |