aboutsummaryrefslogtreecommitdiff
path: root/target-s390x/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-s390x/translate.c')
-rw-r--r--target-s390x/translate.c92
1 files changed, 87 insertions, 5 deletions
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)