[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC v2] ppc: rfi and friends
From: |
Andreas Färber |
Subject: |
[Qemu-devel] [RFC v2] ppc: rfi and friends |
Date: |
Sat, 29 Nov 2008 21:04:23 +0100 |
Am 29.11.2008 um 13:08 schrieb Andreas Färber:
This patch migrates op_40x_rfci et al. to TCG. (op_40x_rfci is the
current dyngen breakage on OSX/gcc4.)
I believe I have spotted and fixed some ops which were lacking env-
>spr[...] in their call to __do_rfi.
The TCG code is still untested since it still breaks for op_440_dlmzb.
Two issues remain with my patch: hreg_store_msr and cpu_dump_rfi. Is
cpu_dump_rfi still needed at all?
hreg_store_msr is defined in helper_regs.h as always_inline - should
we convert it to an inline TCG function or call it as a helper?
Attached is a compile-tested update of the patch, that adds TCG
versions of hreg_store_msr and dependencies.
Still unclear to me is what to do about a tlb_flush call, and an env-
>check_pow callback there.
Signed-off-by: Andreas Faerber <address@hidden>
Andreas
---
diff --git a/target-ppc/op.c b/target-ppc/op.c
index a26b1da..d00ebe8 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -298,26 +298,6 @@ void OPPROTO op_wait (void)
/* Return from interrupt */
#if !defined(CONFIG_USER_ONLY)
-void OPPROTO op_rfi (void)
-{
- do_rfi();
- RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_rfid (void)
-{
- do_rfid();
- RETURN();
-}
-
-void OPPROTO op_hrfid (void)
-{
- do_hrfid();
- RETURN();
-}
-#endif
-
/* Exception vectors */
void OPPROTO op_store_excp_prefix (void)
{
@@ -710,12 +690,6 @@ void OPPROTO op_POWER_rac (void)
do_POWER_rac();
RETURN();
}
-
-void OPPROTO op_POWER_rfsvc (void)
-{
- do_POWER_rfsvc();
- RETURN();
-}
#endif
/* PowerPC 602 specific instruction */
@@ -741,33 +715,6 @@ void OPPROTO op_store_dcr (void)
}
#if !defined(CONFIG_USER_ONLY)
-/* Return from critical interrupt :
- * same as rfi, except nip & MSR are loaded from SRR2/3 instead of
SRR0/1
- */
-void OPPROTO op_40x_rfci (void)
-{
- do_40x_rfci();
- RETURN();
-}
-
-void OPPROTO op_rfci (void)
-{
- do_rfci();
- RETURN();
-}
-
-void OPPROTO op_rfdi (void)
-{
- do_rfdi();
- RETURN();
-}
-
-void OPPROTO op_rfmci (void)
-{
- do_rfmci();
- RETURN();
-}
-
void OPPROTO op_wrte (void)
{
/* We don't call do_store_msr here as we won't trigger
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index a055ee6..e158630 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -1373,55 +1373,6 @@ void do_store_msr (void)
raise_exception(env, T0);
}
}
-
-static always_inline void __do_rfi (target_ulong nip, target_ulong msr,
- target_ulong msrm, int keep_msrh)
-{
-#if defined(TARGET_PPC64)
- if (msr & (1ULL << MSR_SF)) {
- nip = (uint64_t)nip;
- msr &= (uint64_t)msrm;
- } else {
- nip = (uint32_t)nip;
- msr = (uint32_t)(msr & msrm);
- if (keep_msrh)
- msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
- }
-#else
- nip = (uint32_t)nip;
- msr &= (uint32_t)msrm;
-#endif
- /* 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
- /* No need to raise an exception here,
- * as rfi is always the last insn of a TB
- */
- env->interrupt_request |= CPU_INTERRUPT_EXITTB;
-}
-
-void do_rfi (void)
-{
- __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
- ~((target_ulong)0xFFFF0000), 1);
-}
-
-#if defined(TARGET_PPC64)
-void do_rfid (void)
-{
- __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
- ~((target_ulong)0xFFFF0000), 0);
-}
-
-void do_hrfid (void)
-{
- __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
- ~((target_ulong)0xFFFF0000), 0);
-}
-#endif
#endif
void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
@@ -1615,11 +1566,6 @@ void do_POWER_rac (void)
env->nb_BATs = nb_BATs;
}
-void do_POWER_rfsvc (void)
-{
- __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
-}
-
void do_store_hid0_601 (void)
{
uint32_t hid0;
@@ -1715,30 +1661,6 @@ void do_store_dcr (void)
}
#if !defined(CONFIG_USER_ONLY)
-void do_40x_rfci (void)
-{
- __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
- ~((target_ulong)0xFFFF0000), 0);
-}
-
-void do_rfci (void)
-{
- __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
- ~((target_ulong)0x3FFF0000), 0);
-}
-
-void do_rfdi (void)
-{
- __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
- ~((target_ulong)0x3FFF0000), 0);
-}
-
-void do_rfmci (void)
-{
- __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
- ~((target_ulong)0x3FFF0000), 0);
-}
-
void do_load_403_pb (int num)
{
T0 = env->pb[num];
diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h
index aaaba5c..db458b7 100644
--- a/target-ppc/op_helper.h
+++ b/target-ppc/op_helper.h
@@ -62,11 +62,6 @@ void ppc_store_dump_spr (int sprn, target_ulong val);
/* Misc */
#if !defined(CONFIG_USER_ONLY)
void do_store_msr (void);
-void do_rfi (void);
-#if defined(TARGET_PPC64)
-void do_rfid (void);
-void do_hrfid (void);
-#endif
void do_load_6xx_tlb (int is_code);
void do_load_74xx_tlb (int is_code);
#endif
@@ -83,7 +78,6 @@ void do_POWER_maskg (void);
void do_POWER_mulo (void);
#if !defined(CONFIG_USER_ONLY)
void do_POWER_rac (void);
-void do_POWER_rfsvc (void);
void do_store_hid0_601 (void);
#endif
@@ -102,10 +96,6 @@ void do_440_tlbwe (int word);
void do_load_dcr (void);
void do_store_dcr (void);
#if !defined(CONFIG_USER_ONLY)
-void do_40x_rfci (void);
-void do_rfci (void);
-void do_rfdi (void);
-void do_rfmci (void);
void do_4xx_tlbre_lo (void);
void do_4xx_tlbre_hi (void);
void do_4xx_tlbwe_lo (void);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 59533ac..c5c7eb6 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -52,13 +52,16 @@ static char cpu_reg_names[10*3 + 22*4 /* GPR */
#if !defined(TARGET_PPC64)
+ 10*4 + 22*5 /* SPE GPRh */
#endif
+ + 4*6 /* tGPR */
+ 10*4 + 22*5 /* FPR */
+ 2*(10*6 + 22*7) /* AVRh, AVRl */
- + 8*5 /* CRF */];
+ + 8*5 /* CRF */
+ + 1024*8 /* SPR */];
static TCGv cpu_gpr[32];
#if !defined(TARGET_PPC64)
static TCGv cpu_gprh[32];
#endif
+static TCGv cpu_tgpr[4];
static TCGv_i64 cpu_fpr[32];
static TCGv_i64 cpu_avrh[32], cpu_avrl[32];
static TCGv_i32 cpu_crf[8];
@@ -66,8 +69,17 @@ static TCGv cpu_nip;
static TCGv cpu_ctr;
static TCGv cpu_lr;
static TCGv cpu_xer;
+static TCGv cpu_msr, cpu_msr_mask;
static TCGv_i32 cpu_fpscr;
+static TCGv cpu_spr[1024];
static TCGv_i32 cpu_access_type;
+static TCGv_i32 cpu_interrupt_request;
+static TCGv_i32 cpu_flags;
+#if !defined(CONFIG_USER_ONLY)
+static TCGv cpu_excp_prefix;
+#endif
+static TCGv cpu_hflags, cpu_hflags_nmsr;
+static TCGv cpu_mmu_idx;
/* dyngen register indexes */
static TCGv cpu_T[3];
@@ -149,6 +161,13 @@ void ppc_translate_init(void)
p += (i < 10) ? 6 : 7;
}
+ for (i = 0; i < 4; i++) {
+ sprintf(p, "tgpr%d", i);
+ cpu_tgpr[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, tgpr[i]),
p);
+ p += 6;
+ }
+
cpu_nip = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUState, nip), "nip");
@@ -161,12 +180,44 @@ void ppc_translate_init(void)
cpu_xer = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUState, xer), "xer");
+ cpu_msr = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, msr), "msr");
+ cpu_msr_mask = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, msr_mask),
"msr_mask");
+
cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUState, fpscr),
"fpscr");
+ for (i = 0; i < 1024; i++) {
+ sprintf(p, "SPR%d", i);
+ cpu_spr[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, spr[i]), p);
+ p += 8;
+ }
+
cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
offsetof(CPUState,
access_type), "access_type");
+ cpu_interrupt_request = tcg_global_mem_new_i32(TCG_AREG0,
+ offsetof(CPUState,
interrupt_request), "interrupt_request");
+
+ cpu_flags = tcg_global_mem_new_i32(TCG_AREG0,
+ offsetof(CPUState, flags),
"flags");
+
+ cpu_hflags = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, hflags),
"hflags");
+
+ cpu_hflags_nmsr = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState,
hflags_nmsr), "hflags_nmsr");
+
+ cpu_mmu_idx = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState, mmu_idx),
"mmu_idx");
+
+#if !defined(CONFIG_USER_ONLY)
+ cpu_excp_prefix = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPUState,
excp_prefix), "excp_prefix");
+#endif
+
/* register helpers */
#define GEN_HELPER 2
#include "helper.h"
@@ -277,6 +328,165 @@ static always_inline void gen_update_nip
(DisasContext *ctx, target_ulong nip)
tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
}
+static always_inline void gen_get_msr_bit(TCGv dest, TCGv src, int bit)
+{
+ tcg_gen_shri_tl(dest, src, bit);
+ tcg_gen_andi_tl(dest, dest, 1);
+}
+
+static always_inline void gen_hreg_swap_gpr_tgpr()
+{
+ int i;
+ TCGv t0 = tcg_temp_new();
+ for (i = 0; i < 4; i++) {
+ tcg_gen_mov_tl(t0, cpu_gpr[i]);
+ tcg_gen_mov_tl(cpu_gpr[i], cpu_tgpr[i]);
+ tcg_gen_mov_tl(cpu_tgpr[i], t0);
+ }
+ tcg_temp_free(t0);
+}
+
+static always_inline void gen_hreg_compute_mem_idx()
+{
+ /* Precompute MMU index */
+ TCGv t0 = tcg_temp_new();
+ gen_get_msr_bit(t0, cpu_msr, MSR_PR);
+ int elseLabel = gen_new_label();
+ tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, elseLabel);
+
+ int endLabel = gen_new_label();
+#if defined(TARGET_PPC64)
+ gen_get_msr_bit(t0, cpu_msr, MSR_SHV);
+#elif defined(PPC_EMULATE_32BITS_HYPV)
+ gen_get_msr_bit(t0, cpu_msr, MSR_THV);
+#else
+ tcg_gen_movi_tl(t0, 0);
+#endif
+ tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, endLabel);
+
+ tcg_gen_movi_tl(cpu_mmu_idx, 2);
+
+ gen_set_label(elseLabel);
+ TCGv t1 = tcg_const_tl(1);
+ gen_get_msr_bit(t0, cpu_msr, MSR_PR);
+ tcg_gen_sub_tl(cpu_mmu_idx, t1, t0);
+ tcg_gen_br(endLabel);
+ tcg_temp_free(t1);
+
+ gen_set_label(endLabel);
+ tcg_temp_free(t0);
+}
+
+static always_inline void gen_hreg_compute_hflags()
+{
+ target_ulong hflags_mask;
+ hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) |
+ (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) |
+ (1 << MSR_LE);
+ hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB;
+ gen_hreg_compute_mem_idx();
+ tcg_gen_andi_tl(cpu_hflags, cpu_msr, hflags_mask);
+ /* Merge with hflags coming from other registers */
+ tcg_gen_or_tl(cpu_hflags, cpu_hflags, cpu_hflags_nmsr);
+}
+
+static always_inline void gen_hreg_store_msr(TCGv msr, int alter_hv)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_and_tl(t0, msr, cpu_msr_mask);
+#if !defined(CONFIG_USER_ONLY)
+ if (!alter_hv) {
+ /* mtmsr cannot alter the hypervisor state */
+ tcg_gen_andi_tl(t0, t0, (target_ulong)~MSR_HVB);
+ TCGv t1 = tcg_temp_new();
+ tcg_gen_andi_tl(t1, cpu_msr, MSR_HVB);
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_temp_free(t1);
+ }
+
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+ gen_get_msr_bit(t1, t0, MSR_IR);
+ gen_get_msr_bit(t2, cpu_msr, MSR_IR);
+ int labelInner = gen_new_label();
+ tcg_gen_brcond_tl(TCG_COND_NE, t1, t2, labelInner);
+
+ gen_get_msr_bit(t1, t0, MSR_DR);
+ gen_get_msr_bit(t2, cpu_msr, MSR_DR);
+ int labelEnd = gen_new_label();
+ tcg_gen_brcond_tl(TCG_COND_EQ, t1, t2, labelEnd);
+
+ gen_set_label(labelInner);
+ /* Flush all tlb when changing translation mode */
+//TODO tlb_flush(env, 1)
+ tcg_gen_ori_i32(cpu_interrupt_request, cpu_interrupt_request,
CPU_INTERRUPT_EXITTB);
+
+ gen_set_label(labelEnd);
+ labelEnd = gen_new_label();
+ TCGv_i32 t3 = tcg_temp_new_i32();
+ tcg_gen_andi_i32(t3, cpu_flags, POWERPC_FLAG_TGPR);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t3, 0, labelEnd);
+ tcg_temp_free_i32(t3);
+
+ tcg_gen_xor_tl(t1, t0, cpu_msr);
+ tcg_gen_andi_tl(t1, t1, (1 << MSR_TGPR));
+ tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, labelEnd);
+ gen_hreg_swap_gpr_tgpr();
+
+ gen_set_label(labelEnd);
+ labelEnd = gen_new_label();
+ gen_get_msr_bit(t1, t0, MSR_EP);
+ gen_get_msr_bit(t2, cpu_msr, MSR_EP);
+ tcg_gen_brcond_tl(TCG_COND_EQ, t1, t2, labelEnd);
+ /* Change the exception prefix on PowerPC 601 */
+ tcg_gen_muli_tl(cpu_excp_prefix, t1, 0xFFF00000);
+
+ gen_set_label(labelEnd);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+#endif
+ tcg_gen_mov_tl(cpu_msr, t0);
+ gen_hreg_compute_hflags();
+#if !defined(CONFIG_USER_ONLY)
+//XXX
+#endif
+ tcg_temp_free(t0);
+}
+
+static always_inline void gen_do_rfi(TCGv nip, TCGv msr, target_ulong
msrm, int keep_msrh)
+{
+#if defined(TARGET_PPC64)
+ int endLabel = gen_new_label();
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, msr, (1ULL << MSR_SF));
+ tcg_gen_andi_i64(msr, msr, msrm);
+ tcg_gen_brcondi_i64(TCG_COND_EQ, t0, 0, endLabel);
+ tcg_temp_free_i64(t0);
+
+ tcg_gen_andi_i64(nip, nip, 0xFFFFFFFF);
+ tcg_gen_andi_i64(msr, msr, 0xFFFFFFFF);
+ if (keep_msrh) {
+ t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(t0, cpu_msr, ~((uint64_t)0xFFFFFFFF));
+ tcg_gen_or_i64(msr, msr, t0);
+ tcg_temp_free_i64(t0);
+ }
+ gen_set_label(endLabel);
+#else
+ tcg_gen_andi_tl(msr, msr, msrm);
+#endif
+ /* XXX: beware: this is false if VLE is supported */
+ tcg_gen_andi_tl(cpu_nip, nip, ~((target_ulong)0x00000003));
+ gen_hreg_store_msr(msr, 1);
+#if defined (DEBUG_OP)
+//XXX cpu_dump_rfi(env->nip, env->msr);
+#endif
+ /* No need to raise an exception here,
+ * as rfi is always the last insn of a TB
+ */
+ tcg_gen_ori_i32(cpu_interrupt_request, cpu_interrupt_request,
CPU_INTERRUPT_EXITTB);
+}
+
#define GEN_EXCP(ctx, excp,
error) \
do
{ \
TCGv_i32 t0 =
tcg_const_i32(excp); \
@@ -3745,7 +3955,8 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001,
PPC_FLOW)
GEN_EXCP_PRIVOPC(ctx);
return;
}
- gen_op_rfi();
+ gen_do_rfi(cpu_spr[SPR_SRR0], cpu_spr[SPR_SRR1],
+ ~((target_ulong)0xFFFF0000), 1);
GEN_SYNC(ctx);
#endif
}
@@ -3761,7 +3972,8 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001,
PPC_64B)
GEN_EXCP_PRIVOPC(ctx);
return;
}
- gen_op_rfid();
+ gen_do_rfi(cpu_spr[SPR_SRR0], cpu_spr[SPR_SRR1],
+ ~((target_ulong)0xFFFF0000), 0);
GEN_SYNC(ctx);
#endif
}
@@ -3776,7 +3988,8 @@ GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001,
PPC_64H)
GEN_EXCP_PRIVOPC(ctx);
return;
}
- gen_op_hrfid();
+ gen_do_rfi(cpu_spr[SPR_HSRR0], cpu_spr[SPR_HSRR1],
+ ~((target_ulong)0xFFFF0000), 0);
GEN_SYNC(ctx);
#endif
}
@@ -5087,7 +5300,7 @@ GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02,
0x03FFF0001, PPC_POWER)
GEN_EXCP_PRIVOPC(ctx);
return;
}
- gen_op_POWER_rfsvc();
+ gen_do_rfi(cpu_lr, cpu_ctr, 0x0000FFFF, 0);
GEN_SYNC(ctx);
#endif
}
@@ -5631,7 +5844,8 @@ GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01,
0x03FF8001, PPC_40x_EXCP)
return;
}
/* Restore CPU state */
- gen_op_40x_rfci();
+ gen_do_rfi(cpu_spr[SPR_40x_SRR2], cpu_spr[SPR_40x_SRR3],
+ ~((target_ulong)0xFFFF0000), 0);
GEN_SYNC(ctx);
#endif
}
@@ -5646,7 +5860,8 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001,
PPC_BOOKE)
return;
}
/* Restore CPU state */
- gen_op_rfci();
+ gen_do_rfi(cpu_spr[SPR_BOOKE_CSRR0], cpu_spr[SPR_BOOKE_CSRR1],
+ ~((target_ulong)0x3FFF0000), 0);
GEN_SYNC(ctx);
#endif
}
@@ -5663,7 +5878,8 @@ GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001,
PPC_RFDI)
return;
}
/* Restore CPU state */
- gen_op_rfdi();
+ gen_do_rfi(cpu_spr[SPR_BOOKE_DSRR0], cpu_spr[SPR_BOOKE_DSRR1],
+ ~((target_ulong)0x3FFF0000), 0);
GEN_SYNC(ctx);
#endif
}
@@ -5679,7 +5895,8 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001,
PPC_RFMCI)
return;
}
/* Restore CPU state */
- gen_op_rfmci();
+ gen_do_rfi(cpu_spr[SPR_BOOKE_MCSRR0], cpu_spr[SPR_BOOKE_MCSRR1],
+ ~((target_ulong)0x3FFF0000), 0);
GEN_SYNC(ctx);
#endif
}
op_40x_rfci_2.diff
Description: Binary data