]> git.proxmox.com Git - mirror_qemu.git/blobdiff - target-ppc/helper.c
find -type f | xargs sed -i 's/[\t ]$//g' # on most files
[mirror_qemu.git] / target-ppc / helper.c
index 4356edc36ce036dc594bc3e0d3307d0c0402143a..05a7368add29ba45a924be5d38fa4b285277109f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  PowerPC emulation helpers for qemu.
- * 
+ *
  *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -38,7 +38,7 @@
 /* PowerPC MMU emulation */
 
 #if defined(CONFIG_USER_ONLY)
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu)
 {
     int exception, error_code;
@@ -60,7 +60,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
     return 1;
 }
 
-target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 {
     return addr;
 }
@@ -124,14 +124,14 @@ static int pte_check (mmu_ctx_t *ctx,
                 (rw == 1 && (access & PAGE_WRITE))) {
                 /* Access granted */
 #if defined (DEBUG_MMU)
-                if (loglevel > 0)
+                if (loglevel != 0)
                     fprintf(logfile, "PTE access granted !\n");
 #endif
                 ret = 0;
             } else {
                 /* Access right violation */
 #if defined (DEBUG_MMU)
-                if (loglevel > 0)
+                if (loglevel != 0)
                     fprintf(logfile, "PTE access rejected\n");
 #endif
                 ret = -2;
@@ -186,7 +186,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
 
 void ppc6xx_tlb_invalidate_all (CPUState *env)
 {
-    ppc_tlb_t *tlb;
+    ppc6xx_tlb_t *tlb;
     int nr, max;
 
 #if defined (DEBUG_SOFTWARE_TLB) && 0
@@ -199,7 +199,7 @@ void ppc6xx_tlb_invalidate_all (CPUState *env)
     if (env->id_tlbs == 1)
         max *= 2;
     for (nr = 0; nr < max; nr++) {
-        tlb = &env->tlb[nr];
+        tlb = &env->tlb[nr].tlb6;
 #if !defined(FLUSH_ALL_TLBS)
         tlb_flush_page(env, tlb->EPN);
 #endif
@@ -214,14 +214,14 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
                                                  target_ulong eaddr,
                                                  int is_code, int match_epn)
 {
-    ppc_tlb_t *tlb;
+#if !defined(FLUSH_ALL_TLBS)
+    ppc6xx_tlb_t *tlb;
     int way, nr;
 
-#if !defined(FLUSH_ALL_TLBS)
     /* Invalidate ITLB + DTLB, all ways */
     for (way = 0; way < env->nb_ways; way++) {
         nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
-        tlb = &env->tlb[nr];
+        tlb = &env->tlb[nr].tlb6;
         if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
 #if defined (DEBUG_SOFTWARE_TLB)
             if (loglevel != 0) {
@@ -248,14 +248,14 @@ void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
 void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
                        target_ulong pte0, target_ulong pte1)
 {
-    ppc_tlb_t *tlb;
+    ppc6xx_tlb_t *tlb;
     int nr;
 
     nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
-    tlb = &env->tlb[nr];
+    tlb = &env->tlb[nr].tlb6;
 #if defined (DEBUG_SOFTWARE_TLB)
     if (loglevel != 0) {
-        fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX 
+        fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX
                 " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1);
     }
 #endif
@@ -264,8 +264,6 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
     tlb->pte0 = pte0;
     tlb->pte1 = pte1;
     tlb->EPN = EPN;
-    tlb->PID = 0;
-    tlb->size = 1;
     /* Store last way for LRU mechanism */
     env->last_way = way;
 }
@@ -273,7 +271,7 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
 static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
                              target_ulong eaddr, int rw, int access_type)
 {
-    ppc_tlb_t *tlb;
+    ppc6xx_tlb_t *tlb;
     int nr, best, way;
     int ret;
 
@@ -282,7 +280,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
     for (way = 0; way < env->nb_ways; way++) {
         nr = ppc6xx_tlb_getnum(env, eaddr, way,
                                access_type == ACCESS_CODE ? 1 : 0);
-        tlb = &env->tlb[nr];
+        tlb = &env->tlb[nr].tlb6;
         /* This test "emulates" the PTE index match for hardware TLBs */
         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
 #if defined (DEBUG_SOFTWARE_TLB)
@@ -333,13 +331,13 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
     if (best != -1) {
     done:
 #if defined (DEBUG_SOFTWARE_TLB)
-        if (loglevel > 0) {
+        if (loglevel != 0) {
             fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n",
                     ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
         }
 #endif
         /* Update page flags */
-        pte_update_flags(ctx, &env->tlb[best].pte1, ret, rw);
+        pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
     }
 
     return ret;
@@ -355,7 +353,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
     int ret = -1;
 
 #if defined (DEBUG_BATS)
-    if (loglevel > 0) {
+    if (loglevel != 0) {
         fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__,
                 type == ACCESS_CODE ? 'I' : 'D', virtual);
     }
@@ -371,7 +369,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
         break;
     }
 #if defined (DEBUG_BATS)
-    if (loglevel > 0) {
+    if (loglevel != 0) {
         fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__,
                 type == ACCESS_CODE ? 'I' : 'D', virtual);
     }
@@ -384,8 +382,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
         BEPIl = *BATu & 0x0FFE0000;
         bl = (*BATu & 0x00001FFC) << 15;
 #if defined (DEBUG_BATS)
-        if (loglevel > 0) {
-            fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX 
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
                     " BATl 0x" ADDRX "\n",
                     __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
                     *BATu, *BATl);
@@ -405,8 +403,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
                 if (*BATl & 0x00000002)
                     ctx->prot = PAGE_WRITE | PAGE_READ;
 #if defined (DEBUG_BATS)
-                if (loglevel > 0) {
-                    fprintf(logfile, "BAT %d match: r 0x" ADDRX
+                if (loglevel != 0) {
+                    fprintf(logfile, "BAT %d match: r 0x" PADDRX
                             " prot=%c%c\n",
                             i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
                             ctx->prot & PAGE_WRITE ? 'W' : '-');
@@ -419,18 +417,20 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx,
     }
     if (ret < 0) {
 #if defined (DEBUG_BATS)
-        printf("no BAT match for 0x" ADDRX ":\n", virtual);
-        for (i = 0; i < 4; i++) {
-            BATu = &BATut[i];
-            BATl = &BATlt[i];
-            BEPIu = *BATu & 0xF0000000;
-            BEPIl = *BATu & 0x0FFE0000;
-            bl = (*BATu & 0x00001FFC) << 15;
-            printf("%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
-                   " BATl 0x" ADDRX " \n\t"
-                   "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n",
-                   __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
-                   *BATu, *BATl, BEPIu, BEPIl, bl);
+        if (loglevel != 0) {
+            fprintf(logfile, "no BAT match for 0x" ADDRX ":\n", virtual);
+            for (i = 0; i < 4; i++) {
+                BATu = &BATut[i];
+                BATl = &BATlt[i];
+                BEPIu = *BATu & 0xF0000000;
+                BEPIl = *BATu & 0x0FFE0000;
+                bl = (*BATu & 0x00001FFC) << 15;
+                fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
+                        " BATl 0x" ADDRX " \n\t"
+                        "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n",
+                        __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+                        *BATu, *BATl, BEPIu, BEPIl, bl);
+            }
         }
 #endif
     }
@@ -452,7 +452,7 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw)
         pte1 =  ldl_phys(base + (i * 8) + 4);
 #if defined (DEBUG_MMU)
         if (loglevel > 0) {
-            fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX 
+            fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
                     " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
                     base + (i * 8), pte0, pte1,
                     pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem);
@@ -485,8 +485,8 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw)
     if (good != -1) {
     done:
 #if defined (DEBUG_MMU)
-        if (loglevel > 0) {
-            fprintf(logfile, "found PTE at addr 0x" ADDRX " prot=0x%01x "
+        if (loglevel != 0) {
+            fprintf(logfile, "found PTE at addr 0x" PADDRX " prot=0x%01x "
                     "ret=%d\n",
                     ctx->raddr, ctx->prot, ret);
         }
@@ -528,7 +528,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
                 ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
     if ((sr & 0x80000000) == 0) {
 #if defined (DEBUG_MMU)
-        if (loglevel > 0) 
+        if (loglevel > 0)
             fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n",
                     ctx->key, sr & 0x10000000);
 #endif
@@ -551,14 +551,13 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
             if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
                 /* Software TLB search */
                 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
-            } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
-                /* XXX: TODO */
             } else {
 #if defined (DEBUG_MMU)
-                if (loglevel > 0) {
-                    fprintf(logfile, "0 sdr1=0x" ADDRX " vsid=0x%06x "
-                            "api=0x%04x hash=0x%07x pg_addr=0x" ADDRX "\n",
-                            sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
+                if (loglevel != 0) {
+                    fprintf(logfile, "0 sdr1=0x" PADDRX " vsid=0x%06x "
+                            "api=0x%04x hash=0x%07x pg_addr=0x" PADDRX "\n",
+                            sdr, (uint32_t)vsid, (uint32_t)pgidx,
+                            (uint32_t)hash, ctx->pg_addr[0]);
                 }
 #endif
                 /* Primary table lookup */
@@ -566,11 +565,12 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
                 if (ret < 0) {
                     /* Secondary table lookup */
 #if defined (DEBUG_MMU)
-                    if (eaddr != 0xEFFFFFFF && loglevel > 0) {
+                    if (eaddr != 0xEFFFFFFF && loglevel != 0) {
                         fprintf(logfile,
-                                "1 sdr1=0x" ADDRX " vsid=0x%06x api=0x%04x "
-                                "hash=0x%05x pg_addr=0x" ADDRX "\n",
-                                sdr, vsid, pgidx, hash, ctx->pg_addr[1]);
+                                "1 sdr1=0x" PADDRX " vsid=0x%06x api=0x%04x "
+                                "hash=0x%05x pg_addr=0x" PADDRX "\n",
+                                sdr, (uint32_t)vsid, (uint32_t)pgidx,
+                                (uint32_t)hash, ctx->pg_addr[1]);
                     }
 #endif
                     ret2 = find_pte(ctx, 1, rw);
@@ -580,14 +580,14 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
             }
         } else {
 #if defined (DEBUG_MMU)
-            if (loglevel > 0)
+            if (loglevel != 0)
                 fprintf(logfile, "No access allowed\n");
 #endif
             ret = -3;
         }
     } else {
 #if defined (DEBUG_MMU)
-        if (loglevel > 0)
+        if (loglevel != 0)
             fprintf(logfile, "direct store...\n");
 #endif
         /* Direct-store segment : absolutely *BUGGY* for now */
@@ -619,8 +619,6 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
                 fprintf(logfile, "ERROR: instruction should not need "
                         "address translation\n");
             }
-            printf("ERROR: instruction should not need "
-                   "address translation\n");
             return -4;
         }
         if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
@@ -634,11 +632,200 @@ 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;
+    int i;
+
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (tlb->prot & PAGE_VALID) {
+#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB.
+            end = tlb->EPN + tlb->size;
+            for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+                tlb_flush_page(env, page);
+#endif
+            tlb->prot &= ~PAGE_VALID;
+        }
+    }
+    tlb_flush(env, 1);
+}
+
+int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                 target_ulong address, int rw, int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret, zsel, zpr;
+           
+    ret = -1;
+    raddr = -1;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0)
+            continue;
+        zsel = (tlb->attr >> 4) & 0xF;
+        zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
+                    __func__, i, zsel, zpr, rw, tlb->attr);
+        }
+        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;
+                    ret = -3;
+                    break;
+                }
+                /* No break here */
+            case 0x1:
+            check_exec_perm:
+                /* Check from TLB entry */
+                if (!(tlb->prot & PAGE_EXEC)) {
+                    ret = -3;
+                } else {
+                    if (tlb->prot & PAGE_WRITE) {
+                        ctx->prot = PAGE_READ | PAGE_WRITE;
+                    } else {
+                        ctx->prot = PAGE_READ;
+                    }
+                    ret = 0;
+                }
+                break;
+            case 0x3:
+            exec_granted:
+                /* All accesses granted */
+                ctx->prot = PAGE_READ | PAGE_WRITE;
+                ret = 0;
+                break;
+            }
+        } else {
+            switch (zpr) {
+            case 0x2:
+                if (msr_pr)
+                    goto check_rw_perm;
+                goto rw_granted;
+            case 0x0:
+                if (msr_pr) {
+                    ctx->prot = 0;
+                    ret = -2;
+                    break;
+                }
+                /* No break here */
+            case 0x1:
+            check_rw_perm:
+                /* Check from TLB entry */
+                /* Check write protection bit */
+                if (tlb->prot & PAGE_WRITE) {
+                    ctx->prot = PAGE_READ | PAGE_WRITE;
+                    ret = 0;
+                } else {
+                    ctx->prot = PAGE_READ;
+                    if (rw)
+                        ret = -2;
+                    else
+                        ret = 0;
+                }
+                break;
+            case 0x3:
+            rw_granted:
+                /* All accesses granted */
+                ctx->prot = PAGE_READ | PAGE_WRITE;
+                ret = 0;
+                break;
+            }
+        }
+        if (ret >= 0) {
+            ctx->raddr = raddr;
+            if (loglevel != 0) {
+                fprintf(logfile, "%s: access granted " ADDRX " => " REGX
+                        " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                        ret);
+            }
+            return 0;
+        }
+    }
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: access refused " ADDRX " => " REGX
+                " %d %d\n", __func__, address, raddr, ctx->prot,
+                ret);
+    }
+   
+    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)
 {
     int in_plb, ret;
-        
+       
     ctx->raddr = eaddr;
     ctx->prot = PAGE_READ;
     ret = 0;
@@ -675,7 +862,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
 {
     int ret;
 #if 0
-    if (loglevel > 0) {
+    if (loglevel != 0) {
         fprintf(logfile, "%s\n", __func__);
     }
 #endif
@@ -684,26 +871,56 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
         /* No address translation */
         ret = check_physical(env, ctx, eaddr, rw);
     } else {
-        /* Try to find a BAT */
         ret = -1;
-        if (check_BATs)
-            ret = get_bat(env, ctx, eaddr, rw, access_type);
-        if (ret < 0) {
-            /* We didn't match any BAT entry */
-            ret = get_segment(env, ctx, eaddr, rw, access_type);
+        switch (PPC_MMU(env)) {
+        case PPC_FLAGS_MMU_32B:
+        case PPC_FLAGS_MMU_SOFT_6xx:
+            /* 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 PPC_FLAGS_MMU_64B:
+        case PPC_FLAGS_MMU_64BRIDGE:
+#endif
+            if (ret < 0) {
+                /* We didn't match any BAT entry or don't have BATs */
+                ret = get_segment(env, ctx, eaddr, rw, access_type);
+            }
+            break;
+        case PPC_FLAGS_MMU_SOFT_4xx:
+        case PPC_FLAGS_MMU_403:
+            ret = mmu4xx_get_physical_address(env, ctx, eaddr,
+                                              rw, access_type);
+            break;
+        case PPC_FLAGS_MMU_601:
+            /* XXX: TODO */
+            cpu_abort(env, "601 MMU model not implemented\n");
+            return -1;
+        case PPC_FLAGS_MMU_BOOKE:
+            /* XXX: TODO */
+            cpu_abort(env, "BookeE MMU model not implemented\n");
+            return -1;
+        case PPC_FLAGS_MMU_BOOKE_FSL:
+            /* XXX: TODO */
+            cpu_abort(env, "BookE FSL MMU model not implemented\n");
+            return -1;
+        default:
+            cpu_abort(env, "Unknown or invalid MMU model\n");
+            return -1;
         }
     }
 #if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s address " ADDRX " => ADDRX "\n",
-                __func__, eaddr, ctx->raddr);
+    if (loglevel != 0) {
+        fprintf(logfile, "%s address " ADDRX " => %d " PADDRX "\n",
+                __func__, eaddr, ret, ctx->raddr);
     }
 #endif
 
     return ret;
 }
 
-target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 {
     mmu_ctx_t ctx;
 
@@ -714,7 +931,7 @@ target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 }
 
 /* Perform address translation */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu)
 {
     mmu_ctx_t ctx;
@@ -740,7 +957,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
                            is_user, is_softmmu);
     } else if (ret < 0) {
 #if defined (DEBUG_MMU)
-        if (loglevel > 0)
+        if (loglevel != 0)
             cpu_dump_state(env, logfile, fprintf, 0);
 #endif
         if (access_type == ACCESS_CODE) {
@@ -748,16 +965,48 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             switch (ret) {
             case -1:
                 /* No matches in page tables or TLB */
-                if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+                switch (PPC_MMU(env)) {
+                case PPC_FLAGS_MMU_SOFT_6xx:
                     exception = EXCP_I_TLBMISS;
                     env->spr[SPR_IMISS] = address;
                     env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
                     error_code = 1 << 18;
                     goto tlb_miss;
-                } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
-                    /* XXX: TODO */
-                } else {
+                case PPC_FLAGS_MMU_SOFT_4xx:
+                case PPC_FLAGS_MMU_403:
+                    exception = EXCP_40x_ITLBMISS;
+                    error_code = 0;
+                    env->spr[SPR_40x_DEAR] = address;
+                    env->spr[SPR_40x_ESR] = 0x00000000;
+                    break;
+                case PPC_FLAGS_MMU_32B:
                     error_code = 0x40000000;
+                    break;
+#if defined(TARGET_PPC64)
+                case PPC_FLAGS_MMU_64B:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case PPC_FLAGS_MMU_64BRIDGE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+#endif
+                case PPC_FLAGS_MMU_601:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case PPC_FLAGS_MMU_BOOKE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case PPC_FLAGS_MMU_BOOKE_FSL:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                default:
+                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    return -1;
                 }
                 break;
             case -2:
@@ -784,7 +1033,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             switch (ret) {
             case -1:
                 /* No matches in page tables or TLB */
-                if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+                switch (PPC_MMU(env)) {
+                case PPC_FLAGS_MMU_SOFT_6xx:
                     if (rw == 1) {
                         exception = EXCP_DS_TLBMISS;
                         error_code = 1 << 16;
@@ -800,10 +1050,44 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
                     env->spr[SPR_HASH2] = ctx.pg_addr[1];
                     /* Do not alter DAR nor DSISR */
                     goto out;
-                } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
-                    /* XXX: TODO */
-                } else {
+                case PPC_FLAGS_MMU_SOFT_4xx:
+                case PPC_FLAGS_MMU_403:
+                    exception = EXCP_40x_DTLBMISS;
+                    error_code = 0;
+                    env->spr[SPR_40x_DEAR] = address;
+                    if (rw)
+                        env->spr[SPR_40x_ESR] = 0x00800000;
+                    else
+                        env->spr[SPR_40x_ESR] = 0x00000000;
+                    break;
+                case PPC_FLAGS_MMU_32B:
                     error_code = 0x40000000;
+                    break;
+#if defined(TARGET_PPC64)
+                case PPC_FLAGS_MMU_64B:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case PPC_FLAGS_MMU_64BRIDGE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+#endif
+                case PPC_FLAGS_MMU_601:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case PPC_FLAGS_MMU_BOOKE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case PPC_FLAGS_MMU_BOOKE_FSL:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                default:
+                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    return -1;
                 }
                 break;
             case -2:
@@ -978,6 +1262,20 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
     env->DBAT[1][nr] = value;
 }
 
+
+/*****************************************************************************/
+/* TLB management */
+void ppc_tlb_invalidate_all (CPUPPCState *env)
+{
+    if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+        ppc6xx_tlb_invalidate_all(env);
+    } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+        ppc4xx_tlb_invalidate_all(env);
+    } else {
+        tlb_flush(env, 1);
+    }
+}
+
 /*****************************************************************************/
 /* Special registers manipulation */
 #if defined(TARGET_PPC64)
@@ -1195,10 +1493,12 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
         break;
     }
     if (enter_pm) {
-        /* power save: exit cpu loop */
-        env->halted = 1;
-        env->exception_index = EXCP_HLT;
-        cpu_loop_exit();
+        if (likely(!env->halted)) {
+            /* power save: exit cpu loop */
+            env->halted = 1;
+            env->exception_index = EXCP_HLT;
+            cpu_loop_exit();
+        }
     }
 }
 
@@ -1213,11 +1513,12 @@ void ppc_store_msr_32 (CPUPPCState *env, uint32_t value)
 void do_compute_hflags (CPUPPCState *env)
 {
     /* Compute current hflags */
-    env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
-        (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
-        (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) |
-        (msr_se << MSR_SE) | (msr_be << MSR_BE);
+    env->hflags = (msr_cm << MSR_CM) | (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)
+    /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */
     env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32));
 #endif
 }
@@ -1230,11 +1531,9 @@ void do_interrupt (CPUState *env)
     env->exception_index = -1;
 }
 
-int ppc_hw_interrupt (CPUState *env)
+void ppc_hw_interrupt (CPUState *env)
 {
     env->exception_index = -1;
-
-    return 0;
 }
 #else /* defined (CONFIG_USER_ONLY) */
 static void dump_syscall(CPUState *env)
@@ -1247,14 +1546,16 @@ static void dump_syscall(CPUState *env)
 
 void do_interrupt (CPUState *env)
 {
-    target_ulong msr, *srr_0, *srr_1;
-    int excp;
+    target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1;
+    int excp, idx;
 
     excp = env->exception_index;
     msr = do_load_msr(env);
     /* The default is to use SRR0 & SRR1 to save the exception context */
     srr_0 = &env->spr[SPR_SRR0];
     srr_1 = &env->spr[SPR_SRR1];
+    asrr_0 = NULL;
+    asrr_1 = NULL;
 #if defined (DEBUG_EXCEPTIONS)
     if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) {
         if (loglevel != 0) {
@@ -1270,26 +1571,44 @@ void do_interrupt (CPUState *env)
                 env->nip, excp, env->error_code);
     }
     msr_pow = 0;
+    idx = -1;
     /* Generate informations in save/restore registers */
     switch (excp) {
     /* Generic PowerPC exceptions */
     case EXCP_RESET: /* 0x0100 */
-        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
+            srr_0 = &env->spr[SPR_40x_SRR2];
+            srr_1 = &env->spr[SPR_40x_SRR3];
+            break;
+        case PPC_FLAGS_EXCP_BOOKE:
+            idx = 0;
+            srr_0 = &env->spr[SPR_BOOKE_CSRR0];
+            srr_1 = &env->spr[SPR_BOOKE_CSRR1];
+            break;
+        default:
             if (msr_ip)
                 excp += 0xFFC00;
             excp |= 0xFFC00000;
-        } else {
-            srr_0 = &env->spr[SPR_40x_SRR2];
-            srr_1 = &env->spr[SPR_40x_SRR3];
+            break;
         }
         goto store_next;
     case EXCP_MACHINE_CHECK: /* 0x0200 */
-        if (msr_me == 0) {
-            cpu_abort(env, "Machine check exception while not allowed\n");
-        }
-        if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) {
+        switch (PPC_EXCP(env)) {
+        case PPC_FLAGS_EXCP_40x:
             srr_0 = &env->spr[SPR_40x_SRR2];
             srr_1 = &env->spr[SPR_40x_SRR3];
+            break;
+        case PPC_FLAGS_EXCP_BOOKE:
+            idx = 1;
+            srr_0 = &env->spr[SPR_BOOKE_MCSRR0];
+            srr_1 = &env->spr[SPR_BOOKE_MCSRR1];
+            asrr_0 = &env->spr[SPR_BOOKE_CSRR0];
+            asrr_1 = &env->spr[SPR_BOOKE_CSRR1];
+            msr_ce = 0;
+            break;
+        default:
+            break;
         }
         msr_me = 0;
         break;
@@ -1298,19 +1617,18 @@ void do_interrupt (CPUState *env)
         /* data location address has been stored
          * when the fault has been detected
          */
+        idx = 2;
         msr &= ~0xFFFF0000;
 #if defined (DEBUG_EXCEPTIONS)
-        if (loglevel) {
+        if (loglevel != 0) {
             fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX
                     "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-        } else {
-            printf("DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX "\n",
-                   env->spr[SPR_DSISR], env->spr[SPR_DAR]);
         }
 #endif
         goto store_next;
     case EXCP_ISI: /* 0x0400 */
         /* Store exception cause */
+        idx = 3;
         msr &= ~0xFFFF0000;
         msr |= env->error_code;
 #if defined (DEBUG_EXCEPTIONS)
@@ -1321,20 +1639,12 @@ void do_interrupt (CPUState *env)
 #endif
         goto store_next;
     case EXCP_EXTERNAL: /* 0x0500 */
-        if (msr_ee == 0) {
-#if defined (DEBUG_EXCEPTIONS)
-            if (loglevel > 0) {
-                fprintf(logfile, "Skipping hardware interrupt\n");
-            }
-#endif
-            /* Requeue it */
-            env->interrupt_request |= CPU_INTERRUPT_HARD;
-            return;
-        }
+        idx = 4;
         goto store_next;
     case EXCP_ALIGN: /* 0x0600 */
         if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) {
             /* Store exception cause */
+            idx = 5;
             /* Get rS/rD and rA from faulting opcode */
             env->spr[SPR_DSISR] |=
                 (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
@@ -1349,12 +1659,15 @@ void do_interrupt (CPUState *env)
         }
         goto store_current;
     case EXCP_PROGRAM: /* 0x0700 */
+        idx = 6;
         msr &= ~0xFFFF0000;
         switch (env->error_code & ~0xF) {
         case EXCP_FP:
             if (msr_fe0 == 0 && msr_fe1 == 0) {
 #if defined (DEBUG_EXCEPTIONS)
-                printf("Ignore floating point exception\n");
+                if (loglevel != 0) {
+                    fprintf(logfile, "Ignore floating point exception\n");
+                }
 #endif
                 return;
             }
@@ -1367,13 +1680,19 @@ void do_interrupt (CPUState *env)
                 env->fpscr[7] |= 0x4;
             break;
         case EXCP_INVAL:
-            //      printf("Invalid instruction at 0x" ADDRX "\n", env->nip);
+#if defined (DEBUG_EXCEPTIONS)
+            if (loglevel != 0) {
+                fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n",
+                        env->nip);
+            }
+#endif
             msr |= 0x00080000;
             break;
         case EXCP_PRIV:
             msr |= 0x00040000;
             break;
         case EXCP_TRAP:
+            idx = 15;
             msr |= 0x00020000;
             break;
         default:
@@ -1383,18 +1702,13 @@ void do_interrupt (CPUState *env)
         msr |= 0x00010000;
         goto store_current;
     case EXCP_NO_FP: /* 0x0800 */
+        idx = 7;
         msr &= ~0xFFFF0000;
         goto store_current;
     case EXCP_DECR:
-        if (msr_ee == 0) {
-#if 1
-            /* Requeue it */
-            env->interrupt_request |= CPU_INTERRUPT_TIMER;
-#endif
-            return;
-        }
         goto store_next;
     case EXCP_SYSCALL: /* 0x0C00 */
+        idx = 8;
         /* NOTE: this is a temporary hack to support graphics OSI
            calls from the MOL driver */
         if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
@@ -1430,13 +1744,6 @@ void do_interrupt (CPUState *env)
                   "Instruction segment exception is not implemented yet !\n");
         goto store_next;
     case EXCP_HDECR: /* 0x0980 */
-        if (msr_ee == 0) {
-#if 1
-            /* Requeue it */
-            env->interrupt_request |= CPU_INTERRUPT_TIMER;
-#endif
-            return;
-        }
         /* XXX: TODO */
         cpu_abort(env, "Hypervisor decrementer exception is not implemented "
                   "yet !\n");
@@ -1454,6 +1761,7 @@ void do_interrupt (CPUState *env)
         }
         return;
     case 0x0F20:
+        idx = 9;
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* APU unavailable on 405 */
@@ -1473,11 +1781,15 @@ void do_interrupt (CPUState *env)
         }
         return;
     case 0x1000:
+        idx = 10;
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* PIT on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env, "40x PIT exception is not implemented yet !\n");
+            msr &= ~0xFFFF0000;
+#if defined (DEBUG_EXCEPTIONS)
+            if (loglevel != 0)
+                fprintf(logfile, "PIT exception\n");
+#endif
             goto store_next;
         case PPC_FLAGS_EXCP_602:
         case PPC_FLAGS_EXCP_603:
@@ -1492,11 +1804,15 @@ void do_interrupt (CPUState *env)
         }
         return;
     case 0x1010:
+        idx = 11;
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* FIT on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env, "40x FIT exception is not implemented yet !\n");
+            msr &= ~0xFFFF0000;
+#if defined (DEBUG_EXCEPTIONS)
+            if (loglevel != 0)
+                fprintf(logfile, "FIT exception\n");
+#endif
             goto store_next;
         default:
             cpu_abort(env, "Invalid exception 0x1010 !\n");
@@ -1504,25 +1820,31 @@ void do_interrupt (CPUState *env)
         }
         return;
     case 0x1020:
+        idx = 12;
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* Watchdog on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "40x watchdog exception is not implemented yet !\n");
+            msr &= ~0xFFFF0000;
+#if defined (DEBUG_EXCEPTIONS)
+            if (loglevel != 0)
+                fprintf(logfile, "WDT exception\n");
+#endif
             goto store_next;
+        case PPC_FLAGS_EXCP_BOOKE:
+            srr_0 = &env->spr[SPR_BOOKE_CSRR0];
+            srr_1 = &env->spr[SPR_BOOKE_CSRR1];
+            break;
         default:
             cpu_abort(env, "Invalid exception 0x1020 !\n");
             break;
         }
         return;
     case 0x1100:
+        idx = 13;
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* DTLBMISS on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "40x DTLBMISS exception is not implemented yet !\n");
+            msr &= ~0xFFFF0000;
             goto store_next;
         case PPC_FLAGS_EXCP_602:
         case PPC_FLAGS_EXCP_603:
@@ -1537,12 +1859,11 @@ void do_interrupt (CPUState *env)
         }
         return;
     case 0x1200:
+        idx = 14;
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* ITLBMISS on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "40x ITLBMISS exception is not implemented yet !\n");
+            msr &= ~0xFFFF0000;
             goto store_next;
         case PPC_FLAGS_EXCP_602:
         case PPC_FLAGS_EXCP_603:
@@ -1571,7 +1892,7 @@ void do_interrupt (CPUState *env)
                     cmp = &env->spr[SPR_DCMP];
                 }
                 fprintf(logfile, "6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
-                        " H1 " ADDRX " H2 " ADDRX " " ADDRX "\n",
+                        " H1 " ADDRX " H2 " ADDRX " %08x\n",
                         es, en, *miss, en, *cmp,
                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
                         env->error_code);
@@ -1715,6 +2036,10 @@ void do_interrupt (CPUState *env)
             cpu_abort(env,
                       "601 run mode exception is not implemented yet !\n");
             goto store_next;
+        case PPC_FLAGS_EXCP_BOOKE:
+            srr_0 = &env->spr[SPR_BOOKE_CSRR0];
+            srr_1 = &env->spr[SPR_BOOKE_CSRR1];
+            break;
         default:
             cpu_abort(env, "Invalid exception 0x1800 !\n");
             break;
@@ -1729,15 +2054,19 @@ void do_interrupt (CPUState *env)
         return;
     store_current:
         /* save current instruction location */
-        *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL;
+        *srr_0 = env->nip - 4;
         break;
     store_next:
         /* save next instruction location */
-        *srr_0 = env->nip & 0xFFFFFFFFULL;
+        *srr_0 = env->nip;
         break;
     }
     /* Save msr */
     *srr_1 = msr;
+    if (asrr_0 != NULL)
+        *asrr_0 = *srr_0;
+    if (asrr_1 != NULL)
+        *asrr_1 = *srr_1;
     /* If we disactivated any translation, flush TLBs */
     if (msr_ir || msr_dr) {
         tlb_flush(env, 1);
@@ -1754,26 +2083,48 @@ void do_interrupt (CPUState *env)
     msr_dr = 0;
     msr_ri = 0;
     msr_le = msr_ile;
-    msr_sf = msr_isf;
+    if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) {
+        msr_cm = msr_icm;
+        if (idx == -1 || (idx >= 16 && idx < 32)) {
+            cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n",
+                      excp, excp, idx);
+        }
+#if defined(TARGET_PPC64)
+        if (msr_cm)
+            env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR];
+        else
+#endif
+            env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR];
+        if (idx < 16)
+            env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx];
+        else if (idx < 38)
+            env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32];
+    } else {
+        msr_sf = msr_isf;
+        env->nip = excp;
+    }
     do_compute_hflags(env);
     /* Jump to handler */
-    env->nip = excp;
     env->exception_index = EXCP_NONE;
 }
 
-int ppc_hw_interrupt (CPUState *env)
+void ppc_hw_interrupt (CPUPPCState *env)
 {
     int raised = 0;
 
-#if 0
-    printf("%s: %p pending %08x req %08x %08x me %d ee %d\n",
-           __func__, env, env->pending_interrupts,
-           env->interrupt_request, interrupt_request,
-           msr_me, msr_ee);
+#if 1
+    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);
+    }
 #endif
     /* Raise it */
     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
         /* External reset / critical input */
+        /* XXX: critical input should be handled another way.
+         *      This code is not correct !
+         */
         env->exception_index = EXCP_RESET;
         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
         raised = 1;
@@ -1818,8 +2169,20 @@ int ppc_hw_interrupt (CPUState *env)
         /* External interrupt */
         } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
             env->exception_index = EXCP_EXTERNAL;
+            /* Taking an external interrupt does not clear the external
+             * interrupt status
+             */
+#if 0
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
             raised = 1;
+#if 0 // TODO
+        /* Thermal interrupt */
+        } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
+            env->exception_index = EXCP_970_THRM;
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
+            raised = 1;
+#endif
         }
 #if 0 // TODO
     /* External debug exception */
@@ -1833,7 +2196,78 @@ int ppc_hw_interrupt (CPUState *env)
         env->error_code = 0;
         do_interrupt(env);
     }
-    
-    return raised;
 }
 #endif /* !CONFIG_USER_ONLY */
+
+void cpu_dump_EA (target_ulong EA)
+{
+    FILE *f;
+
+    if (logfile) {
+        f = logfile;
+    } else {
+        f = stdout;
+        return;
+    }
+    fprintf(f, "Memory access at address " ADDRX "\n", EA);
+}
+
+void cpu_dump_rfi (target_ulong RA, target_ulong msr)
+{
+    FILE *f;
+
+    if (logfile) {
+        f = logfile;
+    } else {
+        f = stdout;
+        return;
+    }
+    fprintf(f, "Return from exception at " ADDRX " with flags " ADDRX "\n",
+            RA, msr);
+}
+
+void cpu_ppc_reset (void *opaque)
+{
+    CPUPPCState *env;
+
+    env = opaque;
+#if defined (DO_SINGLE_STEP) && 0
+    /* Single step trace mode */
+    msr_se = 1;
+    msr_be = 1;
+#endif
+    msr_fp = 1; /* Allow floating point exceptions */
+    msr_me = 1; /* Allow machine check exceptions  */
+#if defined(TARGET_PPC64)
+    msr_sf = 0; /* Boot in 32 bits mode */
+    msr_cm = 0;
+#endif
+#if defined(CONFIG_USER_ONLY)
+    msr_pr = 1;
+    tlb_flush(env, 1);
+#else
+    env->nip = 0xFFFFFFFC;
+    ppc_tlb_invalidate_all(env);
+#endif
+    do_compute_hflags(env);
+    env->reserve = -1;
+}
+
+CPUPPCState *cpu_ppc_init (void)
+{
+    CPUPPCState *env;
+
+    env = qemu_mallocz(sizeof(CPUPPCState));
+    if (!env)
+        return NULL;
+    cpu_exec_init(env);
+    cpu_ppc_reset(env);
+
+    return env;
+}
+
+void cpu_ppc_close (CPUPPCState *env)
+{
+    /* Should also remove all opcode tables... */
+    free(env);
+}