* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
-#include "qapi/error.h"
#include "cpu.h"
#include "exec/helper-proto.h"
#include "sysemu/kvm.h"
#include "exec/log.h"
#include "helper_regs.h"
#include "qemu/error-report.h"
+#include "mmu-book3s-v3.h"
+#include "mmu-radix64.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
{
- switch (env->mmu_model) {
+ switch (POWERPC_MMU_VER(env->mmu_model)) {
case POWERPC_MMU_BOOKE:
mmubooke_dump_mmu(f, cpu_fprintf, env);
break;
mmu6xx_dump_mmu(f, cpu_fprintf, env);
break;
#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_VER_64B:
+ case POWERPC_MMU_VER_2_03:
+ case POWERPC_MMU_VER_2_06:
+ case POWERPC_MMU_VER_2_07:
dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
break;
+ case POWERPC_MMU_VER_3_00:
+ if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
+ /* TODO - Unsupported */
+ } else {
+ dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
+ break;
+ }
#endif
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
CPUPPCState *env = &cpu->env;
mmu_ctx_t ctx;
- switch (env->mmu_model) {
+ switch (POWERPC_MMU_VER(env->mmu_model)) {
#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_VER_64B:
+ case POWERPC_MMU_VER_2_03:
+ case POWERPC_MMU_VER_2_06:
+ case POWERPC_MMU_VER_2_07:
return ppc_hash64_get_phys_page_debug(cpu, addr);
+ case POWERPC_MMU_VER_3_00:
+ if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
+ return ppc_radix64_get_phys_page_debug(cpu, addr);
+ } else {
+ return ppc_hash64_get_phys_page_debug(cpu, addr);
+ }
+ break;
#endif
case POWERPC_MMU_32B:
env->spr[SPR_40x_ESR] = 0x00000000;
break;
case POWERPC_MMU_BOOKE206:
- booke206_update_mas_tlb_miss(env, address, rw);
+ booke206_update_mas_tlb_miss(env, address, 2);
/* fall through */
case POWERPC_MMU_BOOKE:
cs->exception_index = POWERPC_EXCP_ITLB;
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ env->tlb_need_flush = 0;
+ tlb_flush(CPU(cpu));
+ } else
+#endif /* defined(TARGET_PPC64) */
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
break;
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
- case POWERPC_MMU_3_00:
-#endif /* defined(TARGET_PPC64) */
env->tlb_need_flush = 0;
tlb_flush(CPU(cpu));
break;
default:
/* XXX: TODO */
- cpu_abort(CPU(cpu), "Unknown MMU model %d\n", env->mmu_model);
+ cpu_abort(CPU(cpu), "Unknown MMU model %x\n", env->mmu_model);
break;
}
}
{
#if !defined(FLUSH_ALL_TLBS)
addr &= TARGET_PAGE_MASK;
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ /* tlbie invalidate TLBs for all segments */
+ /* XXX: given the fact that there are too many segments to invalidate,
+ * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
+ * we just invalidate all TLBs
+ */
+ env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+ } else
+#endif /* defined(TARGET_PPC64) */
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
*/
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06a:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_2_07a:
- case POWERPC_MMU_3_00:
- /* tlbie invalidate TLBs for all segments */
- /* XXX: given the fact that there are too many segments to invalidate,
- * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
- * we just invalidate all TLBs
- */
- env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
- break;
-#endif /* defined(TARGET_PPC64) */
default:
/* Should never reach here with other MMU models */
assert(0);
tlb_flush(CPU(cpu));
}
+static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb)
+{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+ if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
+ tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
+ } else {
+ tlb_flush(CPU(cpu));
+ }
+}
+
void helper_booke206_tlbwe(CPUPPCState *env)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
if (msr_gs) {
cpu_abort(CPU(cpu), "missing HV implementation\n");
}
+
+ if (tlb->mas1 & MAS1_VALID) {
+ /* Invalidate the page in QEMU TLB if it was a valid entry.
+ *
+ * In "PowerPC e500 Core Family Reference Manual, Rev. 1",
+ * Section "12.4.2 TLB Write Entry (tlbwe) Instruction":
+ * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf)
+ *
+ * "Note that when an L2 TLB entry is written, it may be displacing an
+ * already valid entry in the same L2 TLB location (a victim). If a
+ * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1
+ * TLB entry is automatically invalidated." */
+ flush_page(env, tlb);
+ }
+
tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
env->spr[SPR_BOOKE_MAS3];
tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
- /* MAV 1.0 only */
- if (!(tlbncfg & TLBnCFG_AVAIL)) {
- /* force !AVAIL TLB entries to correct page size */
- tlb->mas1 &= ~MAS1_TSIZE_MASK;
- /* XXX can be configured in MMUCSR0 */
- tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
+ if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
+ /* For TLB which has a fixed size TSIZE is ignored with MAV2 */
+ booke206_fixed_size_tlbn(env, tlbn, tlb);
+ } else {
+ if (!(tlbncfg & TLBnCFG_AVAIL)) {
+ /* force !AVAIL TLB entries to correct page size */
+ tlb->mas1 &= ~MAS1_TSIZE_MASK;
+ /* XXX can be configured in MMUCSR0 */
+ tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
+ }
}
/* Make a mask from TLB size to discard invalid bits in EPN field */
tlb->mas1 &= ~MAS1_IPROT;
}
- if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
- tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
- } else {
- tlb_flush(CPU(cpu));
- }
+ flush_page(env, tlb);
}
static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
-void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr)
+void tlb_fill(CPUState *cs, target_ulong addr, int size,
+ MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);