summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--default-configs/mips-softmmu-common.mak32
-rw-r--r--default-configs/mips-softmmu.mak31
-rw-r--r--default-configs/mips64-softmmu.mak31
-rw-r--r--default-configs/mips64el-softmmu.mak31
-rw-r--r--default-configs/mipsel-softmmu.mak31
-rw-r--r--fpu/softfloat-specialize.h2
-rw-r--r--hw/net/spapr_llan.c320
-rw-r--r--hw/ppc/spapr.c27
-rw-r--r--qapi-schema.json3
-rw-r--r--target-mips/cpu.h3
-rw-r--r--target-mips/translate.c1
-rw-r--r--target-mips/translate_init.c22
-rw-r--r--target-ppc/cpu.h61
-rw-r--r--target-ppc/kvm.c2
-rw-r--r--target-ppc/translate.c26
-rw-r--r--target-ppc/translate_init.c237
-rw-r--r--target-tricore/Makefile.objs2
-rw-r--r--target-tricore/cpu.h6
-rw-r--r--target-tricore/fpu_helper.c217
-rw-r--r--target-tricore/helper.c12
-rw-r--r--target-tricore/helper.h7
-rw-r--r--target-tricore/op_helper.c2
-rw-r--r--target-tricore/translate.c34
-rw-r--r--target-tricore/tricore-opcodes.h18
-rw-r--r--ui/cocoa.m348
25 files changed, 1098 insertions, 408 deletions
diff --git a/default-configs/mips-softmmu-common.mak b/default-configs/mips-softmmu-common.mak
new file mode 100644
index 0000000000..37009a3637
--- /dev/null
+++ b/default-configs/mips-softmmu-common.mak
@@ -0,0 +1,32 @@
+# Common mips*-softmmu CONFIG defines
+
+include pci.mak
+include sound.mak
+include usb.mak
+CONFIG_ESP=y
+CONFIG_VGA_ISA=y
+CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_ACPI_X86=y
+CONFIG_ACPI_MEMORY_HOTPLUG=y
+CONFIG_ACPI_CPU_HOTPLUG=y
+CONFIG_APM=y
+CONFIG_I8257=y
+CONFIG_PIIX4=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_MIPSNET=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_I8259=y
+CONFIG_MC146818RTC=y
+CONFIG_ISA_TESTDEV=y
+CONFIG_EMPTY_SLOT=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 44467c37c1..9fede6e00f 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -1,32 +1,3 @@
 # Default configuration for mips-softmmu
 
-include pci.mak
-include sound.mak
-include usb.mak
-CONFIG_ESP=y
-CONFIG_VGA_ISA=y
-CONFIG_VGA_ISA_MM=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_VMWARE_VGA=y
-CONFIG_SERIAL=y
-CONFIG_PARALLEL=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_ACPI=y
-CONFIG_ACPI_X86=y
-CONFIG_ACPI_MEMORY_HOTPLUG=y
-CONFIG_ACPI_CPU_HOTPLUG=y
-CONFIG_APM=y
-CONFIG_I8257=y
-CONFIG_PIIX4=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_PIIX=y
-CONFIG_NE2000_ISA=y
-CONFIG_MIPSNET=y
-CONFIG_PFLASH_CFI01=y
-CONFIG_I8259=y
-CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_EMPTY_SLOT=y
+include mips-softmmu-common.mak
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 66ed5f94c5..bad7496672 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -1,38 +1,9 @@
 # Default configuration for mips64-softmmu
 
-include pci.mak
-include sound.mak
-include usb.mak
-CONFIG_ESP=y
-CONFIG_VGA_ISA=y
-CONFIG_VGA_ISA_MM=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_VMWARE_VGA=y
-CONFIG_SERIAL=y
-CONFIG_PARALLEL=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_ACPI=y
-CONFIG_ACPI_X86=y
-CONFIG_ACPI_MEMORY_HOTPLUG=y
-CONFIG_ACPI_CPU_HOTPLUG=y
-CONFIG_APM=y
-CONFIG_I8257=y
-CONFIG_PIIX4=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_PIIX=y
-CONFIG_NE2000_ISA=y
+include mips-softmmu-common.mak
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
-CONFIG_MIPSNET=y
-CONFIG_PFLASH_CFI01=y
 CONFIG_JAZZ=y
 CONFIG_G364FB=y
-CONFIG_I8259=y
 CONFIG_JAZZ_LED=y
-CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_EMPTY_SLOT=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index bfca2b2b7c..485e218cfc 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -1,41 +1,12 @@
 # Default configuration for mips64el-softmmu
 
-include pci.mak
-include sound.mak
-include usb.mak
-CONFIG_ESP=y
-CONFIG_VGA_ISA=y
-CONFIG_VGA_ISA_MM=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_VMWARE_VGA=y
-CONFIG_SERIAL=y
-CONFIG_PARALLEL=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_ACPI=y
-CONFIG_ACPI_X86=y
-CONFIG_ACPI_MEMORY_HOTPLUG=y
-CONFIG_ACPI_CPU_HOTPLUG=y
-CONFIG_APM=y
-CONFIG_I8257=y
-CONFIG_PIIX4=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_PIIX=y
+include mips-softmmu-common.mak
 CONFIG_IDE_VIA=y
-CONFIG_NE2000_ISA=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
-CONFIG_MIPSNET=y
-CONFIG_PFLASH_CFI01=y
 CONFIG_FULONG=y
 CONFIG_JAZZ=y
 CONFIG_G364FB=y
-CONFIG_I8259=y
 CONFIG_JAZZ_LED=y
-CONFIG_MC146818RTC=y
 CONFIG_VT82C686=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_EMPTY_SLOT=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 0162ef0249..a7f6059484 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -1,32 +1,3 @@
 # Default configuration for mipsel-softmmu
 
-include pci.mak
-include sound.mak
-include usb.mak
-CONFIG_ESP=y
-CONFIG_VGA_ISA=y
-CONFIG_VGA_ISA_MM=y
-CONFIG_VGA_CIRRUS=y
-CONFIG_VMWARE_VGA=y
-CONFIG_SERIAL=y
-CONFIG_PARALLEL=y
-CONFIG_I8254=y
-CONFIG_PCSPK=y
-CONFIG_PCKBD=y
-CONFIG_FDC=y
-CONFIG_ACPI=y
-CONFIG_ACPI_X86=y
-CONFIG_ACPI_MEMORY_HOTPLUG=y
-CONFIG_ACPI_CPU_HOTPLUG=y
-CONFIG_APM=y
-CONFIG_I8257=y
-CONFIG_PIIX4=y
-CONFIG_IDE_ISA=y
-CONFIG_IDE_PIIX=y
-CONFIG_NE2000_ISA=y
-CONFIG_MIPSNET=y
-CONFIG_PFLASH_CFI01=y
-CONFIG_I8259=y
-CONFIG_MC146818RTC=y
-CONFIG_ISA_TESTDEV=y
-CONFIG_EMPTY_SLOT=y
+include mips-softmmu-common.mak
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 0875436b83..a4cbdad452 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -113,7 +113,7 @@ const float16 float16_default_nan = const_float16(0xFE00);
 #if defined(TARGET_SPARC)
 const float32 float32_default_nan = const_float32(0x7FFFFFFF);
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
-      defined(TARGET_XTENSA) || defined(TARGET_S390X)
+      defined(TARGET_XTENSA) || defined(TARGET_S390X) || defined(TARGET_TRICORE)
 const float32 float32_default_nan = const_float32(0x7FC00000);
 #elif SNAN_BIT_IS_ONE
 const float32 float32_default_nan = const_float32(0x7FBFFFFF);
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 5237b4d863..efc31cbfba 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -45,6 +45,10 @@
 #define DPRINTF(fmt...)
 #endif
 
+/* Compatibility flags for migration */
+#define SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT  0
+#define SPAPRVLAN_FLAG_RX_BUF_POOLS      (1 << SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT)
+
 /*
  * Virtual LAN device
  */
@@ -86,6 +90,15 @@ typedef uint64_t vlan_bd_t;
 #define VIO_SPAPR_VLAN_DEVICE(obj) \
      OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)
 
+#define RX_POOL_MAX_BDS 4096
+#define RX_MAX_POOLS 5
+
+typedef struct {
+    int32_t bufsize;
+    int32_t count;
+    vlan_bd_t bds[RX_POOL_MAX_BDS];
+} RxBufPool;
+
 typedef struct VIOsPAPRVLANDevice {
     VIOsPAPRDevice sdev;
     NICConf nicconf;
@@ -94,6 +107,8 @@ typedef struct VIOsPAPRVLANDevice {
     target_ulong buf_list;
     uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
     target_ulong rxq_ptr;
+    uint32_t compat_flags;             /* Compatability flags for migration */
+    RxBufPool *rx_pool[RX_MAX_POOLS];  /* Receive buffer descriptor pools */
 } VIOsPAPRVLANDevice;
 
 static int spapr_vlan_can_receive(NetClientState *nc)
@@ -103,6 +118,73 @@ static int spapr_vlan_can_receive(NetClientState *nc)
     return (dev->isopen && dev->rx_bufs > 0);
 }
 
+/**
+ * Get buffer descriptor from one of our receive buffer pools
+ */
+static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev,
+                                                size_t size)
+{
+    vlan_bd_t bd;
+    int pool;
+
+    for (pool = 0; pool < RX_MAX_POOLS; pool++) {
+        if (dev->rx_pool[pool]->count > 0 &&
+            dev->rx_pool[pool]->bufsize >= size + 8) {
+            break;
+        }
+    }
+    if (pool == RX_MAX_POOLS) {
+        /* Failed to find a suitable buffer */
+        return 0;
+    }
+
+    DPRINTF("Found buffer: pool=%d count=%d rxbufs=%d\n", pool,
+            dev->rx_pool[pool]->count, dev->rx_bufs);
+
+    /* Remove the buffer from the pool */
+    dev->rx_pool[pool]->count--;
+    bd = dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count];
+    dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count] = 0;
+
+    return bd;
+}
+
+/**
+ * Get buffer descriptor from the receive buffer list page that has been
+ * supplied by the guest with the H_REGISTER_LOGICAL_LAN call
+ */
+static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev,
+                                                size_t size)
+{
+    int buf_ptr = dev->use_buf_ptr;
+    vlan_bd_t bd;
+
+    do {
+        buf_ptr += 8;
+        if (buf_ptr >= VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF) {
+            buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = vio_ldq(&dev->sdev, dev->buf_list + buf_ptr);
+        DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
+                buf_ptr, (unsigned long long)bd);
+    } while ((!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8)
+             && buf_ptr != dev->use_buf_ptr);
+
+    if (!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8) {
+        /* Failed to find a suitable buffer */
+        return 0;
+    }
+
+    /* Remove the buffer from the pool */
+    dev->use_buf_ptr = buf_ptr;
+    vio_stq(&dev->sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+    DPRINTF("Found buffer: ptr=%d rxbufs=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+    return bd;
+}
+
 static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
                                   size_t size)
 {
@@ -110,7 +192,6 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
     VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev);
     vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
     vlan_bd_t bd;
-    int buf_ptr = dev->use_buf_ptr;
     uint64_t handle;
     uint8_t control;
 
@@ -125,29 +206,16 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
         return -1;
     }
 
-    do {
-        buf_ptr += 8;
-        if (buf_ptr >= (VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF)) {
-            buf_ptr = VLAN_RX_BDS_OFF;
-        }
-
-        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
-        DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
-                buf_ptr, (unsigned long long)bd);
-    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
-             && (buf_ptr != dev->use_buf_ptr));
-
-    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
-        /* Failed to find a suitable buffer */
+    if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+        bd = spapr_vlan_get_rx_bd_from_pool(dev, size);
+    } else {
+        bd = spapr_vlan_get_rx_bd_from_page(dev, size);
+    }
+    if (!bd) {
         return -1;
     }
 
-    /* Remove the buffer from the pool */
     dev->rx_bufs--;
-    dev->use_buf_ptr = buf_ptr;
-    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
-
-    DPRINTF("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
 
     /* Transfer the packet data */
     if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
@@ -195,13 +263,31 @@ static NetClientInfo net_spapr_vlan_info = {
     .receive = spapr_vlan_receive,
 };
 
+static void spapr_vlan_reset_rx_pool(RxBufPool *rxp)
+{
+    /*
+     * Use INT_MAX as bufsize so that unused buffers are moved to the end
+     * of the list during the qsort in spapr_vlan_add_rxbuf_to_pool() later.
+     */
+    rxp->bufsize = INT_MAX;
+    rxp->count = 0;
+    memset(rxp->bds, 0, sizeof(rxp->bds));
+}
+
 static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
 {
     VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+    int i;
 
     dev->buf_list = 0;
     dev->rx_bufs = 0;
     dev->isopen = 0;
+
+    if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+        for (i = 0; i < RX_MAX_POOLS; i++) {
+            spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
+        }
+    }
 }
 
 static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
@@ -218,10 +304,31 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
 static void spapr_vlan_instance_init(Object *obj)
 {
     VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
+    int i;
 
     device_add_bootindex_property(obj, &dev->nicconf.bootindex,
                                   "bootindex", "",
                                   DEVICE(dev), NULL);
+
+    if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+        for (i = 0; i < RX_MAX_POOLS; i++) {
+            dev->rx_pool[i] = g_new(RxBufPool, 1);
+            spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
+        }
+    }
+}
+
+static void spapr_vlan_instance_finalize(Object *obj)
+{
+    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
+    int i;
+
+    if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+        for (i = 0; i < RX_MAX_POOLS; i++) {
+            g_free(dev->rx_pool[i]);
+            dev->rx_pool[i] = NULL;
+        }
+    }
 }
 
 void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
@@ -372,6 +479,113 @@ static target_ulong h_free_logical_lan(PowerPCCPU *cpu,
     return H_SUCCESS;
 }
 
+/**
+ * Used for qsort, this function compares two RxBufPools by size.
+ */
+static int rx_pool_size_compare(const void *p1, const void *p2)
+{
+    const RxBufPool *pool1 = *(RxBufPool **)p1;
+    const RxBufPool *pool2 = *(RxBufPool **)p2;
+
+    if (pool1->bufsize < pool2->bufsize) {
+        return -1;
+    }
+    return pool1->bufsize > pool2->bufsize;
+}
+
+/**
+ * Search for a matching buffer pool with exact matching size,
+ * or return -1 if no matching pool has been found.
+ */
+static int spapr_vlan_get_rx_pool_id(VIOsPAPRVLANDevice *dev, int size)
+{
+    int pool;
+
+    for (pool = 0; pool < RX_MAX_POOLS; pool++) {
+        if (dev->rx_pool[pool]->bufsize == size) {
+            return pool;
+        }
+    }
+
+    return -1;
+}
+
+/**
+ * Enqueuing receive buffer by adding it to one of our receive buffer pools
+ */
+static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev,
+                                                target_ulong buf)
+{
+    int size = VLAN_BD_LEN(buf);
+    int pool;
+
+    pool = spapr_vlan_get_rx_pool_id(dev, size);
+    if (pool < 0) {
+        /*
+         * No matching pool found? Try to use a new one. If the guest used all
+         * pools before, but changed the size of one pool inbetween, we might
+         * need to recycle that pool here (if it's empty already). Thus scan
+         * all buffer pools now, starting with the last (likely empty) one.
+         */
+        for (pool = RX_MAX_POOLS - 1; pool >= 0 ; pool--) {
+            if (dev->rx_pool[pool]->count == 0) {
+                dev->rx_pool[pool]->bufsize = size;
+                /*
+                 * Sort pools by size so that spapr_vlan_receive()
+                 * can later find the smallest buffer pool easily.
+                 */
+                qsort(dev->rx_pool, RX_MAX_POOLS, sizeof(dev->rx_pool[0]),
+                      rx_pool_size_compare);
+                pool = spapr_vlan_get_rx_pool_id(dev, size);
+                DPRINTF("created RX pool %d for size %lld\n", pool,
+                        VLAN_BD_LEN(buf));
+                break;
+            }
+        }
+    }
+    /* Still no usable pool? Give up */
+    if (pool < 0 || dev->rx_pool[pool]->count >= RX_POOL_MAX_BDS) {
+        return H_RESOURCE;
+    }
+
+    DPRINTF("h_add_llan_buf():  Add buf using pool %i (size %lli, count=%i)\n",
+            pool, VLAN_BD_LEN(buf), dev->rx_pool[pool]->count);
+
+    dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count++] = buf;
+
+    return 0;
+}
+
+/**
+ * This is the old way of enqueuing receive buffers: Add it to the rx queue
+ * page that has been supplied by the guest (which is quite limited in size).
+ */
+static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev,
+                                                target_ulong buf)
+{
+    vlan_bd_t bd;
+
+    if (dev->rx_bufs >= VLAN_MAX_BUFS) {
+        return H_RESOURCE;
+    }
+
+    do {
+        dev->add_buf_ptr += 8;
+        if (dev->add_buf_ptr >= VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF) {
+            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = vio_ldq(&dev->sdev, dev->buf_list + dev->add_buf_ptr);
+    } while (bd & VLAN_BD_VALID);
+
+    vio_stq(&dev->sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+    DPRINTF("h_add_llan_buf():  Added buf  ptr=%d  rx_bufs=%d bd=0x%016llx\n",
+            dev->add_buf_ptr, dev->rx_bufs, (unsigned long long)buf);
+
+    return 0;
+}
+
 static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
                                              sPAPRMachineState *spapr,
                                              target_ulong opcode,
@@ -381,7 +595,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
     target_ulong buf = args[1];
     VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
     VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
-    vlan_bd_t bd;
+    target_long ret;
 
     DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
             ", 0x" TARGET_FMT_lx ")\n", reg, buf);
@@ -397,29 +611,23 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
         return H_PARAMETER;
     }
 
-    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+    if (!dev->isopen) {
         return H_RESOURCE;
     }
 
-    do {
-        dev->add_buf_ptr += 8;
-        if (dev->add_buf_ptr >= (VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF)) {
-            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
-        }
-
-        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
-    } while (bd & VLAN_BD_VALID);
-
-    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+    if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+        ret = spapr_vlan_add_rxbuf_to_pool(dev, buf);
+    } else {
+        ret = spapr_vlan_add_rxbuf_to_page(dev, buf);
+    }
+    if (ret) {
+        return ret;
+    }
 
     dev->rx_bufs++;
 
     qemu_flush_queued_packets(qemu_get_queue(dev->nic));
 
-    DPRINTF("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
-            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
-            (unsigned long long)buf);
-
     return H_SUCCESS;
 }
 
@@ -509,9 +717,44 @@ static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 static Property spapr_vlan_properties[] = {
     DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
     DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+    DEFINE_PROP_BIT("use-rx-buffer-pools", VIOsPAPRVLANDevice,
+                    compat_flags, SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
+static bool spapr_vlan_rx_buffer_pools_needed(void *opaque)
+{
+    VIOsPAPRVLANDevice *dev = opaque;
+
+    return (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) != 0;
+}
+
+static const VMStateDescription vmstate_rx_buffer_pool = {
+    .name = "spapr_llan/rx_buffer_pool",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = spapr_vlan_rx_buffer_pools_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(bufsize, RxBufPool),
+        VMSTATE_INT32(count, RxBufPool),
+        VMSTATE_UINT64_ARRAY(bds, RxBufPool, RX_POOL_MAX_BDS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_rx_pools = {
+    .name = "spapr_llan/rx_pools",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = spapr_vlan_rx_buffer_pools_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(rx_pool, VIOsPAPRVLANDevice,
+                                           RX_MAX_POOLS, 1,
+                                           vmstate_rx_buffer_pool, RxBufPool),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_spapr_llan = {
     .name = "spapr_llan",
     .version_id = 1,
@@ -528,6 +771,10 @@ static const VMStateDescription vmstate_spapr_llan = {
 
         VMSTATE_END_OF_LIST()
     },
+    .subsections = (const VMStateDescription * []) {
+        &vmstate_rx_pools,
+        NULL
+    }
 };
 
 static void spapr_vlan_class_init(ObjectClass *klass, void *data)
@@ -554,6 +801,7 @@ static const TypeInfo spapr_vlan_info = {
     .instance_size = sizeof(VIOsPAPRVLANDevice),
     .class_init    = spapr_vlan_class_init,
     .instance_init = spapr_vlan_instance_init,
+    .instance_finalize = spapr_vlan_instance_finalize,
 };
 
 static void spapr_vlan_register_types(void)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d0bb42305b..65abccb2f5 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -497,10 +497,11 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
              * Older KVM versions with older guest kernels were broken with the
              * magic page, don't allow the guest to map it.
              */
-            kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
-                                 sizeof(hypercall));
-            _FDT((fdt_property(fdt, "hcall-instructions", hypercall,
-                              sizeof(hypercall))));
+            if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
+                                      sizeof(hypercall))) {
+                _FDT((fdt_property(fdt, "hcall-instructions", hypercall,
+                                   sizeof(hypercall))));
+            }
         }
         _FDT((fdt_end_node(fdt)));
     }
@@ -1612,15 +1613,8 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
     /* Set time-base frequency to 512 MHz */
     cpu_ppc_tb_init(env, TIMEBASE_FREQ);
 
-    /* PAPR always has exception vectors in RAM not ROM. To ensure this,
-     * MSR[IP] should never be set.
-     */
-    env->msr_mask &= ~(1 << 6);
-
-    /* Tell KVM that we're in PAPR mode */
-    if (kvm_enabled()) {
-        kvmppc_set_papr(cpu);
-    }
+    /* Enable PAPR mode in TCG or KVM */
+    cpu_ppc_set_papr(cpu);
 
     if (cpu->max_compat) {
         Error *local_err = NULL;
@@ -2362,7 +2356,12 @@ DEFINE_SPAPR_MACHINE(2_6, "2.6", true);
  * pseries-2.5
  */
 #define SPAPR_COMPAT_2_5 \
-        HW_COMPAT_2_5
+    HW_COMPAT_2_5 \
+    { \
+        .driver   = "spapr-vlan", \
+        .property = "use-rx-buffer-pools", \
+        .value    = "off", \
+    },
 
 static void spapr_machine_2_5_instance_options(MachineState *machine)
 {
diff --git a/qapi-schema.json b/qapi-schema.json
index 88f9b81c12..7f8d799bde 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3082,6 +3082,7 @@
 #
 # 'unmapped' and 'pause' since 2.0
 # 'ro' and 'kp_comma' since 2.4
+# 'kp_equals' and 'power' since 2.6
 ##
 { 'enum': 'QKeyCode',
   'data': [ 'unmapped',
@@ -3100,7 +3101,7 @@
             'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
             'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
             'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause', 'ro',
-            'kp_comma' ] }
+            'kp_comma', 'kp_equals', 'power' ] }
 
 ##
 # @KeyValue
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 1e2b070cc3..4f3ebb9dbb 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -99,6 +99,7 @@ struct CPUMIPSFPUContext {
     uint32_t fcr0;
 #define FCR0_FREP 29
 #define FCR0_UFRP 28
+#define FCR0_HAS2008 23
 #define FCR0_F64 22
 #define FCR0_L 21
 #define FCR0_W 20
@@ -110,6 +111,8 @@ struct CPUMIPSFPUContext {
 #define FCR0_REV 0
     /* fcsr */
     uint32_t fcr31;
+#define FCR31_ABS2008 19
+#define FCR31_NAN2008 18
 #define SET_FP_COND(num,env)     do { ((env).fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0)
 #define CLEAR_FP_COND(num,env)   do { ((env).fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0)
 #define GET_FP_COND(env)         ((((env).fcr31 >> 24) & 0xfe) | (((env).fcr31 >> 23) & 0x1))
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 12ed8208d0..0f43bf4758 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -20012,6 +20012,7 @@ void cpu_state_reset(CPUMIPSState *env)
     env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
     env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
     env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
+    env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
     env->msair = env->cpu_model->MSAIR;
     env->insn_flags = env->cpu_model->insn_flags;
 
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index cdef59d952..3192db0960 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -84,6 +84,7 @@ struct mips_def_t {
     int32_t CP0_TCStatus_rw_bitmask;
     int32_t CP0_SRSCtl;
     int32_t CP1_fcr0;
+    int32_t CP1_fcr31;
     int32_t MSAIR;
     int32_t SEGBITS;
     int32_t PABITS;
@@ -421,9 +422,10 @@ static const mips_def_t mips_defs[] =
         .CP0_Status_rw_bitmask = 0x3C68FF1F,
         .CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) |
                     (1 << CP0PG_ELPA) | (1 << CP0PG_IEC),
-        .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_UFRP) | (1 << FCR0_F64) |
-                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
-                    (1 << FCR0_S) | (0x03 << FCR0_PRID),
+        .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_UFRP) | (1 << FCR0_HAS2008) |
+                    (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x03 << FCR0_PRID),
+        .CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
         .SEGBITS = 32,
         .PABITS = 40,
         .insn_flags = CPU_MIPS32R5 | ASE_MSA,
@@ -458,9 +460,10 @@ static const mips_def_t mips_defs[] =
         .CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
                          (1U << CP0PG_RIE),
         .CP0_PageGrain_rw_bitmask = 0,
-        .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) |
-                    (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
-                    (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_HAS2008) | (1 << FCR0_F64) |
+                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
+                    (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
         .SEGBITS = 32,
         .PABITS = 32,
         .insn_flags = CPU_MIPS32R6 | ASE_MICROMIPS,
@@ -677,9 +680,10 @@ static const mips_def_t mips_defs[] =
         .CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
                          (1U << CP0PG_RIE),
         .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
-        .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) |
-                    (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
-                    (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_HAS2008) | (1 << FCR0_F64) |
+                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
+                    (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .CP1_fcr31 = (1 << FCR31_ABS2008) | (1 << FCR31_NAN2008),
         .SEGBITS = 48,
         .PABITS = 48,
         .insn_flags = CPU_MIPS64R6 | ASE_MSA,
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 8d90d862de..676081e69d 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -474,9 +474,17 @@ struct ppc_slb_t {
 #define MSR_RI   1  /* Recoverable interrupt                        1        */
 #define MSR_LE   0  /* Little-endian mode                           1 hflags */
 
-#define LPCR_ILE (1 << (63-38))
-#define LPCR_AIL_SHIFT (63-40)      /* Alternate interrupt location */
-#define LPCR_AIL (3 << LPCR_AIL_SHIFT)
+/* LPCR bits */
+#define LPCR_VPM0         (1ull << (63 - 0))
+#define LPCR_VPM1         (1ull << (63 - 1))
+#define LPCR_ISL          (1ull << (63 - 2))
+#define LPCR_KBV          (1ull << (63 - 3))
+#define LPCR_ILE          (1ull << (63 - 38))
+#define LPCR_MER          (1ull << (63 - 52))
+#define LPCR_LPES0        (1ull << (63 - 60))
+#define LPCR_LPES1        (1ull << (63 - 61))
+#define LPCR_AIL_SHIFT    (63 - 40)      /* Alternate interrupt location */
+#define LPCR_AIL          (3ull << LPCR_AIL_SHIFT)
 
 #define msr_sf   ((env->msr >> MSR_SF)   & 1)
 #define msr_isf  ((env->msr >> MSR_ISF)  & 1)
@@ -1260,6 +1268,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);
 void store_booke_tsr (CPUPPCState *env, target_ulong val);
 void ppc_tlb_invalidate_all (CPUPPCState *env);
 void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
+void cpu_ppc_set_papr(PowerPCCPU *cpu);
 #endif
 #endif
 
@@ -1346,11 +1355,14 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define SPR_SRR1              (0x01B)
 #define SPR_CFAR              (0x01C)
 #define SPR_AMR               (0x01D)
+#define SPR_ACOP              (0x01F)
 #define SPR_BOOKE_PID         (0x030)
+#define SPR_BOOKS_PID         (0x030)
 #define SPR_BOOKE_DECAR       (0x036)
 #define SPR_BOOKE_CSRR0       (0x03A)
 #define SPR_BOOKE_CSRR1       (0x03B)
 #define SPR_BOOKE_DEAR        (0x03D)
+#define SPR_IAMR              (0x03D)
 #define SPR_BOOKE_ESR         (0x03E)
 #define SPR_BOOKE_IVPR        (0x03F)
 #define SPR_MPC_EIE           (0x050)
@@ -1381,6 +1393,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define SPR_MPC_ICTRL         (0x09E)
 #define SPR_MPC_BAR           (0x09F)
 #define SPR_PSPB              (0x09F)
+#define SPR_DAWR              (0x0B4)
+#define SPR_RPR               (0x0BA)
+#define SPR_CIABR             (0x0BB)
+#define SPR_DAWRX             (0x0BC)
+#define SPR_HFSCR             (0x0BE)
 #define SPR_VRSAVE            (0x100)
 #define SPR_USPRG0            (0x100)
 #define SPR_USPRG1            (0x101)
@@ -1435,19 +1452,25 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define SPR_HSRR1             (0x13B)
 #define SPR_BOOKE_IAC4        (0x13B)
 #define SPR_BOOKE_DAC1        (0x13C)
-#define SPR_LPIDR             (0x13D)
+#define SPR_MMCRH             (0x13C)
 #define SPR_DABR2             (0x13D)
 #define SPR_BOOKE_DAC2        (0x13D)
+#define SPR_TFMR              (0x13D)
 #define SPR_BOOKE_DVC1        (0x13E)
 #define SPR_LPCR              (0x13E)
 #define SPR_BOOKE_DVC2        (0x13F)
+#define SPR_LPIDR             (0x13F)
 #define SPR_BOOKE_TSR         (0x150)
+#define SPR_HMER              (0x150)
+#define SPR_HMEER             (0x151)
 #define SPR_PCR               (0x152)
+#define SPR_BOOKE_LPIDR       (0x152)
 #define SPR_BOOKE_TCR         (0x154)
 #define SPR_BOOKE_TLB0PS      (0x158)
 #define SPR_BOOKE_TLB1PS      (0x159)
 #define SPR_BOOKE_TLB2PS      (0x15A)
 #define SPR_BOOKE_TLB3PS      (0x15B)
+#define SPR_AMOR              (0x15D)
 #define SPR_BOOKE_MAS7_MAS3   (0x174)
 #define SPR_BOOKE_IVOR0       (0x190)
 #define SPR_BOOKE_IVOR1       (0x191)
@@ -1666,7 +1689,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define SPR_MPC_MD_DBRAM1     (0x32A)
 #define SPR_RCPU_L2U_RA3      (0x32B)
 #define SPR_TAR               (0x32F)
+#define SPR_IC                (0x350)
 #define SPR_VTB               (0x351)
+#define SPR_MMCRC             (0x353)
 #define SPR_440_INV0          (0x370)
 #define SPR_440_INV1          (0x371)
 #define SPR_440_INV2          (0x372)
@@ -1683,6 +1708,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define SPR_POWER_SPMC1       (0x37C)
 #define SPR_POWER_SPMC2       (0x37D)
 #define SPR_POWER_MMCRS       (0x37E)
+#define SPR_WORT              (0x37F)
 #define SPR_PPR               (0x380)
 #define SPR_750_GQR0          (0x390)
 #define SPR_440_DNV0          (0x390)
@@ -1705,6 +1731,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define SPR_440_DVLIM         (0x398)
 #define SPR_750_WPAR          (0x399)
 #define SPR_440_IVLIM         (0x399)
+#define SPR_TSCR              (0x399)
 #define SPR_750_DMAU          (0x39A)
 #define SPR_750_DMAL          (0x39B)
 #define SPR_440_RSTCFG        (0x39B)
@@ -1879,9 +1906,10 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 #define   L1CSR1_ICE		0x00000001	/* Instruction Cache Enable */
 
 /* HID0 bits */
-#define HID0_DEEPNAP        (1 << 24)
-#define HID0_DOZE           (1 << 23)
-#define HID0_NAP            (1 << 22)
+#define HID0_DEEPNAP        (1 << 24)           /* pre-2.06 */
+#define HID0_DOZE           (1 << 23)           /* pre-2.06 */
+#define HID0_NAP            (1 << 22)           /* pre-2.06 */
+#define HID0_HILE           (1ull << (63 - 19)) /* POWER8 */
 
 /*****************************************************************************/
 /* PowerPC Instructions types definitions                                    */
@@ -2230,6 +2258,25 @@ enum {
     PCR_TM_DIS          = 1ull << (63-2), /* Trans. memory disable (POWER8) */
 };
 
+/* HMER/HMEER */
+enum {
+    HMER_MALFUNCTION_ALERT      = 1ull << (63 - 0),
+    HMER_PROC_RECV_DONE         = 1ull << (63 - 2),
+    HMER_PROC_RECV_ERROR_MASKED = 1ull << (63 - 3),
+    HMER_TFAC_ERROR             = 1ull << (63 - 4),
+    HMER_TFMR_PARITY_ERROR      = 1ull << (63 - 5),
+    HMER_XSCOM_FAIL             = 1ull << (63 - 8),
+    HMER_XSCOM_DONE             = 1ull << (63 - 9),
+    HMER_PROC_RECV_AGAIN        = 1ull << (63 - 11),
+    HMER_WARN_RISE              = 1ull << (63 - 14),
+    HMER_WARN_FALL              = 1ull << (63 - 15),
+    HMER_SCOM_FIR_HMI           = 1ull << (63 - 16),
+    HMER_TRIG_FIR_HMI           = 1ull << (63 - 17),
+    HMER_HYP_RESOURCE_ERR       = 1ull << (63 - 20),
+    HMER_XSCOM_STATUS_MASK      = 7ull << (63 - 23),
+    HMER_XSCOM_STATUS_LSH       = (63 - 23),
+};
+
 /*****************************************************************************/
 
 static inline target_ulong cpu_read_xer(CPUPPCState *env)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 2fc993143e..20f113a079 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -2007,7 +2007,7 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
     hc[2] = cpu_to_be32(0x48000008);
     hc[3] = cpu_to_be32(bswap32(0x3860ffff));
 
-    return 0;
+    return 1;
 }
 
 static inline int kvmppc_enable_hcall(KVMState *s, target_ulong hcall)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index e402ff9203..6f0e7b4fac 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4282,14 +4282,17 @@ static inline void gen_op_mfspr(DisasContext *ctx)
     void (*read_cb)(DisasContext *ctx, int gprn, int sprn);
     uint32_t sprn = SPR(ctx->opcode);
 
-#if !defined(CONFIG_USER_ONLY)
-    if (ctx->hv)
+#if defined(CONFIG_USER_ONLY)
+    read_cb = ctx->spr_cb[sprn].uea_read;
+#else
+    if (ctx->pr) {
+        read_cb = ctx->spr_cb[sprn].uea_read;
+    } else if (ctx->hv) {
         read_cb = ctx->spr_cb[sprn].hea_read;
-    else if (!ctx->pr)
+    } else {
         read_cb = ctx->spr_cb[sprn].oea_read;
-    else
+    }
 #endif
-        read_cb = ctx->spr_cb[sprn].uea_read;
     if (likely(read_cb != NULL)) {
         if (likely(read_cb != SPR_NOACCESS)) {
             (*read_cb)(ctx, rD(ctx->opcode), sprn);
@@ -4437,14 +4440,17 @@ static void gen_mtspr(DisasContext *ctx)
     void (*write_cb)(DisasContext *ctx, int sprn, int gprn);
     uint32_t sprn = SPR(ctx->opcode);
 
-#if !defined(CONFIG_USER_ONLY)
-    if (ctx->hv)
+#if defined(CONFIG_USER_ONLY)
+    write_cb = ctx->spr_cb[sprn].uea_write;
+#else
+    if (ctx->pr) {
+        write_cb = ctx->spr_cb[sprn].uea_write;
+    } else if (ctx->hv) {
         write_cb = ctx->spr_cb[sprn].hea_write;
-    else if (!ctx->pr)
+    } else {
         write_cb = ctx->spr_cb[sprn].oea_write;
-    else
+    }
 #endif
-        write_cb = ctx->spr_cb[sprn].uea_write;
     if (likely(write_cb != NULL)) {
         if (likely(write_cb != SPR_NOACCESS)) {
             (*write_cb)(ctx, sprn, rS(ctx->opcode));
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index fb206aff29..0a33597f6b 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -579,17 +579,33 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val)
 #define spr_register_kvm(env, num, name, uea_read, uea_write,                  \
                          oea_read, oea_write, one_reg_id, initial_value)       \
     _spr_register(env, num, name, uea_read, uea_write, initial_value)
+#define spr_register_kvm_hv(env, num, name, uea_read, uea_write,               \
+                            oea_read, oea_write, hea_read, hea_write,          \
+                            one_reg_id, initial_value)                         \
+    _spr_register(env, num, name, uea_read, uea_write, initial_value)
 #else
 #if !defined(CONFIG_KVM)
 #define spr_register_kvm(env, num, name, uea_read, uea_write,                  \
-                         oea_read, oea_write, one_reg_id, initial_value) \
+                         oea_read, oea_write, one_reg_id, initial_value)       \
+    _spr_register(env, num, name, uea_read, uea_write,                         \
+                  oea_read, oea_write, oea_read, oea_write, initial_value)
+#define spr_register_kvm_hv(env, num, name, uea_read, uea_write,               \
+                            oea_read, oea_write, hea_read, hea_write,          \
+                            one_reg_id, initial_value)                         \
     _spr_register(env, num, name, uea_read, uea_write,                         \
-                  oea_read, oea_write, initial_value)
+                  oea_read, oea_write, hea_read, hea_write, initial_value)
 #else
 #define spr_register_kvm(env, num, name, uea_read, uea_write,                  \
-                         oea_read, oea_write, one_reg_id, initial_value) \
+                         oea_read, oea_write, one_reg_id, initial_value)       \
+    _spr_register(env, num, name, uea_read, uea_write,                         \
+                  oea_read, oea_write, oea_read, oea_write,                    \
+                  one_reg_id, initial_value)
+#define spr_register_kvm_hv(env, num, name, uea_read, uea_write,               \
+                            oea_read, oea_write, hea_read, hea_write,          \
+                            one_reg_id, initial_value)                         \
     _spr_register(env, num, name, uea_read, uea_write,                         \
-                  oea_read, oea_write, one_reg_id, initial_value)
+                  oea_read, oea_write, hea_read, hea_write,                    \
+                  one_reg_id, initial_value)
 #endif
 #endif
 
@@ -598,6 +614,13 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val)
     spr_register_kvm(env, num, name, uea_read, uea_write,                      \
                      oea_read, oea_write, 0, initial_value)
 
+#define spr_register_hv(env, num, name, uea_read, uea_write,                   \
+                        oea_read, oea_write, hea_read, hea_write,              \
+                        initial_value)                                         \
+    spr_register_kvm_hv(env, num, name, uea_read, uea_write,                   \
+                        oea_read, oea_write, hea_read, hea_write,              \
+                        0, initial_value)
+
 static inline void _spr_register(CPUPPCState *env, int num,
                                  const char *name,
                                  void (*uea_read)(DisasContext *ctx, int gprn, int sprn),
@@ -606,6 +629,8 @@ static inline void _spr_register(CPUPPCState *env, int num,
 
                                  void (*oea_read)(DisasContext *ctx, int gprn, int sprn),
                                  void (*oea_write)(DisasContext *ctx, int sprn, int gprn),
+                                 void (*hea_read)(DisasContext *opaque, int gprn, int sprn),
+                                 void (*hea_write)(DisasContext *opaque, int sprn, int gprn),
 #endif
 #if defined(CONFIG_KVM)
                                  uint64_t one_reg_id,
@@ -633,6 +658,8 @@ static inline void _spr_register(CPUPPCState *env, int num,
 #if !defined(CONFIG_USER_ONLY)
     spr->oea_read = oea_read;
     spr->oea_write = oea_write;
+    spr->hea_read = hea_read;
+    spr->hea_write = hea_write;
 #endif
 #if defined(CONFIG_KVM)
     spr->one_reg_id = one_reg_id,
@@ -1036,30 +1063,102 @@ static void gen_spr_7xx (CPUPPCState *env)
 
 #ifdef TARGET_PPC64
 #ifndef CONFIG_USER_ONLY
-static void spr_read_uamr (DisasContext *ctx, int gprn, int sprn)
+static void spr_write_amr(DisasContext *ctx, int sprn, int gprn)
 {
-    gen_load_spr(cpu_gpr[gprn], SPR_AMR);
-    spr_load_dump_spr(SPR_AMR);
-}
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
 
-static void spr_write_uamr (DisasContext *ctx, int sprn, int gprn)
-{
-    gen_store_spr(SPR_AMR, cpu_gpr[gprn]);
+    /* Note, the HV=1 PR=0 case is handled earlier by simply using
+     * spr_write_generic for HV mode in the SPR table
+     */
+
+    /* Build insertion mask into t1 based on context */
+    if (ctx->pr) {
+        gen_load_spr(t1, SPR_UAMOR);
+    } else {
+        gen_load_spr(t1, SPR_AMOR);
+    }
+
+    /* Mask new bits into t2 */
+    tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
+
+    /* Load AMR and clear new bits in t0 */
+    gen_load_spr(t0, SPR_AMR);
+    tcg_gen_andc_tl(t0, t0, t1);
+
+    /* Or'in new bits and write it out */
+    tcg_gen_or_tl(t0, t0, t2);
+    gen_store_spr(SPR_AMR, t0);
     spr_store_dump_spr(SPR_AMR);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
 }
 
-static void spr_write_uamr_pr (DisasContext *ctx, int sprn, int gprn)
+static void spr_write_uamor(DisasContext *ctx, int sprn, int gprn)
 {
     TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
+
+    /* Note, the HV=1 case is handled earlier by simply using
+     * spr_write_generic for HV mode in the SPR table
+     */
 
+    /* Build insertion mask into t1 based on context */
+    gen_load_spr(t1, SPR_AMOR);
+
+    /* Mask new bits into t2 */
+    tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
+
+    /* Load AMR and clear new bits in t0 */
     gen_load_spr(t0, SPR_UAMOR);
-    tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
-    gen_store_spr(SPR_AMR, t0);
-    spr_store_dump_spr(SPR_AMR);
+    tcg_gen_andc_tl(t0, t0, t1);
+
+    /* Or'in new bits and write it out */
+    tcg_gen_or_tl(t0, t0, t2);
+    gen_store_spr(SPR_UAMOR, t0);
+    spr_store_dump_spr(SPR_UAMOR);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+}
+
+static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv t1 = tcg_temp_new();
+    TCGv t2 = tcg_temp_new();
+
+    /* Note, the HV=1 case is handled earlier by simply using
+     * spr_write_generic for HV mode in the SPR table
+     */
+
+    /* Build insertion mask into t1 based on context */
+    gen_load_spr(t1, SPR_AMOR);
+
+    /* Mask new bits into t2 */
+    tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
+
+    /* Load AMR and clear new bits in t0 */
+    gen_load_spr(t0, SPR_IAMR);
+    tcg_gen_andc_tl(t0, t0, t1);
+
+    /* Or'in new bits and write it out */
+    tcg_gen_or_tl(t0, t0, t2);
+    gen_store_spr(SPR_IAMR, t0);
+    spr_store_dump_spr(SPR_IAMR);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
 }
 #endif /* CONFIG_USER_ONLY */
 
-static void gen_spr_amr (CPUPPCState *env)
+static void gen_spr_amr(CPUPPCState *env, bool has_iamr)
 {
 #ifndef CONFIG_USER_ONLY
     /* Virtual Page Class Key protection */
@@ -1067,17 +1166,31 @@ static void gen_spr_amr (CPUPPCState *env)
      * userspace accessible, 29 is privileged.  So we only need to set
      * the kvm ONE_REG id on one of them, we use 29 */
     spr_register(env, SPR_UAMR, "UAMR",
-                 &spr_read_uamr, &spr_write_uamr_pr,
-                 &spr_read_uamr, &spr_write_uamr,
+                 &spr_read_generic, &spr_write_amr,
+                 &spr_read_generic, &spr_write_amr,
                  0);
-    spr_register_kvm(env, SPR_AMR, "AMR",
+    spr_register_kvm_hv(env, SPR_AMR, "AMR",
                      SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_amr,
                      &spr_read_generic, &spr_write_generic,
                      KVM_REG_PPC_AMR, 0);
-    spr_register_kvm(env, SPR_UAMOR, "UAMOR",
+    spr_register_kvm_hv(env, SPR_UAMOR, "UAMOR",
                      SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_uamor,
                      &spr_read_generic, &spr_write_generic,
                      KVM_REG_PPC_UAMOR, 0);
+    spr_register_hv(env, SPR_AMOR, "AMOR",
+                    SPR_NOACCESS, SPR_NOACCESS,
+                    SPR_NOACCESS, SPR_NOACCESS,
+                    &spr_read_generic, &spr_write_generic,
+                    0);
+    if (has_iamr) {
+        spr_register_kvm_hv(env, SPR_IAMR, "IAMR",
+                            SPR_NOACCESS, SPR_NOACCESS,
+                            &spr_read_generic, &spr_write_iamr,
+                            &spr_read_generic, &spr_write_generic,
+                            KVM_REG_PPC_IAMR, 0);
+    }
 #endif /* !CONFIG_USER_ONLY */
 }
 #endif /* TARGET_PPC64 */
@@ -7464,6 +7577,25 @@ static void gen_spr_book3s_dbg(CPUPPCState *env)
                      KVM_REG_PPC_DABRX, 0x00000000);
 }
 
+static void gen_spr_book3s_207_dbg(CPUPPCState *env)
+{
+    spr_register_kvm_hv(env, SPR_DAWR, "DAWR",
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        &spr_read_generic, &spr_write_generic,
+                        KVM_REG_PPC_DAWR, 0x00000000);
+    spr_register_kvm_hv(env, SPR_DAWRX, "DAWRX",
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        &spr_read_generic, &spr_write_generic,
+                        KVM_REG_PPC_DAWRX, 0x00000000);
+    spr_register_kvm_hv(env, SPR_CIABR, "CIABR",
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        &spr_read_generic, &spr_write_generic,
+                        KVM_REG_PPC_CIABR, 0x00000000);
+}
+
 static void gen_spr_970_dbg(CPUPPCState *env)
 {
     /* Breakpoints */
@@ -7878,6 +8010,36 @@ static void gen_spr_power8_pspb(CPUPPCState *env)
                      KVM_REG_PPC_PSPB, 0);
 }
 
+static void gen_spr_power8_ic(CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    spr_register_hv(env, SPR_IC, "IC",
+                    SPR_NOACCESS, SPR_NOACCESS,
+                    &spr_read_generic, SPR_NOACCESS,
+                    &spr_read_generic, &spr_write_generic,
+                    0);
+#endif
+}
+
+static void gen_spr_power8_book4(CPUPPCState *env)
+{
+    /* Add a number of P8 book4 registers */
+#if !defined(CONFIG_USER_ONLY)
+    spr_register_kvm(env, SPR_ACOP, "ACOP",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     KVM_REG_PPC_ACOP, 0);
+    spr_register_kvm(env, SPR_BOOKS_PID, "PID",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     KVM_REG_PPC_PID, 0);
+    spr_register_kvm(env, SPR_WORT, "WORT",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     KVM_REG_PPC_WORT, 0);
+#endif
+}
+
 static void init_proc_book3s_64(CPUPPCState *env, int version)
 {
     gen_spr_ne_601(env);
@@ -7899,7 +8061,7 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)
     case BOOK3S_CPU_POWER7:
     case BOOK3S_CPU_POWER8:
         gen_spr_book3s_ids(env);
-        gen_spr_amr(env);
+        gen_spr_amr(env, version >= BOOK3S_CPU_POWER8);
         gen_spr_book3s_purr(env);
         env->ci_large_pages = true;
         break;
@@ -7930,9 +8092,13 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)
         gen_spr_power8_tm(env);
         gen_spr_power8_pspb(env);
         gen_spr_vtb(env);
+        gen_spr_power8_ic(env);
+        gen_spr_power8_book4(env);
     }
     if (version < BOOK3S_CPU_POWER8) {
         gen_spr_book3s_dbg(env);
+    } else {
+        gen_spr_book3s_207_dbg(env);
     }
 #if !defined(CONFIG_USER_ONLY)
     switch (version) {
@@ -8332,8 +8498,33 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
     pcc->l1_icache_size = 0x8000;
     pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
 }
-#endif /* defined (TARGET_PPC64) */
 
+#if !defined(CONFIG_USER_ONLY)
+
+void cpu_ppc_set_papr(PowerPCCPU *cpu)
+{
+    CPUPPCState *env = &cpu->env;
+    ppc_spr_t *amor = &env->spr_cb[SPR_AMOR];
+
+    /* PAPR always has exception vectors in RAM not ROM. To ensure this,
+     * MSR[IP] should never be set.
+     *
+     * We also disallow setting of MSR_HV
+     */
+    env->msr_mask &= ~((1ull << MSR_EP) | MSR_HVB);
+
+    /* Set a full AMOR so guest can use the AMR as it sees fit */
+    env->spr[SPR_AMOR] = amor->default_value = 0xffffffffffffffffull;
+
+    /* Tell KVM that we're in PAPR mode */
+    if (kvm_enabled()) {
+        kvmppc_set_papr(cpu);
+    }
+}
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#endif /* defined (TARGET_PPC64) */
 
 /*****************************************************************************/
 /* Generic CPU instantiation routine                                         */
@@ -9703,7 +9894,7 @@ static void ppc_cpu_reset(CPUState *s)
 
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
-        env->msr |= (1ULL << MSR_SF);
+        msr |= (1ULL << MSR_SF);
     }
 #endif
 
diff --git a/target-tricore/Makefile.objs b/target-tricore/Makefile.objs
index 21e820d8f9..7a05670718 100644
--- a/target-tricore/Makefile.objs
+++ b/target-tricore/Makefile.objs
@@ -1 +1 @@
-obj-y += translate.o helper.o cpu.o op_helper.o
+obj-y += translate.o helper.o cpu.o op_helper.o fpu_helper.o
diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h
index 5fee376674..90045a93d2 100644
--- a/target-tricore/cpu.h
+++ b/target-tricore/cpu.h
@@ -183,8 +183,7 @@ struct CPUTriCoreState {
     uint32_t M2CNT;
     uint32_t M3CNT;
     /* Floating Point Registers */
-    /* XXX: */
-
+    float_status fp_status;
     /* QEMU */
     int error_code;
     uint32_t hflags;    /* CPU State */
@@ -217,6 +216,7 @@ struct CPUTriCoreState {
 #define MASK_PSW_GW  0x00000100
 #define MASK_PSW_CDE 0x00000080
 #define MASK_PSW_CDC 0x0000007f
+#define MASK_PSW_FPU_RM 0x3000000
 
 #define MASK_SYSCON_PRO_TEN 0x2
 #define MASK_SYSCON_FCD_SF  0x1
@@ -339,6 +339,8 @@ enum {
 uint32_t psw_read(CPUTriCoreState *env);
 void psw_write(CPUTriCoreState *env, uint32_t val);
 
+void fpu_set_state(CPUTriCoreState *env);
+
 #include "cpu-qom.h"
 #define MMU_USER_IDX 2
 
diff --git a/target-tricore/fpu_helper.c b/target-tricore/fpu_helper.c
new file mode 100644
index 0000000000..98fe9472b1
--- /dev/null
+++ b/target-tricore/fpu_helper.c
@@ -0,0 +1,217 @@
+/*
+ *  TriCore emulation for qemu: fpu helper.
+ *
+ *  Copyright (c) 2016 Bastian Koppelmann University of Paderborn
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+
+#define ADD_NAN   0x7cf00001
+#define DIV_NAN   0x7fc00008
+#define MUL_NAN   0x7fc00002
+#define FPU_FS PSW_USB_C
+#define FPU_FI PSW_USB_V
+#define FPU_FV PSW_USB_SV
+#define FPU_FZ PSW_USB_AV
+#define FPU_FU PSW_USB_SAV
+
+/* we don't care about input_denormal */
+static inline uint8_t f_get_excp_flags(CPUTriCoreState *env)
+{
+    return get_float_exception_flags(&env->fp_status)
+           & (float_flag_invalid
+              | float_flag_overflow
+              | float_flag_underflow
+              | float_flag_output_denormal
+              | float_flag_divbyzero
+              | float_flag_inexact);
+}
+
+static inline bool f_is_denormal(float32 arg)
+{
+    return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
+}
+
+static void f_update_psw_flags(CPUTriCoreState *env, uint8_t flags)
+{
+    uint8_t some_excp = 0;
+    set_float_exception_flags(0, &env->fp_status);
+
+    if (flags & float_flag_invalid) {
+        env->FPU_FI = 1 << 31;
+        some_excp = 1;
+    }
+
+    if (flags & float_flag_overflow) {
+        env->FPU_FV = 1 << 31;
+        some_excp = 1;
+    }
+
+    if (flags & float_flag_underflow || flags & float_flag_output_denormal) {
+        env->FPU_FU = 1 << 31;
+        some_excp = 1;
+    }
+
+    if (flags & float_flag_divbyzero) {
+        env->FPU_FZ = 1 << 31;
+        some_excp = 1;
+    }
+
+    if (flags & float_flag_inexact || flags & float_flag_output_denormal) {
+        env->PSW |= 1 << 26;
+        some_excp = 1;
+    }
+
+    env->FPU_FS = some_excp;
+}
+
+#define FADD_SUB(op)                                                           \
+uint32_t helper_f##op(CPUTriCoreState *env, uint32_t r1, uint32_t r2)          \
+{                                                                              \
+    float32 arg1 = make_float32(r1);                                           \
+    float32 arg2 = make_float32(r2);                                           \
+    uint32_t flags;                                                            \
+    float32 f_result;                                                          \
+                                                                               \
+    f_result = float32_##op(arg2, arg1, &env->fp_status);                      \
+    flags = f_get_excp_flags(env);                                             \
+    if (flags) {                                                               \
+        /* If the output is a NaN, but the inputs aren't,                      \
+           we return a unique value.  */                                       \
+        if ((flags & float_flag_invalid)                                       \
+            && !float32_is_any_nan(arg1)                                       \
+            && !float32_is_any_nan(arg2)) {                                    \
+            f_result = ADD_NAN;                                                \
+        }                                                                      \
+        f_update_psw_flags(env, flags);                                        \
+    } else {                                                                   \
+        env->FPU_FS = 0;                                                       \
+    }                                                                          \
+    return (uint32_t)f_result;                                                 \
+}
+FADD_SUB(add)
+FADD_SUB(sub)
+
+uint32_t helper_fmul(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+    uint32_t flags;
+    float32 arg1 = make_float32(r1);
+    float32 arg2 = make_float32(r2);
+    float32 f_result;
+
+    f_result = float32_mul(arg1, arg2, &env->fp_status);
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        /* If the output is a NaN, but the inputs aren't,
+           we return a unique value.  */
+        if ((flags & float_flag_invalid)
+            && !float32_is_any_nan(arg1)
+            && !float32_is_any_nan(arg2)) {
+                f_result = MUL_NAN;
+        }
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+    return (uint32_t)f_result;
+
+}
+
+uint32_t helper_fdiv(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+    uint32_t flags;
+    float32 arg1 = make_float32(r1);
+    float32 arg2 = make_float32(r2);
+    float32 f_result;
+
+    f_result = float32_div(arg1, arg2 , &env->fp_status);
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        /* If the output is a NaN, but the inputs aren't,
+           we return a unique value.  */
+        if ((flags & float_flag_invalid)
+            && !float32_is_any_nan(arg1)
+            && !float32_is_any_nan(arg2)) {
+                f_result = DIV_NAN;
+        }
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+
+    return (uint32_t)f_result;
+}
+
+uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
+{
+    uint32_t result, flags;
+    float32 arg1 = make_float32(r1);
+    float32 arg2 = make_float32(r2);
+
+    set_flush_inputs_to_zero(0, &env->fp_status);
+
+    result = 1 << (float32_compare_quiet(arg1, arg2, &env->fp_status) + 1);
+    result |= f_is_denormal(arg1) << 4;
+    result |= f_is_denormal(arg2) << 5;
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+
+    set_flush_inputs_to_zero(1, &env->fp_status);
+    return result;
+}
+
+uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg)
+{
+    float32 f_arg = make_float32(arg);
+    int32_t result, flags;
+
+    result = float32_to_int32(f_arg, &env->fp_status);
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        if (float32_is_any_nan(f_arg)) {
+            result = 0;
+        }
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+    return (uint32_t)result;
+}
+
+uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg)
+{
+    float32 f_result;
+    uint32_t flags;
+    f_result = int32_to_float32(arg, &env->fp_status);
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+    return (uint32_t)f_result;
+}
diff --git a/target-tricore/helper.c b/target-tricore/helper.c
index 7d96daddb1..71b31cdb9b 100644
--- a/target-tricore/helper.c
+++ b/target-tricore/helper.c
@@ -110,10 +110,18 @@ void tricore_cpu_list(FILE *f, fprintf_function cpu_fprintf)
     g_slist_free(list);
 }
 
+void fpu_set_state(CPUTriCoreState *env)
+{
+    set_float_rounding_mode(env->PSW & MASK_PSW_FPU_RM, &env->fp_status);
+    set_flush_inputs_to_zero(1, &env->fp_status);
+    set_flush_to_zero(1, &env->fp_status);
+    set_default_nan_mode(1, &env->fp_status);
+}
+
 uint32_t psw_read(CPUTriCoreState *env)
 {
     /* clear all USB bits */
-    env->PSW &= 0xffffff;
+    env->PSW &= 0x6ffffff;
     /* now set them from the cache */
     env->PSW |= ((env->PSW_USB_C != 0) << 31);
     env->PSW |= ((env->PSW_USB_V   & (1 << 31))  >> 1);
@@ -132,4 +140,6 @@ void psw_write(CPUTriCoreState *env, uint32_t val)
     env->PSW_USB_AV = (val & MASK_USB_AV) << 3;
     env->PSW_USB_SAV = (val & MASK_USB_SAV) << 4;
     env->PSW = val;
+
+    fpu_set_state(env);
 }
diff --git a/target-tricore/helper.h b/target-tricore/helper.h
index 2c8ed78940..9333e161ab 100644
--- a/target-tricore/helper.h
+++ b/target-tricore/helper.h
@@ -105,6 +105,13 @@ DEF_HELPER_FLAGS_1(parity, TCG_CALL_NO_RWG_SE, i32, i32)
 /* float */
 DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32)
 DEF_HELPER_1(unpack, i64, i32)
+DEF_HELPER_3(fadd, i32, env, i32, i32)
+DEF_HELPER_3(fsub, i32, env, i32, i32)
+DEF_HELPER_3(fmul, i32, env, i32, i32)
+DEF_HELPER_3(fdiv, i32, env, i32, i32)
+DEF_HELPER_3(fcmp, i32, env, i32, i32)
+DEF_HELPER_2(ftoi, i32, env, i32)
+DEF_HELPER_2(itof, i32, env, i32)
 /* dvinit */
 DEF_HELPER_3(dvinit_b_13, i64, env, i32, i32)
 DEF_HELPER_3(dvinit_b_131, i64, env, i32, i32)
diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c
index 55f6724da8..40656c357c 100644
--- a/target-tricore/op_helper.c
+++ b/target-tricore/op_helper.c
@@ -1045,6 +1045,8 @@ uint64_t helper_msub64_q_ssov(CPUTriCoreState *env, uint64_t r1, uint32_t r2,
             } else {
                result = INT64_MIN;
             }
+        } else {
+            env->PSW_USB_V = 0;
         }
     } else {
         if (ovf < 0) {
diff --git a/target-tricore/translate.c b/target-tricore/translate.c
index d13e5c8c62..912bf226be 100644
--- a/target-tricore/translate.c
+++ b/target-tricore/translate.c
@@ -6672,6 +6672,21 @@ static void decode_rr_divide(CPUTriCoreState *env, DisasContext *ctx)
             generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
         }
         break;
+    case OPC2_32_RR_MUL_F:
+        gen_helper_fmul(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+        break;
+    case OPC2_32_RR_DIV_F:
+        gen_helper_fdiv(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+        break;
+    case OPC2_32_RR_CMP_F:
+        gen_helper_fcmp(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r2]);
+        break;
+    case OPC2_32_RR_FTOI:
+        gen_helper_ftoi(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]);
+        break;
+    case OPC2_32_RR_ITOF:
+        gen_helper_itof(cpu_gpr_d[r3], cpu_env, cpu_gpr_d[r1]);
+        break;
     default:
         generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
     }
@@ -7013,48 +7028,60 @@ static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx)
     r3 = MASK_OP_RRR_S3(ctx->opcode);
     r4 = MASK_OP_RRR_D(ctx->opcode);
 
-    CHECK_REG_PAIR(r3);
-
     switch (op2) {
     case OPC2_32_RRR_DVADJ:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(dvadj, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_DVSTEP:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(dvstep, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_DVSTEP_U:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(dvstep_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_IXMAX:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(ixmax, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_IXMAX_U:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(ixmax_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_IXMIN:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(ixmin, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_IXMIN_U:
+        CHECK_REG_PAIR(r3);
         CHECK_REG_PAIR(r4);
         GEN_HELPER_RRR(ixmin_u, cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r3],
                        cpu_gpr_d[r3+1], cpu_gpr_d[r2]);
         break;
     case OPC2_32_RRR_PACK:
+        CHECK_REG_PAIR(r3);
         gen_helper_pack(cpu_gpr_d[r4], cpu_PSW_C, cpu_gpr_d[r3],
                         cpu_gpr_d[r3+1], cpu_gpr_d[r1]);
         break;
+    case OPC2_32_RRR_ADD_F:
+        gen_helper_fadd(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r3]);
+        break;
+    case OPC2_32_RRR_SUB_F:
+        gen_helper_fsub(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r3]);
+        break;
     default:
         generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
     }
@@ -8632,6 +8659,7 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
         break;
     case OPCM_32_RRR_DIVIDE:
         decode_rrr_divide(env, ctx);
+        break;
 /* RRR2 Format */
     case OPCM_32_RRR2_MADD:
         decode_rrr2_madd(env, ctx);
@@ -8661,6 +8689,7 @@ static void decode_32Bit_opc(CPUTriCoreState *env, DisasContext *ctx)
 /* RRRR format */
     case OPCM_32_RRRR_EXTRACT_INSERT:
         decode_rrrr_extract_insert(env, ctx);
+        break;
 /* RRRW format */
     case OPCM_32_RRRW_EXTRACT_INSERT:
         decode_rrrw_extract_insert(env, ctx);
@@ -8771,6 +8800,7 @@ void cpu_state_reset(CPUTriCoreState *env)
 {
     /* Reset Regs to Default Value */
     env->PSW = 0xb80;
+    fpu_set_state(env);
 }
 
 static void tricore_tcg_init_csfr(void)
diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h
index 1bfed0ce48..df666b081f 100644
--- a/target-tricore/tricore-opcodes.h
+++ b/target-tricore/tricore-opcodes.h
@@ -1126,6 +1126,20 @@ enum {
     OPC2_32_RR_CRC32                             = 0x03,
     OPC2_32_RR_DIV                               = 0x20,
     OPC2_32_RR_DIV_U                             = 0x21,
+    OPC2_32_RR_MUL_F                             = 0x04,
+    OPC2_32_RR_DIV_F                             = 0x05,
+    OPC2_32_RR_FTOI                              = 0x10,
+    OPC2_32_RR_ITOF                              = 0x14,
+    OPC2_32_RR_CMP_F                             = 0x00,
+    OPC2_32_RR_FTOIZ                             = 0x13,
+    OPC2_32_RR_FTOQ31                            = 0x11,
+    OPC2_32_RR_FTOQ31Z                           = 0x18,
+    OPC2_32_RR_FTOU                              = 0x12,
+    OPC2_32_RR_FTOUZ                             = 0x17,
+    OPC2_32_RR_Q31TOF                            = 0x15,
+    OPC2_32_RR_QSEED_F                           = 0x19,
+    OPC2_32_RR_UPDFL                             = 0x0c,
+    OPC2_32_RR_UTOF                              = 0x16,
 };
 /* OPCM_32_RR_IDIRECT                               */
 enum {
@@ -1209,6 +1223,10 @@ enum {
     OPC2_32_RRR_IXMIN                            = 0x08,
     OPC2_32_RRR_IXMIN_U                          = 0x09,
     OPC2_32_RRR_PACK                             = 0x00,
+    OPC2_32_RRR_ADD_F                            = 0x02,
+    OPC2_32_RRR_SUB_F                            = 0x03,
+    OPC2_32_RRR_MADD_F                           = 0x06,
+    OPC2_32_RRR_MSUB_F                           = 0x07,
 };
 /*
  * RRR1 Format
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 7063a025c0..691471493f 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -33,6 +33,7 @@
 #include "sysemu/sysemu.h"
 #include "qmp-commands.h"
 #include "sysemu/blockdev.h"
+#include <Carbon/Carbon.h>
 
 #ifndef MAC_OS_X_VERSION_10_5
 #define MAC_OS_X_VERSION_10_5 1050
@@ -72,178 +73,139 @@ bool stretch_video;
 NSTextField *pauseLabel;
 NSArray * supportedImageFileTypes;
 
-// keymap conversion
-int keymap[] =
-{
-//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
-    30, //  0       0x00    0x1e            A       QZ_a
-    31, //  1       0x01    0x1f            S       QZ_s
-    32, //  2       0x02    0x20            D       QZ_d
-    33, //  3       0x03    0x21            F       QZ_f
-    35, //  4       0x04    0x23            H       QZ_h
-    34, //  5       0x05    0x22            G       QZ_g
-    44, //  6       0x06    0x2c            Z       QZ_z
-    45, //  7       0x07    0x2d            X       QZ_x
-    46, //  8       0x08    0x2e            C       QZ_c
-    47, //  9       0x09    0x2f            V       QZ_v
-    0,  //  10      0x0A    Undefined
-    48, //  11      0x0B    0x30            B       QZ_b
-    16, //  12      0x0C    0x10            Q       QZ_q
-    17, //  13      0x0D    0x11            W       QZ_w
-    18, //  14      0x0E    0x12            E       QZ_e
-    19, //  15      0x0F    0x13            R       QZ_r
-    21, //  16      0x10    0x15            Y       QZ_y
-    20, //  17      0x11    0x14            T       QZ_t
-    2,  //  18      0x12    0x02            1       QZ_1
-    3,  //  19      0x13    0x03            2       QZ_2
-    4,  //  20      0x14    0x04            3       QZ_3
-    5,  //  21      0x15    0x05            4       QZ_4
-    7,  //  22      0x16    0x07            6       QZ_6
-    6,  //  23      0x17    0x06            5       QZ_5
-    13, //  24      0x18    0x0d            =       QZ_EQUALS
-    10, //  25      0x19    0x0a            9       QZ_9
-    8,  //  26      0x1A    0x08            7       QZ_7
-    12, //  27      0x1B    0x0c            -       QZ_MINUS
-    9,  //  28      0x1C    0x09            8       QZ_8
-    11, //  29      0x1D    0x0b            0       QZ_0
-    27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
-    24, //  31      0x1F    0x18            O       QZ_o
-    22, //  32      0x20    0x16            U       QZ_u
-    26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
-    23, //  34      0x22    0x17            I       QZ_i
-    25, //  35      0x23    0x19            P       QZ_p
-    28, //  36      0x24    0x1c            ENTER   QZ_RETURN
-    38, //  37      0x25    0x26            L       QZ_l
-    36, //  38      0x26    0x24            J       QZ_j
-    40, //  39      0x27    0x28            '       QZ_QUOTE
-    37, //  40      0x28    0x25            K       QZ_k
-    39, //  41      0x29    0x27            ;       QZ_SEMICOLON
-    43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
-    51, //  43      0x2B    0x33            ,       QZ_COMMA
-    53, //  44      0x2C    0x35            /       QZ_SLASH
-    49, //  45      0x2D    0x31            N       QZ_n
-    50, //  46      0x2E    0x32            M       QZ_m
-    52, //  47      0x2F    0x34            .       QZ_PERIOD
-    15, //  48      0x30    0x0f            TAB     QZ_TAB
-    57, //  49      0x31    0x39            SPACE   QZ_SPACE
-    41, //  50      0x32    0x29            `       QZ_BACKQUOTE
-    14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
-    0,  //  52      0x34    Undefined
-    1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
-    220, // 54      0x36    0xdc    E0,5C   R GUI   QZ_RMETA
-    219, // 55      0x37    0xdb    E0,5B   L GUI   QZ_LMETA
-    42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
-    58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
-    56, //  58      0x3A    0x38            L ALT   QZ_LALT
-    29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
-    54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
-    184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
-    157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
-    0,  //  63      0x3F    Undefined
-    0,  //  64      0x40    Undefined
-    0,  //  65      0x41    Undefined
-    0,  //  66      0x42    Undefined
-    55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
-    0,  //  68      0x44    Undefined
-    78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
-    0,  //  70      0x46    Undefined
-    69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
-    0,  //  72      0x48    Undefined
-    0,  //  73      0x49    Undefined
-    0,  //  74      0x4A    Undefined
-    181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
-    152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
-    0,  //  77      0x4D    undefined
-    74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
-    0,  //  79      0x4F    Undefined
-    0,  //  80      0x50    Undefined
-    0,  //  81      0x51                            QZ_KP_EQUALS
-    82, //  82      0x52    0x52            KP 0    QZ_KP0
-    79, //  83      0x53    0x4f            KP 1    QZ_KP1
-    80, //  84      0x54    0x50            KP 2    QZ_KP2
-    81, //  85      0x55    0x51            KP 3    QZ_KP3
-    75, //  86      0x56    0x4b            KP 4    QZ_KP4
-    76, //  87      0x57    0x4c            KP 5    QZ_KP5
-    77, //  88      0x58    0x4d            KP 6    QZ_KP6
-    71, //  89      0x59    0x47            KP 7    QZ_KP7
-    0,  //  90      0x5A    Undefined
-    72, //  91      0x5B    0x48            KP 8    QZ_KP8
-    73, //  92      0x5C    0x49            KP 9    QZ_KP9
-    0,  //  93      0x5D    Undefined
-    0,  //  94      0x5E    Undefined
-    0,  //  95      0x5F    Undefined
-    63, //  96      0x60    0x3f            F5      QZ_F5
-    64, //  97      0x61    0x40            F6      QZ_F6
-    65, //  98      0x62    0x41            F7      QZ_F7
-    61, //  99      0x63    0x3d            F3      QZ_F3
-    66, //  100     0x64    0x42            F8      QZ_F8
-    67, //  101     0x65    0x43            F9      QZ_F9
-    0,  //  102     0x66    Undefined
-    87, //  103     0x67    0x57            F11     QZ_F11
-    0,  //  104     0x68    Undefined
-    183,//  105     0x69    0xb7                    QZ_PRINT
-    0,  //  106     0x6A    Undefined
-    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
-    0,  //  108     0x6C    Undefined
-    68, //  109     0x6D    0x44            F10     QZ_F10
-    0,  //  110     0x6E    Undefined
-    88, //  111     0x6F    0x58            F12     QZ_F12
-    0,  //  112     0x70    Undefined
-    110,//  113     0x71    0x0                     QZ_PAUSE
-    210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
-    199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
-    201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
-    211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
-    62, //  118     0x76    0x3e            F4      QZ_F4
-    207,//  119     0x77    0xcf    E0,4f   END     QZ_END
-    60, //  120     0x78    0x3c            F2      QZ_F2
-    209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
-    59, //  122     0x7A    0x3b            F1      QZ_F1
-    203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
-    205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
-    208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
-    200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
-/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
-
-/* Additional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
-/*
-    221 //          0xdd            e0,5d   APPS
-        //              E0,2A,E0,37         PRNT SCRN
-        //              E1,1D,45,E1,9D,C5   PAUSE
-    83  //          0x53    0x53            KP .
-// ACPI Scan Codes
-    222 //          0xde            E0, 5E  Power
-    223 //          0xdf            E0, 5F  Sleep
-    227 //          0xe3            E0, 63  Wake
-// Windows Multimedia Scan Codes
-    153 //          0x99            E0, 19  Next Track
-    144 //          0x90            E0, 10  Previous Track
-    164 //          0xa4            E0, 24  Stop
-    162 //          0xa2            E0, 22  Play/Pause
-    160 //          0xa0            E0, 20  Mute
-    176 //          0xb0            E0, 30  Volume Up
-    174 //          0xae            E0, 2E  Volume Down
-    237 //          0xed            E0, 6D  Media Select
-    236 //          0xec            E0, 6C  E-Mail
-    161 //          0xa1            E0, 21  Calculator
-    235 //          0xeb            E0, 6B  My Computer
-    229 //          0xe5            E0, 65  WWW Search
-    178 //          0xb2            E0, 32  WWW Home
-    234 //          0xea            E0, 6A  WWW Back
-    233 //          0xe9            E0, 69  WWW Forward
-    232 //          0xe8            E0, 68  WWW Stop
-    231 //          0xe7            E0, 67  WWW Refresh
-    230 //          0xe6            E0, 66  WWW Favorites
-*/
+// Mac to QKeyCode conversion
+const int mac_to_qkeycode_map[] = {
+    [kVK_ANSI_A] = Q_KEY_CODE_A,
+    [kVK_ANSI_B] = Q_KEY_CODE_B,
+    [kVK_ANSI_C] = Q_KEY_CODE_C,
+    [kVK_ANSI_D] = Q_KEY_CODE_D,
+    [kVK_ANSI_E] = Q_KEY_CODE_E,
+    [kVK_ANSI_F] = Q_KEY_CODE_F,
+    [kVK_ANSI_G] = Q_KEY_CODE_G,
+    [kVK_ANSI_H] = Q_KEY_CODE_H,
+    [kVK_ANSI_I] = Q_KEY_CODE_I,
+    [kVK_ANSI_J] = Q_KEY_CODE_J,
+    [kVK_ANSI_K] = Q_KEY_CODE_K,
+    [kVK_ANSI_L] = Q_KEY_CODE_L,
+    [kVK_ANSI_M] = Q_KEY_CODE_M,
+    [kVK_ANSI_N] = Q_KEY_CODE_N,
+    [kVK_ANSI_O] = Q_KEY_CODE_O,
+    [kVK_ANSI_P] = Q_KEY_CODE_P,
+    [kVK_ANSI_Q] = Q_KEY_CODE_Q,
+    [kVK_ANSI_R] = Q_KEY_CODE_R,
+    [kVK_ANSI_S] = Q_KEY_CODE_S,
+    [kVK_ANSI_T] = Q_KEY_CODE_T,
+    [kVK_ANSI_U] = Q_KEY_CODE_U,
+    [kVK_ANSI_V] = Q_KEY_CODE_V,
+    [kVK_ANSI_W] = Q_KEY_CODE_W,
+    [kVK_ANSI_X] = Q_KEY_CODE_X,
+    [kVK_ANSI_Y] = Q_KEY_CODE_Y,
+    [kVK_ANSI_Z] = Q_KEY_CODE_Z,
+
+    [kVK_ANSI_0] = Q_KEY_CODE_0,
+    [kVK_ANSI_1] = Q_KEY_CODE_1,
+    [kVK_ANSI_2] = Q_KEY_CODE_2,
+    [kVK_ANSI_3] = Q_KEY_CODE_3,
+    [kVK_ANSI_4] = Q_KEY_CODE_4,
+    [kVK_ANSI_5] = Q_KEY_CODE_5,
+    [kVK_ANSI_6] = Q_KEY_CODE_6,
+    [kVK_ANSI_7] = Q_KEY_CODE_7,
+    [kVK_ANSI_8] = Q_KEY_CODE_8,
+    [kVK_ANSI_9] = Q_KEY_CODE_9,
+
+    [kVK_ANSI_Grave] = Q_KEY_CODE_GRAVE_ACCENT,
+    [kVK_ANSI_Minus] = Q_KEY_CODE_MINUS,
+    [kVK_ANSI_Equal] = Q_KEY_CODE_EQUAL,
+    [kVK_Delete] = Q_KEY_CODE_BACKSPACE,
+    [kVK_CapsLock] = Q_KEY_CODE_CAPS_LOCK,
+    [kVK_Tab] = Q_KEY_CODE_TAB,
+    [kVK_Return] = Q_KEY_CODE_RET,
+    [kVK_ANSI_LeftBracket] = Q_KEY_CODE_BRACKET_LEFT,
+    [kVK_ANSI_RightBracket] = Q_KEY_CODE_BRACKET_RIGHT,
+    [kVK_ANSI_Backslash] = Q_KEY_CODE_BACKSLASH,
+    [kVK_ANSI_Semicolon] = Q_KEY_CODE_SEMICOLON,
+    [kVK_ANSI_Quote] = Q_KEY_CODE_APOSTROPHE,
+    [kVK_ANSI_Comma] = Q_KEY_CODE_COMMA,
+    [kVK_ANSI_Period] = Q_KEY_CODE_DOT,
+    [kVK_ANSI_Slash] = Q_KEY_CODE_SLASH,
+    [kVK_Shift] = Q_KEY_CODE_SHIFT,
+    [kVK_RightShift] = Q_KEY_CODE_SHIFT_R,
+    [kVK_Control] = Q_KEY_CODE_CTRL,
+    [kVK_RightControl] = Q_KEY_CODE_CTRL_R,
+    [kVK_Option] = Q_KEY_CODE_ALT,
+    [kVK_RightOption] = Q_KEY_CODE_ALT_R,
+    [kVK_Command] = Q_KEY_CODE_META_L,
+    [0x36] = Q_KEY_CODE_META_R, /* There is no kVK_RightCommand */
+    [kVK_Space] = Q_KEY_CODE_SPC,
+
+    [kVK_ANSI_Keypad0] = Q_KEY_CODE_KP_0,
+    [kVK_ANSI_Keypad1] = Q_KEY_CODE_KP_1,
+    [kVK_ANSI_Keypad2] = Q_KEY_CODE_KP_2,
+    [kVK_ANSI_Keypad3] = Q_KEY_CODE_KP_3,
+    [kVK_ANSI_Keypad4] = Q_KEY_CODE_KP_4,
+    [kVK_ANSI_Keypad5] = Q_KEY_CODE_KP_5,
+    [kVK_ANSI_Keypad6] = Q_KEY_CODE_KP_6,
+    [kVK_ANSI_Keypad7] = Q_KEY_CODE_KP_7,
+    [kVK_ANSI_Keypad8] = Q_KEY_CODE_KP_8,
+    [kVK_ANSI_Keypad9] = Q_KEY_CODE_KP_9,
+    [kVK_ANSI_KeypadDecimal] = Q_KEY_CODE_KP_DECIMAL,
+    [kVK_ANSI_KeypadEnter] = Q_KEY_CODE_KP_ENTER,
+    [kVK_ANSI_KeypadPlus] = Q_KEY_CODE_KP_ADD,
+    [kVK_ANSI_KeypadMinus] = Q_KEY_CODE_KP_SUBTRACT,
+    [kVK_ANSI_KeypadMultiply] = Q_KEY_CODE_KP_MULTIPLY,
+    [kVK_ANSI_KeypadDivide] = Q_KEY_CODE_KP_DIVIDE,
+    [kVK_ANSI_KeypadEquals] = Q_KEY_CODE_KP_EQUALS,
+    [kVK_ANSI_KeypadClear] = Q_KEY_CODE_NUM_LOCK,
+
+    [kVK_UpArrow] = Q_KEY_CODE_UP,
+    [kVK_DownArrow] = Q_KEY_CODE_DOWN,
+    [kVK_LeftArrow] = Q_KEY_CODE_LEFT,
+    [kVK_RightArrow] = Q_KEY_CODE_RIGHT,
+
+    [kVK_Help] = Q_KEY_CODE_INSERT,
+    [kVK_Home] = Q_KEY_CODE_HOME,
+    [kVK_PageUp] = Q_KEY_CODE_PGUP,
+    [kVK_PageDown] = Q_KEY_CODE_PGDN,
+    [kVK_End] = Q_KEY_CODE_END,
+    [kVK_ForwardDelete] = Q_KEY_CODE_DELETE,
+
+    [kVK_Escape] = Q_KEY_CODE_ESC,
+
+    /* The Power key can't be used directly because the operating system uses
+     * it. This key can be emulated by using it in place of another key such as
+     * F1. Don't forget to disable the real key binding.
+     */
+    /* [kVK_F1] = Q_KEY_CODE_POWER, */
+
+    [kVK_F1] = Q_KEY_CODE_F1,
+    [kVK_F2] = Q_KEY_CODE_F2,
+    [kVK_F3] = Q_KEY_CODE_F3,
+    [kVK_F4] = Q_KEY_CODE_F4,
+    [kVK_F5] = Q_KEY_CODE_F5,
+    [kVK_F6] = Q_KEY_CODE_F6,
+    [kVK_F7] = Q_KEY_CODE_F7,
+    [kVK_F8] = Q_KEY_CODE_F8,
+    [kVK_F9] = Q_KEY_CODE_F9,
+    [kVK_F10] = Q_KEY_CODE_F10,
+    [kVK_F11] = Q_KEY_CODE_F11,
+    [kVK_F12] = Q_KEY_CODE_F12,
+    [kVK_F13] = Q_KEY_CODE_PRINT,
+    [kVK_F14] = Q_KEY_CODE_SCROLL_LOCK,
+    [kVK_F15] = Q_KEY_CODE_PAUSE,
+
+    /*
+     * The eject and volume keys can't be used here because they are handled at
+     * a lower level than what an Application can see.
+     */
 };
 
 static int cocoa_keycode_to_qemu(int keycode)
 {
-    if (ARRAY_SIZE(keymap) <= keycode) {
+    if (ARRAY_SIZE(mac_to_qkeycode_map) <= keycode) {
         fprintf(stderr, "(cocoa) warning unknown keycode 0x%x\n", keycode);
         return 0;
     }
-    return keymap[keycode];
+    return mac_to_qkeycode_map[keycode];
 }
 
 /* Displays an alert dialog box with the specified message */
@@ -557,21 +519,24 @@ QemuCocoaView *cocoaView;
         case NSFlagsChanged:
             keycode = cocoa_keycode_to_qemu([event keyCode]);
 
-            if ((keycode == 219 || keycode == 220) && !isMouseGrabbed) {
+            if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R)
+               && !isMouseGrabbed) {
               /* Don't pass command key changes to guest unless mouse is grabbed */
               keycode = 0;
             }
 
             if (keycode) {
-                if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
-                    qemu_input_event_send_key_number(dcl->con, keycode, true);
-                    qemu_input_event_send_key_number(dcl->con, keycode, false);
+                // emulate caps lock and num lock keydown and keyup
+                if (keycode == Q_KEY_CODE_CAPS_LOCK ||
+                    keycode == Q_KEY_CODE_NUM_LOCK) {
+                    qemu_input_event_send_key_qcode(dcl->con, keycode, true);
+                    qemu_input_event_send_key_qcode(dcl->con, keycode, false);
                 } else if (qemu_console_is_graphic(NULL)) {
                     if (modifiers_state[keycode] == 0) { // keydown
-                        qemu_input_event_send_key_number(dcl->con, keycode, true);
+                        qemu_input_event_send_key_qcode(dcl->con, keycode, true);
                         modifiers_state[keycode] = 1;
                     } else { // keyup
-                        qemu_input_event_send_key_number(dcl->con, keycode, false);
+                        qemu_input_event_send_key_qcode(dcl->con, keycode, false);
                         modifiers_state[keycode] = 0;
                     }
                 }
@@ -598,14 +563,14 @@ QemuCocoaView *cocoaView;
                 switch (keycode) {
 
                     // enable graphic console
-                    case 0x02 ... 0x0a: // '1' to '9' keys
-                        console_select(keycode - 0x02);
+                    case Q_KEY_CODE_1 ... Q_KEY_CODE_9: // '1' to '9' keys
+                        console_select(keycode - 11);
                         break;
                 }
 
             // handle keys for graphic console
             } else if (qemu_console_is_graphic(NULL)) {
-                qemu_input_event_send_key_number(dcl->con, keycode, true);
+                qemu_input_event_send_key_qcode(dcl->con, keycode, true);
 
             // handlekeys for Monitor
             } else {
@@ -653,7 +618,7 @@ QemuCocoaView *cocoaView;
             }
 
             if (qemu_console_is_graphic(NULL)) {
-                qemu_input_event_send_key_number(dcl->con, keycode, false);
+                qemu_input_event_send_key_qcode(dcl->con, keycode, false);
             }
             break;
         case NSMouseMoved:
@@ -823,7 +788,7 @@ QemuCocoaView *cocoaView;
    for (index = 0; index < max_index; index++) {
        if (modifiers_state[index]) {
            modifiers_state[index] = 0;
-           qemu_input_event_send_key_number(dcl->con, index, false);
+           qemu_input_event_send_key_qcode(dcl->con, index, false);
        }
    }
 }
@@ -858,6 +823,7 @@ QemuCocoaView *cocoaView;
 - (void)ejectDeviceMedia:(id)sender;
 - (void)changeDeviceMedia:(id)sender;
 - (BOOL)verifyQuit;
+- (void)openDocumentation:(NSString *)filename;
 @end
 
 @implementation QemuCocoaAppController
@@ -994,20 +960,42 @@ QemuCocoaView *cocoaView;
     [cocoaView toggleFullScreen:sender];
 }
 
+/* Tries to find then open the specified filename */
+- (void) openDocumentation: (NSString *) filename
+{
+    /* Where to look for local files */
+    NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../"};
+    NSString *full_file_path;
+
+    /* iterate thru the possible paths until the file is found */
+    int index;
+    for (index = 0; index < ARRAY_SIZE(path_array); index++) {
+        full_file_path = [[NSBundle mainBundle] executablePath];
+        full_file_path = [full_file_path stringByDeletingLastPathComponent];
+        full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
+                          path_array[index], filename];
+        if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
+            return;
+        }
+    }
+
+    /* If none of the paths opened a file */
+    NSBeep();
+    QEMU_Alert(@"Failed to open file");
+}
+
 - (void)showQEMUDoc:(id)sender
 {
     COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
 
-    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
-        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+    [self openDocumentation: @"qemu-doc.html"];
 }
 
 - (void)showQEMUTec:(id)sender
 {
     COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
 
-    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
-        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+    [self openDocumentation: @"qemu-tech.html"];
 }
 
 /* Stretches video to fit host monitor size */