return ret;
}
-static int pte32_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1,
- int h, int rw, int type)
+static always_inline int pte32_check (mmu_ctx_t *ctx,
+ target_ulong pte0, target_ulong pte1,
+ int h, int rw, int type)
{
return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
}
#if defined(TARGET_PPC64)
-static int pte64_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1,
- int h, int rw, int type)
+static always_inline int pte64_check (mmu_ctx_t *ctx,
+ target_ulong pte0, target_ulong pte1,
+ int h, int rw, int type)
{
return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
}
#endif
-static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, int rw)
+static always_inline int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
{
int store = 0;
}
/* Software driven TLB helpers */
-static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
- int way, int is_code)
+static always_inline int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
+ int way, int is_code)
{
int nr;
return nr;
}
-static void ppc6xx_tlb_invalidate_all (CPUState *env)
+static always_inline void ppc6xx_tlb_invalidate_all (CPUState *env)
{
ppc6xx_tlb_t *tlb;
int nr, max;
#endif
}
-static void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
- int is_code)
+static always_inline void ppc6xx_tlb_invalidate_virt (CPUState *env,
+ target_ulong eaddr,
+ int is_code)
{
__ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
}
env->last_way = way;
}
-static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type)
+static always_inline int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw,
+ int access_type)
{
ppc6xx_tlb_t *tlb;
int nr, best, way;
}
/* Perform BAT hit & translation */
-static int get_bat (CPUState *env, mmu_ctx_t *ctx,
- target_ulong virtual, int rw, int type)
+static always_inline void bat_size_prot (CPUState *env, target_ulong *blp,
+ int *validp, int *protp,
+ target_ulong *BATu, target_ulong *BATl)
+{
+ target_ulong bl;
+ int pp, valid, prot;
+
+ bl = (*BATu & 0x00001FFC) << 15;
+ valid = 0;
+ prot = 0;
+ if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
+ ((msr_pr != 0) && (*BATu & 0x00000001))) {
+ valid = 1;
+ pp = *BATl & 0x00000003;
+ if (pp != 0) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2)
+ prot |= PAGE_WRITE;
+ }
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp,
+ int *validp, int *protp,
+ target_ulong *BATu,
+ target_ulong *BATl)
+{
+ target_ulong bl;
+ int key, pp, valid, prot;
+
+ bl = (*BATl & 0x0000003F) << 17;
+#if defined (DEBUG_BATS)
+ if (loglevel != 0) {
+ fprintf(logfile, "b %02x ==> bl %08x msk %08x\n",
+ *BATl & 0x0000003F, bl, ~bl);
+ }
+#endif
+ prot = 0;
+ valid = (*BATl >> 6) & 1;
+ if (valid) {
+ pp = *BATu & 0x00000003;
+ if (msr_pr == 0)
+ key = (*BATu >> 3) & 1;
+ else
+ key = (*BATu >> 2) & 1;
+ prot = pp_check(key, pp, 0);
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong base, BEPIl, BEPIu, bl;
- int i, pp, pr;
+ int i, valid, prot;
int ret = -1;
#if defined (DEBUG_BATS)
type == ACCESS_CODE ? 'I' : 'D', virtual);
}
#endif
- pr = msr_pr;
switch (type) {
case ACCESS_CODE:
BATlt = env->IBAT[1];
}
#endif
base = virtual & 0xFFFC0000;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
BEPIu = *BATu & 0xF0000000;
BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
+ if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
+ bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ } else {
+ bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ }
#if defined (DEBUG_BATS)
if (loglevel != 0) {
fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
if ((virtual & 0xF0000000) == BEPIu &&
((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
/* BAT matches */
- if (((pr == 0) && (*BATu & 0x00000002)) ||
- ((pr != 0) && (*BATu & 0x00000001))) {
+ if (valid != 0) {
/* Get physical address */
ctx->raddr = (*BATl & 0xF0000000) |
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
(virtual & 0x0001F000);
/* Compute access rights */
- pp = *BATl & 0x00000003;
- ctx->prot = 0;
- if (pp != 0) {
- ctx->prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2)
- ctx->prot |= PAGE_WRITE;
- }
+ ctx->prot = prot;
ret = check_prot(ctx->prot, rw, type);
#if defined (DEBUG_BATS)
if (ret == 0 && loglevel != 0) {
return ret;
}
-static int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type)
+static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type)
{
return _find_pte(ctx, 0, h, rw, type);
}
#if defined(TARGET_PPC64)
-static int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type)
+static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type)
{
return _find_pte(ctx, 1, h, rw, type);
}
}
#if defined(TARGET_PPC64)
-static inline int slb_is_valid (uint64_t slb64)
+static always_inline int slb_is_valid (uint64_t slb64)
{
return slb64 & 0x0000000008000000ULL ? 1 : 0;
}
-static inline void slb_invalidate (uint64_t *slb64)
+static always_inline void slb_invalidate (uint64_t *slb64)
{
*slb64 &= ~0x0000000008000000ULL;
}
-static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
- target_ulong *vsid, target_ulong *page_mask, int *attr)
+static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
+ target_ulong *vsid,
+ target_ulong *page_mask, int *attr)
{
target_phys_addr_t sr_base;
target_ulong mask;
return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask);
}
-static int get_segment (CPUState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type)
+static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
{
target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
}
/* 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,
- uint32_t pid, int ext, int i)
+static always_inline int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
+ target_phys_addr_t *raddrp,
+ target_ulong address,
+ uint32_t pid, int ext, int i)
{
target_ulong mask;
}
/* Helpers specific to PowerPC 40x implementations */
-static void ppc4xx_tlb_invalidate_all (CPUState *env)
+static always_inline void ppc4xx_tlb_invalidate_all (CPUState *env)
{
ppcemb_tlb_t *tlb;
int i;
tlb_flush(env, 1);
}
-static void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
- uint32_t pid)
+static always_inline void ppc4xx_tlb_invalidate_virt (CPUState *env,
+ target_ulong eaddr,
+ uint32_t pid)
{
#if !defined(FLUSH_ALL_TLBS)
ppcemb_tlb_t *tlb;
return ret;
}
-static int check_physical (CPUState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw)
+static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw)
{
int in_plb, ret;
ret = 0;
switch (env->mmu_model) {
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
case POWERPC_MMU_SOFT_4xx:
}
int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
- int rw, int access_type, int check_BATs)
+ int rw, int access_type)
{
int ret;
ret = -1;
switch (env->mmu_model) {
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
- /* Try to find a BAT */
- if (check_BATs)
- ret = get_bat(env, ctx, eaddr, rw, access_type);
- /* No break here */
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
#endif
+ /* Try to find a BAT */
+ if (env->nb_BATs != 0)
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
ret = get_segment(env, ctx, eaddr, rw, access_type);
{
mmu_ctx_t ctx;
- if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
+ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
return -1;
return ctx.raddr & TARGET_PAGE_MASK;
access_type = ACCESS_INT;
// access_type = env->access_type;
}
- ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
+ ret = get_physical_address(env, &ctx, address, rw, access_type);
if (ret == 0) {
ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
env->spr[SPR_40x_ESR] = 0x00000000;
break;
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
#endif
env->spr[SPR_40x_ESR] = 0x00000000;
break;
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
#endif
env->DBAT[1][nr] = value;
}
+void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
+{
+ target_ulong mask;
+ int do_inval;
+
+ dump_store_bat(env, 'I', 0, nr, value);
+ if (env->IBAT[0][nr] != value) {
+ do_inval = 0;
+ mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
+ if (env->IBAT[1][nr] & 0x40) {
+ /* Invalidate BAT only if it is valid */
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+ /* When storing valid upper BAT, mask BEPI and BRPN
+ * and invalidate all TLBs covered by this BAT
+ */
+ env->IBAT[0][nr] = (value & 0x00001FFFUL) |
+ (value & ~0x0001FFFFUL & ~mask);
+ env->DBAT[0][nr] = env->IBAT[0][nr];
+ if (env->IBAT[1][nr] & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+#if defined(FLUSH_ALL_TLBS)
+ if (do_inval)
+ tlb_flush(env, 1);
+#endif
+ }
+}
+
+void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
+{
+ target_ulong mask;
+ int do_inval;
+
+ dump_store_bat(env, 'I', 1, nr, value);
+ if (env->IBAT[1][nr] != value) {
+ do_inval = 0;
+ if (env->IBAT[1][nr] & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+ mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+ if (value & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+ mask = (value << 17) & 0x0FFE0000UL;
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+ env->IBAT[1][nr] = value;
+ env->DBAT[1][nr] = value;
+#if defined(FLUSH_ALL_TLBS)
+ if (do_inval)
+ tlb_flush(env, 1);
+#endif
+ }
+}
+
/*****************************************************************************/
/* TLB management */
void ppc_tlb_invalidate_all (CPUPPCState *env)
cpu_abort(env, "MMU model not implemented\n");
break;
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
#endif /* defined(TARGET_PPC64) */
cpu_abort(env, "MMU model not implemented\n");
break;
case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
/* tlbie invalidate TLBs for all segments */
addr &= ~((target_ulong)-1 << 28);
/* XXX: this case should be optimized,
env->error_code = 0;
}
#else /* defined (CONFIG_USER_ONLY) */
-static void dump_syscall (CPUState *env)
+static always_inline void dump_syscall (CPUState *env)
{
fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX
" r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n",
{
target_ulong msr, new_msr, vector;
int srr0, srr1, asrr0, asrr1;
+#if defined(TARGET_PPC64H)
+ int lpes0, lpes1, lev;
+
+ lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
+ lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
+#endif
if (loglevel & CPU_LOG_INT) {
fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n",
fprintf(logfile, "Ignore floating point exception\n");
}
#endif
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
return;
}
new_msr &= ~((target_ulong)1 << MSR_RI);
new_msr |= (target_ulong)1 << MSR_HV;
#endif
msr |= 0x00100000;
- /* Set FX */
- env->fpscr[7] |= 0x8;
- /* Finally, update FEX */
- if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
- ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
- env->fpscr[7] |= 0x4;
- if (msr_fe0 != msr_fe1) {
- msr |= 0x00010000;
- goto store_current;
- }
+ if (msr_fe0 == msr_fe1)
+ goto store_next;
+ msr |= 0x00010000;
break;
case POWERPC_EXCP_INVAL:
#if defined (DEBUG_EXCEPTIONS)
env->error_code);
break;
}
- goto store_next;
+ goto store_current;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
new_msr &= ~((target_ulong)1 << MSR_RI);
#if defined(TARGET_PPC64H)
/* XXX: To be removed */
if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
env->osi_call) {
- if (env->osi_call(env) != 0)
+ if (env->osi_call(env) != 0) {
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
return;
+ }
}
if (loglevel & CPU_LOG_INT) {
dump_syscall(env);
}
new_msr &= ~((target_ulong)1 << MSR_RI);
#if defined(TARGET_PPC64H)
+ lev = env->error_code;
if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
new_msr |= (target_ulong)1 << MSR_HV;
#endif
#if defined(TARGET_PPC64H)
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
srr0 = SPR_HSRR0;
- srr1 = SPR_HSSR1;
+ srr1 = SPR_HSRR1;
new_msr |= (target_ulong)1 << MSR_HV;
goto store_next;
#endif
#if defined(TARGET_PPC64H)
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
srr0 = SPR_HSRR0;
- srr1 = SPR_HSSR1;
+ srr1 = SPR_HSRR1;
new_msr |= (target_ulong)1 << MSR_HV;
goto store_next;
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
srr0 = SPR_HSRR0;
- srr1 = SPR_HSSR1;
+ srr1 = SPR_HSRR1;
new_msr |= (target_ulong)1 << MSR_HV;
goto store_next;
case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
srr0 = SPR_HSRR0;
- srr1 = SPR_HSSR1;
+ srr1 = SPR_HSRR1;
new_msr |= (target_ulong)1 << MSR_HV;
goto store_next;
case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
srr0 = SPR_HSRR0;
- srr1 = SPR_HSSR1;
+ srr1 = SPR_HSRR1;
new_msr |= (target_ulong)1 << MSR_HV;
goto store_next;
#endif /* defined(TARGET_PPC64H) */
* any special case that could occur. Just store MSR and update hflags
*/
env->msr = new_msr;
+ env->hflags_nmsr = 0x00000000;
hreg_compute_hflags(env);
env->nip = vector;
/* Reset exception state */
void ppc_hw_interrupt (CPUPPCState *env)
{
+#if defined(TARGET_PPC64H)
+ int hdice;
+#endif
+
#if 0
if (loglevel & CPU_LOG_INT) {
fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n",
}
#endif
#if defined(TARGET_PPC64H)
- if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) & hdice != 0) {
+ hdice = env->spr[SPR_LPCR] & 1;
+ if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
/* Hypervisor decrementer exception */
if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
tlb_flush(env, 1);
}
-CPUPPCState *cpu_ppc_init (void)
+CPUPPCState *cpu_ppc_init (const char *cpu_model)
{
CPUPPCState *env;
+ const ppc_def_t *def;
+
+ def = cpu_ppc_find_by_name(cpu_model);
+ if (!def)
+ return NULL;
env = qemu_mallocz(sizeof(CPUPPCState));
if (!env)
return NULL;
cpu_exec_init(env);
-
+ cpu_ppc_register_internal(env, def);
+ cpu_ppc_reset(env);
return env;
}
void cpu_ppc_close (CPUPPCState *env)
{
/* Should also remove all opcode tables... */
- free(env);
+ qemu_free(env);
}