added cpu_model parameter to cpu_init()
[qemu] / target-ppc / helper.c
index 0ffa28e..f7df19e 100644 (file)
@@ -232,22 +232,24 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
     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;
 
@@ -272,8 +274,8 @@ static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
 }
 
 /* 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;
 
@@ -288,7 +290,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
     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;
@@ -339,8 +341,9 @@ static always_inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
 #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);
 }
@@ -368,8 +371,9 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
     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;
@@ -444,12 +448,67 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
 }
 
 /* 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)
@@ -458,7 +517,6 @@ 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];
@@ -476,12 +534,16 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
     }
 #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
@@ -493,20 +555,13 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
         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) {
@@ -635,13 +690,13 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h,
     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);
 }
@@ -659,18 +714,19 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
 }
 
 #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;
@@ -847,8 +903,8 @@ static always_inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
     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;
@@ -1063,10 +1119,10 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
 }
 
 /* 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;
 
@@ -1122,7 +1178,7 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
 }
 
 /* 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;
@@ -1134,8 +1190,9 @@ static void ppc4xx_tlb_invalidate_all (CPUState *env)
     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;
@@ -1286,8 +1343,8 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
     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;
 
@@ -1296,6 +1353,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
     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:
@@ -1347,7 +1405,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
 }
 
 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;
 
@@ -1364,15 +1422,15 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
         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);
@@ -1413,7 +1471,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 {
     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;
@@ -1438,7 +1496,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         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,
@@ -1470,6 +1528,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     env->spr[SPR_40x_ESR] = 0x00000000;
                     break;
                 case POWERPC_MMU_32B:
+                case POWERPC_MMU_601:
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_64B:
 #endif
@@ -1561,6 +1620,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                         env->spr[SPR_40x_ESR] = 0x00000000;
                     break;
                 case POWERPC_MMU_32B:
+                case POWERPC_MMU_601:
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_64B:
 #endif
@@ -1778,6 +1838,76 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
     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)
@@ -1803,6 +1933,7 @@ 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) */
@@ -1842,6 +1973,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
         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,
@@ -1986,7 +2118,7 @@ void ppc_hw_interrupt (CPUState *env)
     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",
@@ -2002,6 +2134,12 @@ static always_inline void powerpc_excp (CPUState *env,
 {
     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",
@@ -2124,6 +2262,8 @@ static always_inline void powerpc_excp (CPUState *env,
                     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);
@@ -2132,16 +2272,9 @@ static always_inline void powerpc_excp (CPUState *env,
                 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)
@@ -2179,7 +2312,7 @@ static always_inline void powerpc_excp (CPUState *env,
                       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)
@@ -2193,14 +2326,18 @@ static always_inline void powerpc_excp (CPUState *env,
         /* 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
@@ -2322,7 +2459,7 @@ static always_inline void powerpc_excp (CPUState *env,
 #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
@@ -2336,22 +2473,22 @@ static always_inline void powerpc_excp (CPUState *env,
 #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) */
@@ -2619,6 +2756,7 @@ static always_inline void powerpc_excp (CPUState *env,
      *      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 */
@@ -2633,6 +2771,10 @@ void do_interrupt (CPUState *env)
 
 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",
@@ -2661,7 +2803,8 @@ void ppc_hw_interrupt (CPUPPCState *env)
     }
 #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);
@@ -2827,20 +2970,26 @@ void cpu_ppc_reset (void *opaque)
     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);
 }