aboutsummaryrefslogtreecommitdiff
path: root/target-s390x
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-02-03 21:37:16 +0000
committerPeter Maydell <peter.maydell@linaro.org>2015-02-03 21:37:16 +0000
commitec6f25e788ef57ce1e9f734984ef8885172fd9e2 (patch)
tree281a31124534d9676f9700037848d613da32a797 /target-s390x
parent007c99fd0fb4e0f0579872bb71f5de99b5943dc2 (diff)
parent9ef1473693a1400a903567489d3122fc9511765d (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.c18
-rw-r--r--target-s390x/cpu.h4
-rw-r--r--target-s390x/helper.h3
-rw-r--r--target-s390x/insn-data.def16
-rw-r--r--target-s390x/mem_helper.c32
-rw-r--r--target-s390x/translate.c92
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)