summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile.target12
-rwxr-xr-xconfigure7
-rw-r--r--cpu-all.h9
-rw-r--r--cpu-exec.c6
-rw-r--r--def-helper.h26
-rw-r--r--exec-all.h2
-rw-r--r--exec.c18
-rw-r--r--fpu/softfloat-specialize.h8
-rw-r--r--fpu/softfloat.h2
-rw-r--r--hw/apb_pci.c49
-rw-r--r--hw/apb_pci.h3
-rw-r--r--hw/arm11mpcore.c2
-rw-r--r--hw/arm_gic.c8
-rw-r--r--hw/arm_mptimer.c2
-rw-r--r--hw/mips_malta.c84
-rw-r--r--hw/nseries.c12
-rw-r--r--hw/omap.h13
-rw-r--r--hw/omap1.c13
-rw-r--r--hw/omap2.c35
-rw-r--r--hw/omap_i2c.c107
-rw-r--r--hw/openpic.c12
-rw-r--r--hw/ppc405_uc.c2
-rw-r--r--hw/ppce500_spin.c2
-rw-r--r--hw/pxa2xx.c3
-rw-r--r--hw/pxa2xx_dma.c12
-rw-r--r--hw/pxa2xx_lcd.c12
-rw-r--r--hw/spapr.c5
-rw-r--r--hw/spapr.h13
-rw-r--r--hw/spapr_pci.c193
-rw-r--r--hw/spapr_pci.h4
-rw-r--r--hw/spapr_vio.c2
-rw-r--r--hw/sun4u.c57
-rw-r--r--hw/xics.c125
-rw-r--r--hw/xics.h8
-rw-r--r--kvm-all.c5
-rw-r--r--linux-user/signal.c2
-rw-r--r--osdep.h6
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin869584 -> 880496 bytes
m---------roms/SLOF0
-rw-r--r--savevm.c2
-rw-r--r--softmmu_defs.h60
-rw-r--r--softmmu_header.h60
-rw-r--r--softmmu_template.h86
-rw-r--r--target-arm/helper.c5
-rw-r--r--target-arm/translate.c63
-rw-r--r--target-ppc/cpu.h4
-rw-r--r--target-ppc/helper.c12
-rw-r--r--target-ppc/kvm.c12
-rw-r--r--target-ppc/translate.c54
-rw-r--r--target-ppc/translate_init.c11
-rw-r--r--target-sparc/cpu.h11
-rw-r--r--target-sparc/cpu_init.c1
-rw-r--r--target-sparc/helper.h20
-rw-r--r--target-sparc/ldst_helper.c433
-rw-r--r--target-sparc/op_helper.c74
-rw-r--r--target-sparc/translate.c62
-rw-r--r--tcg/arm/tcg-target.c53
-rw-r--r--tcg/hppa/tcg-target.c44
-rw-r--r--tcg/i386/tcg-target.c169
-rw-r--r--tcg/ia64/tcg-target.c46
-rw-r--r--tcg/mips/tcg-target.c44
-rw-r--r--tcg/ppc/tcg-target.c45
-rw-r--r--tcg/ppc/tcg-target.h2
-rw-r--r--tcg/ppc64/tcg-target.c44
-rw-r--r--tcg/s390/tcg-target.c44
-rw-r--r--tcg/sparc/tcg-target.c50
-rw-r--r--tcg/tcg.c28
-rw-r--r--tcg/tcg.h9
-rw-r--r--tcg/tci/tcg-target.c6
-rw-r--r--tcg/tci/tcg-target.h2
-rw-r--r--tci.c4
72 files changed, 1586 insertions, 857 deletions
diff --git a/Makefile.target b/Makefile.target
index eb2594188a..37fb7edd6d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -80,7 +80,10 @@ libobj-y = exec.o translate-all.o cpu-exec.o translate.o
 libobj-y += tcg/tcg.o tcg/optimize.o
 libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
 libobj-y += fpu/softfloat.o
-libobj-y += op_helper.o helper.o
+ifneq ($(TARGET_BASE_ARCH), sparc)
+libobj-y += op_helper.o
+endif
+libobj-y += helper.o
 ifeq ($(TARGET_BASE_ARCH), i386)
 libobj-y += cpuid.o
 endif
@@ -101,9 +104,12 @@ tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci
 
 $(libobj-y): $(GENERATED_HEADERS)
 
-# HELPER_CFLAGS is used for all the code compiled with static register
+# HELPER_CFLAGS is used for all the legacy code compiled with static register
 # variables
-op_helper.o ldst_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+ifneq ($(TARGET_BASE_ARCH), sparc)
+op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+endif
+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.
diff --git a/configure b/configure
index afe7395577..8b4e3c1a02 100755
--- a/configure
+++ b/configure
@@ -3606,6 +3606,13 @@ case "$target_arch2" in
     exit 1
   ;;
 esac
+
+case "$target_arch2" in
+  sparc*)
+    echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
+  ;;
+esac
+
 echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak
 echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
 echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
diff --git a/cpu-all.h b/cpu-all.h
index 8ad1ec7a44..9621c3c92e 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -259,12 +259,21 @@ extern unsigned long reserved_va;
 #define stfl(p, v) stfl_raw(p, v)
 #define stfq(p, v) stfq_raw(p, v)
 
+#ifndef CONFIG_TCG_PASS_AREG0
 #define ldub_code(p) ldub_raw(p)
 #define ldsb_code(p) ldsb_raw(p)
 #define lduw_code(p) lduw_raw(p)
 #define ldsw_code(p) ldsw_raw(p)
 #define ldl_code(p) ldl_raw(p)
 #define ldq_code(p) ldq_raw(p)
+#else
+#define cpu_ldub_code(env1, p) ldub_raw(p)
+#define cpu_ldsb_code(env1, p) ldsb_raw(p)
+#define cpu_lduw_code(env1, p) lduw_raw(p)
+#define cpu_ldsw_code(env1, p) ldsw_raw(p)
+#define cpu_ldl_code(env1, p) ldl_raw(p)
+#define cpu_ldq_code(env1, p) ldq_raw(p)
+#endif
 
 #define ldub_kernel(p) ldub_raw(p)
 #define ldsb_kernel(p) ldsb_raw(p)
diff --git a/cpu-exec.c b/cpu-exec.c
index bd5791f8fa..0fa8325b27 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -55,7 +55,7 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc)
 static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
                              TranslationBlock *orig_tb)
 {
-    unsigned long next_tb;
+    tcg_target_ulong next_tb;
     TranslationBlock *tb;
 
     /* Should never happen.
@@ -186,7 +186,7 @@ int cpu_exec(CPUArchState *env)
     int ret, interrupt_request;
     TranslationBlock *tb;
     uint8_t *tc_ptr;
-    unsigned long next_tb;
+    tcg_target_ulong next_tb;
 
     if (env->halted) {
         if (!cpu_has_work(env)) {
@@ -565,7 +565,7 @@ int cpu_exec(CPUArchState *env)
                     if ((next_tb & 3) == 2) {
                         /* Instruction counter expired.  */
                         int insns_left;
-                        tb = (TranslationBlock *)(long)(next_tb & ~3);
+                        tb = (TranslationBlock *)(next_tb & ~3);
                         /* Restore PC.  */
                         cpu_pc_from_tb(env, tb);
                         insns_left = env->icount_decr.u32;
diff --git a/def-helper.h b/def-helper.h
index 5d057d68d6..0e70c31bc4 100644
--- a/def-helper.h
+++ b/def-helper.h
@@ -118,6 +118,8 @@
     DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3)
 #define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \
     DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4)
+#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \
+    DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5)
 
 #endif /* DEF_HELPER_H */
 
@@ -140,6 +142,10 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3));
 dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
                                    dh_ctype(t4));
 
+#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
+                            dh_ctype(t4), dh_ctype(t5));
+
 #undef GEN_HELPER
 #define GEN_HELPER -1
 
@@ -203,6 +209,22 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1
   tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \
 }
 
+#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
+    dh_arg_decl(t1, 1),  dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
+    dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \
+{ \
+  TCGArg args[5]; \
+  int sizemask = 0; \
+  dh_sizemask(ret, 0); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  dh_arg(t3, 3); \
+  dh_arg(t4, 4); \
+  dh_arg(t5, 5); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 5, args); \
+}
+
 #undef GEN_HELPER
 #define GEN_HELPER -1
 
@@ -224,6 +246,9 @@ DEF_HELPER_FLAGS_0(name, flags, ret)
 #define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
 DEF_HELPER_FLAGS_0(name, flags, ret)
 
+#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
 #undef GEN_HELPER
 #define GEN_HELPER -1
 
@@ -235,6 +260,7 @@ DEF_HELPER_FLAGS_0(name, flags, ret)
 #undef DEF_HELPER_FLAGS_2
 #undef DEF_HELPER_FLAGS_3
 #undef DEF_HELPER_FLAGS_4
+#undef DEF_HELPER_FLAGS_5
 #undef GEN_HELPER
 
 #endif
diff --git a/exec-all.h b/exec-all.h
index 8fca67b117..93a5b22c1c 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -312,7 +312,9 @@ void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx,
 
 #define ACCESS_TYPE (NB_MMU_MODES + 1)
 #define MEMSUFFIX _code
+#ifndef CONFIG_TCG_PASS_AREG0
 #define env cpu_single_env
+#endif
 
 #define DATA_SIZE 1
 #include "softmmu_header.h"
diff --git a/exec.c b/exec.c
index 8fd50a1c4b..a3818ffeb7 100644
--- a/exec.c
+++ b/exec.c
@@ -2031,14 +2031,19 @@ static void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
     cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG);
 }
 
+static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
+{
+    return (tlbe->addr_write & (TLB_INVALID_MASK|TLB_MMIO|TLB_NOTDIRTY)) == 0;
+}
+
 static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
                                          unsigned long start, unsigned long length)
 {
     unsigned long addr;
-    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
+    if (tlb_is_dirty_ram(tlb_entry)) {
         addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
         if ((addr - start) < length) {
-            tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
+            tlb_entry->addr_write |= TLB_NOTDIRTY;
         }
     }
 }
@@ -2091,7 +2096,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
     ram_addr_t ram_addr;
     void *p;
 
-    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
+    if (tlb_is_dirty_ram(tlb_entry)) {
         p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
             + tlb_entry->addend);
         ram_addr = qemu_ram_addr_from_host_nofail(p);
@@ -4595,12 +4600,17 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
     mmu_idx = cpu_mmu_index(env1);
     if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
                  (addr & TARGET_PAGE_MASK))) {
+#ifdef CONFIG_TCG_PASS_AREG0
+        cpu_ldub_code(env1, addr);
+#else
         ldub_code(addr);
+#endif
     }
     pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
     mr = iotlb_to_region(pd);
     if (mr != &io_mem_ram && mr != &io_mem_rom
-        && mr != &io_mem_notdirty && !mr->rom_device) {
+        && mr != &io_mem_notdirty && !mr->rom_device
+        && mr != &io_mem_watch) {
 #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
         cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
 #else
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index c5e2dab9f6..490245004f 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -89,8 +89,8 @@ const float64 float64_default_nan = const_float64(LIT64( 0xFFF8000000000000 ));
 #define floatx80_default_nan_low  LIT64( 0xC000000000000000 )
 #endif
 
-const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high,
-                                                    floatx80_default_nan_low);
+const floatx80 floatx80_default_nan
+    = make_floatx80_init(floatx80_default_nan_high, floatx80_default_nan_low);
 
 /*----------------------------------------------------------------------------
 | The pattern for a default generated quadruple-precision NaN.  The `high' and
@@ -104,8 +104,8 @@ const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high,
 #define float128_default_nan_low  LIT64( 0x0000000000000000 )
 #endif
 
-const float128 float128_default_nan = make_float128(float128_default_nan_high,
-                                                    float128_default_nan_low);
+const float128 float128_default_nan
+    = make_float128_init(float128_default_nan_high, float128_default_nan_low);
 
 /*----------------------------------------------------------------------------
 | Raises the exceptions specified by `flags'.  Floating-point traps can be
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 07c2929613..2ce4110c07 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -129,6 +129,7 @@ typedef struct {
     uint16_t high;
 } floatx80;
 #define make_floatx80(exp, mant) ((floatx80) { mant, exp })
+#define make_floatx80_init(exp, mant) { .low = mant, .high = exp }
 typedef struct {
 #ifdef HOST_WORDS_BIGENDIAN
     uint64_t high, low;
@@ -137,6 +138,7 @@ typedef struct {
 #endif
 } float128;
 #define make_float128(high_, low_) ((float128) { .high = high_, .low = low_ })
+#define make_float128_init(high_, low_) { .high = high_, .low = low_ }
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE floating-point underflow tininess-detection mode.
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 1d25da8da9..7e28808ec4 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
 #define RESET_WCMASK 0x98000000
 #define RESET_WMASK  0x60000000
 
+#define MAX_IVEC 0x30
+
 typedef struct APBState {
     SysBusDevice busdev;
     PCIBus      *bus;
@@ -77,7 +79,8 @@ typedef struct APBState {
     uint32_t pci_control[16];
     uint32_t pci_irq_map[8];
     uint32_t obio_irq_map[32];
-    qemu_irq pci_irqs[32];
+    qemu_irq *pbm_irqs;
+    qemu_irq *ivec_irqs;
     uint32_t reset_control;
     unsigned int nr_resets;
 } APBState;
@@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
 {
     APBState *s = opaque;
 
-    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);
 
     switch (addr & 0xffff) {
     case 0x30 ... 0x4f: /* DMA error registers */
@@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
             s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
         }
         break;
+    case 0x1000 ... 0x1080: /* OBIO interrupt control */
+        if (addr & 4) {
+            s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
+            s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
+        }
+        break;
     case 0x2000 ... 0x202f: /* PCI control */
         s->pci_control[(addr & 0x3f) >> 2] = val;
         break;
@@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque,
             val = 0;
         }
         break;
+    case 0x1000 ... 0x1080: /* OBIO interrupt control */
+        if (addr & 4) {
+            val = s->obio_irq_map[(addr & 0xff) >> 3];
+        } else {
+            val = 0;
+        }
+        break;
     case 0x2000 ... 0x202f: /* PCI control */
         val = s->pci_control[(addr & 0x3f) >> 2];
         break;
@@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque, target_phys_addr_t addr,
     APBState *s = opaque;
 
     val = qemu_bswap_len(val, size);
-    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);
     pci_data_write(s->bus, addr, val, size);
 }
 
@@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
     if (irq_num < 32) {
         if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
             APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
-            qemu_set_irq(s->pci_irqs[irq_num], level);
+            qemu_set_irq(s->ivec_irqs[irq_num], level);
         } else {
             APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
-            qemu_irq_lower(s->pci_irqs[irq_num]);
+            qemu_irq_lower(s->ivec_irqs[irq_num]);
+        }
+    } else {
+        /* OBIO IRQ map onto the next 16 INO.  */
+        if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
+            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+            qemu_set_irq(s->ivec_irqs[irq_num], level);
+        } else {
+            APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
+            qemu_irq_lower(s->ivec_irqs[irq_num]);
         }
     }
 }
@@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
 
 PCIBus *pci_apb_init(target_phys_addr_t special_base,
                      target_phys_addr_t mem_base,
-                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
+                     qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+                     qemu_irq **pbm_irqs)
 {
     DeviceState *dev;
     SysBusDevice *s;
     APBState *d;
-    unsigned int i;
     PCIDevice *pci_dev;
     PCIBridge *br;
 
@@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
                               get_system_io(),
                               0, 32);
 
-    for (i = 0; i < 32; i++) {
-        sysbus_connect_irq(s, i, pic[i]);
-    }
+    *pbm_irqs = d->pbm_irqs;
+    d->ivec_irqs = ivec_irqs;
 
     pci_create_simple(d->bus, 0, "pbm-pci");
 
@@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
     for (i = 0; i < 8; i++) {
         s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
     }
-    for (i = 0; i < 32; i++) {
-        sysbus_init_irq(dev, &s->pci_irqs[i]);
-    }
+    s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
 
     /* apb_config */
     memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
@@ -444,7 +466,6 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
     k->vendor_id = PCI_VENDOR_ID_SUN;
     k->device_id = PCI_DEVICE_ID_SUN_SABRE;
     k->class_id = PCI_CLASS_BRIDGE_HOST;
-    k->is_bridge = 1;
 }
 
 static TypeInfo pbm_pci_host_info = {
diff --git a/hw/apb_pci.h b/hw/apb_pci.h
index 8869f9d326..55f7c4c3b2 100644
--- a/hw/apb_pci.h
+++ b/hw/apb_pci.h
@@ -5,5 +5,6 @@
 
 PCIBus *pci_apb_init(target_phys_addr_t special_base,
                      target_phys_addr_t mem_base,
-                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
+                     qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+                     qemu_irq **pbm_irqs);
 #endif
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index c67b70f3b9..ba6a89d3ed 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -42,7 +42,6 @@ static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
     int id;
-    offset &= 0xff;
     /* SCU */
     switch (offset) {
     case 0x00: /* Control.  */
@@ -63,7 +62,6 @@ static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
                              uint64_t value, unsigned size)
 {
     mpcore_priv_state *s = (mpcore_priv_state *)opaque;
-    offset &= 0xff;
     /* SCU */
     switch (offset) {
     case 0: /* Control register.  */
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index d8a7a190e8..6b34c06a8f 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -658,14 +658,14 @@ static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr,
                                  unsigned size)
 {
     gic_state *s = (gic_state *)opaque;
-    return gic_cpu_read(s, gic_get_current_cpu(), addr & 0xff);
+    return gic_cpu_read(s, gic_get_current_cpu(), addr);
 }
 
 static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
                               uint64_t value, unsigned size)
 {
     gic_state *s = (gic_state *)opaque;
-    gic_cpu_write(s, gic_get_current_cpu(), addr & 0xff, value);
+    gic_cpu_write(s, gic_get_current_cpu(), addr, value);
 }
 
 /* Wrappers to read/write the GIC CPU interface for a specific CPU.
@@ -677,7 +677,7 @@ static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr,
     gic_state **backref = (gic_state **)opaque;
     gic_state *s = *backref;
     int id = (backref - s->backref);
-    return gic_cpu_read(s, id, addr & 0xff);
+    return gic_cpu_read(s, id, addr);
 }
 
 static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr,
@@ -686,7 +686,7 @@ static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr,
     gic_state **backref = (gic_state **)opaque;
     gic_state *s = *backref;
     int id = (backref - s->backref);
-    gic_cpu_write(s, id, addr & 0xff, value);
+    gic_cpu_write(s, id, addr, value);
 }
 
 static const MemoryRegionOps gic_thiscpu_ops = {
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 361e887dec..df7fb4c9bd 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -97,7 +97,6 @@ static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr,
 {
     timerblock *tb = (timerblock *)opaque;
     int64_t val;
-    addr &= 0x1f;
     switch (addr) {
     case 0: /* Load */
         return tb->load;
@@ -126,7 +125,6 @@ static void timerblock_write(void *opaque, target_phys_addr_t addr,
 {
     timerblock *tb = (timerblock *)opaque;
     int64_t old;
-    addr &= 0x1f;
     switch (addr) {
     case 0: /* Load */
         tb->load = value;
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 5e26775e64..4752bb2865 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -55,6 +55,13 @@
 #define ENVP_NB_ENTRIES	 	16
 #define ENVP_ENTRY_SIZE	 	256
 
+/* Hardware addresses */
+#define FLASH_ADDRESS 0x1e000000ULL
+#define FPGA_ADDRESS  0x1f000000ULL
+#define RESET_ADDRESS 0x1fc00000ULL
+
+#define FLASH_SIZE    0x400000
+
 #define MAX_IDE_BUS 2
 
 typedef struct {
@@ -331,9 +338,9 @@ static void malta_fpga_write(void *opaque, target_phys_addr_t addr,
         break;
 
     /* LEDBAR Register */
-    /* XXX: implement a 8-LED array */
     case 0x00408:
         s->leds = val & 0xff;
+        malta_fpga_update_display(s);
         break;
 
     /* ASCIIWORD Register */
@@ -777,7 +784,7 @@ void mips_malta_init (ram_addr_t ram_size,
     MemoryRegion *system_memory = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
-    target_long bios_size;
+    target_long bios_size = FLASH_SIZE;
     int64_t kernel_entry;
     PCIBus *pci_bus;
     ISABus *isa_bus;
@@ -791,7 +798,7 @@ void mips_malta_init (ram_addr_t ram_size,
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     DriveInfo *fd[MAX_FD];
     int fl_idx = 0;
-    int fl_sectors = 0;
+    int fl_sectors = bios_size >> 16;
     int be;
 
     DeviceState *dev = qdev_create(NULL, "mips-malta");
@@ -847,19 +854,26 @@ void mips_malta_init (ram_addr_t ram_size,
     be = 0;
 #endif
     /* FPGA */
-    malta_fpga_init(system_memory, 0x1f000000LL, env->irq[2], serial_hds[2]);
+    malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]);
 
-    /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
+    /* Load firmware in flash / BIOS. */
+    dinfo = drive_get(IF_PFLASH, 0, fl_idx);
+#ifdef DEBUG_BOARD_INIT
+    if (dinfo) {
+        printf("Register parallel flash %d size " TARGET_FMT_lx " at "
+               "addr %08llx '%s' %x\n",
+               fl_idx, bios_size, FLASH_ADDRESS,
+               bdrv_get_device_name(dinfo->bdrv), fl_sectors);
+    }
+#endif
+    fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios",
+                               BIOS_SIZE, dinfo ? dinfo->bdrv : NULL,
+                               65536, fl_sectors,
+                               4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+    bios = pflash_cfi01_get_memory(fl);
+    fl_idx++;
     if (kernel_filename) {
         /* Write a small bootloader to the flash location. */
-        bios = g_new(MemoryRegion, 1);
-        memory_region_init_ram(bios, "mips_malta.bios", BIOS_SIZE);
-        vmstate_register_ram_global(bios);
-        memory_region_set_readonly(bios, true);
-        memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
-        /* Map the bios at two physical locations, as on the real board. */
-        memory_region_add_subregion(system_memory, 0x1e000000LL, bios);
-        memory_region_add_subregion(system_memory, 0x1fc00000LL, bios_alias);
         loaderparams.ram_size = ram_size;
         loaderparams.kernel_filename = kernel_filename;
         loaderparams.kernel_cmdline = kernel_cmdline;
@@ -867,45 +881,15 @@ void mips_malta_init (ram_addr_t ram_size,
         kernel_entry = load_kernel();
         write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
     } else {
-        dinfo = drive_get(IF_PFLASH, 0, fl_idx);
-        if (dinfo) {
-            /* Load firmware from flash. */
-            bios_size = 0x400000;
-            fl_sectors = bios_size >> 16;
-#ifdef DEBUG_BOARD_INIT
-            printf("Register parallel flash %d size " TARGET_FMT_lx " at "
-                   "addr %08llx '%s' %x\n",
-                   fl_idx, bios_size, 0x1e000000LL,
-                   bdrv_get_device_name(dinfo->bdrv), fl_sectors);
-#endif
-            fl = pflash_cfi01_register(0x1e000000LL,
-                                       NULL, "mips_malta.bios", BIOS_SIZE,
-                                       dinfo->bdrv, 65536, fl_sectors,
-                                       4, 0x0000, 0x0000, 0x0000, 0x0000, be);
-            bios = pflash_cfi01_get_memory(fl);
-            /* Map the bios at two physical locations, as on the real board. */
-            memory_region_init_alias(bios_alias, "bios.1fc",
-                                     bios, 0, BIOS_SIZE);
-            memory_region_add_subregion(system_memory, 0x1fc00000LL,
-                                        bios_alias);
-           fl_idx++;
-        } else {
-            bios = g_new(MemoryRegion, 1);
-            memory_region_init_ram(bios, "mips_malta.bios", BIOS_SIZE);
-            vmstate_register_ram_global(bios);
-            memory_region_set_readonly(bios, true);
-            memory_region_init_alias(bios_alias, "bios.1fc",
-                                     bios, 0, BIOS_SIZE);
-            /* Map the bios at two physical locations, as on the real board. */
-            memory_region_add_subregion(system_memory, 0x1e000000LL, bios);
-            memory_region_add_subregion(system_memory, 0x1fc00000LL,
-                                        bios_alias);
+        /* Load firmware from flash. */
+        if (!dinfo) {
             /* Load a BIOS image. */
-            if (bios_name == NULL)
+            if (bios_name == NULL) {
                 bios_name = BIOS_FILENAME;
+            }
             filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
             if (filename) {
-                bios_size = load_image_targphys(filename, 0x1fc00000LL,
+                bios_size = load_image_targphys(filename, FLASH_ADDRESS,
                                                 BIOS_SIZE);
                 g_free(filename);
             } else {
@@ -932,6 +916,10 @@ void mips_malta_init (ram_addr_t ram_size,
 #endif
     }
 
+    /* Map the BIOS at a 2nd physical location, as on the real board. */
+    memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
+    memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias);
+
     /* Board ID = 0x420 (Malta Board with CoreLV)
        XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
        map to the board ID. */
diff --git a/hw/nseries.c b/hw/nseries.c
index c5b31843dd..a5cfa8ccbc 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -45,7 +45,6 @@ struct n800_s {
         uint32_t (*txrx)(void *opaque, uint32_t value, int len);
         uWireSlave *chip;
     } ts;
-    i2c_bus *i2c;
 
     int keymap[0x80];
     DeviceState *kbd;
@@ -194,12 +193,10 @@ static void n8x0_i2c_setup(struct n800_s *s)
 {
     DeviceState *dev;
     qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO);
-
-    /* Attach the CPU on one end of our I2C bus.  */
-    s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
+    i2c_bus *i2c = omap_i2c_bus(s->cpu->i2c[0]);
 
     /* Attach a menelaus PM chip */
-    dev = i2c_create_slave(s->i2c, "twl92230", N8X0_MENELAUS_ADDR);
+    dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
     qdev_connect_gpio_out(dev, 3,
                           qdev_get_gpio_in(s->cpu->ih[0],
                                            OMAP_INT_24XX_SYS_NIRQ));
@@ -207,7 +204,7 @@ static void n8x0_i2c_setup(struct n800_s *s)
     qemu_system_powerdown = qdev_get_gpio_in(dev, 3);
 
     /* Attach a TMP105 PM chip (A0 wired to ground) */
-    dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
+    dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR);
     qdev_connect_gpio_out(dev, 0, tmp_irq);
 }
 
@@ -391,7 +388,8 @@ static void n810_kbd_setup(struct n800_s *s)
 
     /* Attach the LM8322 keyboard to the I2C bus,
      * should happen in n8x0_i2c_setup and s->kbd be initialised here.  */
-    s->kbd = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
+    s->kbd = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[0]),
+                           "lm8323", N810_LM8323_ADDR);
     qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
 }
 
diff --git a/hw/omap.h b/hw/omap.h
index 63ef847ed0..6c3d004719 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -764,16 +764,7 @@ void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
 void omap_mmc_enable(struct omap_mmc_s *s, int enable);
 
 /* omap_i2c.c */
-struct omap_i2c_s;
-struct omap_i2c_s *omap_i2c_init(MemoryRegion *sysmem,
-                                 target_phys_addr_t base,
-                                 qemu_irq irq,
-                                 qemu_irq *dma,
-                                 omap_clk clk);
-struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
-                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk);
-void omap_i2c_reset(struct omap_i2c_s *s);
-i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
+i2c_bus *omap_i2c_bus(DeviceState *omap_i2c);
 
 # define cpu_is_omap310(cpu)		(cpu->mpu_model == omap310)
 # define cpu_is_omap1510(cpu)		(cpu->mpu_model == omap1510)
@@ -867,7 +858,7 @@ struct omap_mpu_state_s {
 
     struct omap_pwl_s *pwl;
     struct omap_pwt_s *pwt;
-    struct omap_i2c_s *i2c[2];
+    DeviceState *i2c[2];
 
     struct omap_rtc_s *rtc;
 
diff --git a/hw/omap1.c b/hw/omap1.c
index 5317b9be2b..2a341bfe7f 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3694,7 +3694,6 @@ static void omap1_mpu_reset(void *opaque)
     omap_uwire_reset(mpu->microwire);
     omap_pwl_reset(mpu->pwl);
     omap_pwt_reset(mpu->pwt);
-    omap_i2c_reset(mpu->i2c[0]);
     omap_rtc_reset(mpu->rtc);
     omap_mcbsp_reset(mpu->mcbsp1);
     omap_mcbsp_reset(mpu->mcbsp2);
@@ -3993,9 +3992,15 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     s->pwt = omap_pwt_init(system_memory, 0xfffb6000,
                            omap_findclk(s, "armxor_ck"));
 
-    s->i2c[0] = omap_i2c_init(system_memory, 0xfffb3800,
-                              qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C),
-                    &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
+    s->i2c[0] = qdev_create(NULL, "omap_i2c");
+    qdev_prop_set_uint8(s->i2c[0], "revision", 0x11);
+    qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck"));
+    qdev_init_nofail(s->i2c[0]);
+    busdev = sysbus_from_qdev(s->i2c[0]);
+    sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C));
+    sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]);
+    sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]);
+    sysbus_mmio_map(busdev, 0, 0xfffb3800);
 
     s->rtc = omap_rtc_init(system_memory, 0xfffb4800,
                            qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER),
diff --git a/hw/omap2.c b/hw/omap2.c
index 157defb393..42fce5e986 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2222,8 +2222,6 @@ static void omap2_mpu_reset(void *opaque)
     omap_mmc_reset(mpu->mmc);
     omap_mcspi_reset(mpu->mcspi[0]);
     omap_mcspi_reset(mpu->mcspi[1]);
-    omap_i2c_reset(mpu->i2c[0]);
-    omap_i2c_reset(mpu->i2c[1]);
     cpu_state_reset(mpu->env);
 }
 
@@ -2395,16 +2393,29 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
                     omap_findclk(s, "clk32-kHz"),
                     omap_findclk(s, "core_l4_iclk"));
 
-    s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5),
-                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ),
-                    &s->drq[OMAP24XX_DMA_I2C1_TX],
-                    omap_findclk(s, "i2c1.fclk"),
-                    omap_findclk(s, "i2c1.iclk"));
-    s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6),
-                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ),
-                    &s->drq[OMAP24XX_DMA_I2C2_TX],
-                    omap_findclk(s, "i2c2.fclk"),
-                    omap_findclk(s, "i2c2.iclk"));
+    s->i2c[0] = qdev_create(NULL, "omap_i2c");
+    qdev_prop_set_uint8(s->i2c[0], "revision", 0x34);
+    qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk"));
+    qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk"));
+    qdev_init_nofail(s->i2c[0]);
+    busdev = sysbus_from_qdev(s->i2c[0]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ));
+    sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]);
+    sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]);
+    sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0));
+
+    s->i2c[1] = qdev_create(NULL, "omap_i2c");
+    qdev_prop_set_uint8(s->i2c[1], "revision", 0x34);
+    qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk"));
+    qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk"));
+    qdev_init_nofail(s->i2c[1]);
+    busdev = sysbus_from_qdev(s->i2c[1]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ));
+    sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]);
+    sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]);
+    sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0));
 
     s->gpio = qdev_create(NULL, "omap2-gpio");
     qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index 5ec422c566..20bc82e3b8 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -19,14 +19,20 @@
 #include "hw.h"
 #include "i2c.h"
 #include "omap.h"
+#include "sysbus.h"
 
-struct omap_i2c_s {
+
+typedef struct OMAPI2CState {
+    SysBusDevice busdev;
     MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq drq[2];
     i2c_bus *bus;
 
     uint8_t revision;
+    void *iclk;
+    void *fclk;
+
     uint8_t mask;
     uint16_t stat;
     uint16_t dma;
@@ -40,12 +46,12 @@ struct omap_i2c_s {
     uint8_t divider;
     uint8_t times[2];
     uint16_t test;
-};
+} OMAPI2CState;
 
 #define OMAP2_INTR_REV	0x34
 #define OMAP2_GC_REV	0x34
 
-static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
+static void omap_i2c_interrupts_update(OMAPI2CState *s)
 {
     qemu_set_irq(s->irq, s->stat & s->mask);
     if ((s->dma >> 15) & 1)					/* RDMA_EN */
@@ -54,7 +60,7 @@ static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
         qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);		/* XRDY */
 }
 
-static void omap_i2c_fifo_run(struct omap_i2c_s *s)
+static void omap_i2c_fifo_run(OMAPI2CState *s)
 {
     int ack = 1;
 
@@ -122,8 +128,10 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s)
         s->control &= ~(1 << 1);				/* STP */
 }
 
-void omap_i2c_reset(struct omap_i2c_s *s)
+static void omap_i2c_reset(DeviceState *dev)
 {
+    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState,
+                                  sysbus_from_qdev(dev));
     s->mask = 0;
     s->stat = 0;
     s->dma = 0;
@@ -143,7 +151,7 @@ void omap_i2c_reset(struct omap_i2c_s *s)
 
 static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
+    OMAPI2CState *s = opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t ret;
 
@@ -243,7 +251,7 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
 static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
+    OMAPI2CState *s = opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     int nack;
 
@@ -309,14 +317,14 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
         }
 
         if (value & 2)
-            omap_i2c_reset(s);
+            omap_i2c_reset(&s->busdev.qdev);
         break;
 
     case 0x24:	/* I2C_CON */
         s->control = value & 0xcf87;
         if (~value & (1 << 15)) {				/* I2C_EN */
             if (s->revision < OMAP2_INTR_REV)
-                omap_i2c_reset(s);
+                omap_i2c_reset(&s->busdev.qdev);
             break;
         }
         if ((value & (1 << 15)) && !(value & (1 << 10))) {	/* MST */
@@ -385,7 +393,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
 static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *) opaque;
+    OMAPI2CState *s = opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
     switch (offset) {
@@ -426,50 +434,59 @@ static const MemoryRegionOps omap_i2c_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-struct omap_i2c_s *omap_i2c_init(MemoryRegion *sysmem,
-                                 target_phys_addr_t base,
-                                 qemu_irq irq,
-                                 qemu_irq *dma,
-                                 omap_clk clk)
+static int omap_i2c_init(SysBusDevice *dev)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *)
-            g_malloc0(sizeof(struct omap_i2c_s));
-
-    /* TODO: set a value greater or equal to real hardware */
-    s->revision = 0x11;
-    s->irq = irq;
-    s->drq[0] = dma[0];
-    s->drq[1] = dma[1];
-    s->bus = i2c_init_bus(NULL, "i2c");
-    omap_i2c_reset(s);
+    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev);
 
-    memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c", 0x800);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    return s;
+    if (!s->fclk) {
+        hw_error("omap_i2c: fclk not connected\n");
+    }
+    if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
+        /* Note that OMAP1 doesn't have a separate interface clock */
+        hw_error("omap_i2c: iclk not connected\n");
+    }
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->drq[0]);
+    sysbus_init_irq(dev, &s->drq[1]);
+    memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c",
+                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    s->bus = i2c_init_bus(&dev->qdev, NULL);
+    return 0;
 }
 
-struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
-                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_i2c_s *s = (struct omap_i2c_s *)
-            g_malloc0(sizeof(struct omap_i2c_s));
+static Property omap_i2c_properties[] = {
+    DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
+    DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
+    DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
 
-    s->revision = 0x34;
-    s->irq = irq;
-    s->drq[0] = dma[0];
-    s->drq[1] = dma[1];
-    s->bus = i2c_init_bus(NULL, "i2c");
-    omap_i2c_reset(s);
+static void omap_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = omap_i2c_init;
+    dc->props = omap_i2c_properties;
+    dc->reset = omap_i2c_reset;
+}
 
-    memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap2.i2c",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
+static TypeInfo omap_i2c_info = {
+    .name = "omap_i2c",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OMAPI2CState),
+    .class_init = omap_i2c_class_init,
+};
 
-    return s;
+static void omap_i2c_register_types(void)
+{
+    type_register_static(&omap_i2c_info);
 }
 
-i2c_bus *omap_i2c_bus(struct omap_i2c_s *s)
+i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
 {
+    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, sysbus_from_qdev(omap_i2c));
     return s->bus;
 }
+
+type_init(omap_i2c_register_types)
diff --git a/hw/openpic.c b/hw/openpic.c
index 280b7a9bbb..58ef871f68 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -713,7 +713,7 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
         return;
-    addr -= 0x1100;
+    addr -= 0x10;
     addr &= 0xFFFF;
     idx = (addr & 0xFFF0) >> 6;
     addr = addr & 0x30;
@@ -746,7 +746,7 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
     retval = 0xFFFFFFFF;
     if (addr & 0xF)
         return retval;
-    addr -= 0x1100;
+    addr -= 0x10;
     addr &= 0xFFFF;
     idx = (addr & 0xFFF0) >> 6;
     addr = addr & 0x30;
@@ -1361,7 +1361,6 @@ static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
     if (addr & 0xF)
         return;
 
-    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_EXT_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1385,7 +1384,6 @@ static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
     if (addr & 0xF)
         return retval;
 
-    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_EXT_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1411,7 +1409,6 @@ static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
     if (addr & 0xF)
         return;
 
-    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_INT_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1435,7 +1432,6 @@ static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
     if (addr & 0xF)
         return retval;
 
-    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_INT_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1461,7 +1457,6 @@ static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
     if (addr & 0xF)
         return;
 
-    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_MSG_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1485,7 +1480,6 @@ static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
     if (addr & 0xF)
         return retval;
 
-    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_MSG_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1511,7 +1505,6 @@ static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
     if (addr & 0xF)
         return;
 
-    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_MSI_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
@@ -1534,7 +1527,6 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
     if (addr & 0xF)
         return retval;
 
-    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
     if (addr < MPIC_MSI_REG_SIZE) {
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 6f8342e0e7..89e5013b57 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -2471,6 +2471,8 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
     ppc4xx_pob_init(env);
     /* OBP arbitrer */
     ppc4xx_opba_init(0xef600600);
+    /* Initialize timers */
+    ppc_booke_timers_init(env, sysclk, 0);
     /* Universal interrupt controller */
     irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
     irqs[PPCUIC_OUTPUT_INT] =
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index 268f5fdb9c..960b7b0c3d 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -182,7 +182,7 @@ static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len)
     }
 }
 
-const MemoryRegionOps spin_rw_ops = {
+static const MemoryRegionOps spin_rw_ops = {
     .read = spin_read,
     .write = spin_write,
     .endianness = DEVICE_BIG_ENDIAN,
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index f55287774a..1d5c35f174 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1507,8 +1507,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
 
     i2c_dev = sysbus_from_qdev(qdev_create(NULL, "pxa2xx_i2c"));
     qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1);
-    qdev_prop_set_uint32(&i2c_dev->qdev, "offset",
-            base - (base & (~region_size) & TARGET_PAGE_MASK));
+    qdev_prop_set_uint32(&i2c_dev->qdev, "offset", base & region_size);
 
     qdev_init_nofail(&i2c_dev->qdev);
 
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index 8ced0dd8ec..031015400b 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -18,9 +18,9 @@
 #define PXA2XX_DMA_NUM_REQUESTS 75
 
 typedef struct {
-    target_phys_addr_t descr;
-    target_phys_addr_t src;
-    target_phys_addr_t dest;
+    uint32_t descr;
+    uint32_t src;
+    uint32_t dest;
     uint32_t cmd;
     uint32_t state;
     int request;
@@ -512,9 +512,9 @@ static VMStateDescription vmstate_pxa2xx_dma_chan = {
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_UINTTL(descr, PXA2xxDMAChannel),
-        VMSTATE_UINTTL(src, PXA2xxDMAChannel),
-        VMSTATE_UINTTL(dest, PXA2xxDMAChannel),
+        VMSTATE_UINT32(descr, PXA2xxDMAChannel),
+        VMSTATE_UINT32(src, PXA2xxDMAChannel),
+        VMSTATE_UINT32(dest, PXA2xxDMAChannel),
         VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
         VMSTATE_UINT32(state, PXA2xxDMAChannel),
         VMSTATE_INT32(request, PXA2xxDMAChannel),
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index fcbdfb3fba..ee8bf577cb 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -19,15 +19,15 @@
 #include "framebuffer.h"
 
 struct DMAChannel {
-    target_phys_addr_t branch;
+    uint32_t branch;
     uint8_t up;
     uint8_t palette[1024];
     uint8_t pbuffer[1024];
     void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr,
                    int *miny, int *maxy);
 
-    target_phys_addr_t descriptor;
-    target_phys_addr_t source;
+    uint32_t descriptor;
+    uint32_t source;
     uint32_t id;
     uint32_t command;
 };
@@ -929,11 +929,11 @@ static const VMStateDescription vmstate_dma_channel = {
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
     .fields      = (VMStateField[]) {
-        VMSTATE_UINTTL(branch, struct DMAChannel),
+        VMSTATE_UINT32(branch, struct DMAChannel),
         VMSTATE_UINT8(up, struct DMAChannel),
         VMSTATE_BUFFER(pbuffer, struct DMAChannel),
-        VMSTATE_UINTTL(descriptor, struct DMAChannel),
-        VMSTATE_UINTTL(source, struct DMAChannel),
+        VMSTATE_UINT32(descriptor, struct DMAChannel),
+        VMSTATE_UINT32(source, struct DMAChannel),
         VMSTATE_UINT32(id, struct DMAChannel),
         VMSTATE_UINT32(command, struct DMAChannel),
         VMSTATE_END_OF_LIST()
diff --git a/hw/spapr.c b/hw/spapr.c
index 3719e0e4a7..bfaf260d54 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -83,7 +83,8 @@
 
 sPAPREnvironment *spapr;
 
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
+                            enum xics_irq_type type)
 {
     uint32_t irq;
     qemu_irq qirq;
@@ -95,7 +96,7 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
         irq = spapr->next_irq++;
     }
 
-    qirq = xics_find_qirq(spapr->icp, irq);
+    qirq = xics_assign_irq(spapr->icp, irq, type);
     if (!qirq) {
         return NULL;
     }
diff --git a/hw/spapr.h b/hw/spapr.h
index a41641fdde..11160b02da 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -286,7 +286,18 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
 target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
                              target_ulong *args);
 
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num);
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
+                            enum xics_irq_type type);
+
+static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num)
+{
+    return spapr_allocate_irq(hint, irq_num, XICS_MSI);
+}
+
+static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num)
+{
+    return spapr_allocate_irq(hint, irq_num, XICS_LSI);
+}
 
 static inline uint32_t rtas_ld(target_ulong phys, int n)
 {
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 374dcf8be7..e7ef551c1c 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -32,13 +32,6 @@
 
 #include "hw/pci_internals.h"
 
-static const uint32_t bars[] = {
-    PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
-    PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
-    PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
-    /*, PCI_ROM_ADDRESS*/
-};
-
 static PCIDevice *find_dev(sPAPREnvironment *spapr,
                            uint64_t buid, uint32_t config_addr)
 {
@@ -187,69 +180,6 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
 }
 
-static int spapr_phb_init(SysBusDevice *s)
-{
-    sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
-    int i;
-
-    /* Initialize the LSI table */
-    for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) {
-        qemu_irq qirq;
-        uint32_t num;
-
-        qirq = spapr_allocate_irq(0, &num);
-        if (!qirq) {
-            return -1;
-        }
-
-        phb->lsi_table[i].dt_irq = num;
-        phb->lsi_table[i].qirq = qirq;
-    }
-
-    return 0;
-}
-
-static int spapr_main_pci_host_init(PCIDevice *d)
-{
-    return 0;
-}
-
-static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = spapr_main_pci_host_init;
-}
-
-static TypeInfo spapr_main_pci_host_info = {
-    .name          = "spapr-pci-host-bridge-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init    = spapr_main_pci_host_class_init,
-};
-
-static void spapr_phb_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = spapr_phb_init;
-}
-
-static TypeInfo spapr_phb_info = {
-    .name          = "spapr-pci-host-bridge",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(sPAPRPHBState),
-    .class_init    = spapr_phb_class_init,
-};
-
-static void spapr_register_types(void)
-{
-    type_register_static(&spapr_phb_info);
-    type_register_static(&spapr_main_pci_host_info);
-}
-
-type_init(spapr_register_types)
-
 static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
                               unsigned size)
 {
@@ -287,35 +217,29 @@ static const MemoryRegionOps spapr_io_ops = {
     .write = spapr_io_write
 };
 
-void spapr_create_phb(sPAPREnvironment *spapr,
-                      const char *busname, uint64_t buid,
-                      uint64_t mem_win_addr, uint64_t mem_win_size,
-                      uint64_t io_win_addr)
+/*
+ * PHB PCI device
+ */
+static int spapr_phb_init(SysBusDevice *s)
 {
-    DeviceState *dev;
-    SysBusDevice *s;
-    sPAPRPHBState *phb;
+    sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
+    char *namebuf;
+    int i;
     PCIBus *bus;
-    char namebuf[strlen(busname)+11];
-
-    dev = qdev_create(NULL, "spapr-pci-host-bridge");
-    qdev_init_nofail(dev);
-    s = sysbus_from_qdev(dev);
-    phb = FROM_SYSBUS(sPAPRPHBState, s);
 
-    phb->mem_win_addr = mem_win_addr;
+    phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid);
+    namebuf = alloca(strlen(phb->dtbusname) + 32);
 
-    sprintf(namebuf, "%s-mem", busname);
+    /* Initialize memory regions */
+    sprintf(namebuf, "%s.mmio", phb->dtbusname);
     memory_region_init(&phb->memspace, namebuf, INT64_MAX);
 
-    sprintf(namebuf, "%s-memwindow", busname);
+    sprintf(namebuf, "%s.mmio-alias", phb->dtbusname);
     memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace,
-                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size);
-    memory_region_add_subregion(get_system_memory(), mem_win_addr,
+                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, phb->mem_win_size);
+    memory_region_add_subregion(get_system_memory(), phb->mem_win_addr,
                                 &phb->memwindow);
 
-    phb->io_win_addr = io_win_addr;
-
     /* On ppc, we only have MMIO no specific IO space from the CPU
      * perspective.  In theory we ought to be able to embed the PCI IO
      * memory region direction in the system memory space.  However,
@@ -324,33 +248,92 @@ void spapr_create_phb(sPAPREnvironment *spapr,
      * system io address space.  This hack to bounce things via
      * system_io works around the problem until all the users of
      * old_portion are updated */
-    sprintf(namebuf, "%s-io", busname);
+    sprintf(namebuf, "%s.io", phb->dtbusname);
     memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
     /* FIXME: fix to support multiple PHBs */
     memory_region_add_subregion(get_system_io(), 0, &phb->iospace);
 
-    sprintf(namebuf, "%s-iowindow", busname);
+    sprintf(namebuf, "%s.io-alias", phb->dtbusname);
     memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb,
                           namebuf, SPAPR_PCI_IO_WIN_SIZE);
-    memory_region_add_subregion(get_system_memory(), io_win_addr,
+    memory_region_add_subregion(get_system_memory(), phb->io_win_addr,
                                 &phb->iowindow);
 
-    phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname,
-                                                 pci_spapr_set_irq,
-                                                 pci_spapr_map_irq,
-                                                 phb,
-                                                 &phb->memspace, &phb->iospace,
-                                                 PCI_DEVFN(0, 0),
-                                                 SPAPR_PCI_NUM_LSI);
+    bus = pci_register_bus(&phb->busdev.qdev,
+                           phb->busname ? phb->busname : phb->dtbusname,
+                           pci_spapr_set_irq, pci_spapr_map_irq, phb,
+                           &phb->memspace, &phb->iospace,
+                           PCI_DEVFN(0, 0), SPAPR_PCI_NUM_LSI);
+    phb->host_state.bus = bus;
+
+    QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
+
+    /* Initialize the LSI table */
+    for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) {
+        qemu_irq qirq;
+        uint32_t num;
+
+        qirq = spapr_allocate_lsi(0, &num);
+        if (!qirq) {
+            return -1;
+        }
+
+        phb->lsi_table[i].dt_irq = num;
+        phb->lsi_table[i].qirq = qirq;
+    }
+
+    return 0;
+}
+
+static Property spapr_phb_properties[] = {
+    DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0),
+    DEFINE_PROP_STRING("busname", sPAPRPHBState, busname),
+    DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, 0),
+    DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000),
+    DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0),
+    DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_phb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sdc->init = spapr_phb_init;
+    dc->props = spapr_phb_properties;
 
     spapr_rtas_register("read-pci-config", rtas_read_pci_config);
     spapr_rtas_register("write-pci-config", rtas_write_pci_config);
     spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
     spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+}
 
-    QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
+static TypeInfo spapr_phb_info = {
+    .name          = "spapr-pci-host-bridge",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(sPAPRPHBState),
+    .class_init    = spapr_phb_class_init,
+};
+
+void spapr_create_phb(sPAPREnvironment *spapr,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, spapr_phb_info.name);
 
-    /* pci_bus_set_mem_base(bus, mem_va_start - SPAPR_PCI_MEM_BAR_START); */
+    if (busname) {
+        qdev_prop_set_string(dev, "busname", g_strdup(busname));
+    }
+    qdev_prop_set_uint64(dev, "buid", buid);
+    qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr);
+    qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size);
+    qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr);
+
+    qdev_init_nofail(dev);
 }
 
 /* Macros to operate with address in OF binding to PCI */
@@ -442,3 +425,9 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
 
     return 0;
 }
+
+static void register_types(void)
+{
+    type_register_static(&spapr_phb_info);
+}
+type_init(register_types)
diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h
index 213340c915..039f85bd4b 100644
--- a/hw/spapr_pci.h
+++ b/hw/spapr_pci.h
@@ -33,9 +33,11 @@ typedef struct sPAPRPHBState {
     PCIHostState host_state;
 
     uint64_t buid;
+    char *busname;
+    char *dtbusname;
 
     MemoryRegion memspace, iospace;
-    target_phys_addr_t mem_win_addr, io_win_addr;
+    target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size;
     MemoryRegion memwindow, iowindow;
 
     struct {
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 2fb3cee266..dbf5a9017e 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -670,7 +670,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
         dev->qdev.id = id;
     }
 
-    dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num);
+    dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num);
     if (!dev->qirq) {
         return -1;
     }
diff --git a/hw/sun4u.c b/hw/sun4u.c
index c32eddb31f..237e20c1bf 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -81,7 +81,7 @@
 #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
 #define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
 
-#define MAX_PILS 16
+#define IVEC_MAX             0x30
 
 #define TICK_MAX             0x7fffffffffffffffULL
 
@@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUSPARCState *env)
     qemu_cpu_kick(env);
 }
 
-static void cpu_set_irq(void *opaque, int irq, int level)
+static void cpu_set_ivec_irq(void *opaque, int irq, int level)
 {
     CPUSPARCState *env = opaque;
 
     if (level) {
-        CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
-        env->pil_in |= 1 << irq;
-        cpu_kick_irq(env);
-    } else {
-        CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
-        env->pil_in &= ~(1 << irq);
-        cpu_check_irqs(env);
+        CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
+        env->interrupt_index = TT_IVEC;
+        env->pil_in |= 1 << 5;
+        env->ivec_status |= 0x20;
+        env->ivec_data[0] = (0x1f << 6) | irq;
+        env->ivec_data[1] = 0;
+        env->ivec_data[2] = 0;
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+      } else {
+        CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+        env->pil_in &= ~(1 << 5);
+        env->ivec_status &= ~0x20;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
     }
 }
 
-static void dummy_isa_irq_handler(void *opaque, int n, int level)
+static void isa_irq_handler(void *opaque, int n, int level)
 {
+    static const int isa_irq_to_ivec[16] = {
+        [1] = 0x29, /* keyboard */
+        [4] = 0x2b, /* serial */
+        [6] = 0x27, /* floppy */
+        [7] = 0x22, /* parallel */
+        [12] = 0x2a, /* mouse */
+    };
+    qemu_irq *irqs = opaque;
+    int ivec;
+
+    assert(n < 16);
+    ivec = isa_irq_to_ivec[n];
+    EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
+    if (ivec) {
+        qemu_set_irq(irqs[ivec], level);
+    }
 }
 
 /* EBUS (Eight bit bus) bridge */
 static ISABus *
-pci_ebus_init(PCIBus *bus, int devfn)
+pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
 {
     qemu_irq *isa_irq;
     PCIDevice *pci_dev;
@@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
     pci_dev = pci_create_simple(bus, devfn, "ebus");
     isa_bus = DO_UPCAST(ISABus, qbus,
                         qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
-    isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
+    isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
     isa_bus_irqs(isa_bus, isa_irq);
     return isa_bus;
 }
@@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
     long initrd_size, kernel_size;
     PCIBus *pci_bus, *pci_bus2, *pci_bus3;
     ISABus *isa_bus;
-    qemu_irq *irq;
+    qemu_irq *ivec_irqs, *pbm_irqs;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     DriveInfo *fd[MAX_FD];
     void *fw_cfg;
@@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
 
     prom_init(hwdef->prom_addr, bios_name);
 
-
-    irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
-    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
-                           &pci_bus3);
+    ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX);
+    pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
+                           &pci_bus3, &pbm_irqs);
     pci_vga_init(pci_bus);
 
     // XXX Should be pci_bus3
-    isa_bus = pci_ebus_init(pci_bus, -1);
+    isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
 
     i = 0;
     if (hwdef->console_serial_base) {
diff --git a/hw/xics.c b/hw/xics.c
index f7963f3096..668a0d6484 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -132,9 +132,9 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
 {
     struct icp_server_state *ss = icp->ss + server;
 
-    ics_eoi(icp->ics, xirr & XISR_MASK);
     /* Send EOI -> ICS */
     ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+    ics_eoi(icp->ics, xirr & XISR_MASK);
     if (!XISR(ss)) {
         icp_resend(icp, server);
     }
@@ -165,8 +165,9 @@ struct ics_irq_state {
     int server;
     uint8_t priority;
     uint8_t saved_priority;
-    /* int pending:1; */
-    /* int presented:1; */
+    enum xics_irq_type type;
+    int asserted:1;
+    int sent:1;
     int rejected:1;
     int masked_pending:1;
 };
@@ -185,9 +186,32 @@ static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
         && (nr < (ics->offset + ics->nr_irqs));
 }
 
-static void ics_set_irq_msi(void *opaque, int srcno, int val)
+static void resend_msi(struct ics_state *ics, int srcno)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    /* FIXME: filter by server#? */
+    if (irq->rejected) {
+        irq->rejected = 0;
+        if (irq->priority != 0xff) {
+            icp_irq(ics->icp, irq->server, srcno + ics->offset,
+                    irq->priority);
+        }
+    }
+}
+
+static void resend_lsi(struct ics_state *ics, int srcno)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    if ((irq->priority != 0xff) && irq->asserted && !irq->sent) {
+        irq->sent = 1;
+        icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
+    }
+}
+
+static void set_irq_msi(struct ics_state *ics, int srcno, int val)
 {
-    struct ics_state *ics = (struct ics_state *)opaque;
     struct ics_irq_state *irq = ics->irqs + srcno;
 
     if (val) {
@@ -200,71 +224,108 @@ static void ics_set_irq_msi(void *opaque, int srcno, int val)
     }
 }
 
-static void ics_reject_msi(struct ics_state *ics, int nr)
+static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
 {
-    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+    struct ics_irq_state *irq = ics->irqs + srcno;
 
-    irq->rejected = 1;
+    irq->asserted = val;
+    resend_lsi(ics, srcno);
 }
 
-static void ics_resend_msi(struct ics_state *ics)
+static void ics_set_irq(void *opaque, int srcno, int val)
 {
-    int i;
+    struct ics_state *ics = (struct ics_state *)opaque;
+    struct ics_irq_state *irq = ics->irqs + srcno;
 
-    for (i = 0; i < ics->nr_irqs; i++) {
-        struct ics_irq_state *irq = ics->irqs + i;
+    if (irq->type == XICS_LSI) {
+        set_irq_lsi(ics, srcno, val);
+    } else {
+        set_irq_msi(ics, srcno, val);
+    }
+}
 
-        /* FIXME: filter by server#? */
-        if (irq->rejected) {
-            irq->rejected = 0;
-            if (irq->priority != 0xff) {
-                icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
-            }
-        }
+static void write_xive_msi(struct ics_state *ics, int srcno)
+{
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    if (!irq->masked_pending || (irq->priority == 0xff)) {
+        return;
     }
+
+    irq->masked_pending = 0;
+    icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
 }
 
-static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
-                               uint8_t priority)
+static void write_xive_lsi(struct ics_state *ics, int srcno)
 {
-    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+    resend_lsi(ics, srcno);
+}
+
+static void ics_write_xive(struct ics_state *ics, int nr, int server,
+                           uint8_t priority)
+{
+    int srcno = nr - ics->offset;
+    struct ics_irq_state *irq = ics->irqs + srcno;
 
     irq->server = server;
     irq->priority = priority;
 
-    if (!irq->masked_pending || (priority == 0xff)) {
-        return;
+    if (irq->type == XICS_LSI) {
+        write_xive_lsi(ics, srcno);
+    } else {
+        write_xive_msi(ics, srcno);
     }
-
-    irq->masked_pending = 0;
-    icp_irq(ics->icp, server, nr, priority);
 }
 
 static void ics_reject(struct ics_state *ics, int nr)
 {
-    ics_reject_msi(ics, nr);
+    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+    irq->rejected = 1; /* Irrelevant but harmless for LSI */
+    irq->sent = 0; /* Irrelevant but harmless for MSI */
 }
 
 static void ics_resend(struct ics_state *ics)
 {
-    ics_resend_msi(ics);
+    int i;
+
+    for (i = 0; i < ics->nr_irqs; i++) {
+        struct ics_irq_state *irq = ics->irqs + i;
+
+        /* FIXME: filter by server#? */
+        if (irq->type == XICS_LSI) {
+            resend_lsi(ics, i);
+        } else {
+            resend_msi(ics, i);
+        }
+    }
 }
 
 static void ics_eoi(struct ics_state *ics, int nr)
 {
+    int srcno = nr - ics->offset;
+    struct ics_irq_state *irq = ics->irqs + srcno;
+
+    if (irq->type == XICS_LSI) {
+        irq->sent = 0;
+    }
 }
 
 /*
  * Exported functions
  */
 
-qemu_irq xics_find_qirq(struct icp_state *icp, int irq)
+qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
+                         enum xics_irq_type type)
 {
     if ((irq < icp->ics->offset)
         || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
         return NULL;
     }
 
+    assert((type == XICS_MSI) || (type == XICS_LSI));
+
+    icp->ics->irqs[irq - icp->ics->offset].type = type;
     return icp->ics->qirqs[irq - icp->ics->offset];
 }
 
@@ -332,7 +393,7 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
         return;
     }
 
-    ics_write_xive_msi(ics, nr, server, priority);
+    ics_write_xive(ics, nr, server, priority);
 
     rtas_st(rets, 0, 0); /* Success */
 }
@@ -477,7 +538,7 @@ struct icp_state *xics_system_init(int nr_irqs)
         ics->irqs[i].saved_priority = 0xff;
     }
 
-    ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs);
+    ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs);
 
     spapr_register_hypercall(H_CPPR, h_cppr);
     spapr_register_hypercall(H_IPI, h_ipi);
diff --git a/hw/xics.h b/hw/xics.h
index 83c1182598..208015939c 100644
--- a/hw/xics.h
+++ b/hw/xics.h
@@ -31,7 +31,13 @@
 
 struct icp_state;
 
-qemu_irq xics_find_qirq(struct icp_state *icp, int irq);
+enum xics_irq_type {
+    XICS_MSI,        /* Message-signalled (edge) interrupt */
+    XICS_LSI,        /* Level-signalled interrupt */
+};
+
+qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
+                         enum xics_irq_type type);
 
 struct icp_state *xics_system_init(int nr_irqs);
 
diff --git a/kvm-all.c b/kvm-all.c
index 42e5e23d5d..ba2cee10f2 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -79,7 +79,10 @@ struct KVMState
     int pit_state2;
     int xsave, xcrs;
     int many_ioeventfds;
-    int irqchip_inject_ioctl;
+    /* The man page (and posix) say ioctl numbers are signed int, but
+     * they're not.  Linux, glibc and *BSD all treat ioctl numbers as
+     * unsigned, and treating them as signed here can break things */
+    unsigned irqchip_inject_ioctl;
 #ifdef KVM_CAP_IRQ_ROUTING
     struct kvm_irq_routing *irq_routes;
     int nr_allocated_irq_routes;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index fca51e2b11..b1e139d6fd 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4118,7 +4118,7 @@ static target_ulong get_sigframe(struct target_sigaction *ka,
     oldsp = env->gpr[1];
 
     if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
-        (sas_ss_flags(oldsp))) {
+        (sas_ss_flags(oldsp) == 0)) {
         oldsp = (target_sigaltstack_used.ss_sp
                  + target_sigaltstack_used.ss_size);
     }
diff --git a/osdep.h b/osdep.h
index 0350383711..156666e0ee 100644
--- a/osdep.h
+++ b/osdep.h
@@ -70,12 +70,6 @@
 #define inline always_inline
 #endif
 
-#ifdef __i386__
-#define REGPARM __attribute((regparm(3)))
-#else
-#define REGPARM
-#endif
-
 #define qemu_printf printf
 
 int qemu_daemon(int nochdir, int noclose);
diff --git a/pc-bios/README b/pc-bios/README
index 5dce355f56..71f48711b2 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
   implementation for certain IBM POWER hardware.  The sources are at
   https://github.com/dgibson/SLOF, and the image currently in qemu is
-  built from git tag qemu-slof-20120111.1.
+  built from git tag qemu-slof-20120217.
 
 - sgabios (the Serial Graphics Adapter option ROM) provides a means for
   legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 8554f54b57..449a7bb2af 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differdiff --git a/roms/SLOF b/roms/SLOF
-Subproject ab062ff3b37c39649f2b0d94ed607adc6f6b3c7
+Subproject d153364253548d6cd91403711f84996e6a7dab3
diff --git a/savevm.c b/savevm.c
index 5fdc3e1c56..962175ac34 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1486,6 +1486,8 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
                 n_elems = field->num;
             } else if (field->flags & VMS_VARRAY_INT32) {
                 n_elems = *(int32_t *)(opaque+field->num_offset);
+            } else if (field->flags & VMS_VARRAY_UINT32) {
+                n_elems = *(uint32_t *)(opaque+field->num_offset);
             } else if (field->flags & VMS_VARRAY_UINT16) {
                 n_elems = *(uint16_t *)(opaque+field->num_offset);
             } else if (field->flags & VMS_VARRAY_UINT8) {
diff --git a/softmmu_defs.h b/softmmu_defs.h
index c5a2bcd3e2..8d59f9d4f8 100644
--- a/softmmu_defs.h
+++ b/softmmu_defs.h
@@ -9,22 +9,50 @@
 #ifndef SOFTMMU_DEFS_H
 #define SOFTMMU_DEFS_H
 
-uint8_t REGPARM __ldb_mmu(target_ulong addr, int mmu_idx);
-void REGPARM __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx);
-uint16_t REGPARM __ldw_mmu(target_ulong addr, int mmu_idx);
-void REGPARM __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx);
-uint32_t REGPARM __ldl_mmu(target_ulong addr, int mmu_idx);
-void REGPARM __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx);
-uint64_t REGPARM __ldq_mmu(target_ulong addr, int mmu_idx);
-void REGPARM __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx);
+#ifndef CONFIG_TCG_PASS_AREG0
+uint8_t __ldb_mmu(target_ulong addr, int mmu_idx);
+void __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx);
+uint16_t __ldw_mmu(target_ulong addr, int mmu_idx);
+void __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx);
+uint32_t __ldl_mmu(target_ulong addr, int mmu_idx);
+void __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx);
+uint64_t __ldq_mmu(target_ulong addr, int mmu_idx);
+void __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx);
 
-uint8_t REGPARM __ldb_cmmu(target_ulong addr, int mmu_idx);
-void REGPARM __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx);
-uint16_t REGPARM __ldw_cmmu(target_ulong addr, int mmu_idx);
-void REGPARM __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx);
-uint32_t REGPARM __ldl_cmmu(target_ulong addr, int mmu_idx);
-void REGPARM __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx);
-uint64_t REGPARM __ldq_cmmu(target_ulong addr, int mmu_idx);
-void REGPARM __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx);
+uint8_t __ldb_cmmu(target_ulong addr, int mmu_idx);
+void __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx);
+uint16_t __ldw_cmmu(target_ulong addr, int mmu_idx);
+void __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx);
+uint32_t __ldl_cmmu(target_ulong addr, int mmu_idx);
+void __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx);
+uint64_t __ldq_cmmu(target_ulong addr, int mmu_idx);
+void __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx);
+#else
+uint8_t helper_ldb_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
+                    int mmu_idx);
+uint16_t helper_ldw_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
+                    int mmu_idx);
+uint32_t helper_ldl_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
+                    int mmu_idx);
+uint64_t helper_ldq_mmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
+                    int mmu_idx);
+
+uint8_t helper_ldb_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stb_cmmu(CPUArchState *env, target_ulong addr, uint8_t val,
+int mmu_idx);
+uint16_t helper_ldw_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stw_cmmu(CPUArchState *env, target_ulong addr, uint16_t val,
+                     int mmu_idx);
+uint32_t helper_ldl_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stl_cmmu(CPUArchState *env, target_ulong addr, uint32_t val,
+                     int mmu_idx);
+uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
+void helper_stq_cmmu(CPUArchState *env, target_ulong addr, uint64_t val,
+                     int mmu_idx);
+#endif
 
 #endif
diff --git a/softmmu_header.h b/softmmu_header.h
index 818d7b662e..6b72093a0c 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -78,9 +78,23 @@
 #define ADDR_READ addr_read
 #endif
 
+#ifndef CONFIG_TCG_PASS_AREG0
+#define ENV_PARAM
+#define ENV_VAR
+#define CPU_PREFIX
+#define HELPER_PREFIX __
+#else
+#define ENV_PARAM CPUArchState *env,
+#define ENV_VAR env,
+#define CPU_PREFIX cpu_
+#define HELPER_PREFIX helper_
+#endif
+
 /* generic load/store macros */
 
-static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
+static inline RES_TYPE
+glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM
+                                                     target_ulong ptr)
 {
     int page_index;
     RES_TYPE res;
@@ -93,7 +107,9 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
     mmu_idx = CPU_MMU_INDEX;
     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
-        res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
+        res = glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_VAR
+                                                                     addr,
+                                                                     mmu_idx);
     } else {
         physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
         res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
@@ -102,7 +118,9 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
 }
 
 #if DATA_SIZE <= 2
-static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
+static inline int
+glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM
+                                                     target_ulong ptr)
 {
     int res, page_index;
     target_ulong addr;
@@ -114,7 +132,8 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
     mmu_idx = CPU_MMU_INDEX;
     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
-        res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
+        res = (DATA_STYPE)glue(glue(glue(HELPER_PREFIX, ld), SUFFIX),
+                               MMUSUFFIX)(ENV_VAR addr, mmu_idx);
     } else {
         physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
         res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
@@ -127,7 +146,9 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
 
 /* generic store macro */
 
-static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
+static inline void
+glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr,
+                                                    RES_TYPE v)
 {
     int page_index;
     target_ulong addr;
@@ -139,7 +160,8 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
     mmu_idx = CPU_MMU_INDEX;
     if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write !=
                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
-        glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx);
+        glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_VAR addr, v,
+                                                               mmu_idx);
     } else {
         physaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
         glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
@@ -151,46 +173,52 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
 #if ACCESS_TYPE != (NB_MMU_MODES + 1)
 
 #if DATA_SIZE == 8
-static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr)
+static inline float64 glue(glue(CPU_PREFIX, ldfq), MEMSUFFIX)(ENV_PARAM
+                                                              target_ulong ptr)
 {
     union {
         float64 d;
         uint64_t i;
     } u;
-    u.i = glue(ldq, MEMSUFFIX)(ptr);
+    u.i = glue(glue(CPU_PREFIX, ldq), MEMSUFFIX)(ENV_VAR ptr);
     return u.d;
 }
 
-static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v)
+static inline void glue(glue(CPU_PREFIX, stfq), MEMSUFFIX)(ENV_PARAM
+                                                           target_ulong ptr,
+                                                           float64 v)
 {
     union {
         float64 d;
         uint64_t i;
     } u;
     u.d = v;
-    glue(stq, MEMSUFFIX)(ptr, u.i);
+    glue(glue(CPU_PREFIX, stq), MEMSUFFIX)(ENV_VAR ptr, u.i);
 }
 #endif /* DATA_SIZE == 8 */
 
 #if DATA_SIZE == 4
-static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr)
+static inline float32 glue(glue(CPU_PREFIX, ldfl), MEMSUFFIX)(ENV_PARAM
+                                                              target_ulong ptr)
 {
     union {
         float32 f;
         uint32_t i;
     } u;
-    u.i = glue(ldl, MEMSUFFIX)(ptr);
+    u.i = glue(glue(CPU_PREFIX, ldl), MEMSUFFIX)(ENV_VAR ptr);
     return u.f;
 }
 
-static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v)
+static inline void glue(glue(CPU_PREFIX, stfl), MEMSUFFIX)(ENV_PARAM
+                                                           target_ulong ptr,
+                                                           float32 v)
 {
     union {
         float32 f;
         uint32_t i;
     } u;
     u.f = v;
-    glue(stl, MEMSUFFIX)(ptr, u.i);
+    glue(glue(CPU_PREFIX, stl), MEMSUFFIX)(ENV_VAR ptr, u.i);
 }
 #endif /* DATA_SIZE == 4 */
 
@@ -205,3 +233,7 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v)
 #undef CPU_MMU_INDEX
 #undef MMUSUFFIX
 #undef ADDR_READ
+#undef ENV_PARAM
+#undef ENV_VAR
+#undef CPU_PREFIX
+#undef HELPER_PREFIX
diff --git a/softmmu_template.h b/softmmu_template.h
index e3950204cd..afcab1e6a9 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -54,10 +54,24 @@
 #define ADDR_READ addr_read
 #endif
 
-static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
+#ifndef CONFIG_TCG_PASS_AREG0
+#define ENV_PARAM
+#define ENV_VAR
+#define CPU_PREFIX
+#define HELPER_PREFIX __
+#else
+#define ENV_PARAM CPUArchState *env,
+#define ENV_VAR env,
+#define CPU_PREFIX cpu_
+#define HELPER_PREFIX helper_
+#endif
+
+static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
+                                                        target_ulong addr,
                                                         int mmu_idx,
                                                         void *retaddr);
-static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
+static inline DATA_TYPE glue(io_read, SUFFIX)(ENV_PARAM
+                                              target_phys_addr_t physaddr,
                                               target_ulong addr,
                                               void *retaddr)
 {
@@ -89,8 +103,10 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
 }
 
 /* handle all cases except unaligned access which span two pages */
-DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                      int mmu_idx)
+DATA_TYPE
+glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM
+                                                       target_ulong addr,
+                                                       int mmu_idx)
 {
     DATA_TYPE res;
     int index;
@@ -111,22 +127,22 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
                 goto do_unaligned_access;
             retaddr = GETPC();
             ioaddr = env->iotlb[mmu_idx][index];
-            res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
+            res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
             /* slow unaligned access (it spans two pages or IO) */
         do_unaligned_access:
             retaddr = GETPC();
 #ifdef ALIGNED_ONLY
-            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+            do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 #endif
-            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
+            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr,
                                                          mmu_idx, retaddr);
         } else {
             /* unaligned/aligned access in the same page */
 #ifdef ALIGNED_ONLY
             if ((addr & (DATA_SIZE - 1)) != 0) {
                 retaddr = GETPC();
-                do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+                do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
             }
 #endif
             addend = env->tlb_table[mmu_idx][index].addend;
@@ -137,7 +153,7 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
         retaddr = GETPC();
 #ifdef ALIGNED_ONLY
         if ((addr & (DATA_SIZE - 1)) != 0)
-            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+            do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 #endif
         tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
@@ -146,9 +162,11 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
 }
 
 /* handle all unaligned cases */
-static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                        int mmu_idx,
-                                                        void *retaddr)
+static DATA_TYPE
+glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM
+                                       target_ulong addr,
+                                       int mmu_idx,
+                                       void *retaddr)
 {
     DATA_TYPE res, res1, res2;
     int index, shift;
@@ -165,15 +183,15 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
             ioaddr = env->iotlb[mmu_idx][index];
-            res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr);
+            res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
             /* slow unaligned access (it spans two pages) */
             addr1 = addr & ~(DATA_SIZE - 1);
             addr2 = addr1 + DATA_SIZE;
-            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
+            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr1,
                                                           mmu_idx, retaddr);
-            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
+            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr2,
                                                           mmu_idx, retaddr);
             shift = (addr & (DATA_SIZE - 1)) * 8;
 #ifdef TARGET_WORDS_BIGENDIAN
@@ -197,12 +215,14 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
 #ifndef SOFTMMU_CODE_ACCESS
 
-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM
+                                                   target_ulong addr,
                                                    DATA_TYPE val,
                                                    int mmu_idx,
                                                    void *retaddr);
 
-static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
+static inline void glue(io_write, SUFFIX)(ENV_PARAM
+                                          target_phys_addr_t physaddr,
                                           DATA_TYPE val,
                                           target_ulong addr,
                                           void *retaddr)
@@ -232,9 +252,10 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
 #endif /* SHIFT > 2 */
 }
 
-void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
-                                                 DATA_TYPE val,
-                                                 int mmu_idx)
+void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM
+                                                            target_ulong addr,
+                                                            DATA_TYPE val,
+                                                            int mmu_idx)
 {
     target_phys_addr_t ioaddr;
     unsigned long addend;
@@ -252,21 +273,21 @@ void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
                 goto do_unaligned_access;
             retaddr = GETPC();
             ioaddr = env->iotlb[mmu_idx][index];
-            glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
+            glue(io_write, SUFFIX)(ENV_VAR ioaddr, val, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
             retaddr = GETPC();
 #ifdef ALIGNED_ONLY
-            do_unaligned_access(addr, 1, mmu_idx, retaddr);
+            do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr);
 #endif
-            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
+            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_VAR addr, val,
                                                    mmu_idx, retaddr);
         } else {
             /* aligned/unaligned access in the same page */
 #ifdef ALIGNED_ONLY
             if ((addr & (DATA_SIZE - 1)) != 0) {
                 retaddr = GETPC();
-                do_unaligned_access(addr, 1, mmu_idx, retaddr);
+                do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr);
             }
 #endif
             addend = env->tlb_table[mmu_idx][index].addend;
@@ -277,7 +298,7 @@ void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
         retaddr = GETPC();
 #ifdef ALIGNED_ONLY
         if ((addr & (DATA_SIZE - 1)) != 0)
-            do_unaligned_access(addr, 1, mmu_idx, retaddr);
+            do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr);
 #endif
         tlb_fill(env, addr, 1, mmu_idx, retaddr);
         goto redo;
@@ -285,7 +306,8 @@ void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
 }
 
 /* handles all unaligned cases */
-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM
+                                                   target_ulong addr,
                                                    DATA_TYPE val,
                                                    int mmu_idx,
                                                    void *retaddr)
@@ -304,7 +326,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
             ioaddr = env->iotlb[mmu_idx][index];
-            glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr);
+            glue(io_write, SUFFIX)(ENV_VAR ioaddr, val, addr, retaddr);
         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
             /* XXX: not efficient, but simple */
@@ -312,10 +334,12 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
              * previous page from the TLB cache.  */
             for(i = DATA_SIZE - 1; i >= 0; i--) {
 #ifdef TARGET_WORDS_BIGENDIAN
-                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
+                glue(slow_stb, MMUSUFFIX)(ENV_VAR addr + i,
+                                          val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
                                           mmu_idx, retaddr);
 #else
-                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
+                glue(slow_stb, MMUSUFFIX)(ENV_VAR addr + i,
+                                          val >> (i * 8),
                                           mmu_idx, retaddr);
 #endif
             }
@@ -340,3 +364,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
 #undef USUFFIX
 #undef DATA_SIZE
 #undef ADDR_READ
+#undef ENV_PARAM
+#undef ENV_VAR
+#undef CPU_PREFIX
+#undef HELPER_PREFIX
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 8a08db8d57..1314f23d59 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -877,7 +877,8 @@ static void do_interrupt_v7m(CPUARMState *env)
     v7m_push(env, env->regs[1]);
     v7m_push(env, env->regs[0]);
     switch_v7m_sp(env, 0);
-    env->uncached_cpsr &= ~CPSR_IT;
+    /* Clear IT bits */
+    env->condexec_bits = 0;
     env->regs[14] = lr;
     addr = ldl_phys(env->v7m.vecbase + env->v7m.exception * 4);
     env->regs[15] = addr & 0xfffffffe;
@@ -2025,7 +2026,7 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn)
             return env->cp15.c5_data;
         case 1:
             if (arm_feature(env, ARM_FEATURE_MPU))
-                return simple_mpu_ap_bits(env->cp15.c5_data);
+                return simple_mpu_ap_bits(env->cp15.c5_insn);
             return env->cp15.c5_insn;
         case 2:
             if (!arm_feature(env, ARM_FEATURE_MPU))
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 2709010f4a..81725d1687 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -9704,32 +9704,49 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
             store_reg(s, rd, tmp);
             break;
 
-        case 6: /* cps */
-            ARCH(6);
-            if (IS_USER(s))
+        case 6:
+            switch ((insn >> 5) & 7) {
+            case 2:
+                /* setend */
+                ARCH(6);
+                if (insn & (1 << 3)) {
+                    /* BE8 mode not implemented.  */
+                    goto illegal_op;
+                }
                 break;
-            if (IS_M(env)) {
-                tmp = tcg_const_i32((insn & (1 << 4)) != 0);
-                /* FAULTMASK */
-                if (insn & 1) {
-                    addr = tcg_const_i32(19);
-                    gen_helper_v7m_msr(cpu_env, addr, tmp);
-                    tcg_temp_free_i32(addr);
+            case 3:
+                /* cps */
+                ARCH(6);
+                if (IS_USER(s)) {
+                    break;
                 }
-                /* PRIMASK */
-                if (insn & 2) {
-                    addr = tcg_const_i32(16);
-                    gen_helper_v7m_msr(cpu_env, addr, tmp);
-                    tcg_temp_free_i32(addr);
+                if (IS_M(env)) {
+                    tmp = tcg_const_i32((insn & (1 << 4)) != 0);
+                    /* FAULTMASK */
+                    if (insn & 1) {
+                        addr = tcg_const_i32(19);
+                        gen_helper_v7m_msr(cpu_env, addr, tmp);
+                        tcg_temp_free_i32(addr);
+                    }
+                    /* PRIMASK */
+                    if (insn & 2) {
+                        addr = tcg_const_i32(16);
+                        gen_helper_v7m_msr(cpu_env, addr, tmp);
+                        tcg_temp_free_i32(addr);
+                    }
+                    tcg_temp_free_i32(tmp);
+                    gen_lookup_tb(s);
+                } else {
+                    if (insn & (1 << 4)) {
+                        shift = CPSR_A | CPSR_I | CPSR_F;
+                    } else {
+                        shift = 0;
+                    }
+                    gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
                 }
-                tcg_temp_free_i32(tmp);
-                gen_lookup_tb(s);
-            } else {
-                if (insn & (1 << 4))
-                    shift = CPSR_A | CPSR_I | CPSR_F;
-                else
-                    shift = 0;
-                gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
+                break;
+            default:
+                goto undef;
             }
             break;
 
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index ad09cbe06a..ca6f1cb58c 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1918,8 +1918,10 @@ enum {
     PPC2_DFP           = 0x0000000000000004ULL,
     /* Embedded.Processor Control                                            */
     PPC2_PRCNTL        = 0x0000000000000008ULL,
+    /* Byte-reversed, indexed, double-word load and store                    */
+    PPC2_DBRX          = 0x0000000000000010ULL,
 
-#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL)
+#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX)
 };
 
 /*****************************************************************************/
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index bd711b6e22..39dcc273e5 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -591,12 +591,6 @@ static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
                 pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
             }
 
-            /* We have a TLB that saves 4K pages, so let's
-             * split a huge page to 4k chunks */
-            if (target_page_bits != TARGET_PAGE_BITS)
-                pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1))
-                        & TARGET_PAGE_MASK;
-
             r = pte64_check(ctx, pte0, pte1, h, rw, type);
             LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                     TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
@@ -672,6 +666,12 @@ static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
         }
     }
 
+    /* We have a TLB that saves 4K pages, so let's
+     * split a huge page to 4k chunks */
+    if (target_page_bits != TARGET_PAGE_BITS) {
+        ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
+                      & TARGET_PAGE_MASK;
+    }
     return ret;
 }
 
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index aeb3de9ae7..724f4c7815 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -843,12 +843,18 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
     int fd;
     void *table;
 
+    /* Must set fd to -1 so we don't try to munmap when called for
+     * destroying the table, which the upper layers -will- do
+     */
+    *pfd = -1;
     if (!cap_spapr_tce) {
         return NULL;
     }
 
     fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args);
     if (fd < 0) {
+        fprintf(stderr, "KVM: Failed to create TCE table for liobn 0x%x\n",
+                liobn);
         return NULL;
     }
 
@@ -857,6 +863,8 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
 
     table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     if (table == MAP_FAILED) {
+        fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n",
+                liobn);
         close(fd);
         return NULL;
     }
@@ -876,8 +884,8 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
     len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE);
     if ((munmap(table, len) < 0) ||
         (close(fd) < 0)) {
-        fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE "
-                "table: %s", strerror(errno));
+        fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",
+                strerror(errno));
         /* Leak the table */
     }
 
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 3ec59a7eeb..c9a503a1db 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2650,7 +2650,7 @@ static void glue(gen_, name##ux)(DisasContext *ctx)
     tcg_temp_free(EA);                                                        \
 }
 
-#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
+#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2)                        \
 static void glue(gen_, name##x)(DisasContext *ctx)                            \
 {                                                                             \
     TCGv EA;                                                                  \
@@ -2660,6 +2660,8 @@ static void glue(gen_, name##x)(DisasContext *ctx)                            \
     gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
     tcg_temp_free(EA);                                                        \
 }
+#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
+    GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE)
 
 #define GEN_LDS(name, ldop, op, type)                                         \
 GEN_LD(name, ldop, op | 0x20, type);                                          \
@@ -2793,8 +2795,8 @@ static void glue(gen_, name##ux)(DisasContext *ctx)
     tcg_temp_free(EA);                                                        \
 }
 
-#define GEN_STX(name, stop, opc2, opc3, type)                                 \
-static void glue(gen_, name##x)(DisasContext *ctx)                                    \
+#define GEN_STX_E(name, stop, opc2, opc3, type, type2)                        \
+static void glue(gen_, name##x)(DisasContext *ctx)                            \
 {                                                                             \
     TCGv EA;                                                                  \
     gen_set_access_type(ctx, ACCESS_INT);                                     \
@@ -2803,6 +2805,8 @@ static void glue(gen_, name##x)(DisasContext *ctx)
     gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
     tcg_temp_free(EA);                                                        \
 }
+#define GEN_STX(name, stop, opc2, opc3, type)                                 \
+    GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE)
 
 #define GEN_STS(name, stop, op, type)                                         \
 GEN_ST(name, stop, op | 0x20, type);                                          \
@@ -2891,6 +2895,18 @@ static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
 }
 GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
 
+#if defined(TARGET_PPC64)
+/* ldbrx */
+static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
+    if (likely(!ctx->le_mode)) {
+        tcg_gen_bswap64_tl(arg1, arg1);
+    }
+}
+GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX);
+#endif  /* TARGET_PPC64 */
+
 /* sthbrx */
 static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
@@ -2921,6 +2937,22 @@ static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2)
 }
 GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
 
+#if defined(TARGET_PPC64)
+/* stdbrx */
+static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2)
+{
+    if (likely(!ctx->le_mode)) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_bswap64_tl(t0, arg1);
+        tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx);
+    }
+}
+GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX);
+#endif  /* TARGET_PPC64 */
+
 /***                    Integer load and store multiple                    ***/
 
 /* lmw */
@@ -8818,7 +8850,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT),
 #undef GEN_LD
 #undef GEN_LDU
 #undef GEN_LDUX
-#undef GEN_LDX
+#undef GEN_LDX_E
 #undef GEN_LDS
 #define GEN_LD(name, ldop, opc, type)                                         \
 GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
@@ -8826,8 +8858,8 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
 GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
 #define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
 GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type),
-#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
-GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2)                        \
+GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),
 #define GEN_LDS(name, ldop, op, type)                                         \
 GEN_LD(name, ldop, op | 0x20, type)                                           \
 GEN_LDU(name, ldop, op | 0x21, type)                                          \
@@ -8843,6 +8875,7 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B)
 GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B)
 GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B)
 GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B)
+GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX)
 #endif
 GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)
 GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
@@ -8850,7 +8883,7 @@ GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
 #undef GEN_ST
 #undef GEN_STU
 #undef GEN_STUX
-#undef GEN_STX
+#undef GEN_STX_E
 #undef GEN_STS
 #define GEN_ST(name, stop, opc, type)                                         \
 GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
@@ -8858,8 +8891,8 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
 GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type),
 #define GEN_STUX(name, stop, opc2, opc3, type)                                \
 GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type),
-#define GEN_STX(name, stop, opc2, opc3, type)                                 \
-GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_STX_E(name, stop, opc2, opc3, type, type2)                        \
+GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),
 #define GEN_STS(name, stop, op, type)                                         \
 GEN_ST(name, stop, op | 0x20, type)                                           \
 GEN_STU(name, stop, op | 0x21, type)                                          \
@@ -8872,6 +8905,7 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER)
 #if defined(TARGET_PPC64)
 GEN_STUX(std, st64, 0x15, 0x05, PPC_64B)
 GEN_STX(std, st64, 0x15, 0x04, PPC_64B)
+GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX)
 #endif
 GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
 GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
@@ -9285,6 +9319,8 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf,
 
     int i;
 
+    cpu_synchronize_state(env);
+
     cpu_fprintf(f, "NIP " TARGET_FMT_lx "   LR " TARGET_FMT_lx " CTR "
                 TARGET_FMT_lx " XER " TARGET_FMT_lx "\n",
                 env->nip, env->lr, env->ctr, env->xer);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 1ec6f4248f..367eefaf9e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -6571,7 +6571,7 @@ static void init_proc_970MP (CPUPPCState *env)
                               PPC_64B | PPC_ALTIVEC |                         \
                               PPC_SEGMENT_64B | PPC_SLBI |                    \
                               PPC_POPCNTB | PPC_POPCNTWD)
-#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP)
+#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP | PPC2_DBRX)
 #define POWERPC_MSRM_POWER7   (0x800000000204FF36ULL)
 #define POWERPC_MMU_POWER7    (POWERPC_MMU_2_06)
 #define POWERPC_EXCP_POWER7   (POWERPC_EXCP_POWER7)
@@ -6588,6 +6588,11 @@ static void init_proc_POWER7 (CPUPPCState *env)
     gen_spr_7xx(env);
     /* Time base */
     gen_tbl(env);
+    /* Processor identification */
+    spr_register(env, SPR_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
 #if !defined(CONFIG_USER_ONLY)
     /* PURR & SPURR: Hack - treat these as aliases for the TB for now */
     spr_register(env, SPR_PURR,   "PURR",
@@ -6713,7 +6718,7 @@ static void init_proc_620 (CPUPPCState *env)
 #if defined (TARGET_PPC64) && 0 // XXX: TODO
 #define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC64
 #define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC64
-#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC64
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS2_PPC64
 #define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC64
 #define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC64
 #define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC64
@@ -6725,7 +6730,7 @@ static void init_proc_620 (CPUPPCState *env)
 #else
 #define CPU_POWERPC_DEFAULT    CPU_POWERPC_PPC32
 #define POWERPC_INSNS_DEFAULT  POWERPC_INSNS_PPC32
-#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC32
+#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS2_PPC32
 #define POWERPC_MSRM_DEFAULT   POWERPC_MSRM_PPC32
 #define POWERPC_MMU_DEFAULT    POWERPC_MMU_PPC32
 #define POWERPC_EXCP_DEFAULT   POWERPC_EXCP_PPC32
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 86f9de6cfe..1025752e8f 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -415,14 +415,15 @@ struct CPUSPARCState {
 #if !defined(TARGET_SPARC64)
     int      psref;    /* enable fpu */
 #endif
-    target_ulong version;
     int interrupt_index;
-    uint32_t nwindows;
     /* NOTE: we allow 8 more registers to handle wrapping */
     target_ulong regbase[MAX_NWINDOWS * 16 + 8];
 
     CPU_COMMON
 
+    target_ulong version;
+    uint32_t nwindows;
+
     /* MMU regs */
 #if defined(TARGET_SPARC64)
     uint64_t lsu;
@@ -492,6 +493,9 @@ struct CPUSPARCState {
     /* UA 2005 hyperprivileged registers */
     uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
     CPUTimer *hstick; // UA 2005
+    /* Interrupt vector registers */
+    uint64_t ivec_status;
+    uint64_t ivec_data[3];
     uint32_t softint;
 #define SOFTINT_TIMER   1
 #define SOFTINT_STIMER  (1 << 16)
@@ -582,7 +586,6 @@ void cpu_unassigned_access(CPUSPARCState *env1, target_phys_addr_t addr,
 #if defined(TARGET_SPARC64)
 target_phys_addr_t cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
                                            int mmu_idx);
-
 #endif
 #endif
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
@@ -696,6 +699,8 @@ uint64_t cpu_tick_get_count(CPUTimer *timer);
 void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
 trap_state* cpu_tsptr(CPUSPARCState* env);
 #endif
+void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
+                         int is_user, void *retaddr);
 
 #define TB_FLAG_FPU_ENABLED (1 << 4)
 #define TB_FLAG_AM_ENABLED (1 << 5)
diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c
index 29132fb995..5c03f0b893 100644
--- a/target-sparc/cpu_init.c
+++ b/target-sparc/cpu_init.c
@@ -30,6 +30,7 @@ void cpu_state_reset(CPUSPARCState *env)
         log_cpu_state(env, 0);
     }
 
+    memset(env, 0, offsetof(CPUSPARCState, breakpoints));
     tlb_flush(env, 1);
     env->cwp = 0;
 #ifndef TARGET_SPARC64
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 1f67b08065..c4d6225102 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -18,11 +18,11 @@ DEF_HELPER_1(rdcwp, tl, env)
 DEF_HELPER_2(wrcwp, void, env, tl)
 DEF_HELPER_FLAGS_2(array8, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
 DEF_HELPER_1(popc, tl, tl)
-DEF_HELPER_3(ldda_asi, void, tl, int, int)
-DEF_HELPER_4(ldf_asi, void, tl, int, int, int)
-DEF_HELPER_4(stf_asi, void, tl, int, int, int)
-DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32)
-DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32)
+DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
+DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
+DEF_HELPER_5(stf_asi, void, env, tl, int, int, int)
+DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32)
+DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32)
 DEF_HELPER_2(set_softint, void, env, i64)
 DEF_HELPER_2(clear_softint, void, env, i64)
 DEF_HELPER_2(write_softint, void, env, i64)
@@ -30,7 +30,7 @@ DEF_HELPER_2(tick_set_count, void, ptr, i64)
 DEF_HELPER_1(tick_get_count, i64, ptr)
 DEF_HELPER_2(tick_set_limit, void, ptr, i64)
 #endif
-DEF_HELPER_2(check_align, void, tl, i32)
+DEF_HELPER_3(check_align, void, env, tl, i32)
 DEF_HELPER_1(debug, void, env)
 DEF_HELPER_1(save, void, env)
 DEF_HELPER_1(restore, void, env)
@@ -38,11 +38,11 @@ DEF_HELPER_3(udiv, tl, env, tl, tl)
 DEF_HELPER_3(udiv_cc, tl, env, tl, tl)
 DEF_HELPER_3(sdiv, tl, env, tl, tl)
 DEF_HELPER_3(sdiv_cc, tl, env, tl, tl)
-DEF_HELPER_2(ldqf, void, tl, int)
-DEF_HELPER_2(stqf, void, tl, int)
+DEF_HELPER_3(ldqf, void, env, tl, int)
+DEF_HELPER_3(stqf, void, env, tl, int)
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-DEF_HELPER_4(ld_asi, i64, tl, int, int, int)
-DEF_HELPER_4(st_asi, void, tl, i64, int, int)
+DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int)
+DEF_HELPER_5(st_asi, void, env, tl, i64, int, int)
 #endif
 DEF_HELPER_2(ldfsr, void, env, i32)
 DEF_HELPER_FLAGS_1(fabss, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 48d433c571..1418205f99 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -18,13 +18,8 @@
  */
 
 #include "cpu.h"
-#include "dyngen-exec.h"
 #include "helper.h"
 
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif
-
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
 //#define DEBUG_UNALIGNED
@@ -70,13 +65,21 @@
 #define QT1 (env->qt1)
 
 #if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size);
-#else
-#ifdef TARGET_SPARC64
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                                 int is_asi, int size);
-#endif
+#include "softmmu_exec.h"
+#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
 #endif
 
 #if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
@@ -300,7 +303,7 @@ static inline int is_translating_asi(int asi)
 #endif
 }
 
-static inline target_ulong asi_address_mask(CPUSPARCState *env1,
+static inline target_ulong asi_address_mask(CPUSPARCState *env,
                                             int asi, target_ulong addr)
 {
     if (is_translating_asi(asi)) {
@@ -310,7 +313,7 @@ static inline target_ulong asi_address_mask(CPUSPARCState *env1,
     }
 }
 
-void helper_check_align(target_ulong addr, uint32_t align)
+void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align)
 {
     if (addr & align) {
 #ifdef DEBUG_UNALIGNED
@@ -372,7 +375,8 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
 
 /* Leon3 cache control */
 
-static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+static void leon3_cache_control_st(CPUSPARCState *env, target_ulong addr,
+                                   uint64_t val, int size)
 {
     DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
                           addr, val, size);
@@ -404,7 +408,8 @@ static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
     };
 }
 
-static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+static uint64_t leon3_cache_control_ld(CPUSPARCState *env, target_ulong addr,
+                                       int size)
 {
     uint64_t ret = 0;
 
@@ -436,14 +441,15 @@ static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
     return ret;
 }
 
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
+                       int sign)
 {
     uint64_t ret = 0;
 #if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
     uint32_t last_addr = addr;
 #endif
 
-    helper_check_align(addr, size - 1);
+    helper_check_align(env, addr, size - 1);
     switch (asi) {
     case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
@@ -451,7 +457,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         case 0x08:          /* Leon3 Instruction Cache config */
         case 0x0C:          /* Leon3 Date Cache config */
             if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                ret = leon3_cache_control_ld(addr, size);
+                ret = leon3_cache_control_ld(env, addr, size);
             }
             break;
         case 0x01c00a00: /* MXCC control register */
@@ -535,51 +541,51 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     case 9: /* Supervisor code access */
         switch (size) {
         case 1:
-            ret = ldub_code(addr);
+            ret = cpu_ldub_code(env, addr);
             break;
         case 2:
-            ret = lduw_code(addr);
+            ret = cpu_lduw_code(env, addr);
             break;
         default:
         case 4:
-            ret = ldl_code(addr);
+            ret = cpu_ldl_code(env, addr);
             break;
         case 8:
-            ret = ldq_code(addr);
+            ret = cpu_ldq_code(env, addr);
             break;
         }
         break;
     case 0xa: /* User data access */
         switch (size) {
         case 1:
-            ret = ldub_user(addr);
+            ret = cpu_ldub_user(env, addr);
             break;
         case 2:
-            ret = lduw_user(addr);
+            ret = cpu_lduw_user(env, addr);
             break;
         default:
         case 4:
-            ret = ldl_user(addr);
+            ret = cpu_ldl_user(env, addr);
             break;
         case 8:
-            ret = ldq_user(addr);
+            ret = cpu_ldq_user(env, addr);
             break;
         }
         break;
     case 0xb: /* Supervisor data access */
         switch (size) {
         case 1:
-            ret = ldub_kernel(addr);
+            ret = cpu_ldub_kernel(env, addr);
             break;
         case 2:
-            ret = lduw_kernel(addr);
+            ret = cpu_lduw_kernel(env, addr);
             break;
         default:
         case 4:
-            ret = ldl_kernel(addr);
+            ret = cpu_ldl_kernel(env, addr);
             break;
         case 8:
-            ret = ldq_kernel(addr);
+            ret = cpu_ldq_kernel(env, addr);
             break;
         }
         break;
@@ -669,7 +675,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         break;
     case 8: /* User code access, XXX */
     default:
-        do_unassigned_access(addr, 0, 0, asi, size);
+        cpu_unassigned_access(env, addr, 0, 0, asi, size);
         ret = 0;
         break;
     }
@@ -694,9 +700,10 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     return ret;
 }
 
-void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
+void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi,
+                   int size)
 {
-    helper_check_align(addr, size - 1);
+    helper_check_align(env, addr, size - 1);
     switch (asi) {
     case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
@@ -704,7 +711,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
         case 0x08:          /* Leon3 Instruction Cache config */
         case 0x0C:          /* Leon3 Date Cache config */
             if (env->def->features & CPU_FEATURE_CACHE_CTRL) {
-                leon3_cache_control_st(addr, val, size);
+                leon3_cache_control_st(env, addr, val, size);
             }
             break;
 
@@ -902,34 +909,34 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
     case 0xa: /* User data access */
         switch (size) {
         case 1:
-            stb_user(addr, val);
+            cpu_stb_user(env, addr, val);
             break;
         case 2:
-            stw_user(addr, val);
+            cpu_stw_user(env, addr, val);
             break;
         default:
         case 4:
-            stl_user(addr, val);
+            cpu_stl_user(env, addr, val);
             break;
         case 8:
-            stq_user(addr, val);
+            cpu_stq_user(env, addr, val);
             break;
         }
         break;
     case 0xb: /* Supervisor data access */
         switch (size) {
         case 1:
-            stb_kernel(addr, val);
+            cpu_stb_kernel(env, addr, val);
             break;
         case 2:
-            stw_kernel(addr, val);
+            cpu_stw_kernel(env, addr, val);
             break;
         default:
         case 4:
-            stl_kernel(addr, val);
+            cpu_stl_kernel(env, addr, val);
             break;
         case 8:
-            stq_kernel(addr, val);
+            cpu_stq_kernel(env, addr, val);
             break;
         }
         break;
@@ -952,8 +959,8 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
             uint32_t src = val & ~3, dst = addr & ~3, temp;
 
             for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
-                temp = ldl_kernel(src);
-                stl_kernel(dst, temp);
+                temp = cpu_ldl_kernel(env, src);
+                cpu_stl_kernel(env, dst, temp);
             }
         }
         break;
@@ -965,7 +972,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
             uint32_t dst = addr & 7;
 
             for (i = 0; i < 32; i += 8, dst += 8) {
-                stq_kernel(dst, val);
+                cpu_stq_kernel(env, dst, val);
             }
         }
         break;
@@ -1056,7 +1063,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
     case 8: /* User code access, XXX */
     case 9: /* Supervisor code access, XXX */
     default:
-        do_unassigned_access(addr, 1, 0, asi, size);
+        cpu_unassigned_access(env, addr, 1, 0, asi, size);
         break;
     }
 #ifdef DEBUG_ASI
@@ -1068,7 +1075,8 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
 #else /* TARGET_SPARC64 */
 
 #ifdef CONFIG_USER_ONLY
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
+                       int sign)
 {
     uint64_t ret = 0;
 #if defined(DEBUG_ASI)
@@ -1079,7 +1087,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         helper_raise_exception(env, TT_PRIV_ACT);
     }
 
-    helper_check_align(addr, size - 1);
+    helper_check_align(env, addr, size - 1);
     addr = asi_address_mask(env, asi, addr);
 
     switch (asi) {
@@ -1174,7 +1182,8 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     return ret;
 }
 
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
+                   int asi, int size)
 {
 #ifdef DEBUG_ASI
     dump_asi("write", addr, asi, size, val);
@@ -1183,7 +1192,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
         helper_raise_exception(env, TT_PRIV_ACT);
     }
 
-    helper_check_align(addr, size - 1);
+    helper_check_align(env, addr, size - 1);
     addr = asi_address_mask(env, asi, addr);
 
     /* Convert to little endian */
@@ -1238,14 +1247,15 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
     case 0x8a: /* Primary no-fault LE, RO */
     case 0x8b: /* Secondary no-fault LE, RO */
     default:
-        do_unassigned_access(addr, 1, 0, 1, size);
+        helper_raise_exception(env, TT_DATA_ACCESS);
         return;
     }
 }
 
 #else /* CONFIG_USER_ONLY */
 
-uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
+uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
+                       int sign)
 {
     uint64_t ret = 0;
 #if defined(DEBUG_ASI)
@@ -1261,7 +1271,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         helper_raise_exception(env, TT_PRIV_ACT);
     }
 
-    helper_check_align(addr, size - 1);
+    helper_check_align(env, addr, size - 1);
     addr = asi_address_mask(env, asi, addr);
 
     /* process nonfaulting loads first */
@@ -1302,17 +1312,17 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
             if (cpu_hypervisor_mode(env)) {
                 switch (size) {
                 case 1:
-                    ret = ldub_hypv(addr);
+                    ret = cpu_ldub_hypv(env, addr);
                     break;
                 case 2:
-                    ret = lduw_hypv(addr);
+                    ret = cpu_lduw_hypv(env, addr);
                     break;
                 case 4:
-                    ret = ldl_hypv(addr);
+                    ret = cpu_ldl_hypv(env, addr);
                     break;
                 default:
                 case 8:
-                    ret = ldq_hypv(addr);
+                    ret = cpu_ldq_hypv(env, addr);
                     break;
                 }
             } else {
@@ -1320,33 +1330,33 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
                 if (asi & 1) {
                     switch (size) {
                     case 1:
-                        ret = ldub_kernel_secondary(addr);
+                        ret = cpu_ldub_kernel_secondary(env, addr);
                         break;
                     case 2:
-                        ret = lduw_kernel_secondary(addr);
+                        ret = cpu_lduw_kernel_secondary(env, addr);
                         break;
                     case 4:
-                        ret = ldl_kernel_secondary(addr);
+                        ret = cpu_ldl_kernel_secondary(env, addr);
                         break;
                     default:
                     case 8:
-                        ret = ldq_kernel_secondary(addr);
+                        ret = cpu_ldq_kernel_secondary(env, addr);
                         break;
                     }
                 } else {
                     switch (size) {
                     case 1:
-                        ret = ldub_kernel(addr);
+                        ret = cpu_ldub_kernel(env, addr);
                         break;
                     case 2:
-                        ret = lduw_kernel(addr);
+                        ret = cpu_lduw_kernel(env, addr);
                         break;
                     case 4:
-                        ret = ldl_kernel(addr);
+                        ret = cpu_ldl_kernel(env, addr);
                         break;
                     default:
                     case 8:
-                        ret = ldq_kernel(addr);
+                        ret = cpu_ldq_kernel(env, addr);
                         break;
                     }
                 }
@@ -1356,33 +1366,33 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
             if (asi & 1) {
                 switch (size) {
                 case 1:
-                    ret = ldub_user_secondary(addr);
+                    ret = cpu_ldub_user_secondary(env, addr);
                     break;
                 case 2:
-                    ret = lduw_user_secondary(addr);
+                    ret = cpu_lduw_user_secondary(env, addr);
                     break;
                 case 4:
-                    ret = ldl_user_secondary(addr);
+                    ret = cpu_ldl_user_secondary(env, addr);
                     break;
                 default:
                 case 8:
-                    ret = ldq_user_secondary(addr);
+                    ret = cpu_ldq_user_secondary(env, addr);
                     break;
                 }
             } else {
                 switch (size) {
                 case 1:
-                    ret = ldub_user(addr);
+                    ret = cpu_ldub_user(env, addr);
                     break;
                 case 2:
-                    ret = lduw_user(addr);
+                    ret = cpu_lduw_user(env, addr);
                     break;
                 case 4:
-                    ret = ldl_user(addr);
+                    ret = cpu_ldl_user(env, addr);
                     break;
                 default:
                 case 8:
-                    ret = ldq_user(addr);
+                    ret = cpu_ldq_user(env, addr);
                     break;
                 }
             }
@@ -1420,17 +1430,17 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         {
             switch (size) {
             case 1:
-                ret = ldub_nucleus(addr);
+                ret = cpu_ldub_nucleus(env, addr);
                 break;
             case 2:
-                ret = lduw_nucleus(addr);
+                ret = cpu_lduw_nucleus(env, addr);
                 break;
             case 4:
-                ret = ldl_nucleus(addr);
+                ret = cpu_ldl_nucleus(env, addr);
                 break;
             default:
             case 8:
-                ret = ldq_nucleus(addr);
+                ret = cpu_ldq_nucleus(env, addr);
                 break;
             }
             break;
@@ -1526,6 +1536,19 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
             ret = env->dtlb[reg].tag;
             break;
         }
+    case 0x48: /* Interrupt dispatch, RO */
+        break;
+    case 0x49: /* Interrupt data receive */
+        ret = env->ivec_status;
+        break;
+    case 0x7f: /* Incoming interrupt vector, RO */
+        {
+            int reg = (addr >> 4) & 0x3;
+            if (reg < 3) {
+                ret = env->ivec_data[reg];
+            }
+            break;
+        }
     case 0x46: /* D-cache data */
     case 0x47: /* D-cache tag access */
     case 0x4b: /* E-cache error enable */
@@ -1540,18 +1563,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     case 0x7e: /* E-cache tag */
         break;
     case 0x5b: /* D-MMU data pointer */
-    case 0x48: /* Interrupt dispatch, RO */
-    case 0x49: /* Interrupt data receive */
-    case 0x7f: /* Incoming interrupt vector, RO */
-        /* XXX */
-        break;
     case 0x54: /* I-MMU data in, WO */
     case 0x57: /* I-MMU demap, WO */
     case 0x5c: /* D-MMU data in, WO */
     case 0x5f: /* D-MMU demap, WO */
     case 0x77: /* Interrupt vector, WO */
     default:
-        do_unassigned_access(addr, 0, 0, 1, size);
+        cpu_unassigned_access(env, addr, 0, 0, 1, size);
         ret = 0;
         break;
     }
@@ -1604,7 +1622,8 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     return ret;
 }
 
-void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
+void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
+                   int asi, int size)
 {
 #ifdef DEBUG_ASI
     dump_asi("write", addr, asi, size, val);
@@ -1619,7 +1638,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
         helper_raise_exception(env, TT_PRIV_ACT);
     }
 
-    helper_check_align(addr, size - 1);
+    helper_check_align(env, addr, size - 1);
     addr = asi_address_mask(env, asi, addr);
 
     /* Convert to little endian */
@@ -1663,17 +1682,17 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
             if (cpu_hypervisor_mode(env)) {
                 switch (size) {
                 case 1:
-                    stb_hypv(addr, val);
+                    cpu_stb_hypv(env, addr, val);
                     break;
                 case 2:
-                    stw_hypv(addr, val);
+                    cpu_stw_hypv(env, addr, val);
                     break;
                 case 4:
-                    stl_hypv(addr, val);
+                    cpu_stl_hypv(env, addr, val);
                     break;
                 case 8:
                 default:
-                    stq_hypv(addr, val);
+                    cpu_stq_hypv(env, addr, val);
                     break;
                 }
             } else {
@@ -1681,33 +1700,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                 if (asi & 1) {
                     switch (size) {
                     case 1:
-                        stb_kernel_secondary(addr, val);
+                        cpu_stb_kernel_secondary(env, addr, val);
                         break;
                     case 2:
-                        stw_kernel_secondary(addr, val);
+                        cpu_stw_kernel_secondary(env, addr, val);
                         break;
                     case 4:
-                        stl_kernel_secondary(addr, val);
+                        cpu_stl_kernel_secondary(env, addr, val);
                         break;
                     case 8:
                     default:
-                        stq_kernel_secondary(addr, val);
+                        cpu_stq_kernel_secondary(env, addr, val);
                         break;
                     }
                 } else {
                     switch (size) {
                     case 1:
-                        stb_kernel(addr, val);
+                        cpu_stb_kernel(env, addr, val);
                         break;
                     case 2:
-                        stw_kernel(addr, val);
+                        cpu_stw_kernel(env, addr, val);
                         break;
                     case 4:
-                        stl_kernel(addr, val);
+                        cpu_stl_kernel(env, addr, val);
                         break;
                     case 8:
                     default:
-                        stq_kernel(addr, val);
+                        cpu_stq_kernel(env, addr, val);
                         break;
                     }
                 }
@@ -1717,33 +1736,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
             if (asi & 1) {
                 switch (size) {
                 case 1:
-                    stb_user_secondary(addr, val);
+                    cpu_stb_user_secondary(env, addr, val);
                     break;
                 case 2:
-                    stw_user_secondary(addr, val);
+                    cpu_stw_user_secondary(env, addr, val);
                     break;
                 case 4:
-                    stl_user_secondary(addr, val);
+                    cpu_stl_user_secondary(env, addr, val);
                     break;
                 case 8:
                 default:
-                    stq_user_secondary(addr, val);
+                    cpu_stq_user_secondary(env, addr, val);
                     break;
                 }
             } else {
                 switch (size) {
                 case 1:
-                    stb_user(addr, val);
+                    cpu_stb_user(env, addr, val);
                     break;
                 case 2:
-                    stw_user(addr, val);
+                    cpu_stw_user(env, addr, val);
                     break;
                 case 4:
-                    stl_user(addr, val);
+                    cpu_stl_user(env, addr, val);
                     break;
                 case 8:
                 default:
-                    stq_user(addr, val);
+                    cpu_stq_user(env, addr, val);
                     break;
                 }
             }
@@ -1781,17 +1800,17 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
         {
             switch (size) {
             case 1:
-                stb_nucleus(addr, val);
+                cpu_stb_nucleus(env, addr, val);
                 break;
             case 2:
-                stw_nucleus(addr, val);
+                cpu_stw_nucleus(env, addr, val);
                 break;
             case 4:
-                stl_nucleus(addr, val);
+                cpu_stl_nucleus(env, addr, val);
                 break;
             default:
             case 8:
-                stq_nucleus(addr, val);
+                cpu_stq_nucleus(env, addr, val);
                 break;
             }
             break;
@@ -1954,7 +1973,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
         demap_tlb(env->dtlb, addr, "dmmu", env);
         return;
     case 0x49: /* Interrupt data receive */
-        /* XXX */
+        env->ivec_status = val & 0x20;
         return;
     case 0x46: /* D-cache data */
     case 0x47: /* D-cache tag access */
@@ -1983,13 +2002,13 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
     case 0x8a: /* Primary no-fault LE, RO */
     case 0x8b: /* Secondary no-fault LE, RO */
     default:
-        do_unassigned_access(addr, 1, 0, 1, size);
+        cpu_unassigned_access(env, addr, 1, 0, 1, size);
         return;
     }
 }
 #endif /* CONFIG_USER_ONLY */
 
-void helper_ldda_asi(target_ulong addr, int asi, int rd)
+void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd)
 {
     if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
         || (cpu_has_hypervisor(env)
@@ -2004,22 +2023,22 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd)
 #if !defined(CONFIG_USER_ONLY)
     case 0x24: /* Nucleus quad LDD 128 bit atomic */
     case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */
-        helper_check_align(addr, 0xf);
+        helper_check_align(env, addr, 0xf);
         if (rd == 0) {
-            env->gregs[1] = ldq_nucleus(addr + 8);
+            env->gregs[1] = cpu_ldq_nucleus(env, addr + 8);
             if (asi == 0x2c) {
                 bswap64s(&env->gregs[1]);
             }
         } else if (rd < 8) {
-            env->gregs[rd] = ldq_nucleus(addr);
-            env->gregs[rd + 1] = ldq_nucleus(addr + 8);
+            env->gregs[rd] = cpu_ldq_nucleus(env, addr);
+            env->gregs[rd + 1] = cpu_ldq_nucleus(env, addr + 8);
             if (asi == 0x2c) {
                 bswap64s(&env->gregs[rd]);
                 bswap64s(&env->gregs[rd + 1]);
             }
         } else {
-            env->regwptr[rd] = ldq_nucleus(addr);
-            env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
+            env->regwptr[rd] = cpu_ldq_nucleus(env, addr);
+            env->regwptr[rd + 1] = cpu_ldq_nucleus(env, addr + 8);
             if (asi == 0x2c) {
                 bswap64s(&env->regwptr[rd]);
                 bswap64s(&env->regwptr[rd + 1]);
@@ -2028,26 +2047,27 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd)
         break;
 #endif
     default:
-        helper_check_align(addr, 0x3);
+        helper_check_align(env, addr, 0x3);
         if (rd == 0) {
-            env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
+            env->gregs[1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
         } else if (rd < 8) {
-            env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+            env->gregs[rd] = helper_ld_asi(env, addr, asi, 4, 0);
+            env->gregs[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
         } else {
-            env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
-            env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
+            env->regwptr[rd] = helper_ld_asi(env, addr, asi, 4, 0);
+            env->regwptr[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0);
         }
         break;
     }
 }
 
-void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
+void helper_ldf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
+                    int rd)
 {
     unsigned int i;
     target_ulong val;
 
-    helper_check_align(addr, 3);
+    helper_check_align(env, addr, 3);
     addr = asi_address_mask(env, asi, addr);
 
     switch (asi) {
@@ -2059,9 +2079,9 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
             helper_raise_exception(env, TT_ILL_INSN);
             return;
         }
-        helper_check_align(addr, 0x3f);
+        helper_check_align(env, addr, 0x3f);
         for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x8f, 8, 0);
+            env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x8f, 8, 0);
         }
         return;
 
@@ -2077,9 +2097,9 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
             helper_raise_exception(env, TT_ILL_INSN);
             return;
         }
-        helper_check_align(addr, 0x3f);
+        helper_check_align(env, addr, 0x3f);
         for (i = 0; i < 8; i++, rd += 2, addr += 4) {
-            env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x19, 8, 0);
+            env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x19, 8, 0);
         }
         return;
 
@@ -2090,29 +2110,30 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
     switch (size) {
     default:
     case 4:
-        val = helper_ld_asi(addr, asi, size, 0);
+        val = helper_ld_asi(env, addr, asi, size, 0);
         if (rd & 1) {
-            env->fpr[rd/2].l.lower = val;
+            env->fpr[rd / 2].l.lower = val;
         } else {
-            env->fpr[rd/2].l.upper = val;
+            env->fpr[rd / 2].l.upper = val;
         }
         break;
     case 8:
-        env->fpr[rd/2].ll = helper_ld_asi(addr, asi, size, 0);
+        env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, size, 0);
         break;
     case 16:
-        env->fpr[rd/2].ll = helper_ld_asi(addr, asi, 8, 0);
-        env->fpr[rd/2 + 1].ll = helper_ld_asi(addr + 8, asi, 8, 0);
+        env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, 8, 0);
+        env->fpr[rd / 2 + 1].ll = helper_ld_asi(env, addr + 8, asi, 8, 0);
         break;
     }
 }
 
-void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
+void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
+                    int rd)
 {
     unsigned int i;
     target_ulong val;
 
-    helper_check_align(addr, 3);
+    helper_check_align(env, addr, 3);
     addr = asi_address_mask(env, asi, addr);
 
     switch (asi) {
@@ -2126,9 +2147,9 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
             helper_raise_exception(env, TT_ILL_INSN);
             return;
         }
-        helper_check_align(addr, 0x3f);
+        helper_check_align(env, addr, 0x3f);
         for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x8f, 8);
+            helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x8f, 8);
         }
 
         return;
@@ -2144,9 +2165,9 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
             helper_raise_exception(env, TT_ILL_INSN);
             return;
         }
-        helper_check_align(addr, 0x3f);
+        helper_check_align(env, addr, 0x3f);
         for (i = 0; i < 8; i++, rd += 2, addr += 8) {
-            helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x19, 8);
+            helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x19, 8);
         }
 
         return;
@@ -2158,71 +2179,72 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
     default:
     case 4:
         if (rd & 1) {
-            val = env->fpr[rd/2].l.lower;
+            val = env->fpr[rd / 2].l.lower;
         } else {
-            val = env->fpr[rd/2].l.upper;
+            val = env->fpr[rd / 2].l.upper;
         }
-        helper_st_asi(addr, val, asi, size);
+        helper_st_asi(env, addr, val, asi, size);
         break;
     case 8:
-        helper_st_asi(addr, env->fpr[rd/2].ll, asi, size);
+        helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, size);
         break;
     case 16:
-        helper_st_asi(addr, env->fpr[rd/2].ll, asi, 8);
-        helper_st_asi(addr + 8, env->fpr[rd/2 + 1].ll, asi, 8);
+        helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, 8);
+        helper_st_asi(env, addr + 8, env->fpr[rd / 2 + 1].ll, asi, 8);
         break;
     }
 }
 
-target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
-                            target_ulong val2, uint32_t asi)
+target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr,
+                            target_ulong val1, target_ulong val2, uint32_t asi)
 {
     target_ulong ret;
 
     val2 &= 0xffffffffUL;
-    ret = helper_ld_asi(addr, asi, 4, 0);
+    ret = helper_ld_asi(env, addr, asi, 4, 0);
     ret &= 0xffffffffUL;
     if (val2 == ret) {
-        helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
+        helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4);
     }
     return ret;
 }
 
-target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
-                             target_ulong val2, uint32_t asi)
+target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr,
+                             target_ulong val1, target_ulong val2,
+                             uint32_t asi)
 {
     target_ulong ret;
 
-    ret = helper_ld_asi(addr, asi, 8, 0);
+    ret = helper_ld_asi(env, addr, asi, 8, 0);
     if (val2 == ret) {
-        helper_st_asi(addr, val1, asi, 8);
+        helper_st_asi(env, addr, val1, asi, 8);
     }
     return ret;
 }
 #endif /* TARGET_SPARC64 */
 
-void helper_ldqf(target_ulong addr, int mem_idx)
+void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx)
 {
     /* XXX add 128 bit load */
     CPU_QuadU u;
 
-    helper_check_align(addr, 7);
+    helper_check_align(env, addr, 7);
 #if !defined(CONFIG_USER_ONLY)
     switch (mem_idx) {
     case MMU_USER_IDX:
-        u.ll.upper = ldq_user(addr);
-        u.ll.lower = ldq_user(addr + 8);
+        u.ll.upper = cpu_ldq_user(env, addr);
+        u.ll.lower = cpu_ldq_user(env, addr + 8);
         QT0 = u.q;
         break;
     case MMU_KERNEL_IDX:
-        u.ll.upper = ldq_kernel(addr);
-        u.ll.lower = ldq_kernel(addr + 8);
+        u.ll.upper = cpu_ldq_kernel(env, addr);
+        u.ll.lower = cpu_ldq_kernel(env, addr + 8);
         QT0 = u.q;
         break;
 #ifdef TARGET_SPARC64
     case MMU_HYPV_IDX:
-        u.ll.upper = ldq_hypv(addr);
-        u.ll.lower = ldq_hypv(addr + 8);
+        u.ll.upper = cpu_ldq_hypv(env, addr);
+        u.ll.lower = cpu_ldq_hypv(env, addr + 8);
         QT0 = u.q;
         break;
 #endif
@@ -2237,29 +2259,29 @@ void helper_ldqf(target_ulong addr, int mem_idx)
 #endif
 }
 
-void helper_stqf(target_ulong addr, int mem_idx)
+void helper_stqf(CPUSPARCState *env, target_ulong addr, int mem_idx)
 {
     /* XXX add 128 bit store */
     CPU_QuadU u;
 
-    helper_check_align(addr, 7);
+    helper_check_align(env, addr, 7);
 #if !defined(CONFIG_USER_ONLY)
     switch (mem_idx) {
     case MMU_USER_IDX:
         u.q = QT0;
-        stq_user(addr, u.ll.upper);
-        stq_user(addr + 8, u.ll.lower);
+        cpu_stq_user(env, addr, u.ll.upper);
+        cpu_stq_user(env, addr + 8, u.ll.lower);
         break;
     case MMU_KERNEL_IDX:
         u.q = QT0;
-        stq_kernel(addr, u.ll.upper);
-        stq_kernel(addr + 8, u.ll.lower);
+        cpu_stq_kernel(env, addr, u.ll.upper);
+        cpu_stq_kernel(env, addr + 8, u.ll.lower);
         break;
 #ifdef TARGET_SPARC64
     case MMU_HYPV_IDX:
         u.q = QT0;
-        stq_hypv(addr, u.ll.upper);
-        stq_hypv(addr + 8, u.ll.lower);
+        cpu_stq_hypv(env, addr, u.ll.upper);
+        cpu_stq_hypv(env, addr + 8, u.ll.lower);
         break;
 #endif
     default:
@@ -2273,10 +2295,10 @@ void helper_stqf(target_ulong addr, int mem_idx)
 #endif
 }
 
-#ifndef TARGET_SPARC64
 #if !defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size)
+#ifndef TARGET_SPARC64
+void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
 {
     int fault_type;
 
@@ -2334,15 +2356,9 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
         tlb_flush(env, 1);
     }
 }
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
-                                 int is_asi, int size)
 #else
-static void do_unassigned_access(target_phys_addr_t addr, int is_write,
-                                 int is_exec, int is_asi, int size)
-#endif
+void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr,
+                           int is_write, int is_exec, int is_asi, int size)
 {
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
@@ -2356,16 +2372,51 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
     }
 }
 #endif
+#endif
 
 #if !defined(CONFIG_USER_ONLY)
-void cpu_unassigned_access(CPUSPARCState *env1, target_phys_addr_t addr,
-                           int is_write, int is_exec, int is_asi, int size)
+/* XXX: make it generic ? */
+static void cpu_restore_state2(CPUSPARCState *env, void *retaddr)
 {
-    CPUSPARCState *saved_env;
+    TranslationBlock *tb;
+    unsigned long pc;
+
+    if (retaddr) {
+        /* now we have a real cpu fault */
+        pc = (unsigned long)retaddr;
+        tb = tb_find_pc(pc);
+        if (tb) {
+            /* the PC is inside the translated code. It means that we have
+               a virtual CPU fault */
+            cpu_restore_state(tb, env, pc);
+        }
+    }
+}
+
+void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
+                         int is_user, void *retaddr)
+{
+#ifdef DEBUG_UNALIGNED
+    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
+           "\n", addr, env->pc);
+#endif
+    cpu_restore_state2(env, retaddr);
+    helper_raise_exception(env, TT_UNALIGNED);
+}
 
-    saved_env = env;
-    env = env1;
-    do_unassigned_access(addr, is_write, is_exec, is_asi, size);
-    env = saved_env;
+/* try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUSPARCState *env, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
+{
+    int ret;
+
+    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    if (ret) {
+        cpu_restore_state2(env, retaddr);
+        cpu_loop_exit(env);
+    }
 }
 #endif
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
deleted file mode 100644
index 1aff12516e..0000000000
--- a/target-sparc/op_helper.c
+++ /dev/null
@@ -1,74 +0,0 @@
-#include "cpu.h"
-#include "dyngen-exec.h"
-#include "helper.h"
-
-#if !defined(CONFIG_USER_ONLY)
-static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
-                                void *retaddr);
-
-#define MMUSUFFIX _mmu
-#define ALIGNED_ONLY
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* XXX: make it generic ? */
-static void cpu_restore_state2(void *retaddr)
-{
-    TranslationBlock *tb;
-    unsigned long pc;
-
-    if (retaddr) {
-        /* now we have a real cpu fault */
-        pc = (unsigned long)retaddr;
-        tb = tb_find_pc(pc);
-        if (tb) {
-            /* the PC is inside the translated code. It means that we have
-               a virtual CPU fault */
-            cpu_restore_state(tb, env, pc);
-        }
-    }
-}
-
-static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
-                                void *retaddr)
-{
-#ifdef DEBUG_UNALIGNED
-    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
-           "\n", addr, env->pc);
-#endif
-    cpu_restore_state2(retaddr);
-    helper_raise_exception(env, TT_UNALIGNED);
-}
-
-/* try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUSPARCState *env1, target_ulong addr, int is_write, int mmu_idx,
-              void *retaddr)
-{
-    int ret;
-    CPUSPARCState *saved_env;
-
-    saved_env = env;
-    env = env1;
-
-    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx);
-    if (ret) {
-        cpu_restore_state2(retaddr);
-        cpu_loop_exit(env);
-    }
-    env = saved_env;
-}
-
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index ef176e94b3..4967152e88 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1955,7 +1955,7 @@ static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size,
     r_asi = gen_get_asi(insn, addr);
     r_size = tcg_const_i32(size);
     r_sign = tcg_const_i32(sign);
-    gen_helper_ld_asi(dst, addr, r_asi, r_size, r_sign);
+    gen_helper_ld_asi(dst, cpu_env, addr, r_asi, r_size, r_sign);
     tcg_temp_free_i32(r_sign);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
@@ -1967,7 +1967,7 @@ static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size)
 
     r_asi = gen_get_asi(insn, addr);
     r_size = tcg_const_i32(size);
-    gen_helper_st_asi(addr, src, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
 }
@@ -1979,7 +1979,7 @@ static inline void gen_ldf_asi(TCGv addr, int insn, int size, int rd)
     r_asi = gen_get_asi(insn, addr);
     r_size = tcg_const_i32(size);
     r_rd = tcg_const_i32(rd);
-    gen_helper_ldf_asi(addr, r_asi, r_size, r_rd);
+    gen_helper_ldf_asi(cpu_env, addr, r_asi, r_size, r_rd);
     tcg_temp_free_i32(r_rd);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
@@ -1992,7 +1992,7 @@ static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd)
     r_asi = gen_get_asi(insn, addr);
     r_size = tcg_const_i32(size);
     r_rd = tcg_const_i32(rd);
-    gen_helper_stf_asi(addr, r_asi, r_size, r_rd);
+    gen_helper_stf_asi(cpu_env, addr, r_asi, r_size, r_rd);
     tcg_temp_free_i32(r_rd);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
@@ -2005,9 +2005,9 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn)
     r_asi = gen_get_asi(insn, addr);
     r_size = tcg_const_i32(4);
     r_sign = tcg_const_i32(0);
-    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign);
     tcg_temp_free_i32(r_sign);
-    gen_helper_st_asi(addr, dst, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, dst, r_asi, r_size);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
     tcg_gen_trunc_i64_tl(dst, cpu_tmp64);
@@ -2019,7 +2019,7 @@ static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd)
 
     r_asi = gen_get_asi(insn, addr);
     r_rd = tcg_const_i32(rd);
-    gen_helper_ldda_asi(addr, r_asi, r_rd);
+    gen_helper_ldda_asi(cpu_env, addr, r_asi, r_rd);
     tcg_temp_free_i32(r_rd);
     tcg_temp_free_i32(r_asi);
 }
@@ -2032,7 +2032,7 @@ static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd)
     tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi);
     r_asi = gen_get_asi(insn, addr);
     r_size = tcg_const_i32(8);
-    gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
 }
@@ -2046,7 +2046,7 @@ static inline void gen_cas_asi(TCGv dst, TCGv addr, TCGv val2, int insn,
     r_val1 = tcg_temp_new();
     gen_movl_reg_TN(rd, r_val1);
     r_asi = gen_get_asi(insn, addr);
-    gen_helper_cas_asi(dst, addr, r_val1, val2, r_asi);
+    gen_helper_cas_asi(dst, cpu_env, addr, r_val1, val2, r_asi);
     tcg_temp_free_i32(r_asi);
     tcg_temp_free(r_val1);
 }
@@ -2058,7 +2058,7 @@ static inline void gen_casx_asi(TCGv dst, TCGv addr, TCGv val2, int insn,
 
     gen_movl_reg_TN(rd, cpu_tmp64);
     r_asi = gen_get_asi(insn, addr);
-    gen_helper_casx_asi(dst, addr, cpu_tmp64, val2, r_asi);
+    gen_helper_casx_asi(dst, cpu_env, addr, cpu_tmp64, val2, r_asi);
     tcg_temp_free_i32(r_asi);
 }
 
@@ -2072,7 +2072,7 @@ static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size,
     r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
     r_size = tcg_const_i32(size);
     r_sign = tcg_const_i32(sign);
-    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign);
     tcg_temp_free(r_sign);
     tcg_temp_free(r_size);
     tcg_temp_free(r_asi);
@@ -2086,7 +2086,7 @@ static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size)
     tcg_gen_extu_tl_i64(cpu_tmp64, src);
     r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
     r_size = tcg_const_i32(size);
-    gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size);
     tcg_temp_free(r_size);
     tcg_temp_free(r_asi);
 }
@@ -2099,11 +2099,11 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn)
     r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
     r_size = tcg_const_i32(4);
     r_sign = tcg_const_i32(0);
-    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign);
     tcg_temp_free(r_sign);
     r_val = tcg_temp_new_i64();
     tcg_gen_extu_tl_i64(r_val, dst);
-    gen_helper_st_asi(addr, r_val, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size);
     tcg_temp_free_i64(r_val);
     tcg_temp_free(r_size);
     tcg_temp_free(r_asi);
@@ -2117,7 +2117,7 @@ static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd)
     r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
     r_size = tcg_const_i32(8);
     r_sign = tcg_const_i32(0);
-    gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign);
+    gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign);
     tcg_temp_free(r_sign);
     tcg_temp_free(r_size);
     tcg_temp_free(r_asi);
@@ -2136,7 +2136,7 @@ static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd)
     tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi);
     r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
     r_size = tcg_const_i32(8);
-    gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size);
     tcg_temp_free(r_size);
     tcg_temp_free(r_asi);
 }
@@ -2153,7 +2153,7 @@ static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn)
     r_val = tcg_const_i64(0xffULL);
     r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
     r_size = tcg_const_i32(1);
-    gen_helper_st_asi(addr, r_val, r_asi, r_size);
+    gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size);
     tcg_temp_free_i32(r_size);
     tcg_temp_free_i32(r_asi);
     tcg_temp_free_i64(r_val);
@@ -2373,9 +2373,9 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2)
         goto nfpu_insn;
 
 /* before an instruction, dc->pc must be static */
-static void disas_sparc_insn(DisasContext * dc)
+static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
 {
-    unsigned int insn, opc, rs1, rs2, rd;
+    unsigned int opc, rs1, rs2, rd;
     TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2;
     TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32;
     TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64;
@@ -2383,7 +2383,7 @@ static void disas_sparc_insn(DisasContext * dc)
 
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
         tcg_gen_debug_insn_start(dc->pc);
-    insn = ldl_code(dc->pc);
+
     opc = GET_FIELD(insn, 0, 1);
 
     rd = GET_FIELD(insn, 2, 6);
@@ -4547,7 +4547,7 @@ static void disas_sparc_insn(DisasContext * dc)
                 gen_helper_restore(cpu_env);
                 gen_mov_pc_npc(dc, cpu_cond);
                 r_const = tcg_const_i32(3);
-                gen_helper_check_align(cpu_dst, r_const);
+                gen_helper_check_align(cpu_env, cpu_dst, r_const);
                 tcg_temp_free_i32(r_const);
                 tcg_gen_mov_tl(cpu_npc, cpu_dst);
                 dc->npc = DYNAMIC_PC;
@@ -4577,7 +4577,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_temp_free(r_pc);
                         gen_mov_pc_npc(dc, cpu_cond);
                         r_const = tcg_const_i32(3);
-                        gen_helper_check_align(cpu_dst, r_const);
+                        gen_helper_check_align(cpu_env, cpu_dst, r_const);
                         tcg_temp_free_i32(r_const);
                         tcg_gen_mov_tl(cpu_npc, cpu_dst);
                         dc->npc = DYNAMIC_PC;
@@ -4592,7 +4592,7 @@ static void disas_sparc_insn(DisasContext * dc)
                             goto priv_insn;
                         gen_mov_pc_npc(dc, cpu_cond);
                         r_const = tcg_const_i32(3);
-                        gen_helper_check_align(cpu_dst, r_const);
+                        gen_helper_check_align(cpu_env, cpu_dst, r_const);
                         tcg_temp_free_i32(r_const);
                         tcg_gen_mov_tl(cpu_npc, cpu_dst);
                         dc->npc = DYNAMIC_PC;
@@ -4696,7 +4696,8 @@ static void disas_sparc_insn(DisasContext * dc)
 
                         save_state(dc, cpu_cond);
                         r_const = tcg_const_i32(7);
-                        gen_helper_check_align(cpu_addr, r_const); // XXX remove
+                        /* XXX remove alignment check */
+                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_address_mask(dc, cpu_addr);
                         tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx);
@@ -4921,7 +4922,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         CHECK_FPU_FEATURE(dc, FLOAT128);
                         r_const = tcg_const_i32(dc->mem_idx);
                         gen_address_mask(dc, cpu_addr);
-                        gen_helper_ldqf(cpu_addr, r_const);
+                        gen_helper_ldqf(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_op_store_QT0_fpr(QFPREG(rd));
                         gen_update_fprs_dirty(QFPREG(rd));
@@ -4961,7 +4962,8 @@ static void disas_sparc_insn(DisasContext * dc)
                         save_state(dc, cpu_cond);
                         gen_address_mask(dc, cpu_addr);
                         r_const = tcg_const_i32(7);
-                        gen_helper_check_align(cpu_addr, r_const); // XXX remove
+                        /* XXX remove alignment check */
+                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_movl_reg_TN(rd + 1, cpu_tmp0);
                         tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, cpu_val);
@@ -5065,7 +5067,7 @@ static void disas_sparc_insn(DisasContext * dc)
                         gen_op_load_fpr_QT0(QFPREG(rd));
                         r_const = tcg_const_i32(dc->mem_idx);
                         gen_address_mask(dc, cpu_addr);
-                        gen_helper_stqf(cpu_addr, r_const);
+                        gen_helper_stqf(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                     }
                     break;
@@ -5108,7 +5110,7 @@ static void disas_sparc_insn(DisasContext * dc)
                             goto jmp_insn;
                         }
                         r_const = tcg_const_i32(7);
-                        gen_helper_check_align(cpu_addr, r_const);
+                        gen_helper_check_align(cpu_env, cpu_addr, r_const);
                         tcg_temp_free_i32(r_const);
                         gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd));
                     }
@@ -5238,6 +5240,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
     int j, lj = -1;
     int num_insns;
     int max_insns;
+    unsigned int insn;
 
     memset(dc, 0, sizeof(DisasContext));
     dc->tb = tb;
@@ -5297,7 +5300,8 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
         if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
             gen_io_start();
         last_pc = dc->pc;
-        disas_sparc_insn(dc);
+        insn = cpu_ldl_code(env, dc->pc);
+        disas_sparc_insn(dc, insn);
         num_insns++;
 
         if (dc->is_br)
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 5af21b3f5d..4d59a63855 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -929,6 +929,27 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index)
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -936,6 +957,8 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
@@ -943,6 +966,7 @@ static void *qemu_st_helpers[4] = {
     __stq_mmu,
 };
 #endif
+#endif
 
 #define TLB_SHIFT	(CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
 
@@ -1075,6 +1099,19 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
                     TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
     tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
 # endif
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal and incorrect for 64 bit */
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[2], 0,
+                    tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[1], 0,
+                    tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
+
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
+                    SHIFT_IMM_LSL(0));
+#endif
     tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
 
     switch (opc) {
@@ -1341,6 +1378,22 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
     }
 # endif
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal and incorrect for 64 bit */
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[3], 0,
+                    tcg_target_call_iarg_regs[2], SHIFT_IMM_LSL(0));
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[2], 0,
+                    tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[1], 0,
+                    tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
+
+    tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
+                    tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
+                    SHIFT_IMM_LSL(0));
+#endif
     tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
     if (opc == 3)
         tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index c5a3730a2b..e579ef06a1 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -882,6 +882,27 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret,
 #if defined(CONFIG_SOFTMMU)
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -889,12 +910,15 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
     __stl_mmu,
     __stq_mmu,
 };
+#endif
 
 /* Load and compare a TLB entry, and branch if TLB miss.  OFFSET is set to
    the offset of the first ADDR_READ or ADDR_WRITE member of the appropriate
@@ -1061,6 +1085,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
     }
     tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_call(s, qemu_ld_helpers[opc & 3]);
 
     switch (opc) {
@@ -1212,6 +1245,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
         tcg_abort();
     }
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_call(s, qemu_st_helpers[opc]);
 
     /* label2: */
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index fafd900c5a..43a51a1c54 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -116,17 +116,7 @@ static inline int tcg_target_get_call_iarg_regs_count(int flags)
         return 6;
     }
 
-    flags &= TCG_CALL_TYPE_MASK;
-    switch(flags) {
-    case TCG_CALL_TYPE_STD:
-        return 0;
-    case TCG_CALL_TYPE_REGPARM_1:
-    case TCG_CALL_TYPE_REGPARM_2:
-    case TCG_CALL_TYPE_REGPARM:
-        return flags - TCG_CALL_TYPE_REGPARM_1 + 1;
-    default:
-        tcg_abort();
-    }
+    return 0;
 }
 
 /* parse target specific constraints */
@@ -188,6 +178,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
             tcg_regset_set32(ct->u.regs, 0, 0xffff);
             tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
             tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
+#ifdef CONFIG_TCG_PASS_AREG0
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDX);
+#endif
         } else {
             tcg_regset_set32(ct->u.regs, 0, 0xff);
             tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
@@ -967,6 +960,27 @@ static void tcg_out_jmp(TCGContext *s, tcg_target_long dest)
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void *qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void *qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -974,12 +988,15 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
     __stl_mmu,
     __stq_mmu,
 };
+#endif
 
 /* Perform the TLB load and compare.
 
@@ -1148,7 +1165,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     int data_reg, data_reg2 = 0;
     int addrlo_idx;
 #if defined(CONFIG_SOFTMMU)
-    int mem_index, s_bits, arg_idx;
+    int mem_index, s_bits;
+#if TCG_TARGET_REG_BITS == 64
+    int arg_idx;
+#else
+    int stack_adjust;
+#endif
     uint8_t *label_ptr[3];
 #endif
 
@@ -1184,16 +1206,48 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     }
 
     /* XXX: move that code at the end of the TB */
+#if TCG_TARGET_REG_BITS == 32
+    tcg_out_pushi(s, mem_index);
+    stack_adjust = 4;
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_push(s, args[addrlo_idx + 1]);
+        stack_adjust += 4;
+    }
+    tcg_out_push(s, args[addrlo_idx]);
+    stack_adjust += 4;
+#ifdef CONFIG_TCG_PASS_AREG0
+    tcg_out_push(s, TCG_AREG0);
+    stack_adjust += 4;
+#endif
+#else
     /* The first argument is already loaded with addrlo.  */
     arg_idx = 1;
-    if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) {
-        tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx++],
-                    args[addrlo_idx + 1]);
-    }
     tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx],
                  mem_index);
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
+#endif
+
     tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]);
 
+#if TCG_TARGET_REG_BITS == 32
+    if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) {
+        /* Pop and discard.  This is 2 bytes smaller than the add.  */
+        tcg_out_pop(s, TCG_REG_ECX);
+    } else if (stack_adjust != 0) {
+        tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust);
+    }
+#endif
+
     switch(opc) {
     case 0 | 4:
         tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
@@ -1359,45 +1413,42 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     }
 
     /* XXX: move that code at the end of the TB */
-    if (TCG_TARGET_REG_BITS == 64) {
-        tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
-                    TCG_REG_RSI, data_reg);
-        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
-        stack_adjust = 0;
-    } else if (TARGET_LONG_BITS == 32) {
-        tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, data_reg);
-        if (opc == 3) {
-            tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg2);
-            tcg_out_pushi(s, mem_index);
-            stack_adjust = 4;
-        } else {
-            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
-            stack_adjust = 0;
-        }
-    } else {
-        if (opc == 3) {
-            tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
-            tcg_out_pushi(s, mem_index);
-            tcg_out_push(s, data_reg2);
-            tcg_out_push(s, data_reg);
-            stack_adjust = 12;
-        } else {
-            tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
-            switch(opc) {
-            case 0:
-                tcg_out_ext8u(s, TCG_REG_ECX, data_reg);
-                break;
-            case 1:
-                tcg_out_ext16u(s, TCG_REG_ECX, data_reg);
-                break;
-            case 2:
-                tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg);
-                break;
-            }
-            tcg_out_pushi(s, mem_index);
-            stack_adjust = 4;
-        }
+#if TCG_TARGET_REG_BITS == 32
+    tcg_out_pushi(s, mem_index);
+    stack_adjust = 4;
+    if (opc == 3) {
+        tcg_out_push(s, data_reg2);
+        stack_adjust += 4;
     }
+    tcg_out_push(s, data_reg);
+    stack_adjust += 4;
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_push(s, args[addrlo_idx + 1]);
+        stack_adjust += 4;
+    }
+    tcg_out_push(s, args[addrlo_idx]);
+    stack_adjust += 4;
+#ifdef CONFIG_TCG_PASS_AREG0
+    tcg_out_push(s, TCG_AREG0);
+    stack_adjust += 4;
+#endif
+#else
+    tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+                TCG_REG_RSI, data_reg);
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
+    stack_adjust = 0;
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
+#endif
 
     tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]);
 
@@ -1962,9 +2013,15 @@ static void tcg_target_qemu_prologue(TCGContext *s)
         tcg_out_push(s, tcg_target_callee_save_regs[i]);
     }
 
-    tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
-
+#if TCG_TARGET_REG_BITS == 32
+    tcg_out_ld(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP,
+               (ARRAY_SIZE(tcg_target_callee_save_regs) + 1) * 4);
+    tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[1], TCG_REG_ESP,
+               (ARRAY_SIZE(tcg_target_callee_save_regs) + 2) * 4);
+#else
     tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+#endif
+    tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
 
     /* jmp *tb.  */
     tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]);
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index f90252a443..e02dacc84f 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1452,12 +1452,25 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg,
                                TCG_REG_P7, TCG_REG_R3, TCG_REG_R57));
 }
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
     __ldl_mmu,
     __ldq_mmu,
 };
+#endif
 
 static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
 {
@@ -1517,6 +1530,15 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
                        tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2),
                        tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0));
     }
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     if (!bswap || s_bits == 0) {
         tcg_out_bundle(s, miB,
                        tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
@@ -1547,12 +1569,25 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
     }
 }
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
     __stl_mmu,
     __stq_mmu,
 };
+#endif
 
 static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
 {
@@ -1622,6 +1657,17 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
         data_reg = TCG_REG_R2;
     }
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_bundle(s, miB,
                    tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
                                data_reg, TCG_REG_R3),
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index c6aa5bced5..393ba07f25 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -750,6 +750,27 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, int ret,
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -757,6 +778,8 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
@@ -764,6 +787,7 @@ static void *qemu_st_helpers[4] = {
     __stq_mmu,
 };
 #endif
+#endif
 
 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
                             int opc)
@@ -858,6 +882,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
 # endif
     tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
     tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
     tcg_out_nop(s);
 
@@ -1069,6 +1102,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     }
 
     tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
     tcg_out_nop(s);
 
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 6a34cab5f9..b0aa914798 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -508,6 +508,27 @@ static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -515,6 +536,8 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
@@ -522,6 +545,7 @@ static void *qemu_st_helpers[4] = {
     __stq_mmu,
 };
 #endif
+#endif
 
 static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 {
@@ -598,6 +622,16 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
     tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index);
 #endif
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
+
     tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
     switch (opc) {
     case 0|4:
@@ -829,6 +863,17 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
     ir++;
 
     tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index);
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
     label2_ptr = s->code_ptr;
     tcg_out32 (s, B);
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 3f22aaac9d..2f37fd289b 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -98,5 +98,5 @@ typedef enum {
 #define TCG_TARGET_HAS_GUEST_BASE
 
 #define tcg_qemu_tb_exec(env, tb_ptr) \
-    ((long REGPARM __attribute__ ((longcall)) \
+    ((long __attribute__ ((longcall)) \
       (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 7f723b5c2c..409a1ac1ce 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -552,6 +552,27 @@ static void tcg_out_ldsta (TCGContext *s, int ret, int addr,
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -559,12 +580,15 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
     __stl_mmu,
     __stq_mmu,
 };
+#endif
 
 static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2,
                               int addr_reg, int s_bits, int offset)
@@ -648,6 +672,15 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
     tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
     tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index);
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
 
     switch (opc) {
@@ -796,6 +829,17 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
     tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc)));
     tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index);
 
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
     tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
 
     label2_ptr = s->code_ptr;
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 47ffcc1f51..04662c15fd 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -301,6 +301,27 @@ static const uint8_t tcg_cond_to_ltr_cond[10] = {
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static void *qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -308,6 +329,8 @@ static void *qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static void *qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
@@ -315,6 +338,7 @@ static void *qemu_st_helpers[4] = {
     __stq_mmu,
 };
 #endif
+#endif
 
 static uint8_t *tb_ret_addr;
 
@@ -1483,9 +1507,29 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg,
             tcg_abort();
         }
         tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index);
+#ifdef CONFIG_TCG_PASS_AREG0
+        /* XXX/FIXME: suboptimal */
+        tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
+                    tcg_target_call_iarg_regs[1]);
+        tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                    tcg_target_call_iarg_regs[0]);
+        tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                    TCG_AREG0);
+#endif
         tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]);
     } else {
         tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
+#ifdef CONFIG_TCG_PASS_AREG0
+        /* XXX/FIXME: suboptimal */
+        tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                    tcg_target_call_iarg_regs[2]);
+        tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                    tcg_target_call_iarg_regs[1]);
+        tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                    tcg_target_call_iarg_regs[0]);
+        tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                    TCG_AREG0);
+#endif
         tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]);
 
         /* sign extension */
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index b287122df5..80f0818679 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -59,6 +59,12 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
 };
 #endif
 
+#ifdef CONFIG_TCG_PASS_AREG0
+#define ARG_OFFSET 1
+#else
+#define ARG_OFFSET 0
+#endif
+
 static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_L0,
     TCG_REG_L1,
@@ -86,9 +92,9 @@ static const int tcg_target_call_iarg_regs[6] = {
 
 static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_O0,
-#if TCG_TARGET_REG_BITS == 32
-    TCG_REG_O1
-#endif
+    TCG_REG_O1,
+    TCG_REG_O2,
+    TCG_REG_O3,
 };
 
 static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
@@ -155,6 +161,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0);
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1);
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2);
+#ifdef CONFIG_TCG_PASS_AREG0
+        tcg_regset_reset_reg(ct->u.regs, TCG_REG_O3);
+#endif
         break;
     case 'I':
         ct->ct |= TCG_CT_CONST_S11;
@@ -706,6 +715,27 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 
 #include "../../softmmu_defs.h"
 
+#ifdef CONFIG_TCG_PASS_AREG0
+/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
+   int mmu_idx) */
+static const void * const qemu_ld_helpers[4] = {
+    helper_ldb_mmu,
+    helper_ldw_mmu,
+    helper_ldl_mmu,
+    helper_ldq_mmu,
+};
+
+/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
+   uintxx_t val, int mmu_idx) */
+static const void * const qemu_st_helpers[4] = {
+    helper_stb_mmu,
+    helper_stw_mmu,
+    helper_stl_mmu,
+    helper_stq_mmu,
+};
+#else
+/* legacy helper signature: __ld_mmu(target_ulong addr, int
+   mmu_idx) */
 static const void * const qemu_ld_helpers[4] = {
     __ldb_mmu,
     __ldw_mmu,
@@ -713,6 +743,8 @@ static const void * const qemu_ld_helpers[4] = {
     __ldq_mmu,
 };
 
+/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val,
+   int mmu_idx) */
 static const void * const qemu_st_helpers[4] = {
     __stb_mmu,
     __stw_mmu,
@@ -720,6 +752,7 @@ static const void * const qemu_st_helpers[4] = {
     __stq_mmu,
 };
 #endif
+#endif
 
 #if TARGET_LONG_BITS == 32
 #define TARGET_LD_OP LDUW
@@ -801,6 +834,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
 
     /* mov */
     tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
+#ifdef CONFIG_TCG_PASS_AREG0
+    /* XXX/FIXME: suboptimal */
+    tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
+                tcg_target_call_iarg_regs[2]);
+    tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
+                tcg_target_call_iarg_regs[1]);
+    tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+                tcg_target_call_iarg_regs[0]);
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
+                TCG_AREG0);
+#endif
 
     /* XXX: move that code at the end of the TB */
     /* qemu_ld_helper[s_bits](arg0, arg1) */
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 531db55f5d..ccfcd1abe1 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -173,11 +173,9 @@ void *tcg_malloc_internal(TCGContext *s, int size)
         /* big malloc: insert a new pool (XXX: could optimize) */
         p = g_malloc(sizeof(TCGPool) + size);
         p->size = size;
-        if (s->pool_current)
-            s->pool_current->next = p;
-        else
-            s->pool_first = p;
-        p->next = s->pool_current;
+        p->next = s->pool_first_large;
+        s->pool_first_large = p;
+        return p->data;
     } else {
         p = s->pool_current;
         if (!p) {
@@ -208,6 +206,12 @@ void *tcg_malloc_internal(TCGContext *s, int size)
 
 void tcg_pool_reset(TCGContext *s)
 {
+    TCGPool *p, *t;
+    for (p = s->pool_first_large; p; p = t) {
+        t = p->next;
+        g_free(p);
+    }
+    s->pool_first_large = NULL;
     s->pool_cur = s->pool_end = NULL;
     s->pool_current = NULL;
 }
@@ -590,9 +594,6 @@ void tcg_register_helper(void *func, const char *name)
 void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
                    int sizemask, TCGArg ret, int nargs, TCGArg *args)
 {
-#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
-    int call_type;
-#endif
     int i;
     int real_args;
     int nb_rets;
@@ -617,9 +618,6 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
 
     *gen_opc_ptr++ = INDEX_op_call;
     nparam = gen_opparam_ptr++;
-#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
-    call_type = (flags & TCG_CALL_TYPE_MASK);
-#endif
     if (ret != TCG_CALL_DUMMY_ARG) {
 #if TCG_TARGET_REG_BITS < 64
         if (sizemask & 1) {
@@ -645,14 +643,6 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
 #if TCG_TARGET_REG_BITS < 64
         int is_64bit = sizemask & (1 << (i+1)*2);
         if (is_64bit) {
-#ifdef TCG_TARGET_I386
-            /* REGPARM case: if the third parameter is 64 bit, it is
-               allocated on the stack */
-            if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
-                call_type = TCG_CALL_TYPE_REGPARM_2;
-                flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
-            }
-#endif
 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
             /* some targets want aligned 64 bit args */
             if (real_args & 1) {
diff --git a/tcg/tcg.h b/tcg/tcg.h
index cc223ea540..5f6c647ea5 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -252,11 +252,6 @@ typedef int TCGv_i64;
 #define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1)
 
 /* call flags */
-#define TCG_CALL_TYPE_MASK      0x000f
-#define TCG_CALL_TYPE_STD       0x0000 /* standard C call */
-#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */
-#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */
-#define TCG_CALL_TYPE_REGPARM   0x0003 /* i386 style regparm call (3 regs) */
 /* A pure function only reads its arguments and TCG global variables
    and cannot raise exceptions. Hence a call to a pure function can be
    safely suppressed if the return value is not used. */
@@ -337,7 +332,7 @@ typedef struct TCGContext TCGContext;
 
 struct TCGContext {
     uint8_t *pool_cur, *pool_end;
-    TCGPool *pool_first, *pool_current;
+    TCGPool *pool_first, *pool_current, *pool_first_large;
     TCGLabel *labels;
     int nb_labels;
     TCGTemp *temps; /* globals first, temps after */
@@ -589,5 +584,5 @@ extern uint8_t code_gen_prologue[];
 /* TCG targets may use a different definition of tcg_qemu_tb_exec. */
 #if !defined(tcg_qemu_tb_exec)
 # define tcg_qemu_tb_exec(env, tb_ptr) \
-    ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
+    ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
 #endif
diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c
index bd85073662..453f1875e2 100644
--- a/tcg/tci/tcg-target.c
+++ b/tcg/tci/tcg-target.c
@@ -798,6 +798,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
     case INDEX_op_qemu_st8:
     case INDEX_op_qemu_st16:
     case INDEX_op_qemu_st32:
+#ifdef CONFIG_TCG_PASS_AREG0
+        tcg_out_r(s, TCG_AREG0);
+#endif
         tcg_out_r(s, *args++);
         tcg_out_r(s, *args++);
 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
@@ -808,6 +811,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
 #endif
         break;
     case INDEX_op_qemu_st64:
+#ifdef CONFIG_TCG_PASS_AREG0
+        tcg_out_r(s, TCG_AREG0);
+#endif
         tcg_out_r(s, *args++);
 #if TCG_TARGET_REG_BITS == 32
         tcg_out_r(s, *args++);
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index b61e99aff1..30a0f21596 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -154,7 +154,7 @@ typedef enum {
 
 void tci_disas(uint8_t opc);
 
-unsigned long tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr);
+tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr);
 #define tcg_qemu_tb_exec tcg_qemu_tb_exec
 
 static inline void flush_icache_range(tcg_target_ulong start,
diff --git a/tci.c b/tci.c
index fb9ebef107..70e7bfb759 100644
--- a/tci.c
+++ b/tci.c
@@ -429,9 +429,9 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
 }
 
 /* Interpret pseudo code in tb. */
-unsigned long tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
+tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
 {
-    unsigned long next_tb = 0;
+    tcg_target_ulong next_tb = 0;
 
     env = cpustate;
     tci_reg[TCG_AREG0] = (tcg_target_ulong)env;