]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
authorBlue Swirl <blauwirbel@gmail.com>
Fri, 1 Jul 2011 21:12:50 +0000 (21:12 +0000)
committerBlue Swirl <blauwirbel@gmail.com>
Fri, 1 Jul 2011 21:12:50 +0000 (21:12 +0000)
* 'ppc-next' of git://repo.or.cz/qemu/agraf:
  PPC: move TLBs to their own arrays
  PPC: 440: Use 440 style MMU as default, so Qemu knows the MMU type
  PPC: E500: Use MAS registers instead of internal TLB representation
  PPC: Only set lower 32bits with mtmsr
  PPC: update openbios firmware
  PPC: mpc8544ds: Add hypervisor node
  PPC: calculate kernel,initrd,cmdline locations dynamically
  target-ppc: Handle memory-forced I/O controller access
  PPC: E500: Implement reboot controller

1  2 
Makefile.target
target-ppc/cpu.h
target-ppc/helper.c
target-ppc/op_helper.c
target-ppc/translate.c

diff --combined Makefile.target
index 38afdb8e940e010666da987d720ab7d30b5740a0,d3ebe579eb7888482b416e6be519ad0ce4dc7e1c..a53a2ff6ed0734e5e55b7e8831e65a7943856fcc
@@@ -14,10 -14,7 +14,10 @@@ endi
  
  TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
  $(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw)
 -QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H
 +ifdef CONFIG_LINUX
 +QEMU_CFLAGS += -I../linux-headers
 +endif
 +QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
  
  include $(SRC_PATH)/Makefile.objs
  
@@@ -40,6 -37,8 +40,6 @@@ ifndef CONFIG_HAIK
  LIBS+=-lm
  endif
  
 -kvm.o kvm-all.o vhost.o vhost_net.o kvmclock.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
 -
  config-target.h: config-target.h-timestamp
  config-target.h-timestamp: config-target.mak
  
@@@ -94,7 -93,7 +94,7 @@@ tcg/tcg.o: cpu.
  
  # HELPER_CFLAGS is used for all the code compiled with static register
  # variables
 -%_helper.o cpu-exec.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
 +%_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
  
  # Note: this is a workaround. The real fix is to avoid compiling
  # cpu_signal_handler() in user-exec.c.
@@@ -219,8 -218,6 +219,8 @@@ obj-$(CONFIG_NO_XEN) += xen-stub.
  obj-i386-$(CONFIG_XEN_MAPCACHE) += xen-mapcache.o
  obj-$(CONFIG_NO_XEN_MAPCACHE) += xen-mapcache-stub.o
  
 +obj-i386-$(CONFIG_XEN) += xen_platform.o
 +
  # Inter-VM PCI shared memory
  CONFIG_IVSHMEM =
  ifeq ($(CONFIG_KVM), y)
@@@ -237,8 -234,7 +237,8 @@@ obj-i386-y += cirrus_vga.o sga.o apic.
  obj-i386-y += vmport.o
  obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
  obj-i386-y += debugcon.o multiboot.o
 -obj-i386-y += pc_piix.o kvmclock.o
 +obj-i386-y += pc_piix.o
 +obj-i386-$(CONFIG_KVM) += kvmclock.o
  obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
  
  # shared objects
@@@ -260,7 -256,7 +260,7 @@@ endi
  obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
  obj-ppc-y += ppc440.o ppc440_bamboo.o
  # PowerPC E500 boards
- obj-ppc-y += ppce500_mpc8544ds.o
+ obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o
  # PowerPC 440 Xilinx ML507 reference board.
  obj-ppc-y += virtex_ml507.o
  obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
diff --combined target-ppc/cpu.h
index 6d60d147691276ed3cb21edbd0bb67209b2fdb19,46d86be4d7ec27813f9721388a05c6d764948df3..84f8ff6748f4f7df5288bde75a27d1f378ffc730
@@@ -360,10 -360,24 +360,24 @@@ struct ppcemb_tlb_t 
      uint32_t attr; /* Storage attributes */
  };
  
+ typedef struct ppcmas_tlb_t {
+      uint32_t mas8;
+      uint32_t mas1;
+      uint64_t mas2;
+      uint64_t mas7_3;
+ } ppcmas_tlb_t;
  union ppc_tlb_t {
-     ppc6xx_tlb_t tlb6;
-     ppcemb_tlb_t tlbe;
+     ppc6xx_tlb_t *tlb6;
+     ppcemb_tlb_t *tlbe;
+     ppcmas_tlb_t *tlbm;
  };
+ /* possible TLB variants */
+ #define TLB_NONE               0
+ #define TLB_6XX                1
+ #define TLB_EMB                2
+ #define TLB_MAS                3
  #endif
  
  #define SDR_32_HTABORG         0xFFFF0000UL
@@@ -903,7 -917,8 +917,8 @@@ struct CPUPPCState 
      int last_way;    /* Last used way used to allocate TLB in a LRU way      */
      int id_tlbs;     /* If 1, MMU has separated TLBs for instructions & data */
      int nb_pids;     /* Number of available PID registers                    */
-     ppc_tlb_t *tlb;  /* TLB is optional. Allocate them only if needed        */
+     int tlb_type;    /* Type of TLB we're dealing with                       */
+     ppc_tlb_t tlb;   /* TLB is optional. Allocate them only if needed        */
      /* 403 dedicated access protection registers */
      target_ulong pb[4];
  #endif
@@@ -1075,9 -1090,13 +1090,13 @@@ void store_40x_sler (CPUPPCState *env, 
  void store_booke_tcr (CPUPPCState *env, target_ulong val);
  void store_booke_tsr (CPUPPCState *env, target_ulong val);
  void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot);
+ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb);
  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);
+ int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
+                      target_phys_addr_t *raddrp, target_ulong address,
+                      uint32_t pid);
  void ppc_tlb_invalidate_all (CPUPPCState *env);
  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
  #if defined(TARGET_PPC64)
@@@ -1927,12 -1946,12 +1946,12 @@@ static inline void cpu_set_tls(CPUStat
  }
  
  #if !defined(CONFIG_USER_ONLY)
- static inline int booke206_tlbe_id(CPUState *env, ppcemb_tlb_t *tlbe)
+ static inline int booke206_tlbm_id(CPUState *env, ppcmas_tlb_t *tlbm)
  {
-     uintptr_t tlbel = (uintptr_t)tlbe;
-     uintptr_t tlbl = (uintptr_t)env->tlb;
+     uintptr_t tlbml = (uintptr_t)tlbm;
+     uintptr_t tlbl = (uintptr_t)env->tlb.tlbm;
  
-     return (tlbel - tlbl) / sizeof(env->tlb[0]);
+     return (tlbml - tlbl) / sizeof(env->tlb.tlbm[0]);
  }
  
  static inline int booke206_tlb_size(CPUState *env, int tlbn)
@@@ -1949,9 -1968,9 +1968,9 @@@ static inline int booke206_tlb_ways(CPU
      return r;
  }
  
- static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe)
+ static inline int booke206_tlbm_to_tlbn(CPUState *env, ppcmas_tlb_t *tlbm)
  {
-     int id = booke206_tlbe_id(env, tlbe);
+     int id = booke206_tlbm_id(env, tlbm);
      int end = 0;
      int i;
  
      return 0;
  }
  
- static inline int booke206_tlbe_to_way(CPUState *env, ppcemb_tlb_t *tlb)
+ static inline int booke206_tlbm_to_way(CPUState *env, ppcmas_tlb_t *tlb)
  {
-     int tlbn = booke206_tlbe_to_tlbn(env, tlb);
-     int tlbid = booke206_tlbe_id(env, tlb);
+     int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+     int tlbid = booke206_tlbm_id(env, tlb);
      return tlbid & (booke206_tlb_ways(env, tlbn) - 1);
  }
  
- static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn,
+ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
                                                target_ulong ea, int way)
  {
      int r;
          r += booke206_tlb_size(env, i);
      }
  
-     return &env->tlb[r].tlbe;
+     return &env->tlb.tlbm[r];
  }
  
  #endif
  
  extern void (*cpu_ppc_hypercall)(CPUState *);
  
 +static inline bool cpu_has_work(CPUState *env)
 +{
 +    return msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD);
 +}
 +
 +#include "exec-all.h"
 +
 +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
 +{
 +    env->nip = tb->pc;
 +}
 +
  #endif /* !defined (__CPU_PPC_H__) */
diff --combined target-ppc/helper.c
index 395ea0e549bfc17a077f95cf03daf9954fae4257,38849768c522e1efbf4ab330727814ac036a4556..176128a3e247db42f8eb76c94b291d326711f567
@@@ -23,6 -23,7 +23,6 @@@
  #include <inttypes.h>
  
  #include "cpu.h"
 -#include "exec-all.h"
  #include "helper_regs.h"
  #include "qemu-common.h"
  #include "kvm.h"
@@@ -322,7 -323,7 +322,7 @@@ static inline void ppc6xx_tlb_invalidat
      if (env->id_tlbs == 1)
          max *= 2;
      for (nr = 0; nr < max; nr++) {
-         tlb = &env->tlb[nr].tlb6;
+         tlb = &env->tlb.tlb6[nr];
          pte_invalidate(&tlb->pte0);
      }
      tlb_flush(env, 1);
@@@ -339,7 -340,7 +339,7 @@@ static inline void __ppc6xx_tlb_invalid
      /* 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].tlb6;
+         tlb = &env->tlb.tlb6[nr];
          if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
              LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
                        env->nb_tlb, eaddr);
@@@ -366,7 -367,7 +366,7 @@@ void ppc6xx_tlb_store (CPUState *env, t
      int nr;
  
      nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
-     tlb = &env->tlb[nr].tlb6;
+     tlb = &env->tlb.tlb6[nr];
      LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
                " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
      /* Invalidate any pending reference in Qemu for this virtual address */
@@@ -390,7 -391,7 +390,7 @@@ static inline int ppc6xx_tlb_check(CPUS
      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].tlb6;
+         tlb = &env->tlb.tlb6[nr];
          /* This test "emulates" the PTE index match for hardware TLBs */
          if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
              LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
          LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
                    ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
          /* Update page flags */
-         pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
+         pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
      }
  
      return ret;
@@@ -948,8 -949,24 +948,24 @@@ static inline int get_segment(CPUState 
              ret = -3;
          }
      } else {
+         target_ulong sr;
          LOG_MMU("direct store...\n");
          /* Direct-store segment : absolutely *BUGGY* for now */
+         /* Direct-store implies a 32-bit MMU.
+          * Check the Segment Register's bus unit ID (BUID).
+          */
+         sr = env->sr[eaddr >> 28];
+         if ((sr & 0x1FF00000) >> 20 == 0x07f) {
+             /* Memory-forced I/O controller interface access */
+             /* If T=1 and BUID=x'07F', the 601 performs a memory access
+              * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
+              */
+             ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
+             ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+             return 0;
+         }
          switch (type) {
          case ACCESS_INT:
              /* Integer load/store : only access allowed */
@@@ -1032,7 -1049,7 +1048,7 @@@ int ppcemb_tlb_search (CPUPPCState *env
      /* Default return value is no match */
      ret = -1;
      for (i = 0; i < env->nb_tlb; i++) {
-         tlb = &env->tlb[i].tlbe;
+         tlb = &env->tlb.tlbe[i];
          if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
              ret = i;
              break;
@@@ -1049,7 -1066,7 +1065,7 @@@ static inline void ppc4xx_tlb_invalidat
      int i;
  
      for (i = 0; i < env->nb_tlb; i++) {
-         tlb = &env->tlb[i].tlbe;
+         tlb = &env->tlb.tlbe[i];
          tlb->prot &= ~PAGE_VALID;
      }
      tlb_flush(env, 1);
@@@ -1065,7 -1082,7 +1081,7 @@@ static inline void ppc4xx_tlb_invalidat
      int i;
  
      for (i = 0; i < env->nb_tlb; i++) {
-         tlb = &env->tlb[i].tlbe;
+         tlb = &env->tlb.tlbe[i];
          if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
              end = tlb->EPN + tlb->size;
              for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
@@@ -1090,7 -1107,7 +1106,7 @@@ static int mmu40x_get_physical_address 
      raddr = (target_phys_addr_t)-1ULL;
      pr = msr_pr;
      for (i = 0; i < env->nb_tlb; i++) {
-         tlb = &env->tlb[i].tlbe;
+         tlb = &env->tlb.tlbe[i];
          if (ppcemb_tlb_check(env, tlb, &raddr, address,
                               env->spr[SPR_40x_PID], 0, i) < 0)
              continue;
@@@ -1231,7 -1248,7 +1247,7 @@@ static int mmubooke_get_physical_addres
      ret = -1;
      raddr = (target_phys_addr_t)-1ULL;
      for (i = 0; i < env->nb_tlb; i++) {
-         tlb = &env->tlb[i].tlbe;
+         tlb = &env->tlb.tlbe[i];
          ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
                                   access_type, i);
          if (!ret) {
@@@ -1256,14 -1273,14 +1272,14 @@@ void booke206_flush_tlb(CPUState *env, 
  {
      int tlb_size;
      int i, j;
-     ppc_tlb_t *tlb = env->tlb;
+     ppcmas_tlb_t *tlb = env->tlb.tlbm;
  
      for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
          if (flags & (1 << i)) {
              tlb_size = booke206_tlb_size(env, i);
              for (j = 0; j < tlb_size; j++) {
-                 if (!check_iprot || !(tlb[j].tlbe.attr & MAS1_IPROT)) {
-                     tlb[j].tlbe.prot = 0;
+                 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
+                     tlb[j].mas1 &= ~MAS1_VALID;
                  }
              }
          }
      tlb_flush(env, 1);
  }
  
+ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
+ {
+     uint32_t tlbncfg;
+     int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+     target_phys_addr_t tlbm_size;
+     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+     if (tlbncfg & TLBnCFG_AVAIL) {
+         tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+     } else {
+         tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+     }
+     return (1 << (tlbm_size << 1)) << 10;
+ }
+ /* TLB check function for MAS based SoftTLBs */
+ int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
+                      target_phys_addr_t *raddrp,
+                      target_ulong address, uint32_t pid)
+ {
+     target_ulong mask;
+     uint32_t tlb_pid;
+     /* Check valid flag */
+     if (!(tlb->mas1 & MAS1_VALID)) {
+         return -1;
+     }
+     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+     LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
+               PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
+               __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
+               tlb->mas8);
+     /* Check PID */
+     tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
+     if (tlb_pid != 0 && tlb_pid != pid) {
+         return -1;
+     }
+     /* Check effective address */
+     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
+         return -1;
+     }
+     *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+     return 0;
+ }
+ static int mmubooke206_check_tlb(CPUState *env, ppcmas_tlb_t *tlb,
+                                  target_phys_addr_t *raddr, int *prot,
+                                  target_ulong address, int rw,
+                                  int access_type)
+ {
+     int ret;
+     int _prot = 0;
+     if (ppcmas_tlb_check(env, tlb, raddr, address,
+                          env->spr[SPR_BOOKE_PID]) >= 0) {
+         goto found_tlb;
+     }
+     if (env->spr[SPR_BOOKE_PID1] &&
+         ppcmas_tlb_check(env, tlb, raddr, address,
+                          env->spr[SPR_BOOKE_PID1]) >= 0) {
+         goto found_tlb;
+     }
+     if (env->spr[SPR_BOOKE_PID2] &&
+         ppcmas_tlb_check(env, tlb, raddr, address,
+                          env->spr[SPR_BOOKE_PID2]) >= 0) {
+         goto found_tlb;
+     }
+     LOG_SWTLB("%s: TLB entry not found\n", __func__);
+     return -1;
+ found_tlb:
+     if (msr_pr != 0) {
+         if (tlb->mas7_3 & MAS3_UR) {
+             _prot |= PAGE_READ;
+         }
+         if (tlb->mas7_3 & MAS3_UW) {
+             _prot |= PAGE_WRITE;
+         }
+         if (tlb->mas7_3 & MAS3_UX) {
+             _prot |= PAGE_EXEC;
+         }
+     } else {
+         if (tlb->mas7_3 & MAS3_SR) {
+             _prot |= PAGE_READ;
+         }
+         if (tlb->mas7_3 & MAS3_SW) {
+             _prot |= PAGE_WRITE;
+         }
+         if (tlb->mas7_3 & MAS3_SX) {
+             _prot |= PAGE_EXEC;
+         }
+     }
+     /* Check the address space and permissions */
+     if (access_type == ACCESS_CODE) {
+         if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+             LOG_SWTLB("%s: AS doesn't match\n", __func__);
+             return -1;
+         }
+         *prot = _prot;
+         if (_prot & PAGE_EXEC) {
+             LOG_SWTLB("%s: good TLB!\n", __func__);
+             return 0;
+         }
+         LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+         ret = -3;
+     } else {
+         if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+             LOG_SWTLB("%s: AS doesn't match\n", __func__);
+             return -1;
+         }
+         *prot = _prot;
+         if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+             LOG_SWTLB("%s: found TLB!\n", __func__);
+             return 0;
+         }
+         LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+         ret = -2;
+     }
+     return ret;
+ }
  static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
-                                         target_ulong address, int rw,
-                                         int access_type)
+                                             target_ulong address, int rw,
+                                             int access_type)
  {
-     ppcemb_tlb_t *tlb;
+     ppcmas_tlb_t *tlb;
      target_phys_addr_t raddr;
      int i, j, ret;
  
          int ways = booke206_tlb_ways(env, i);
  
          for (j = 0; j < ways; j++) {
-             tlb = booke206_get_tlbe(env, i, address, j);
-             ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
-                                      access_type, j);
+             tlb = booke206_get_tlbm(env, i, address, j);
+             ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
+                                         rw, access_type);
              if (ret != -1) {
                  goto found_tlb;
              }
@@@ -1395,7 -1549,7 +1548,7 @@@ int get_physical_address (CPUState *env
                                                  rw, access_type);
          } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
              ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
-                                                access_type);
+                                                    access_type);
          } else {
              /* No address translation.  */
              ret = check_physical(env, ctx, eaddr, rw);
diff --combined target-ppc/op_helper.c
index 29f72e1a349f5b0c57deb621d7dd59cd5ff825cd,82b66519253c16d3a311bc73b73c54eb8385bba3..dde7595fda2c644dc30bb5eb9d5c5d29c9784f39
@@@ -44,7 -44,7 +44,7 @@@ void helper_raise_exception_err (uint32
  #endif
      env->exception_index = exception;
      env->error_code = error_code;
 -    cpu_loop_exit();
 +    cpu_loop_exit(env);
  }
  
  void helper_raise_exception (uint32_t exception)
@@@ -3959,7 -3959,7 +3959,7 @@@ target_ulong helper_4xx_tlbre_hi (targe
      int size;
  
      entry &= PPC4XX_TLB_ENTRY_MASK;
-     tlb = &env->tlb[entry].tlbe;
+     tlb = &env->tlb.tlbe[entry];
      ret = tlb->EPN;
      if (tlb->prot & PAGE_VALID) {
          ret |= PPC4XX_TLBHI_V;
@@@ -3979,7 -3979,7 +3979,7 @@@ target_ulong helper_4xx_tlbre_lo (targe
      target_ulong ret;
  
      entry &= PPC4XX_TLB_ENTRY_MASK;
-     tlb = &env->tlb[entry].tlbe;
+     tlb = &env->tlb.tlbe[entry];
      ret = tlb->RPN;
      if (tlb->prot & PAGE_EXEC) {
          ret |= PPC4XX_TLBLO_EX;
@@@ -3998,7 -3998,7 +3998,7 @@@ void helper_4xx_tlbwe_hi (target_ulong 
      LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
                val);
      entry &= PPC4XX_TLB_ENTRY_MASK;
-     tlb = &env->tlb[entry].tlbe;
+     tlb = &env->tlb.tlbe[entry];
      /* Invalidate previous TLB (if it's valid) */
      if (tlb->prot & PAGE_VALID) {
          end = tlb->EPN + tlb->size;
@@@ -4056,7 -4056,7 +4056,7 @@@ void helper_4xx_tlbwe_lo (target_ulong 
      LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
                val);
      entry &= PPC4XX_TLB_ENTRY_MASK;
-     tlb = &env->tlb[entry].tlbe;
+     tlb = &env->tlb.tlbe[entry];
      tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
      tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
      tlb->prot = PAGE_READ;
@@@ -4091,7 -4091,7 +4091,7 @@@ void helper_440_tlbwe (uint32_t word, t
                __func__, word, (int)entry, value);
      do_flush_tlbs = 0;
      entry &= 0x3F;
-     tlb = &env->tlb[entry].tlbe;
+     tlb = &env->tlb.tlbe[entry];
      switch (word) {
      default:
          /* Just here to please gcc */
@@@ -4150,7 -4150,7 +4150,7 @@@ target_ulong helper_440_tlbre (uint32_
      int size;
  
      entry &= 0x3F;
-     tlb = &env->tlb[entry].tlbe;
+     tlb = &env->tlb.tlbe[entry];
      switch (word) {
      default:
          /* Just here to please gcc */
@@@ -4196,7 -4196,7 +4196,7 @@@ target_ulong helper_440_tlbsx (target_u
  
  /* PowerPC BookE 2.06 TLB management */
  
- static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env)
+ static ppcmas_tlb_t *booke206_cur_tlb(CPUState *env)
  {
      uint32_t tlbncfg = 0;
      int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
          cpu_abort(env, "we don't support HES yet\n");
      }
  
-     return booke206_get_tlbe(env, tlb, ea, esel);
- }
- static inline target_phys_addr_t booke206_tlb_to_page_size(int size)
- {
-     return (1 << (size << 1)) << 10;
- }
- static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
- {
-     return (ffs(size >> 10) - 1) >> 1;
+     return booke206_get_tlbm(env, tlb, ea, esel);
  }
  
  void helper_booke_setpid(uint32_t pidn, target_ulong pid)
  void helper_booke206_tlbwe(void)
  {
      uint32_t tlbncfg, tlbn;
-     ppcemb_tlb_t *tlb;
-     target_phys_addr_t rpn;
-     int tlbe_size;
+     ppcmas_tlb_t *tlb;
  
      switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
      case MAS0_WQ_ALWAYS:
  
      if (msr_gs) {
          cpu_abort(env, "missing HV implementation\n");
-     } else {
-         rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
-               (env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
-     }
-     tlb->RPN = rpn;
-     tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
-     if (tlbncfg & TLBnCFG_AVAIL) {
-         tlbe_size = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK)
-                     >> MAS1_TSIZE_SHIFT;
-     } else {
-         tlbe_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
      }
+     tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
+                   env->spr[SPR_BOOKE_MAS3];
+     tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+     /* XXX needs to change when supporting 64-bit e500 */
+     tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
  
-     tlb->size = booke206_tlb_to_page_size(tlbe_size);
-     tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
-     tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W |
-                                             MAS2_I | MAS2_M | MAS2_G | MAS2_E)
-                 << 1;
-     if (tlbncfg & TLBnCFG_IPROT) {
-         tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT;
-     }
-     tlb->attr |= (env->spr[SPR_BOOKE_MAS3] &
-                   ((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8);
-     if (env->spr[SPR_BOOKE_MAS1] & MAS1_TS) {
-         tlb->attr |= 1;
-     }
-     tlb->prot = 0;
-     if (env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) {
-         tlb->prot |= PAGE_VALID;
-     }
-     if (env->spr[SPR_BOOKE_MAS3] & MAS3_UX) {
-         tlb->prot |= PAGE_EXEC;
-     }
-     if (env->spr[SPR_BOOKE_MAS3] & MAS3_SX) {
-         tlb->prot |= PAGE_EXEC << 4;
-     }
-     if (env->spr[SPR_BOOKE_MAS3] & MAS3_UW) {
-         tlb->prot |= PAGE_WRITE;
-     }
-     if (env->spr[SPR_BOOKE_MAS3] & MAS3_SW) {
-         tlb->prot |= PAGE_WRITE << 4;
-     }
-     if (env->spr[SPR_BOOKE_MAS3] & MAS3_UR) {
-         tlb->prot |= PAGE_READ;
-     }
-     if (env->spr[SPR_BOOKE_MAS3] & MAS3_SR) {
-         tlb->prot |= PAGE_READ << 4;
+     if (!(tlbncfg & TLBnCFG_IPROT)) {
+         /* no IPROT supported by TLB */
+         tlb->mas1 &= ~MAS1_IPROT;
      }
  
-     if (tlb->size == TARGET_PAGE_SIZE) {
-         tlb_flush_page(env, tlb->EPN);
+     if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
+         tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
      } else {
          tlb_flush(env, 1);
      }
  }
  
- static inline void booke206_tlb_to_mas(CPUState *env, ppcemb_tlb_t *tlb)
+ static inline void booke206_tlb_to_mas(CPUState *env, ppcmas_tlb_t *tlb)
  {
-     int tlbn = booke206_tlbe_to_tlbn(env, tlb);
-     int way = booke206_tlbe_to_way(env, tlb);
+     int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+     int way = booke206_tlbm_to_way(env, tlb);
  
      env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
      env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
-     env->spr[SPR_BOOKE_MAS1] = MAS1_VALID;
-     env->spr[SPR_BOOKE_MAS2] = 0;
-     env->spr[SPR_BOOKE_MAS7] = (uint64_t)tlb->RPN >> 32;
-     env->spr[SPR_BOOKE_MAS3] = tlb->RPN;
-     env->spr[SPR_BOOKE_MAS1] |= tlb->PID << MAS1_TID_SHIFT;
-     env->spr[SPR_BOOKE_MAS1] |= booke206_page_size_to_tlb(tlb->size)
-                                 << MAS1_TSIZE_SHIFT;
-     env->spr[SPR_BOOKE_MAS1] |= tlb->attr & MAS1_IPROT;
-     if (tlb->attr & 1) {
-         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
-     }
-     env->spr[SPR_BOOKE_MAS2] = tlb->EPN;
-     env->spr[SPR_BOOKE_MAS2] |= (tlb->attr >> 1) &
-         (MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E);
-     if (tlb->prot & PAGE_EXEC) {
-         env->spr[SPR_BOOKE_MAS3] |= MAS3_UX;
-     }
-     if (tlb->prot & (PAGE_EXEC << 4)) {
-         env->spr[SPR_BOOKE_MAS3] |= MAS3_SX;
-     }
-     if (tlb->prot & PAGE_WRITE) {
-         env->spr[SPR_BOOKE_MAS3] |= MAS3_UW;
-     }
-     if (tlb->prot & (PAGE_WRITE << 4)) {
-         env->spr[SPR_BOOKE_MAS3] |= MAS3_SW;
-     }
-     if (tlb->prot & PAGE_READ) {
-         env->spr[SPR_BOOKE_MAS3] |= MAS3_UR;
-     }
-     if (tlb->prot & (PAGE_READ << 4)) {
-         env->spr[SPR_BOOKE_MAS3] |= MAS3_SR;
-     }
      env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+     env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
+     env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
+     env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
+     env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
  }
  
  void helper_booke206_tlbre(void)
  {
-     ppcemb_tlb_t *tlb = NULL;
+     ppcmas_tlb_t *tlb = NULL;
  
      tlb = booke206_cur_tlb(env);
      booke206_tlb_to_mas(env, tlb);
  
  void helper_booke206_tlbsx(target_ulong address)
  {
-     ppcemb_tlb_t *tlb = NULL;
+     ppcmas_tlb_t *tlb = NULL;
      int i, j;
      target_phys_addr_t raddr;
      uint32_t spid, sas;
          int ways = booke206_tlb_ways(env, i);
  
          for (j = 0; j < ways; j++) {
-             tlb = booke206_get_tlbe(env, i, address, j);
+             tlb = booke206_get_tlbm(env, i, address, j);
  
-             if (ppcemb_tlb_check(env, tlb, &raddr, address, spid, 0, j)) {
+             if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
                  continue;
              }
  
-             if (sas != (tlb->attr & MAS6_SAS)) {
+             if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
                  continue;
              }
  
@@@ -4439,13 -4354,14 +4354,14 @@@ static inline void booke206_invalidate_
  {
      int i;
      int ways = booke206_tlb_ways(env, tlbn);
+     target_ulong mask;
  
      for (i = 0; i < ways; i++) {
-         ppcemb_tlb_t *tlb = booke206_get_tlbe(env, tlbn, ea, i);
-         target_phys_addr_t masked_ea = ea & ~(tlb->size - 1);
-         if ((tlb->EPN == (masked_ea >> MAS2_EPN_SHIFT)) &&
-             !(tlb->attr & MAS1_IPROT)) {
-             tlb->prot = 0;
+         ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+         mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+         if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
+             !(tlb->mas1 & MAS1_IPROT)) {
+             tlb->mas1 &= ~MAS1_VALID;
          }
      }
  }
diff --combined target-ppc/translate.c
index 0a03b4465ab2177b03eec0665b4f0a4dd1d669a2,7e318e397a56c29984e4344d4ff0d9729cf1aeba..fd7c2087d7903e6de6c33e39ce02a3f72682e36a
@@@ -24,6 -24,7 +24,6 @@@
  #include <inttypes.h>
  
  #include "cpu.h"
 -#include "exec-all.h"
  #include "disas.h"
  #include "tcg-op.h"
  #include "qemu-common.h"
@@@ -3877,24 -3878,19 +3877,19 @@@ static void gen_mtmsr(DisasContext *ctx
          tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
          tcg_temp_free(t0);
      } else {
+         TCGv msr = tcg_temp_new();
          /* XXX: we need to update nip before the store
           *      if we enter power saving mode, we will exit the loop
           *      directly from ppc_store_msr
           */
          gen_update_nip(ctx, ctx->nip);
  #if defined(TARGET_PPC64)
-         if (!ctx->sf_mode) {
-             TCGv t0 = tcg_temp_new();
-             TCGv t1 = tcg_temp_new();
-             tcg_gen_andi_tl(t0, cpu_msr, 0xFFFFFFFF00000000ULL);
-             tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]);
-             tcg_gen_or_tl(t0, t0, t1);
-             tcg_temp_free(t1);
-             gen_helper_store_msr(t0);
-             tcg_temp_free(t0);
-         } else
+         tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32);
+ #else
+         tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]);
  #endif
-             gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
+         gen_helper_store_msr(msr);
          /* Must stop the translation as machine state (may have) changed */
          /* Note that mtmsr is not always defined as context-synchronizing */
          gen_stop_exception(ctx);