summaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2012-01-20 04:09:15 +0100
committerAlexander Graf <agraf@suse.de>2012-02-02 02:47:46 +0100
commit6d3db821c18fdc9727108b5b4bbb38cb7ab5c0e6 (patch)
treec1884c2333164f47bd34145305f7eb4976e58496 /target-ppc
parent5935ee072d6fbcdf28ff6132ba6d8c3a1356bb0a (diff)
downloadqemu-6d3db821c18fdc9727108b5b4bbb38cb7ab5c0e6.tar.gz
qemu-6d3db821c18fdc9727108b5b4bbb38cb7ab5c0e6.tar.bz2
qemu-6d3db821c18fdc9727108b5b4bbb38cb7ab5c0e6.zip
PPC: booke206: Implement tlbilx
The PowerPC 2.06 BookE ISA defines an opcode called "tlbilx" which is used to flush TLB entries. It's the recommended way of flushing in virtualized environments. So far we got away without implementing it, but Linux for e500mc uses this instruction, so we better add it :). Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/helper.h3
-rw-r--r--target-ppc/op_helper.c64
-rw-r--r--target-ppc/translate.c35
3 files changed, 102 insertions, 0 deletions
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 470e42f676..4798fd57ee 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -336,6 +336,9 @@ DEF_HELPER_0(booke206_tlbre, void)
DEF_HELPER_0(booke206_tlbwe, void)
DEF_HELPER_1(booke206_tlbsx, void, tl)
DEF_HELPER_1(booke206_tlbivax, void, tl)
+DEF_HELPER_1(booke206_tlbilx0, void, tl)
+DEF_HELPER_1(booke206_tlbilx1, void, tl)
+DEF_HELPER_1(booke206_tlbilx3, void, tl)
DEF_HELPER_1(booke206_tlbflush, void, i32)
DEF_HELPER_2(booke_setpid, void, i32, tl)
DEF_HELPER_1(6xx_tlbd, void, tl)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 3b197f2deb..1f1fa09368 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4406,6 +4406,70 @@ void helper_booke206_tlbivax(target_ulong address)
}
}
+void helper_booke206_tlbilx0(target_ulong address)
+{
+ /* XXX missing LPID handling */
+ booke206_flush_tlb(env, -1, 1);
+}
+
+void helper_booke206_tlbilx1(target_ulong address)
+{
+ int i, j;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ ppcmas_tlb_t *tlb = env->tlb.tlbm;
+ int tlb_size;
+
+ /* XXX missing LPID handling */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ tlb_size = booke206_tlb_size(env, i);
+ for (j = 0; j < tlb_size; j++) {
+ if (!(tlb[j].mas1 & MAS1_IPROT) &&
+ ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
+ tlb[j].mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb += booke206_tlb_size(env, i);
+ }
+ tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbilx3(target_ulong address)
+{
+ int i, j;
+ ppcmas_tlb_t *tlb;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ int pid = tid >> MAS6_SPID_SHIFT;
+ int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
+ int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
+ /* XXX check for unsupported isize and raise an invalid opcode then */
+ int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
+ /* XXX implement MAV2 handling */
+ bool mav2 = false;
+
+ /* XXX missing LPID handling */
+ /* flush by pid and ea */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int ways = booke206_tlb_ways(env, i);
+
+ for (j = 0; j < ways; j++) {
+ tlb = booke206_get_tlbm(env, i, address, j);
+ if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
+ (tlb->mas1 & MAS1_IPROT) ||
+ ((tlb->mas1 & MAS1_IND) != ind) ||
+ ((tlb->mas8 & MAS8_TGS) != sgs)) {
+ continue;
+ }
+ if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
+ /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
+ continue;
+ }
+ /* XXX e500mc doesn't match SAS, but other cores might */
+ tlb->mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb_flush(env, 1);
+}
+
void helper_booke206_tlbflush(uint32_t type)
{
int flags = 0;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index adde65b277..d8ef7196b4 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6110,6 +6110,39 @@ static void gen_tlbivax_booke206(DisasContext *ctx)
#endif
}
+static void gen_tlbilx_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ TCGv t0;
+ if (unlikely(!ctx->mem_idx)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ t0 = tcg_temp_new();
+ gen_addr_reg_index(ctx, t0);
+
+ switch((ctx->opcode >> 21) & 0x3) {
+ case 0:
+ gen_helper_booke206_tlbilx0(t0);
+ break;
+ case 1:
+ gen_helper_booke206_tlbilx1(t0);
+ break;
+ case 3:
+ gen_helper_booke206_tlbilx3(t0);
+ break;
+ default:
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ break;
+ }
+
+ tcg_temp_free(t0);
+#endif
+}
+
/* wrtee */
static void gen_wrtee(DisasContext *ctx)
@@ -8574,6 +8607,8 @@ GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001,
+ PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),