Loading target-ppc/cpu.h +2 −0 Original line number Diff line number Diff line Loading @@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); target_ulong load_40x_pit (CPUPPCState *env); void store_40x_pit (CPUPPCState *env, target_ulong val); void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); #endif #endif Loading target-ppc/helper.c +74 −22 Original line number Diff line number Diff line Loading @@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, return ret; } /* Generic TLB check function for embedded PowerPC implementations */ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, target_phys_addr_t *raddrp, target_ulong address, int i) { target_ulong mask; /* Check valid flag */ if (!(tlb->prot & PAGE_VALID)) { if (loglevel != 0) fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); return -1; } mask = ~(tlb->size - 1); if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, (int)env->spr[SPR_40x_PID], tlb->EPN, mask, (int)tlb->PID); } /* Check PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) return -1; /* Check effective address */ if ((address & mask) != tlb->EPN) return -1; *raddrp = (tlb->RPN & mask) | (address & ~mask); return 0; } /* Generic TLB search function for PowerPC embedded implementations */ int ppcemb_tlb_search (CPUState *env, target_ulong address) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; int i, ret; /* Default return value is no match */ ret = -1; for (i = 0; i < 64; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) { ret = i; break; } } return ret; } /* Helpers specific to PowerPC 40x implementations */ void ppc4xx_tlb_invalidate_all (CPUState *env) { ppcemb_tlb_t *tlb; Loading @@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; target_ulong mask; int i, ret, zsel, zpr; ret = -1; raddr = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; /* Check valid flag */ if (!(tlb->prot & PAGE_VALID)) { if (loglevel != 0) fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0) continue; } mask = ~(tlb->size - 1); if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, (int)env->spr[SPR_40x_PID], tlb->EPN, mask, (int)tlb->PID); } /* Check PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) continue; /* Check effective address */ if ((address & mask) != tlb->EPN) continue; raddr = (tlb->RPN & mask) | (address & ~mask); zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; if (loglevel != 0) { Loading @@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (access_type == ACCESS_CODE) { /* Check execute enable bit */ switch (zpr) { case 0x2: if (msr_pr) goto check_exec_perm; goto exec_granted; case 0x0: if (msr_pr) { ctx->prot = 0; Loading @@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } /* No break here */ case 0x1: case 0x2: check_exec_perm: /* Check from TLB entry */ if (!(tlb->prot & PAGE_EXEC)) { ret = -3; Loading @@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } break; case 0x3: exec_granted: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE; ret = 0; Loading @@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } } else { switch (zpr) { case 0x2: if (msr_pr) goto check_rw_perm; goto rw_granted; case 0x0: if (msr_pr) { ctx->prot = 0; Loading @@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } /* No break here */ case 0x1: case 0x2: check_rw_perm: /* Check from TLB entry */ /* Check write protection bit */ if (tlb->prot & PAGE_WRITE) { Loading @@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } break; case 0x3: rw_granted: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE; ret = 0; Loading @@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, return ret; } void store_40x_sler (CPUPPCState *env, uint32_t val) { /* XXX: TO BE FIXED */ if (val != 0x00000000) { cpu_abort(env, "Little-endian regions are not supported by now\n"); } env->spr[SPR_405_SLER] = val; } static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { Loading target-ppc/op.c +6 −0 Original line number Diff line number Diff line Loading @@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void) store_40x_dbcr0(env, T0); } void OPPROTO op_store_40x_sler (void) { store_40x_sler(env, T0); RETURN(); } void OPPROTO op_store_booke_tcr (void) { store_booke_tcr(env, T0); Loading target-ppc/op_helper.c +16 −32 Original line number Diff line number Diff line Loading @@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void) T0 |= 0x100; } static int tlb_4xx_search (target_ulong virtual) { ppcemb_tlb_t *tlb; target_ulong base, mask; int i, ret; /* Default return value is no match */ ret = -1; for (i = 0; i < 64; i++) { tlb = &env->tlb[i].tlbe; /* Check TLB validity */ if (!(tlb->prot & PAGE_VALID)) continue; /* Check TLB PID vs current PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) continue; /* Check TLB address vs virtual address */ base = tlb->EPN; mask = ~(tlb->size - 1); if ((base & mask) != (virtual & mask)) continue; ret = i; break; } return ret; } void do_4xx_tlbsx (void) { T0 = tlb_4xx_search(T0); T0 = ppcemb_tlb_search(env, T0); } void do_4xx_tlbsx_ (void) { int tmp = xer_ov; T0 = tlb_4xx_search(T0); T0 = ppcemb_tlb_search(env, T0); if (T0 != -1) tmp |= 0x02; env->crf[0] = tmp; Loading Loading @@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void) tlb_flush_page(env, page); } tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); /* We cannot handle TLB size < TARGET_PAGE_SIZE. * If this ever occurs, one should use the ppcemb target instead * of the ppc or ppc64 one */ if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) { cpu_abort(env, "TLB size %u < %u are not supported (%d)\n", tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7)); } tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); if (T1 & 0x40) tlb->prot |= PAGE_VALID; else tlb->prot &= ~PAGE_VALID; if (T1 & 0x20) { /* XXX: TO BE FIXED */ cpu_abort(env, "Little-endian TLB entries are not supported by now\n"); } tlb->PID = env->spr[SPR_40x_PID]; /* PID */ tlb->attr = T1 & 0xFF; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel) { fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX if (loglevel != 0) { fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, (int)T0, tlb->RPN, tlb->EPN, tlb->size, tlb->prot & PAGE_READ ? 'r' : '-', Loading target-ppc/translate_init.c +13 −3 Original line number Diff line number Diff line Loading @@ -355,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn) RET_STOP(ctx); } static void spr_write_40x_sler (void *opaque, int sprn) { DisasContext *ctx = opaque; gen_op_store_40x_sler(); /* We must stop the translation as we may have changed * some regions endianness */ RET_STOP(ctx); } static void spr_write_booke_tcr (void *opaque, int sprn) { gen_op_store_booke_tcr(); Loading Loading @@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Storage control */ /* XXX : not implemented */ spr_register(env, SPR_405_SLER, "SLER", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_40x_sler, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_405_SU0R, "SU0R", Loading Loading @@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, .msr_mask = 0x00000000000ED630ULL, }, #if defined (TODO) /* PowerPC 405 EZ */ Loading Loading
target-ppc/cpu.h +2 −0 Original line number Diff line number Diff line Loading @@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); target_ulong load_40x_pit (CPUPPCState *env); void store_40x_pit (CPUPPCState *env, target_ulong val); void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); #endif #endif Loading
target-ppc/helper.c +74 −22 Original line number Diff line number Diff line Loading @@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, return ret; } /* Generic TLB check function for embedded PowerPC implementations */ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, target_phys_addr_t *raddrp, target_ulong address, int i) { target_ulong mask; /* Check valid flag */ if (!(tlb->prot & PAGE_VALID)) { if (loglevel != 0) fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); return -1; } mask = ~(tlb->size - 1); if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, (int)env->spr[SPR_40x_PID], tlb->EPN, mask, (int)tlb->PID); } /* Check PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) return -1; /* Check effective address */ if ((address & mask) != tlb->EPN) return -1; *raddrp = (tlb->RPN & mask) | (address & ~mask); return 0; } /* Generic TLB search function for PowerPC embedded implementations */ int ppcemb_tlb_search (CPUState *env, target_ulong address) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; int i, ret; /* Default return value is no match */ ret = -1; for (i = 0; i < 64; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) { ret = i; break; } } return ret; } /* Helpers specific to PowerPC 40x implementations */ void ppc4xx_tlb_invalidate_all (CPUState *env) { ppcemb_tlb_t *tlb; Loading @@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; target_ulong mask; int i, ret, zsel, zpr; ret = -1; raddr = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; /* Check valid flag */ if (!(tlb->prot & PAGE_VALID)) { if (loglevel != 0) fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0) continue; } mask = ~(tlb->size - 1); if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, (int)env->spr[SPR_40x_PID], tlb->EPN, mask, (int)tlb->PID); } /* Check PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) continue; /* Check effective address */ if ((address & mask) != tlb->EPN) continue; raddr = (tlb->RPN & mask) | (address & ~mask); zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; if (loglevel != 0) { Loading @@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (access_type == ACCESS_CODE) { /* Check execute enable bit */ switch (zpr) { case 0x2: if (msr_pr) goto check_exec_perm; goto exec_granted; case 0x0: if (msr_pr) { ctx->prot = 0; Loading @@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } /* No break here */ case 0x1: case 0x2: check_exec_perm: /* Check from TLB entry */ if (!(tlb->prot & PAGE_EXEC)) { ret = -3; Loading @@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } break; case 0x3: exec_granted: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE; ret = 0; Loading @@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } } else { switch (zpr) { case 0x2: if (msr_pr) goto check_rw_perm; goto rw_granted; case 0x0: if (msr_pr) { ctx->prot = 0; Loading @@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } /* No break here */ case 0x1: case 0x2: check_rw_perm: /* Check from TLB entry */ /* Check write protection bit */ if (tlb->prot & PAGE_WRITE) { Loading @@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } break; case 0x3: rw_granted: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE; ret = 0; Loading @@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, return ret; } void store_40x_sler (CPUPPCState *env, uint32_t val) { /* XXX: TO BE FIXED */ if (val != 0x00000000) { cpu_abort(env, "Little-endian regions are not supported by now\n"); } env->spr[SPR_405_SLER] = val; } static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { Loading
target-ppc/op.c +6 −0 Original line number Diff line number Diff line Loading @@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void) store_40x_dbcr0(env, T0); } void OPPROTO op_store_40x_sler (void) { store_40x_sler(env, T0); RETURN(); } void OPPROTO op_store_booke_tcr (void) { store_booke_tcr(env, T0); Loading
target-ppc/op_helper.c +16 −32 Original line number Diff line number Diff line Loading @@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void) T0 |= 0x100; } static int tlb_4xx_search (target_ulong virtual) { ppcemb_tlb_t *tlb; target_ulong base, mask; int i, ret; /* Default return value is no match */ ret = -1; for (i = 0; i < 64; i++) { tlb = &env->tlb[i].tlbe; /* Check TLB validity */ if (!(tlb->prot & PAGE_VALID)) continue; /* Check TLB PID vs current PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) continue; /* Check TLB address vs virtual address */ base = tlb->EPN; mask = ~(tlb->size - 1); if ((base & mask) != (virtual & mask)) continue; ret = i; break; } return ret; } void do_4xx_tlbsx (void) { T0 = tlb_4xx_search(T0); T0 = ppcemb_tlb_search(env, T0); } void do_4xx_tlbsx_ (void) { int tmp = xer_ov; T0 = tlb_4xx_search(T0); T0 = ppcemb_tlb_search(env, T0); if (T0 != -1) tmp |= 0x02; env->crf[0] = tmp; Loading Loading @@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void) tlb_flush_page(env, page); } tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); /* We cannot handle TLB size < TARGET_PAGE_SIZE. * If this ever occurs, one should use the ppcemb target instead * of the ppc or ppc64 one */ if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) { cpu_abort(env, "TLB size %u < %u are not supported (%d)\n", tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7)); } tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); if (T1 & 0x40) tlb->prot |= PAGE_VALID; else tlb->prot &= ~PAGE_VALID; if (T1 & 0x20) { /* XXX: TO BE FIXED */ cpu_abort(env, "Little-endian TLB entries are not supported by now\n"); } tlb->PID = env->spr[SPR_40x_PID]; /* PID */ tlb->attr = T1 & 0xFF; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel) { fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX if (loglevel != 0) { fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, (int)T0, tlb->RPN, tlb->EPN, tlb->size, tlb->prot & PAGE_READ ? 'r' : '-', Loading
target-ppc/translate_init.c +13 −3 Original line number Diff line number Diff line Loading @@ -355,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn) RET_STOP(ctx); } static void spr_write_40x_sler (void *opaque, int sprn) { DisasContext *ctx = opaque; gen_op_store_40x_sler(); /* We must stop the translation as we may have changed * some regions endianness */ RET_STOP(ctx); } static void spr_write_booke_tcr (void *opaque, int sprn) { gen_op_store_booke_tcr(); Loading Loading @@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Storage control */ /* XXX : not implemented */ spr_register(env, SPR_405_SLER, "SLER", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_40x_sler, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_405_SU0R, "SU0R", Loading Loading @@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, .msr_mask = 0x00000000000ED630ULL, }, #if defined (TODO) /* PowerPC 405 EZ */ Loading