summaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/ppc/cpu.h1
-rw-r--r--target/ppc/excp_helper.c38
-rw-r--r--target/ppc/helper_regs.c3
-rw-r--r--target/ppc/int_helper.c61
-rw-r--r--target/ppc/trace-events8
-rw-r--r--target/ppc/translate.c28
6 files changed, 93 insertions, 46 deletions
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 01d3773bc7..baa4e7c34d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -600,6 +600,7 @@ enum {
HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */
HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */
HFLAGS_DR = 4, /* MSR_DR */
+ HFLAGS_HR = 5, /* computed from SPR_LPCR[HR] */
HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */
HFLAGS_TM = 8, /* computed from MSR_TM */
HFLAGS_BE = 9, /* MSR_BE -- from elsewhere on embedded ppc */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d7e32ee107..b7d1767920 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -23,20 +23,14 @@
#include "internal.h"
#include "helper_regs.h"
+#include "trace.h"
+
#ifdef CONFIG_TCG
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
#endif
-/* #define DEBUG_OP */
/* #define DEBUG_SOFTWARE_TLB */
-/* #define DEBUG_EXCEPTIONS */
-
-#ifdef DEBUG_EXCEPTIONS
-# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_EXCP(...) do { } while (0)
-#endif
/*****************************************************************************/
/* Exception processing */
@@ -414,12 +408,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
- LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
- "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
- LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
- "\n", msr, env->nip);
+ trace_ppc_excp_isi(msr, env->nip);
msr |= env->error_code;
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
@@ -474,7 +466,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
- LOG_EXCP("Ignore floating point exception\n");
+ trace_ppc_excp_fp_ignore();
cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
return;
@@ -489,7 +481,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
env->spr[SPR_BOOKE_ESR] = ESR_FP;
break;
case POWERPC_EXCP_INVAL:
- LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
+ trace_ppc_excp_inval(env->nip);
msr |= 0x00080000;
env->spr[SPR_BOOKE_ESR] = ESR_PIL;
break;
@@ -547,10 +539,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
break;
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
/* FIT on 4xx */
- LOG_EXCP("FIT exception\n");
+ trace_ppc_excp_print("FIT");
break;
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
- LOG_EXCP("WDT exception\n");
+ trace_ppc_excp_print("WDT");
switch (excp_model) {
case POWERPC_EXCP_BOOKE:
srr0 = SPR_BOOKE_CSRR0;
@@ -657,7 +649,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
#endif
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
- LOG_EXCP("PIT exception\n");
+ trace_ppc_excp_print("PIT");
break;
case POWERPC_EXCP_IO: /* IO error exception */
/* XXX: TODO */
@@ -1115,14 +1107,6 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
#endif /* !CONFIG_USER_ONLY */
-#if defined(DEBUG_OP)
-static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
-{
- qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
- TARGET_FMT_lx "\n", RA, msr);
-}
-#endif
-
/*****************************************************************************/
/* Exceptions processing helpers */
@@ -1221,9 +1205,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
/* XXX: beware: this is false if VLE is supported */
env->nip = nip & ~((target_ulong)0x00000003);
hreg_store_msr(env, msr, 1);
-#if defined(DEBUG_OP)
- cpu_dump_rfi(env->nip, env->msr);
-#endif
+ trace_ppc_excp_rfi(env->nip, env->msr);
/*
* No need to raise an exception here, as rfi is always the last
* insn of a TB
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 405450d863..1bfb480ecf 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -106,6 +106,9 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
if (env->spr[SPR_LPCR] & LPCR_GTSE) {
hflags |= 1 << HFLAGS_GTSE;
}
+ if (env->spr[SPR_LPCR] & LPCR_HR) {
+ hflags |= 1 << HFLAGS_HR;
+ }
#ifndef CONFIG_USER_ONLY
if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index c2d3248d1e..f5dac3aa87 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2480,10 +2480,26 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
return cr;
}
+/**
+ * Compare 2 128-bit unsigned integers, passed in as unsigned 64-bit pairs
+ *
+ * Returns:
+ * > 0 if ahi|alo > bhi|blo,
+ * 0 if ahi|alo == bhi|blo,
+ * < 0 if ahi|alo < bhi|blo
+ */
+static inline int ucmp128(uint64_t alo, uint64_t ahi,
+ uint64_t blo, uint64_t bhi)
+{
+ return (ahi == bhi) ?
+ (alo > blo ? 1 : (alo == blo ? 0 : -1)) :
+ (ahi > bhi ? 1 : -1);
+}
+
uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
{
int i;
- int cr = 0;
+ int cr;
uint64_t lo_value;
uint64_t hi_value;
ppc_avr_t ret = { .u64 = { 0, 0 } };
@@ -2492,28 +2508,47 @@ uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
lo_value = -b->VsrSD(1);
hi_value = ~b->VsrD(0) + !lo_value;
bcd_put_digit(&ret, 0xD, 0);
+
+ cr = CRF_LT;
} else {
lo_value = b->VsrD(1);
hi_value = b->VsrD(0);
bcd_put_digit(&ret, bcd_preferred_sgn(0, ps), 0);
- }
- if (divu128(&lo_value, &hi_value, 1000000000000000ULL) ||
- lo_value > 9999999999999999ULL) {
- cr = CRF_SO;
+ if (hi_value == 0 && lo_value == 0) {
+ cr = CRF_EQ;
+ } else {
+ cr = CRF_GT;
+ }
}
- for (i = 1; i < 16; hi_value /= 10, i++) {
- bcd_put_digit(&ret, hi_value % 10, i);
- }
+ /*
+ * Check src limits: abs(src) <= 10^31 - 1
+ *
+ * 10^31 - 1 = 0x0000007e37be2022 c0914b267fffffff
+ */
+ if (ucmp128(lo_value, hi_value,
+ 0xc0914b267fffffffULL, 0x7e37be2022ULL) > 0) {
+ cr |= CRF_SO;
- for (; i < 32; lo_value /= 10, i++) {
- bcd_put_digit(&ret, lo_value % 10, i);
- }
+ /*
+ * According to the ISA, if src wouldn't fit in the destination
+ * register, the result is undefined.
+ * In that case, we leave r unchanged.
+ */
+ } else {
+ divu128(&lo_value, &hi_value, 1000000000000000ULL);
- cr |= bcd_cmp_zero(&ret);
+ for (i = 1; i < 16; hi_value /= 10, i++) {
+ bcd_put_digit(&ret, hi_value % 10, i);
+ }
- *r = ret;
+ for (; i < 32; lo_value /= 10, i++) {
+ bcd_put_digit(&ret, lo_value % 10, i);
+ }
+
+ *r = ret;
+ }
return cr;
}
diff --git a/target/ppc/trace-events b/target/ppc/trace-events
index c88cfccf8d..53b107f56e 100644
--- a/target/ppc/trace-events
+++ b/target/ppc/trace-events
@@ -28,3 +28,11 @@ kvm_handle_epr(void) "handle epr"
kvm_handle_watchdog_expiry(void) "handle watchdog expiry"
kvm_handle_debug_exception(void) "handle debug exception"
kvm_handle_nmi_exception(void) "handle NMI exception"
+
+# excp_helper.c
+ppc_excp_rfi(uint64_t nip, uint64_t msr) "Return from exception at 0x%" PRIx64 " with flags 0x%016" PRIx64
+ppc_excp_dsi(uint64_t dsisr, uint64_t dar) "DSI exception: DSISR=0x%" PRIx64 " DAR=0x%" PRIx64
+ppc_excp_isi(uint64_t msr, uint64_t nip) "ISI exception: msr=0x%016" PRIx64 " nip=0x%" PRIx64
+ppc_excp_fp_ignore(void) "Ignore floating point exception"
+ppc_excp_inval(uint64_t nip) "Invalid instruction at 0x%" PRIx64
+ppc_excp_print(const char *excp) "%s exception"
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 5d8b06bd80..b985e9e55b 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -175,6 +175,7 @@ struct DisasContext {
bool spe_enabled;
bool tm_enabled;
bool gtse;
+ bool hr;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
uint32_t flags;
@@ -5516,7 +5517,15 @@ static void gen_tlbiel(DisasContext *ctx)
#if defined(CONFIG_USER_ONLY)
GEN_PRIV;
#else
- CHK_SV;
+ bool psr = (ctx->opcode >> 17) & 0x1;
+
+ if (ctx->pr || (!ctx->hv && !psr && ctx->hr)) {
+ /*
+ * tlbiel is privileged except when PSR=0 and HR=1, making it
+ * hypervisor privileged.
+ */
+ GEN_PRIV;
+ }
gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif /* defined(CONFIG_USER_ONLY) */
@@ -5528,12 +5537,20 @@ static void gen_tlbie(DisasContext *ctx)
#if defined(CONFIG_USER_ONLY)
GEN_PRIV;
#else
+ bool psr = (ctx->opcode >> 17) & 0x1;
TCGv_i32 t1;
- if (ctx->gtse) {
- CHK_SV; /* If gtse is set then tlbie is supervisor privileged */
- } else {
- CHK_HV; /* Else hypervisor privileged */
+ if (ctx->pr) {
+ /* tlbie is privileged... */
+ GEN_PRIV;
+ } else if (!ctx->hv) {
+ if (!ctx->gtse || (!psr && ctx->hr)) {
+ /*
+ * ... except when GTSE=0 or when PSR=0 and HR=1, making it
+ * hypervisor privileged.
+ */
+ GEN_PRIV;
+ }
}
if (NARROW_MODE(ctx)) {
@@ -8539,6 +8556,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->vsx_enabled = (hflags >> HFLAGS_VSX) & 1;
ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1;
ctx->gtse = (hflags >> HFLAGS_GTSE) & 1;
+ ctx->hr = (hflags >> HFLAGS_HR) & 1;
ctx->singlestep_enabled = 0;
if ((hflags >> HFLAGS_SE) & 1) {