From 50728199c549467b01609ddbb831237f72c8f3f6 Mon Sep 17 00:00:00 2001 From: Roman Kapl Date: Fri, 21 Sep 2018 08:59:07 +0200 Subject: target/ppc: add external PID support External PID is a mechanism present on BookE 2.06 that enables application to store/load data from different address spaces. There are special version of some instructions, which operate on alternate address space, which is specified in the EPLC/EPSC regiser. This implementation uses two additional MMU modes (mmu_idx) to provide the address space for the load and store instructions. The QEMU TLB fill code was modified to recognize these MMU modes and use the values in EPLC/EPSC to find the proper entry in he PPC TLB. These two QEMU TLBs are also flushed on each write to EPLC/EPSC. Following instructions are implemented: dcbfep dcbstep dcbtep dcbtstep dcbzep dcbzlep icbiep lbepx ldepx lfdepx lhepx lwepx stbepx stdepx stfdepx sthepx stwepx. Following vector instructions are not: evlddepx evstddepx lvepx lvepxl stvepx stvepxl. Signed-off-by: Roman Kapl Signed-off-by: David Gibson --- target/ppc/mem_helper.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'target/ppc/mem_helper.c') diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index a1485fad9b..9c5a68579e 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -142,11 +142,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, } } -void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) +static void dcbz_common(CPUPPCState *env, target_ulong addr, + uint32_t opcode, bool epid, uintptr_t retaddr) { target_ulong mask, dcbz_size = env->dcache_line_size; uint32_t i; void *haddr; + int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx; #if defined(TARGET_PPC64) /* Check for dcbz vs dcbzl on 970 */ @@ -166,17 +168,34 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) } /* Try fast path translate */ - haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx); + haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx); if (haddr) { memset(haddr, 0, dcbz_size); } else { /* Slow path */ for (i = 0; i < dcbz_size; i += 8) { - cpu_stq_data_ra(env, addr + i, 0, GETPC()); + if (epid) { +#if !defined(CONFIG_USER_ONLY) + /* Does not make sense on USER_ONLY config */ + cpu_stq_eps_ra(env, addr + i, 0, retaddr); +#endif + } else { + cpu_stq_data_ra(env, addr + i, 0, retaddr); + } } } } +void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) +{ + dcbz_common(env, addr, opcode, false, GETPC()); +} + +void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode) +{ + dcbz_common(env, addr, opcode, true, GETPC()); +} + void helper_icbi(CPUPPCState *env, target_ulong addr) { addr &= ~(env->dcache_line_size - 1); @@ -188,6 +207,15 @@ void helper_icbi(CPUPPCState *env, target_ulong addr) cpu_ldl_data_ra(env, addr, GETPC()); } +void helper_icbiep(CPUPPCState *env, target_ulong addr) +{ +#if !defined(CONFIG_USER_ONLY) + /* See comments above */ + addr &= ~(env->dcache_line_size - 1); + cpu_ldl_epl_ra(env, addr, GETPC()); +#endif +} + /* XXX: to be tested */ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) -- cgit v1.2.3-55-g7522