diff options
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu.h | 82 | ||||
-rw-r--r-- | target-ppc/exec.h | 2 | ||||
-rw-r--r-- | target-ppc/helper.c | 418 | ||||
-rw-r--r-- | target-ppc/helper_regs.h | 142 | ||||
-rw-r--r-- | target-ppc/op.c | 41 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 149 | ||||
-rw-r--r-- | target-ppc/op_helper.h | 3 | ||||
-rw-r--r-- | target-ppc/translate.c | 22 |
8 files changed, 398 insertions, 461 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index aeaacb2579..cf4a110ac4 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -368,7 +368,7 @@ union ppc_tlb_t { #define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ #define MSR_FE1 8 /* Floating point exception mode 1 hflags */ #define MSR_AL 7 /* AL bit on POWER */ -#define MSR_EP 3 /* Exception prefix on 601 */ +#define MSR_EP 6 /* Exception prefix on 601 */ #define MSR_IR 5 /* Instruction relocate */ #define MSR_DR 4 /* Data relocate */ #define MSR_PE 3 /* Protection enable on 403 */ @@ -376,41 +376,42 @@ union ppc_tlb_t { #define MSR_PMM 2 /* Performance monitor mark on POWER x */ #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ -#define msr_sf env->msr[MSR_SF] -#define msr_isf env->msr[MSR_ISF] -#define msr_hv env->msr[MSR_HV] -#define msr_cm env->msr[MSR_CM] -#define msr_icm env->msr[MSR_ICM] -#define msr_ucle env->msr[MSR_UCLE] -#define msr_vr env->msr[MSR_VR] -#define msr_spe env->msr[MSR_SPE] -#define msr_ap env->msr[MSR_AP] -#define msr_sa env->msr[MSR_SA] -#define msr_key env->msr[MSR_KEY] -#define msr_pow env->msr[MSR_POW] -#define msr_tgpr env->msr[MSR_TGPR] -#define msr_ce env->msr[MSR_CE] -#define msr_ile env->msr[MSR_ILE] -#define msr_ee env->msr[MSR_EE] -#define msr_pr env->msr[MSR_PR] -#define msr_fp env->msr[MSR_FP] -#define msr_me env->msr[MSR_ME] -#define msr_fe0 env->msr[MSR_FE0] -#define msr_se env->msr[MSR_SE] -#define msr_dwe env->msr[MSR_DWE] -#define msr_uble env->msr[MSR_UBLE] -#define msr_be env->msr[MSR_BE] -#define msr_de env->msr[MSR_DE] -#define msr_fe1 env->msr[MSR_FE1] -#define msr_al env->msr[MSR_AL] -#define msr_ir env->msr[MSR_IR] -#define msr_dr env->msr[MSR_DR] -#define msr_pe env->msr[MSR_PE] -#define msr_ep env->msr[MSR_EP] -#define msr_px env->msr[MSR_PX] -#define msr_pmm env->msr[MSR_PMM] -#define msr_ri env->msr[MSR_RI] -#define msr_le env->msr[MSR_LE] + +#define msr_sf ((env->msr >> MSR_SF) & 1) +#define msr_isf ((env->msr >> MSR_ISF) & 1) +#define msr_hv ((env->msr >> MSR_HV) & 1) +#define msr_cm ((env->msr >> MSR_CM) & 1) +#define msr_icm ((env->msr >> MSR_ICM) & 1) +#define msr_ucle ((env->msr >> MSR_UCLE) & 1) +#define msr_vr ((env->msr >> MSR_VR) & 1) +#define msr_spe ((env->msr >> MSR_SE) & 1) +#define msr_ap ((env->msr >> MSR_AP) & 1) +#define msr_sa ((env->msr >> MSR_SA) & 1) +#define msr_key ((env->msr >> MSR_KEY) & 1) +#define msr_pow ((env->msr >> MSR_POW) & 1) +#define msr_tgpr ((env->msr >> MSR_TGPR) & 1) +#define msr_ce ((env->msr >> MSR_CE) & 1) +#define msr_ile ((env->msr >> MSR_ILE) & 1) +#define msr_ee ((env->msr >> MSR_EE) & 1) +#define msr_pr ((env->msr >> MSR_PR) & 1) +#define msr_fp ((env->msr >> MSR_FP) & 1) +#define msr_me ((env->msr >> MSR_ME) & 1) +#define msr_fe0 ((env->msr >> MSR_FE0) & 1) +#define msr_se ((env->msr >> MSR_SE) & 1) +#define msr_dwe ((env->msr >> MSR_DWE) & 1) +#define msr_uble ((env->msr >> MSR_UBLE) & 1) +#define msr_be ((env->msr >> MSR_BE) & 1) +#define msr_de ((env->msr >> MSR_DE) & 1) +#define msr_fe1 ((env->msr >> MSR_FE1) & 1) +#define msr_al ((env->msr >> MSR_AL) & 1) +#define msr_ep ((env->msr >> MSR_EP) & 1) +#define msr_ir ((env->msr >> MSR_IR) & 1) +#define msr_dr ((env->msr >> MSR_DR) & 1) +#define msr_pe ((env->msr >> MSR_PE) & 1) +#define msr_px ((env->msr >> MSR_PX) & 1) +#define msr_pmm ((env->msr >> MSR_PMM) & 1) +#define msr_ri ((env->msr >> MSR_RI) & 1) +#define msr_le ((env->msr >> MSR_LE) & 1) enum { POWERPC_FLAG_NONE = 0x00000000, @@ -468,7 +469,7 @@ struct CPUPPCState { /* Those ones are used in supervisor mode only */ /* machine state register */ - uint8_t msr[64]; + target_ulong msr; /* temporary general purpose registers */ ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */ @@ -639,13 +640,8 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); -target_ulong do_load_msr (CPUPPCState *env); -int do_store_msr (CPUPPCState *env, target_ulong value); -#if defined(TARGET_PPC64) -int ppc_store_msr_32 (CPUPPCState *env, uint32_t value); -#endif +void ppc_store_msr (CPUPPCState *env, target_ulong value); -void do_compute_hflags (CPUPPCState *env); void cpu_ppc_reset (void *opaque); CPUPPCState *cpu_ppc_init (void); void cpu_ppc_close(CPUPPCState *env); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 5685fd7a4b..5abcee0522 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -118,7 +118,7 @@ static always_inline int cpu_halted (CPUState *env) { if (!env->halted) return 0; - if (env->msr[MSR_EE] && (env->interrupt_request & CPU_INTERRUPT_HARD)) { + if (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD)) { env->halted = 0; return 0; } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 76312476a0..ea672bb4a2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -27,10 +27,12 @@ #include "cpu.h" #include "exec-all.h" +#include "helper_regs.h" //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_SOFTWARE_TLB +//#define DUMP_PAGE_TABLES //#define DEBUG_EXCEPTIONS //#define FLUSH_ALL_TLBS @@ -447,7 +449,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; - int i, pp; + int i, pp, pr; int ret = -1; #if defined (DEBUG_BATS) @@ -456,6 +458,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif + pr = msr_pr; switch (type) { case ACCESS_CODE: BATlt = env->IBAT[1]; @@ -490,8 +493,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, if ((virtual & 0xF0000000) == BEPIu && ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { /* BAT matches */ - if ((msr_pr == 0 && (*BATu & 0x00000002)) || - (msr_pr == 1 && (*BATu & 0x00000001))) { + if (((pr == 0) && (*BATu & 0x00000002)) || + ((pr != 0) && (*BATu & 0x00000001))) { /* Get physical address */ ctx->raddr = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | @@ -851,9 +854,10 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) int attr; #endif - int ds, vsid_sh, sdr_sh; + int ds, vsid_sh, sdr_sh, pr; int ret, ret2; + pr = msr_pr; #if defined(TARGET_PPC64) if (env->mmu_model == POWERPC_MMU_64B) { #if defined (DEBUG_MMU) @@ -864,8 +868,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; - ctx->key = ((attr & 0x40) && msr_pr == 1) || - ((attr & 0x80) && msr_pr == 0) ? 1 : 0; + ctx->key = ((attr & 0x40) && (pr != 0)) || + ((attr & 0x80) && (pr == 0)) ? 1 : 0; ds = 0; ctx->nx = attr & 0x20 ? 1 : 0; vsid_mask = 0x00003FFFFFFFFF80ULL; @@ -877,8 +881,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, { sr = env->sr[eaddr >> 28]; page_mask = 0x0FFFFFFF; - ctx->key = (((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; + ctx->key = (((sr & 0x20000000) && (pr != 0)) || + ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; @@ -892,7 +896,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, " nip=0x" ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, rw, type); + env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0, + rw, type); } #endif } @@ -981,7 +986,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = ret2; } } -#if defined (DEBUG_MMU) +#if defined (DUMP_PAGE_TABLES) if (loglevel != 0) { target_phys_addr_t curaddr; uint32_t a0, a1, a2, a3; @@ -1157,10 +1162,11 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; - int i, ret, zsel, zpr; + int i, ret, zsel, zpr, pr; ret = -1; raddr = -1; + pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, @@ -1177,7 +1183,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, /* Check execute enable bit */ switch (zpr) { case 0x2: - if (msr_pr) + if (pr != 0) goto check_perms; /* No break here */ case 0x3: @@ -1186,7 +1192,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ret = 0; break; case 0x0: - if (msr_pr) { + if (pr != 0) { ctx->prot = 0; ret = -2; break; @@ -1248,7 +1254,7 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (ppcemb_tlb_check(env, tlb, &raddr, address, env->spr[SPR_BOOKE_PID], 1, i) < 0) continue; - if (msr_pr) + if (msr_pr != 0) prot = tlb->prot & 0xF; else prot = (tlb->prot >> 4) & 0xF; @@ -1343,6 +1349,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int access_type, int check_BATs) { int ret; + #if 0 if (loglevel != 0) { fprintf(logfile, "%s\n", __func__); @@ -1949,180 +1956,18 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) target_ulong ppc_load_xer (CPUPPCState *env) { - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); + return hreg_load_xer(env); } void ppc_store_xer (CPUPPCState *env, target_ulong value) { - xer_so = (value >> XER_SO) & 0x01; - xer_ov = (value >> XER_OV) & 0x01; - xer_ca = (value >> XER_CA) & 0x01; - xer_cmp = (value >> XER_CMP) & 0xFF; - xer_bc = (value >> XER_BC) & 0x7F; -} - -/* Swap temporary saved registers with GPRs */ -static always_inline void swap_gpr_tgpr (CPUPPCState *env) -{ - ppc_gpr_t tmp; - - tmp = env->gpr[0]; - env->gpr[0] = env->tgpr[0]; - env->tgpr[0] = tmp; - tmp = env->gpr[1]; - env->gpr[1] = env->tgpr[1]; - env->tgpr[1] = tmp; - tmp = env->gpr[2]; - env->gpr[2] = env->tgpr[2]; - env->tgpr[2] = tmp; - tmp = env->gpr[3]; - env->gpr[3] = env->tgpr[3]; - env->tgpr[3] = tmp; + hreg_store_xer(env, value); } /* GDBstub can read and write MSR... */ -target_ulong do_load_msr (CPUPPCState *env) -{ - return -#if defined (TARGET_PPC64) - ((target_ulong)msr_sf << MSR_SF) | - ((target_ulong)msr_isf << MSR_ISF) | - ((target_ulong)msr_hv << MSR_HV) | -#endif - ((target_ulong)msr_ucle << MSR_UCLE) | - ((target_ulong)msr_vr << MSR_VR) | /* VR / SPE */ - ((target_ulong)msr_ap << MSR_AP) | - ((target_ulong)msr_sa << MSR_SA) | - ((target_ulong)msr_key << MSR_KEY) | - ((target_ulong)msr_pow << MSR_POW) | - ((target_ulong)msr_tgpr << MSR_TGPR) | /* TGPR / CE */ - ((target_ulong)msr_ile << MSR_ILE) | - ((target_ulong)msr_ee << MSR_EE) | - ((target_ulong)msr_pr << MSR_PR) | - ((target_ulong)msr_fp << MSR_FP) | - ((target_ulong)msr_me << MSR_ME) | - ((target_ulong)msr_fe0 << MSR_FE0) | - ((target_ulong)msr_se << MSR_SE) | /* SE / DWE / UBLE */ - ((target_ulong)msr_be << MSR_BE) | /* BE / DE */ - ((target_ulong)msr_fe1 << MSR_FE1) | - ((target_ulong)msr_al << MSR_AL) | - ((target_ulong)msr_ep << MSR_EP) | - ((target_ulong)msr_ir << MSR_IR) | - ((target_ulong)msr_dr << MSR_DR) | - ((target_ulong)msr_pe << MSR_PE) | - ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */ - ((target_ulong)msr_ri << MSR_RI) | - ((target_ulong)msr_le << MSR_LE); -} - -int do_store_msr (CPUPPCState *env, target_ulong value) -{ - int enter_pm; - - value &= env->msr_mask; - if (((value >> MSR_IR) & 1) != msr_ir || - ((value >> MSR_DR) & 1) != msr_dr) { - /* Flush all tlb when changing translation mode */ - tlb_flush(env, 1); - env->interrupt_request |= CPU_INTERRUPT_EXITTB; - } -#if !defined (CONFIG_USER_ONLY) - if (unlikely((env->flags & POWERPC_FLAG_TGPR) && - ((value >> MSR_TGPR) & 1) != msr_tgpr)) { - /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - } - if (unlikely((value >> MSR_EP) & 1) != msr_ep) { - /* Change the exception prefix on PowerPC 601 */ - env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; - } -#endif -#if defined (TARGET_PPC64) - msr_sf = (value >> MSR_SF) & 1; - msr_isf = (value >> MSR_ISF) & 1; - msr_hv = (value >> MSR_HV) & 1; -#endif - msr_ucle = (value >> MSR_UCLE) & 1; - msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */ - msr_ap = (value >> MSR_AP) & 1; - msr_sa = (value >> MSR_SA) & 1; - msr_key = (value >> MSR_KEY) & 1; - msr_pow = (value >> MSR_POW) & 1; - msr_tgpr = (value >> MSR_TGPR) & 1; /* TGPR / CE */ - msr_ile = (value >> MSR_ILE) & 1; - msr_ee = (value >> MSR_EE) & 1; - msr_pr = (value >> MSR_PR) & 1; - msr_fp = (value >> MSR_FP) & 1; - msr_me = (value >> MSR_ME) & 1; - msr_fe0 = (value >> MSR_FE0) & 1; - msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */ - msr_be = (value >> MSR_BE) & 1; /* BE / DE */ - msr_fe1 = (value >> MSR_FE1) & 1; - msr_al = (value >> MSR_AL) & 1; - msr_ep = (value >> MSR_EP) & 1; - msr_ir = (value >> MSR_IR) & 1; - msr_dr = (value >> MSR_DR) & 1; - msr_pe = (value >> MSR_PE) & 1; - msr_px = (value >> MSR_PX) & 1; /* PX / PMM */ - msr_ri = (value >> MSR_RI) & 1; - msr_le = (value >> MSR_LE) & 1; - do_compute_hflags(env); - - enter_pm = 0; - switch (env->excp_model) { - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - /* Don't handle SLEEP mode: we should disable all clocks... - * No dynamic power-management. - */ - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0) - enter_pm = 1; - break; - case POWERPC_EXCP_604: - if (msr_pow == 1) - enter_pm = 1; - break; - case POWERPC_EXCP_7x0: - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) - enter_pm = 1; - break; - default: - break; - } - - return enter_pm; -} - -#if defined(TARGET_PPC64) -int ppc_store_msr_32 (CPUPPCState *env, uint32_t value) -{ - return do_store_msr(env, (do_load_msr(env) & ~0xFFFFFFFFULL) | - (value & 0xFFFFFFFF)); -} -#endif - -void do_compute_hflags (CPUPPCState *env) +void ppc_store_msr (CPUPPCState *env, target_ulong value) { - /* Compute current hflags */ - env->hflags = (msr_vr << MSR_VR) | - (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | - (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); -#if defined (TARGET_PPC64) - env->hflags |= msr_cm << MSR_CM; - env->hflags |= (uint64_t)msr_sf << MSR_SF; - env->hflags |= (uint64_t)msr_hv << MSR_HV; - /* Precompute MMU index */ - if (msr_pr == 0 && msr_hv == 1) - env->mmu_idx = 2; - else -#endif - env->mmu_idx = 1 - msr_pr; + hreg_store_msr(env, value); } /*****************************************************************************/ @@ -2154,14 +1999,15 @@ static void dump_syscall (CPUState *env) static always_inline void powerpc_excp (CPUState *env, int excp_model, int excp) { - target_ulong msr, vector; + target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; if (loglevel & CPU_LOG_INT) { fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", env->nip, excp, env->error_code); } - msr = do_load_msr(env); + msr = env->msr; + new_msr = msr; srr0 = SPR_SRR0; srr1 = SPR_SRR1; asrr0 = -1; @@ -2172,7 +2018,7 @@ static always_inline void powerpc_excp (CPUState *env, /* Should never happen */ return; case POWERPC_EXCP_CRITICAL: /* Critical input */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ switch (excp_model) { case POWERPC_EXCP_40x: srr0 = SPR_40x_SRR2; @@ -2203,10 +2049,10 @@ static always_inline void powerpc_excp (CPUState *env, env->halted = 1; env->interrupt_request |= CPU_INTERRUPT_EXITTB; } - msr_ri = 0; - msr_me = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); + new_msr &= ~((target_ulong)1 << MSR_ME); #if defined(TARGET_PPC64H) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: should also have something loaded in DAR / DSISR */ switch (excp_model) { @@ -2231,10 +2077,10 @@ static always_inline void powerpc_excp (CPUState *env, "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISI: /* Instruction storage exception */ @@ -2244,25 +2090,25 @@ static always_inline void powerpc_excp (CPUState *env, "\n", msr, env->nip); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= env->error_code; goto store_next; case POWERPC_EXCP_EXTERNAL: /* External input */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes0 == 1) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ @@ -2279,10 +2125,10 @@ static always_inline void powerpc_excp (CPUState *env, #endif return; } - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00100000; /* Set FX */ @@ -2303,26 +2149,26 @@ static always_inline void powerpc_excp (CPUState *env, env->nip); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00080000; break; case POWERPC_EXCP_PRIV: - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00040000; break; case POWERPC_EXCP_TRAP: - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00020000; break; @@ -2334,10 +2180,10 @@ static always_inline void powerpc_excp (CPUState *env, } goto store_next; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_current; case POWERPC_EXCP_SYSCALL: /* System call exception */ @@ -2352,20 +2198,20 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel & CPU_LOG_INT) { dump_syscall(env); } - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ @@ -2374,7 +2220,7 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel != 0) fprintf(logfile, "FIT exception\n"); #endif - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ #if defined (DEBUG_EXCEPTIONS) @@ -2389,13 +2235,13 @@ static always_inline void powerpc_excp (CPUState *env, default: break; } - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_DTLB: /* Data TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { @@ -2413,7 +2259,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; #if defined(TARGET_PPCEMB) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_current; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ /* XXX: TODO */ @@ -2426,7 +2272,7 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: TODO */ cpu_abort(env, "Performance counter exception is not implemented yet !\n"); @@ -2451,24 +2297,24 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; #endif /* defined(TARGET_PPCEMB) */ case POWERPC_EXCP_RESET: /* System reset exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #if defined(TARGET_PPC64) case POWERPC_EXCP_DSEG: /* Data segment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #endif /* defined(TARGET_PPC64) */ @@ -2476,46 +2322,43 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif case POWERPC_EXCP_TRACE: /* Trace exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #if defined(TARGET_PPC64H) case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; - /* XXX: TODO */ - cpu_abort(env, "Hypervisor instruction storage exception " - "is not implemented yet !\n"); + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif /* defined(TARGET_PPC64H) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ @@ -2523,7 +2366,7 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel != 0) fprintf(logfile, "PIT exception\n"); #endif - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_IO: /* IO error exception */ /* XXX: TODO */ @@ -2539,10 +2382,10 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2560,10 +2403,10 @@ static always_inline void powerpc_excp (CPUState *env, } break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2581,10 +2424,10 @@ static always_inline void powerpc_excp (CPUState *env, } break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2593,8 +2436,10 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_G2: tlb_miss_tgpr: /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - msr_tgpr = 1; + if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { + new_msr |= (target_ulong)1 << MSR_TGPR; + hreg_swap_gpr_tgpr(env); + } goto tlb_miss; case POWERPC_EXCP_7x5: tlb_miss: @@ -2639,8 +2484,8 @@ static always_inline void powerpc_excp (CPUState *env, if (excp == POWERPC_EXCP_IFTLB) { es = "I"; en = 'I'; - miss = &env->spr[SPR_IMISS]; - cmp = &env->spr[SPR_ICMP]; + miss = &env->spr[SPR_TLBMISS]; + cmp = &env->spr[SPR_PTEHI]; } else { if (excp == POWERPC_EXCP_DLTLB) es = "DL"; @@ -2681,10 +2526,10 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: TODO */ cpu_abort(env, @@ -2725,23 +2570,26 @@ static always_inline void powerpc_excp (CPUState *env, if (asrr1 != -1) env->spr[asrr1] = env->spr[srr1]; /* If we disactivated any translation, flush TLBs */ - if (msr_ir || msr_dr) + if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR))) tlb_flush(env, 1); /* reload MSR with correct bits */ - msr_ee = 0; - msr_pr = 0; - msr_fp = 0; - msr_fe0 = 0; - msr_se = 0; - msr_be = 0; - msr_fe1 = 0; - msr_ir = 0; - msr_dr = 0; + new_msr &= ~((target_ulong)1 << MSR_EE); + new_msr &= ~((target_ulong)1 << MSR_PR); + new_msr &= ~((target_ulong)1 << MSR_FP); + new_msr &= ~((target_ulong)1 << MSR_FE0); + new_msr &= ~((target_ulong)1 << MSR_SE); + new_msr &= ~((target_ulong)1 << MSR_BE); + new_msr &= ~((target_ulong)1 << MSR_FE1); + new_msr &= ~((target_ulong)1 << MSR_IR); + new_msr &= ~((target_ulong)1 << MSR_DR); #if 0 /* Fix this: not on all targets */ - msr_pmm = 0; + new_msr &= ~((target_ulong)1 << MSR_PMM); #endif - msr_le = msr_ile; - do_compute_hflags(env); + new_msr &= ~((target_ulong)1 << MSR_LE); + if (msr_ile) + new_msr |= (target_ulong)1 << MSR_LE; + else + new_msr &= ~((target_ulong)1 << MSR_LE); /* Jump to handler */ vector = env->excp_vectors[excp]; if (vector == (target_ulong)-1) { @@ -2751,15 +2599,26 @@ static always_inline void powerpc_excp (CPUState *env, vector |= env->excp_prefix; #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_BOOKE) { - msr_cm = msr_icm; - if (!msr_cm) + if (!msr_icm) { + new_msr &= ~((target_ulong)1 << MSR_CM); vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_CM; + } } else { - msr_sf = msr_isf; - if (!msr_sf) + if (!msr_isf) { + new_msr &= ~((target_ulong)1 << MSR_SF); vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_SF; + } } #endif + /* XXX: we don't use hreg_store_msr here as already have treated + * any special case that could occur. Just store MSR and update hflags + */ + env->msr = new_msr; + hreg_compute_hflags(env); env->nip = vector; /* Reset exception state */ env->exception_index = POWERPC_EXCP_NONE; @@ -2773,11 +2632,11 @@ void do_interrupt (CPUState *env) void ppc_hw_interrupt (CPUPPCState *env) { -#if 1 +#if 0 if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", __func__, env, env->pending_interrupts, - env->interrupt_request, msr_me, msr_ee); + env->interrupt_request, (int)msr_me, (int)msr_ee); } #endif /* External reset */ @@ -2801,7 +2660,7 @@ void ppc_hw_interrupt (CPUPPCState *env) } #endif #if defined(TARGET_PPC64H) - if ((msr_ee != 0 || msr_hv == 0 || msr_pr == 1) & hdice != 0) { + 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); @@ -2933,34 +2792,31 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) void cpu_ppc_reset (void *opaque) { CPUPPCState *env; - int i; + target_ulong msr; env = opaque; - /* XXX: some of those flags initialisation values could depend - * on the actual PowerPC implementation - */ - for (i = 0; i < 63; i++) - env->msr[i] = 0; + msr = (target_ulong)0; #if defined(TARGET_PPC64) - msr_hv = 0; /* Should be 1... */ + msr |= (target_ulong)0 << MSR_HV; /* Should be 1... */ #endif - msr_ap = 0; /* TO BE CHECKED */ - msr_sa = 0; /* TO BE CHECKED */ - msr_ep = 1; + msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ + msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ + msr |= (target_ulong)1 << MSR_EP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ - msr_se = 1; - msr_be = 1; + msr |= (target_ulong)1 << MSR_SE; + msr |= (target_ulong)1 << MSR_BE; #endif #if defined(CONFIG_USER_ONLY) - msr_fp = 1; /* Allow floating point exceptions */ - msr_pr = 1; + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_PR; #else env->nip = env->hreset_vector | env->excp_prefix; if (env->mmu_model != POWERPC_MMU_REAL_4xx) ppc_tlb_invalidate_all(env); #endif - do_compute_hflags(env); + env->msr = msr; + hreg_compute_hflags(env); env->reserve = -1; /* Be sure no exception or interrupt is pending */ env->pending_interrupts = 0; diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h new file mode 100644 index 0000000000..75a3dddd52 --- /dev/null +++ b/target-ppc/helper_regs.h @@ -0,0 +1,142 @@ +/* + * PowerPC emulation special registers manipulation helpers for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(__HELPER_REGS_H__) +#define __HELPER_REGS_H__ + +static always_inline target_ulong hreg_load_xer (CPUPPCState *env) +{ + return (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); +} + +static always_inline void hreg_store_xer (CPUPPCState *env, target_ulong value) +{ + xer_so = (value >> XER_SO) & 0x01; + xer_ov = (value >> XER_OV) & 0x01; + xer_ca = (value >> XER_CA) & 0x01; + xer_cmp = (value >> XER_CMP) & 0xFF; + xer_bc = (value >> XER_BC) & 0x7F; +} + +/* Swap temporary saved registers with GPRs */ +static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) +{ + ppc_gpr_t tmp; + + tmp = env->gpr[0]; + env->gpr[0] = env->tgpr[0]; + env->tgpr[0] = tmp; + tmp = env->gpr[1]; + env->gpr[1] = env->tgpr[1]; + env->tgpr[1] = tmp; + tmp = env->gpr[2]; + env->gpr[2] = env->tgpr[2]; + env->tgpr[2] = tmp; + tmp = env->gpr[3]; + env->gpr[3] = env->tgpr[3]; + env->tgpr[3] = tmp; +} + +static always_inline void hreg_compute_hflags (CPUPPCState *env) +{ + target_ulong hflags_mask; + + /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ + hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | + (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | + (1 << MSR_LE); +#if defined (TARGET_PPC64) + hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); +#if defined (TARGET_PPC64H) + hflags_mask |= 1ULL << MSR_HV; + /* Precompute MMU index */ + if (msr_pr == 0 && msr_hv != 0) + env->mmu_idx = 2; + else +#endif +#endif + env->mmu_idx = 1 - msr_pr; + env->hflags = env->msr & hflags_mask; +} + +static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) +{ + int enter_pm, excp; + + excp = 0; + value &= env->msr_mask; +#if !defined (CONFIG_USER_ONLY) + if (((value >> MSR_IR) & 1) != msr_ir || + ((value >> MSR_DR) & 1) != msr_dr) { + /* Flush all tlb when changing translation mode */ + tlb_flush(env, 1); + excp = POWERPC_EXCP_NONE; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + } + if (unlikely((env->flags & POWERPC_FLAG_TGPR) && + ((value ^ env->msr) & (1 << MSR_TGPR)))) { + /* Swap temporary saved registers with GPRs */ + hreg_swap_gpr_tgpr(env); + } + if (unlikely((value >> MSR_EP) & 1) != msr_ep) { + /* Change the exception prefix on PowerPC 601 */ + env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + } +#endif + env->msr = value; + hreg_compute_hflags(env); + enter_pm = 0; +#if !defined (CONFIG_USER_ONLY) + if (unlikely(msr_pow == 1)) { + switch (env->excp_model) { + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + /* Don't handle SLEEP mode: we should disable all clocks... + * No dynamic power-management. + */ + if ((env->spr[SPR_HID0] & 0x00C00000) != 0) + enter_pm = 1; + break; + case POWERPC_EXCP_604: + enter_pm = 1; + break; + case POWERPC_EXCP_7x0: + if ((env->spr[SPR_HID0] & 0x00E00000) != 0) + enter_pm = 1; + break; + default: + break; + } + if (enter_pm) { + env->halted = 1; + excp = EXCP_HALTED; + } + } +#endif + + return excp; +} + +#endif /* !defined(__HELPER_REGS_H__) */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 4889ad476f..0030c14661 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -22,6 +22,7 @@ #include "config.h" #include "exec.h" +#include "helper_regs.h" #include "op_helper.h" #define REG 0 @@ -284,13 +285,13 @@ void OPPROTO op_store_xer_bc (void) void OPPROTO op_load_xer (void) { - do_load_xer(); + T0 = hreg_load_xer(env); RETURN(); } void OPPROTO op_store_xer (void) { - do_store_xer(); + hreg_store_xer(env, T0); RETURN(); } @@ -358,37 +359,36 @@ void OPPROTO op_store_asr (void) void OPPROTO op_load_msr (void) { - T0 = do_load_msr(env); + T0 = env->msr; RETURN(); } void OPPROTO op_store_msr (void) { - if (do_store_msr(env, T0)) { - env->halted = 1; - do_raise_exception(EXCP_HLT); - } + do_store_msr(); RETURN(); } -void OPPROTO op_update_riee (void) +#if defined (TARGET_PPC64) +void OPPROTO op_store_msr_32 (void) { - msr_ri = (T0 >> MSR_RI) & 1; - msr_ee = (T0 >> MSR_EE) & 1; + T0 = (env->msr & ~0xFFFFFFFFULL) | (T0 & 0xFFFFFFFF); + do_store_msr(); RETURN(); } +#endif -#if defined (TARGET_PPC64) -void OPPROTO op_store_msr_32 (void) +void OPPROTO op_update_riee (void) { - if (ppc_store_msr_32(env, T0)) { - env->halted = 1; - do_raise_exception(EXCP_HLT); - } + /* We don't call do_store_msr here as we won't trigger + * any special case nor change hflags + */ + T0 &= (1 << MSR_RI) | (1 << MSR_EE); + env->msr &= ~(1 << MSR_RI) | (1 << MSR_EE); + env->msr |= T0; RETURN(); } #endif -#endif /* SPR */ void OPPROTO op_load_spr (void) @@ -2517,7 +2517,12 @@ void OPPROTO op_rfmci (void) void OPPROTO op_wrte (void) { - msr_ee = T0 >> 16; + /* We don't call do_store_msr here as we won't trigger + * any special case nor change hflags + */ + T0 &= 1 << MSR_EE; + env->msr &= ~(1 << MSR_EE); + env->msr |= T0; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index f5331bace4..c654b139cc 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -19,6 +19,7 @@ */ #include "exec.h" +#include "helper_regs.h" #include "op_helper.h" #define MEMSUFFIX _raw @@ -98,24 +99,6 @@ void do_store_cr (uint32_t mask) } } -void do_load_xer (void) -{ - T0 = (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - -void do_store_xer (void) -{ - xer_so = (T0 >> XER_SO) & 0x01; - xer_ov = (T0 >> XER_OV) & 0x01; - xer_ca = (T0 >> XER_CA) & 0x01; - xer_cmp = (T0 >> XER_CMP) & 0xFF; - xer_bc = (T0 >> XER_BC) & 0x7F; -} - #if defined(TARGET_PPC64) void do_store_pri (int prio) { @@ -970,56 +953,63 @@ void do_fcmpo (void) #if !defined (CONFIG_USER_ONLY) void cpu_dump_rfi (target_ulong RA, target_ulong msr); -void do_rfi (void) + +void do_store_msr (void) +{ + T0 = hreg_store_msr(env, T0); + if (T0 != 0) { + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + do_raise_exception(T0); + } +} + +static always_inline void __do_rfi (target_ulong nip, target_ulong msr, + target_ulong msrm, int keep_msrh) { #if defined(TARGET_PPC64) - if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + if (msr & (1ULL << MSR_SF)) { + nip = (uint64_t)nip; + msr &= (uint64_t)msrm; } else { - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + nip = (uint32_t)nip; + msr = (uint32_t)(msr & msrm); + if (keep_msrh) + msr |= env->msr & ~((uint64_t)0xFFFFFFFF); } #else - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + nip = (uint32_t)nip; + msr &= (uint32_t)msrm; #endif + /* XXX: beware: this is false if VLE is supported */ + env->nip = nip & ~((target_ulong)0x00000003); + hreg_store_msr(env, msr); #if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); + cpu_dump_rfi(env->nip, env->msr); #endif + /* No need to raise an exception here, + * as rfi is always the last insn of a TB + */ env->interrupt_request |= CPU_INTERRUPT_EXITTB; } +void do_rfi (void) +{ + __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0xFFFF0000), 1); +} + #if defined(TARGET_PPC64) void do_rfid (void) { - if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); - } else { - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); - } -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0xFFFF0000), 0); } #endif #if defined(TARGET_PPC64H) void do_hrfid (void) { - if (env->spr[SPR_HSRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_HSRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL)); - } else { - env->nip = (uint32_t)(env->spr[SPR_HSRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL)); - } -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], + ~((target_ulong)0xFFFF0000), 0); } #endif #endif @@ -1214,13 +1204,7 @@ void do_POWER_rac (void) void do_POWER_rfsvc (void) { - env->nip = env->lr & ~0x00000003UL; - T0 = env->ctr & 0x0000FFFFUL; - do_store_msr(env, T0); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); } /* PowerPC 601 BAT management helper */ @@ -1332,63 +1316,26 @@ void do_store_dcr (void) #if !defined(CONFIG_USER_ONLY) void do_40x_rfci (void) { - env->nip = env->spr[SPR_40x_SRR2]; - do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], + ~((target_ulong)0xFFFF0000), 0); } void do_rfci (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_rfdi (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_rfmci (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_load_403_pb (int num) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 4688bc2fa4..e260b4ff97 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -57,8 +57,6 @@ void do_print_mem_EA (target_ulong EA); /* Registers load and stores */ void do_load_cr (void); void do_store_cr (uint32_t mask); -void do_load_xer (void); -void do_store_xer (void); #if defined(TARGET_PPC64) void do_store_pri (int prio); #endif @@ -129,6 +127,7 @@ void do_tw (int flags); void do_td (int flags); #endif #if !defined(CONFIG_USER_ONLY) +void do_store_msr (void); void do_rfi (void); #if defined(TARGET_PPC64) void do_rfid (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6f2a9721f2..817045de8c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6538,18 +6538,10 @@ GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); // GEN_OPCODE_MARK(end); #include "translate_init.c" +#include "helper_regs.h" /*****************************************************************************/ /* Misc PowerPC helpers */ -static always_inline uint32_t load_xer (CPUState *env) -{ - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -6566,8 +6558,8 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; - cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n", - env->nip, env->lr, env->ctr); + cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " idx %d\n", + env->nip, env->lr, env->ctr, env->mmu_idx); cpu_fprintf(f, "MSR " REGX FILL " XER %08x " #if !defined(NO_TIMER_DUMP) "TB %08x %08x " @@ -6576,7 +6568,7 @@ void cpu_dump_state (CPUState *env, FILE *f, #endif #endif "\n", - do_load_msr(env), load_xer(env) + env->msr, hreg_load_xer(env) #if !defined(NO_TIMER_DUMP) , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) #if !defined(CONFIG_USER_ONLY) @@ -6753,7 +6745,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n", - ctx.nip, 1 - msr_pr, msr_ir); + ctx.nip, supervisor, (int)msr_ir); } #endif ctx.opcode = ldl_code(ctx.nip); @@ -6787,12 +6779,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, fprintf(logfile, "invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } else { printf("invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { if (unlikely((ctx.opcode & handler->inval) != 0)) { |