summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--target-ppc/cpu.h16
-rw-r--r--target-ppc/excp_helper.c5
-rw-r--r--target-ppc/helper.h1
-rw-r--r--target-ppc/misc_helper.c27
-rw-r--r--target-ppc/translate.c7
-rw-r--r--target-ppc/translate_init.c10
6 files changed, 66 insertions, 0 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 9f9ffb1..6514edd 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -238,6 +238,7 @@ enum {
POWERPC_EXCP_DTLBE = 93, /* Data TLB error */
/* VSX Unavailable (Power ISA 2.06 and later) */
POWERPC_EXCP_VSXU = 94, /* VSX Unavailable */
+ POWERPC_EXCP_FU = 95, /* Facility Unavailable */
/* EOL */
POWERPC_EXCP_NB = 96,
/* QEMU exceptions: used internally during code translation */
@@ -516,6 +517,19 @@ struct ppc_slb_t {
#endif
#endif
+/* Facility Status and Control (FSCR) bits */
+#define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */
+#define FSCR_TAR (63 - 55) /* Target Address Register */
+/* Interrupt cause mask and position in FSCR. HFSCR has the same format */
+#define FSCR_IC_MASK (0xFFULL)
+#define FSCR_IC_POS (63 - 7)
+#define FSCR_IC_DSCR_SPR3 2
+#define FSCR_IC_PMU 3
+#define FSCR_IC_BHRB 4
+#define FSCR_IC_TM 5
+#define FSCR_IC_EBB 7
+#define FSCR_IC_TAR 8
+
/* Exception state register bits definition */
#define ESR_PIL (1 << (63 - 36)) /* Illegal Instruction */
#define ESR_PPR (1 << (63 - 37)) /* Privileged Instruction */
@@ -1102,6 +1116,7 @@ do { \
/*****************************************************************************/
PowerPCCPU *cpu_ppc_init(const char *cpu_model);
void ppc_translate_init(void);
+void gen_update_current_nip(void *opaque);
int cpu_ppc_exec (CPUPPCState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
@@ -1268,6 +1283,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_CTRL (0x098)
#define SPR_MPC_CMPE (0x098)
#define SPR_MPC_CMPF (0x099)
+#define SPR_FSCR (0x099)
#define SPR_MPC_CMPG (0x09A)
#define SPR_MPC_CMPH (0x09B)
#define SPR_MPC_LCTRL1 (0x09C)
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 7dfc52d..9639d21 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -399,6 +399,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
new_msr |= (target_ulong)MSR_HVB;
}
goto store_current;
+ case POWERPC_EXCP_FU: /* Facility unavailable exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_current;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
LOG_EXCP("PIT exception\n");
goto store_next;
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 5ee4706..c1417ea 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -577,6 +577,7 @@ DEF_HELPER_3(store_dcr, void, env, tl, tl)
DEF_HELPER_2(load_dump_spr, void, env, i32)
DEF_HELPER_2(store_dump_spr, void, env, i32)
+DEF_HELPER_4(fscr_facility_check, void, env, i32, i32, i32)
DEF_HELPER_1(load_tbl, tl, env)
DEF_HELPER_1(load_tbu, tl, env)
DEF_HELPER_1(load_atbl, tl, env)
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index 7331b1b..554831f 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -34,6 +34,33 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
env->spr[sprn]);
}
+
+#ifdef TARGET_PPC64
+static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
+ uint32_t sprn, uint32_t cause)
+{
+ qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
+
+ env->spr[SPR_FSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
+ cause &= FSCR_IC_MASK;
+ env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
+
+ helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
+}
+#endif
+
+void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
+ uint32_t sprn, uint32_t cause)
+{
+#ifdef TARGET_PPC64
+ if (env->spr[SPR_FSCR] & (1ULL << bit)) {
+ /* Facility is enabled, continue */
+ return;
+ }
+ raise_fu_exception(env, bit, sprn, cause);
+#endif
+}
+
#if !defined(CONFIG_USER_ONLY)
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 6affe7e..4801721 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -284,6 +284,13 @@ static inline void gen_update_nip(DisasContext *ctx, target_ulong nip)
tcg_gen_movi_tl(cpu_nip, nip);
}
+void gen_update_current_nip(void *opaque)
+{
+ DisasContext *ctx = opaque;
+
+ tcg_gen_movi_tl(cpu_nip, ctx->nip);
+}
+
static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
{
TCGv_i32 t0, t1;
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 1df69e0..4e139b4 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -3080,6 +3080,7 @@ static void init_excp_POWER7 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20;
env->excp_vectors[POWERPC_EXCP_VSXU] = 0x00000F40;
+ env->excp_vectors[POWERPC_EXCP_FU] = 0x00000F60;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
@@ -7586,6 +7587,14 @@ static void gen_spr_power8_tce_address_control(CPUPPCState *env)
0x00000000);
}
+static void gen_spr_power8_fscr(CPUPPCState *env)
+{
+ spr_register_kvm(env, SPR_FSCR, "FSCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_FSCR, 0x00000000);
+}
+
static void init_proc_book3s_64(CPUPPCState *env, int version)
{
gen_spr_ne_601(env);
@@ -7631,6 +7640,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)
if (version >= BOOK3S_CPU_POWER8) {
gen_spr_power8_tce_address_control(env);
gen_spr_power8_ids(env);
+ gen_spr_power8_fscr(env);
}
#if !defined(CONFIG_USER_ONLY)
switch (version) {
OpenPOWER on IntegriCloud