[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 07/12] target-mips: add TLBINV support
From: |
Leon Alrae |
Subject: |
[Qemu-devel] [PATCH 07/12] target-mips: add TLBINV support |
Date: |
Thu, 19 Jun 2014 15:45:38 +0100 |
For Standard TLB configuration (Config.MT=1):
TLBINV invalidates a set of TLB entries based on ASID. The virtual address is
ignored in the entry match. TLB entries which have their G bit set to 1 are not
modified.
TLBINVF causes all entries to be invalidated.
Note that this commit introduces support for Config4.IE == 3 only (i.e. TLBINV*
instructions operate on entire MMU).
Single TLB entry can be marked as invalid on TLB entry write by having
EntryHi.EHINV set to 1.
Signed-off-by: Leon Alrae <address@hidden>
---
disas/mips.c | 2 +
target-mips/cpu.h | 7 ++++
target-mips/helper.c | 2 +-
target-mips/helper.h | 2 +
target-mips/op_helper.c | 65 +++++++++++++++++++++++++++++++++++++----
target-mips/translate.c | 22 ++++++++++++++
target-mips/translate_init.c | 2 +
7 files changed, 94 insertions(+), 8 deletions(-)
diff --git a/disas/mips.c b/disas/mips.c
index e3e253f..ff2e4b3 100644
--- a/disas/mips.c
+++ b/disas/mips.c
@@ -2410,6 +2410,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0,
I1 },
{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0,
I1 },
{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0,
I1 },
+{"tlbinv", "", 0x42000003, 0xffffffff, INSN_TLB, 0, I32
},
+{"tlbinvf", "", 0x42000004, 0xffffffff, INSN_TLB, 0, I32
},
{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0,
I1 },
{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0,
I2 },
{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0,
I2 },
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 78158bd..14edf57 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -34,6 +34,7 @@ struct r4k_tlb_t {
uint_fast16_t XI1:1;
uint_fast16_t RI0:1;
uint_fast16_t RI1:1;
+ uint_fast16_t EHINV:1;
target_ulong PFN[2];
};
@@ -47,6 +48,8 @@ struct CPUMIPSTLBContext {
void (*helper_tlbwr)(struct CPUMIPSState *env);
void (*helper_tlbp)(struct CPUMIPSState *env);
void (*helper_tlbr)(struct CPUMIPSState *env);
+ void (*helper_tlbinv)(struct CPUMIPSState *env);
+ void (*helper_tlbinvf)(struct CPUMIPSState *env);
union {
struct {
r4k_tlb_t tlb[MIPS_TLB_MAX];
@@ -282,6 +285,7 @@ struct CPUMIPSState {
target_ulong CP0_BadVAddr;
int32_t CP0_Count;
target_ulong CP0_EntryHi;
+#define CP0EnHi_EHINV 10
int32_t CP0_Compare;
int32_t CP0_Status;
#define CP0St_CU3 31
@@ -393,6 +397,7 @@ struct CPUMIPSState {
uint32_t CP0_Config4;
uint32_t CP0_Config4_rw_bitmask;
#define CP0C4_KScrExist 16
+#define CP0C4_IE 29
#define CP0C4_M 31
uint32_t CP0_Config5;
uint32_t CP0_Config5_rw_bitmask;
@@ -531,6 +536,8 @@ void r4k_helper_tlbwi(CPUMIPSState *env);
void r4k_helper_tlbwr(CPUMIPSState *env);
void r4k_helper_tlbp(CPUMIPSState *env);
void r4k_helper_tlbr(CPUMIPSState *env);
+void r4k_helper_tlbinv(CPUMIPSState *env);
+void r4k_helper_tlbinvf(CPUMIPSState *env);
void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
bool is_write, bool is_exec, int unused,
diff --git a/target-mips/helper.c b/target-mips/helper.c
index e9f31ca..ab9217f 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -88,7 +88,7 @@ int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int
*prot,
#endif
/* Check ASID, virtual page number & size */
- if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
+ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
/* TLB match */
int n = !!(address & mask & ~(mask >> 1));
/* Check access rights */
diff --git a/target-mips/helper.h b/target-mips/helper.h
index c30104e..cb6e4b4 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -343,6 +343,8 @@ DEF_HELPER_1(tlbwi, void, env)
DEF_HELPER_1(tlbwr, void, env)
DEF_HELPER_1(tlbp, void, env)
DEF_HELPER_1(tlbr, void, env)
+DEF_HELPER_1(tlbinv, void, env)
+DEF_HELPER_1(tlbinvf, void, env)
DEF_HELPER_1(di, tl, env)
DEF_HELPER_1(ei, tl, env)
DEF_HELPER_1(eret, void, env)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 4570af4..dcdeeef 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1362,10 +1362,14 @@ void helper_mtc0_count(CPUMIPSState *env, target_ulong
arg1)
void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
{
- target_ulong old, val;
+ target_ulong old, val, mask;
+ mask = (TARGET_PAGE_MASK << 1) | 0xFF;
+ if (env->CP0_Config4 & (1 << CP0C4_IE)) {
+ mask |= 1 << CP0EnHi_EHINV;
+ }
/* 1k pages not implemented */
- val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
+ val = arg1 & mask;
#if defined(TARGET_MIPS64)
val &= env->SEGMask;
#endif
@@ -1859,6 +1863,11 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx)
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->tlb->mmu.r4k.tlb[idx];
+ if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
+ tlb->EHINV = 1;
+ return;
+ }
+ tlb->EHINV = 0;
tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
#if defined(TARGET_MIPS64)
tlb->VPN &= env->SEGMask;
@@ -1880,6 +1889,31 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx)
tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}
+void r4k_helper_tlbinv(CPUMIPSState *env)
+{
+ int idx;
+ r4k_tlb_t *tlb;
+ uint8_t ASID = env->CP0_EntryHi & 0xFF;
+
+ for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+ if (!tlb->G && tlb->ASID == ASID) {
+ tlb->EHINV = 1;
+ }
+ }
+ cpu_mips_tlb_flush(env, 1);
+}
+
+void r4k_helper_tlbinvf(CPUMIPSState *env)
+{
+ int idx;
+
+ for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
+ env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
+ }
+ cpu_mips_tlb_flush(env, 1);
+}
+
void r4k_helper_tlbwi(CPUMIPSState *env)
{
r4k_tlb_t *tlb;
@@ -1941,7 +1975,7 @@ void r4k_helper_tlbp(CPUMIPSState *env)
tag &= env->SEGMask;
#endif
/* Check ASID, virtual page number & size */
- if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
+ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
/* TLB match */
env->CP0_Index = i;
break;
@@ -1985,16 +2019,23 @@ void r4k_helper_tlbr(CPUMIPSState *env)
r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
- env->CP0_EntryHi = tlb->VPN | tlb->ASID;
- env->CP0_PageMask = tlb->PageMask;
- env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
+ if (tlb->EHINV) {
+ env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
+ env->CP0_PageMask = 0;
+ env->CP0_EntryLo0 = 0;
+ env->CP0_EntryLo1 = 0;
+ } else {
+ env->CP0_EntryHi = tlb->VPN | tlb->ASID;
+ env->CP0_PageMask = tlb->PageMask;
+ env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
((target_ulong)tlb->RI0 << CP0EnLo_RI) |
((target_ulong)tlb->XI0 << CP0EnLo_XI) |
(tlb->C0 << 3) | (tlb->PFN[0] >> 6);
- env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
+ env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
((target_ulong)tlb->RI1 << CP0EnLo_RI) |
((target_ulong)tlb->XI1 << CP0EnLo_XI) |
(tlb->C1 << 3) | (tlb->PFN[1] >> 6);
+ }
}
void helper_tlbwi(CPUMIPSState *env)
@@ -2017,6 +2058,16 @@ void helper_tlbr(CPUMIPSState *env)
env->tlb->helper_tlbr(env);
}
+void helper_tlbinv(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbinv(env);
+}
+
+void helper_tlbinvf(CPUMIPSState *env)
+{
+ env->tlb->helper_tlbinvf(env);
+}
+
/* Specials */
target_ulong helper_di(CPUMIPSState *env)
{
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 4ddb83e..e511c75 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -901,6 +901,8 @@ enum {
enum {
OPC_TLBR = 0x01 | OPC_C0,
OPC_TLBWI = 0x02 | OPC_C0,
+ OPC_TLBINV = 0x03 | OPC_C0,
+ OPC_TLBINVF = 0x04 | OPC_C0,
OPC_TLBWR = 0x06 | OPC_C0,
OPC_TLBP = 0x08 | OPC_C0,
OPC_RFE = 0x10 | OPC_C0,
@@ -1176,6 +1178,7 @@ typedef struct DisasContext {
bool ulri;
int32_t kscrexist;
bool rxi;
+ bool ie;
} DisasContext;
enum {
@@ -7548,6 +7551,24 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext
*ctx, uint32_t opc, int rt,
goto die;
gen_helper_tlbwi(cpu_env);
break;
+ case OPC_TLBINV:
+ opn = "tlbinv";
+ if (ctx->ie) {
+ if (!env->tlb->helper_tlbinv) {
+ goto die;
+ }
+ gen_helper_tlbinv(cpu_env);
+ } /* treat as nop if TLBINV not supported */
+ break;
+ case OPC_TLBINVF:
+ opn = "tlbinvf";
+ if (ctx->ie) {
+ if (!env->tlb->helper_tlbinvf) {
+ goto die;
+ }
+ gen_helper_tlbinvf(cpu_env);
+ } /* treat as nop if TLBINV not supported */
+ break;
case OPC_TLBWR:
opn = "tlbwr";
if (!env->tlb->helper_tlbwr)
@@ -17546,6 +17567,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu,
TranslationBlock *tb,
ctx.bstate = BS_NONE;
ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff;
ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1;
+ ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 1;
/* Restore delay slot state from the tb context. */
ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
ctx.ulri = env->CP0_Config3 & (1 << CP0C3_ULRI);
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 71cb350..561eeb0 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -656,6 +656,8 @@ static void r4k_mmu_init (CPUMIPSState *env, const
mips_def_t *def)
env->tlb->helper_tlbwr = r4k_helper_tlbwr;
env->tlb->helper_tlbp = r4k_helper_tlbp;
env->tlb->helper_tlbr = r4k_helper_tlbr;
+ env->tlb->helper_tlbinv = r4k_helper_tlbinv;
+ env->tlb->helper_tlbinvf = r4k_helper_tlbinvf;
}
static void mmu_init (CPUMIPSState *env, const mips_def_t *def)
--
1.7.5.4
- [Qemu-devel] [PATCH 00/12] implement features required in MIPS64 Release 6, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 01/12] target-mips: add KScratch registers, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 02/12] target-mips: update cpu_save/cpu_load to support KScratch registers, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 03/12] target-mips: distinguish between data load and instruction fetch, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 04/12] target-mips: add RI and XI fields to TLB entry, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 05/12] target-mips: update PageGrain and m{t, f}c0 EntryLo{0, 1}, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 08/12] target-mips: add BadInstr and BadInstrP support, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 07/12] target-mips: add TLBINV support,
Leon Alrae <=
- [Qemu-devel] [PATCH 06/12] target-mips: add new Read-Inhibit and Execute-Inhibit exceptions, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 09/12] target-mips: save cpu state if instruction can cause an exception, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 10/12] target-mips: update cpu_save/cpu_load to support BadInstr registers, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 11/12] target-mips: enable features in MIPS32R5-generic core, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 12/12] target-mips: enable features in MIPS64R6-generic core, Leon Alrae, 2014/06/19