]> www.infradead.org Git - users/dwmw2/qemu.git/commitdiff
PPC: booke206: Implement tlbilx
authorAlexander Graf <agraf@suse.de>
Fri, 20 Jan 2012 03:09:15 +0000 (04:09 +0100)
committerAlexander Graf <agraf@suse.de>
Thu, 2 Feb 2012 01:47:46 +0000 (02:47 +0100)
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>
target-ppc/helper.h
target-ppc/op_helper.c
target-ppc/translate.c

index 470e42f676ea405678d3f6ba9cae70704dcea440..4798fd57eedd0323c4755c77fee713ef19c66bd4 100644 (file)
@@ -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)
index 3b197f2deb31fe49ca87bb6a829fe1f6c8639ed7..1f1fa0936847cb9f5a8c6288ff7fbf8a0e632dff 100644 (file)
@@ -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;
index adde65b2776c132bf07ac8f034e44438433fd29d..d8ef7196b4444e9115bbaa38c9aa6c240cc70287 100644 (file)
@@ -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),