summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/block/xen_disk.c153
-rw-r--r--hw/dma/rc4030.c81
-rw-r--r--hw/i386/amd_iommu.c16
-rw-r--r--hw/i386/intel_iommu.c18
-rw-r--r--hw/i386/kvm/apic.c5
-rw-r--r--hw/i386/kvmvapic.c6
-rw-r--r--hw/i386/trace-events4
-rw-r--r--hw/ide/ahci.c1
-rw-r--r--hw/ide/core.c4
-rw-r--r--hw/ide/qdev.c11
-rw-r--r--hw/input/ps2.c612
-rw-r--r--hw/intc/ioapic.c2
-rw-r--r--hw/mem/trace-events5
-rw-r--r--hw/ppc/ppce500_spin.c31
-rw-r--r--hw/ppc/spapr.c6
-rw-r--r--hw/ppc/spapr_hcall.c17
-rw-r--r--hw/ppc/spapr_iommu.c18
-rw-r--r--hw/vfio/common.c4
-rw-r--r--hw/virtio/trace-events5
19 files changed, 817 insertions, 182 deletions
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 342868904d..5aa350a1bf 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -119,6 +119,9 @@ struct XenBlkDev {
     unsigned int        persistent_gnt_count;
     unsigned int        max_grants;
 
+    /* Grant copy */
+    gboolean            feature_grant_copy;
+
     /* qemu block driver */
     DriveInfo           *dinfo;
     BlockBackend        *blk;
@@ -489,6 +492,106 @@ static int ioreq_map(struct ioreq *ioreq)
     return 0;
 }
 
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 480
+
+static void ioreq_free_copy_buffers(struct ioreq *ioreq)
+{
+    int i;
+
+    for (i = 0; i < ioreq->v.niov; i++) {
+        ioreq->page[i] = NULL;
+    }
+
+    qemu_vfree(ioreq->pages);
+}
+
+static int ioreq_init_copy_buffers(struct ioreq *ioreq)
+{
+    int i;
+
+    if (ioreq->v.niov == 0) {
+        return 0;
+    }
+
+    ioreq->pages = qemu_memalign(XC_PAGE_SIZE, ioreq->v.niov * XC_PAGE_SIZE);
+
+    for (i = 0; i < ioreq->v.niov; i++) {
+        ioreq->page[i] = ioreq->pages + i * XC_PAGE_SIZE;
+        ioreq->v.iov[i].iov_base = ioreq->page[i];
+    }
+
+    return 0;
+}
+
+static int ioreq_grant_copy(struct ioreq *ioreq)
+{
+    xengnttab_handle *gnt = ioreq->blkdev->xendev.gnttabdev;
+    xengnttab_grant_copy_segment_t segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    int i, count, rc;
+    int64_t file_blk = ioreq->blkdev->file_blk;
+
+    if (ioreq->v.niov == 0) {
+        return 0;
+    }
+
+    count = ioreq->v.niov;
+
+    for (i = 0; i < count; i++) {
+        if (ioreq->req.operation == BLKIF_OP_READ) {
+            segs[i].flags = GNTCOPY_dest_gref;
+            segs[i].dest.foreign.ref = ioreq->refs[i];
+            segs[i].dest.foreign.domid = ioreq->domids[i];
+            segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
+            segs[i].source.virt = ioreq->v.iov[i].iov_base;
+        } else {
+            segs[i].flags = GNTCOPY_source_gref;
+            segs[i].source.foreign.ref = ioreq->refs[i];
+            segs[i].source.foreign.domid = ioreq->domids[i];
+            segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
+            segs[i].dest.virt = ioreq->v.iov[i].iov_base;
+        }
+        segs[i].len = (ioreq->req.seg[i].last_sect
+                       - ioreq->req.seg[i].first_sect + 1) * file_blk;
+    }
+
+    rc = xengnttab_grant_copy(gnt, count, segs);
+
+    if (rc) {
+        xen_be_printf(&ioreq->blkdev->xendev, 0,
+                      "failed to copy data %d\n", rc);
+        ioreq->aio_errors++;
+        return -1;
+    }
+
+    for (i = 0; i < count; i++) {
+        if (segs[i].status != GNTST_okay) {
+            xen_be_printf(&ioreq->blkdev->xendev, 3,
+                          "failed to copy data %d for gref %d, domid %d\n",
+                          segs[i].status, ioreq->refs[i], ioreq->domids[i]);
+            ioreq->aio_errors++;
+            rc = -1;
+        }
+    }
+
+    return rc;
+}
+#else
+static void ioreq_free_copy_buffers(struct ioreq *ioreq)
+{
+    abort();
+}
+
+static int ioreq_init_copy_buffers(struct ioreq *ioreq)
+{
+    abort();
+}
+
+static int ioreq_grant_copy(struct ioreq *ioreq)
+{
+    abort();
+}
+#endif
+
 static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
 
 static void qemu_aio_complete(void *opaque, int ret)
@@ -511,8 +614,31 @@ static void qemu_aio_complete(void *opaque, int ret)
         return;
     }
 
+    if (ioreq->blkdev->feature_grant_copy) {
+        switch (ioreq->req.operation) {
+        case BLKIF_OP_READ:
+            /* in case of failure ioreq->aio_errors is increased */
+            if (ret == 0) {
+                ioreq_grant_copy(ioreq);
+            }
+            ioreq_free_copy_buffers(ioreq);
+            break;
+        case BLKIF_OP_WRITE:
+        case BLKIF_OP_FLUSH_DISKCACHE:
+            if (!ioreq->req.nr_segments) {
+                break;
+            }
+            ioreq_free_copy_buffers(ioreq);
+            break;
+        default:
+            break;
+        }
+    }
+
     ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
-    ioreq_unmap(ioreq);
+    if (!ioreq->blkdev->feature_grant_copy) {
+        ioreq_unmap(ioreq);
+    }
     ioreq_finish(ioreq);
     switch (ioreq->req.operation) {
     case BLKIF_OP_WRITE:
@@ -538,8 +664,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
 {
     struct XenBlkDev *blkdev = ioreq->blkdev;
 
-    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
-        goto err_no_map;
+    if (ioreq->blkdev->feature_grant_copy) {
+        ioreq_init_copy_buffers(ioreq);
+        if (ioreq->req.nr_segments && (ioreq->req.operation == BLKIF_OP_WRITE ||
+            ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
+            ioreq_grant_copy(ioreq)) {
+                ioreq_free_copy_buffers(ioreq);
+                goto err;
+        }
+    } else {
+        if (ioreq->req.nr_segments && ioreq_map(ioreq)) {
+            goto err;
+        }
     }
 
     ioreq->aio_inflight++;
@@ -582,6 +718,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
     }
     default:
         /* unknown operation (shouldn't happen -- parse catches this) */
+        if (!ioreq->blkdev->feature_grant_copy) {
+            ioreq_unmap(ioreq);
+        }
         goto err;
     }
 
@@ -590,8 +729,6 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
     return 0;
 
 err:
-    ioreq_unmap(ioreq);
-err_no_map:
     ioreq_finish(ioreq);
     ioreq->status = BLKIF_RSP_ERROR;
     return -1;
@@ -1034,6 +1171,12 @@ static int blk_connect(struct XenDevice *xendev)
 
     xen_be_bind_evtchn(&blkdev->xendev);
 
+    blkdev->feature_grant_copy =
+                (xengnttab_grant_copy(blkdev->xendev.gnttabdev, 0, NULL) == 0);
+
+    xen_be_printf(&blkdev->xendev, 3, "grant copy operation %s\n",
+                  blkdev->feature_grant_copy ? "enabled" : "disabled");
+
     xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
                   "remote port %d, local port %d\n",
                   blkdev->xendev.protocol, blkdev->ring_ref,
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index 2f2576fafb..17c8518fea 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -616,34 +616,9 @@ static void rc4030_reset(DeviceState *dev)
     qemu_irq_lower(s->jazz_bus_irq);
 }
 
-static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
+static int rc4030_post_load(void *opaque, int version_id)
 {
     rc4030State* s = opaque;
-    int i, j;
-
-    if (version_id != 2)
-        return -EINVAL;
-
-    s->config = qemu_get_be32(f);
-    s->invalid_address_register = qemu_get_be32(f);
-    for (i = 0; i < 8; i++)
-        for (j = 0; j < 4; j++)
-            s->dma_regs[i][j] = qemu_get_be32(f);
-    s->dma_tl_base = qemu_get_be32(f);
-    s->dma_tl_limit = qemu_get_be32(f);
-    s->cache_maint = qemu_get_be32(f);
-    s->remote_failed_address = qemu_get_be32(f);
-    s->memory_failed_address = qemu_get_be32(f);
-    s->cache_ptag = qemu_get_be32(f);
-    s->cache_ltag = qemu_get_be32(f);
-    s->cache_bmask = qemu_get_be32(f);
-    s->memory_refresh_rate = qemu_get_be32(f);
-    s->nvram_protect = qemu_get_be32(f);
-    for (i = 0; i < 15; i++)
-        s->rem_speed[i] = qemu_get_be32(f);
-    s->imr_jazz = qemu_get_be32(f);
-    s->isr_jazz = qemu_get_be32(f);
-    s->itr = qemu_get_be32(f);
 
     set_next_tick(s);
     update_jazz_irq(s);
@@ -651,32 +626,31 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void rc4030_save(QEMUFile *f, void *opaque)
-{
-    rc4030State* s = opaque;
-    int i, j;
-
-    qemu_put_be32(f, s->config);
-    qemu_put_be32(f, s->invalid_address_register);
-    for (i = 0; i < 8; i++)
-        for (j = 0; j < 4; j++)
-            qemu_put_be32(f, s->dma_regs[i][j]);
-    qemu_put_be32(f, s->dma_tl_base);
-    qemu_put_be32(f, s->dma_tl_limit);
-    qemu_put_be32(f, s->cache_maint);
-    qemu_put_be32(f, s->remote_failed_address);
-    qemu_put_be32(f, s->memory_failed_address);
-    qemu_put_be32(f, s->cache_ptag);
-    qemu_put_be32(f, s->cache_ltag);
-    qemu_put_be32(f, s->cache_bmask);
-    qemu_put_be32(f, s->memory_refresh_rate);
-    qemu_put_be32(f, s->nvram_protect);
-    for (i = 0; i < 15; i++)
-        qemu_put_be32(f, s->rem_speed[i]);
-    qemu_put_be32(f, s->imr_jazz);
-    qemu_put_be32(f, s->isr_jazz);
-    qemu_put_be32(f, s->itr);
-}
+static const VMStateDescription vmstate_rc4030 = {
+    .name = "rc4030",
+    .version_id = 3,
+    .post_load = rc4030_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(config, rc4030State),
+        VMSTATE_UINT32(invalid_address_register, rc4030State),
+        VMSTATE_UINT32_2DARRAY(dma_regs, rc4030State, 8, 4),
+        VMSTATE_UINT32(dma_tl_base, rc4030State),
+        VMSTATE_UINT32(dma_tl_limit, rc4030State),
+        VMSTATE_UINT32(cache_maint, rc4030State),
+        VMSTATE_UINT32(remote_failed_address, rc4030State),
+        VMSTATE_UINT32(memory_failed_address, rc4030State),
+        VMSTATE_UINT32(cache_ptag, rc4030State),
+        VMSTATE_UINT32(cache_ltag, rc4030State),
+        VMSTATE_UINT32(cache_bmask, rc4030State),
+        VMSTATE_UINT32(memory_refresh_rate, rc4030State),
+        VMSTATE_UINT32(nvram_protect, rc4030State),
+        VMSTATE_UINT32_ARRAY(rem_speed, rc4030State, 16),
+        VMSTATE_UINT32(imr_jazz, rc4030State),
+        VMSTATE_UINT32(isr_jazz, rc4030State),
+        VMSTATE_UINT32(itr, rc4030State),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
 {
@@ -753,8 +727,6 @@ static void rc4030_initfn(Object *obj)
     sysbus_init_irq(sysbus, &s->timer_irq);
     sysbus_init_irq(sysbus, &s->jazz_bus_irq);
 
-    register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
-
     sysbus_init_mmio(sysbus, &s->iomem_chipset);
     sysbus_init_mmio(sysbus, &s->iomem_jazzio);
 }
@@ -813,6 +785,7 @@ static void rc4030_class_init(ObjectClass *klass, void *class_data)
     dc->realize = rc4030_realize;
     dc->unrealize = rc4030_unrealize;
     dc->reset = rc4030_reset;
+    dc->vmsd = &vmstate_rc4030;
 }
 
 static const TypeInfo rc4030_info = {
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index a91a1798cb..023de526f6 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -21,6 +21,7 @@
  */
 #include "qemu/osdep.h"
 #include "hw/i386/amd_iommu.h"
+#include "qemu/error-report.h"
 #include "trace.h"
 
 /* used AMD-Vi MMIO registers */
@@ -1066,13 +1067,18 @@ static const MemoryRegionOps mmio_mem_ops = {
     }
 };
 
-static void amdvi_iommu_notify_started(MemoryRegion *iommu)
+static void amdvi_iommu_notify_flag_changed(MemoryRegion *iommu,
+                                            IOMMUNotifierFlag old,
+                                            IOMMUNotifierFlag new)
 {
     AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu);
 
-    hw_error("device %02x.%02x.%x requires iommu notifier which is not "
-             "currently supported", as->bus_num, PCI_SLOT(as->devfn),
-             PCI_FUNC(as->devfn));
+    if (new & IOMMU_NOTIFIER_MAP) {
+        error_report("device %02x.%02x.%x requires iommu notifier which is not "
+                     "currently supported", as->bus_num, PCI_SLOT(as->devfn),
+                     PCI_FUNC(as->devfn));
+        exit(1);
+    }
 }
 
 static void amdvi_init(AMDVIState *s)
@@ -1080,7 +1086,7 @@ static void amdvi_init(AMDVIState *s)
     amdvi_iotlb_reset(s);
 
     s->iommu_ops.translate = amdvi_translate;
-    s->iommu_ops.notify_started = amdvi_iommu_notify_started;
+    s->iommu_ops.notify_flag_changed = amdvi_iommu_notify_flag_changed;
     s->devtab_len = 0;
     s->cmdbuf_len = 0;
     s->cmdbuf_head = 0;
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index d6e02c821a..9f4e64af1a 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -1974,14 +1974,20 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr,
     return ret;
 }
 
-static void vtd_iommu_notify_started(MemoryRegion *iommu)
+static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
+                                          IOMMUNotifierFlag old,
+                                          IOMMUNotifierFlag new)
 {
     VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu);
 
-    hw_error("Device at bus %s addr %02x.%d requires iommu notifier which "
-             "is currently not supported by intel-iommu emulation",
-             vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn),
-             PCI_FUNC(vtd_as->devfn));
+    if (new & IOMMU_NOTIFIER_MAP) {
+        error_report("Device at bus %s addr %02x.%d requires iommu "
+                     "notifier which is currently not supported by "
+                     "intel-iommu emulation",
+                     vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn),
+                     PCI_FUNC(vtd_as->devfn));
+        exit(1);
+    }
 }
 
 static const VMStateDescription vtd_vmstate = {
@@ -2348,7 +2354,7 @@ static void vtd_init(IntelIOMMUState *s)
     memset(s->womask, 0, DMAR_REG_SIZE);
 
     s->iommu_ops.translate = vtd_iommu_translate;
-    s->iommu_ops.notify_started = vtd_iommu_notify_started;
+    s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed;
     s->root = 0;
     s->root_extended = false;
     s->dmar_enabled = false;
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index f57fed1cb0..c016e63fc2 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -125,7 +125,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
     }
 }
 
-static void kvm_apic_put(void *data)
+static void kvm_apic_put(CPUState *cs, void *data)
 {
     APICCommonState *s = data;
     struct kvm_lapic_state kapic;
@@ -146,10 +146,9 @@ static void kvm_apic_post_load(APICCommonState *s)
     run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
 }
 
-static void do_inject_external_nmi(void *data)
+static void do_inject_external_nmi(CPUState *cpu, void *data)
 {
     APICCommonState *s = data;
-    CPUState *cpu = CPU(s->cpu);
     uint32_t lvt;
     int ret;
 
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index a1cd9b5a29..74a549becf 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -483,7 +483,7 @@ typedef struct VAPICEnableTPRReporting {
     bool enable;
 } VAPICEnableTPRReporting;
 
-static void vapic_do_enable_tpr_reporting(void *data)
+static void vapic_do_enable_tpr_reporting(CPUState *cpu, void *data)
 {
     VAPICEnableTPRReporting *info = data;
 
@@ -734,10 +734,10 @@ static void vapic_realize(DeviceState *dev, Error **errp)
     nb_option_roms++;
 }
 
-static void do_vapic_enable(void *data)
+static void do_vapic_enable(CPUState *cs, void *data)
 {
     VAPICROMState *s = data;
-    X86CPU *cpu = X86_CPU(first_cpu);
+    X86CPU *cpu = X86_CPU(cs);
 
     static const uint8_t enabled = 1;
     cpu_physical_memory_write(s->vapic_paddr + offsetof(VAPICState, enabled),
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 1938b988d9..d2b497327e 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -7,10 +7,6 @@ xen_platform_log(char *s) "xen platform: %s"
 xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")"
 xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")"
 
-# hw/i386/pc.c
-mhp_pc_dimm_assigned_slot(int slot) "%d"
-mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
-
 # hw/i386/x86-iommu.c
 x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32
 
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index f3438ad78a..63ead21047 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -948,6 +948,7 @@ static void ncq_cb(void *opaque, int ret)
     NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
     IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
 
+    ncq_tfs->aiocb = NULL;
     if (ret == -ECANCELED) {
         return;
     }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index b0e42a6562..7291677109 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -908,7 +908,7 @@ eot:
 
 static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
 {
-    s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
+    s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
     s->io_buffer_size = 0;
     s->dma_cmd = dma_cmd;
 
@@ -2582,7 +2582,7 @@ static void ide_restart_cb(void *opaque, int running, RunState state)
 void ide_register_restart_cb(IDEBus *bus)
 {
     if (bus->dma->ops->restart_dma) {
-        qemu_add_vm_change_state_handler(ide_restart_cb, bus);
+        bus->vmstate = qemu_add_vm_change_state_handler(ide_restart_cb, bus);
     }
 }
 
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 2eb055ae70..dbaa75cf59 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -31,6 +31,7 @@
 /* --------------------------------- */
 
 static char *idebus_get_fw_dev_path(DeviceState *dev);
+static void idebus_unrealize(DeviceState *qdev, Error **errp);
 
 static Property ide_props[] = {
     DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
@@ -44,6 +45,15 @@ static void ide_bus_class_init(ObjectClass *klass, void *data)
     k->get_fw_dev_path = idebus_get_fw_dev_path;
 }
 
+static void idebus_unrealize(DeviceState *qdev, Error **errp)
+{
+    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
+
+    if (bus->vmstate) {
+        qemu_del_vm_change_state_handler(bus->vmstate);
+    }
+}
+
 static const TypeInfo ide_bus_info = {
     .name = TYPE_IDE_BUS,
     .parent = TYPE_BUS,
@@ -355,6 +365,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data)
     k->init = ide_qdev_init;
     set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
     k->bus_type = TYPE_IDE_BUS;
+    k->unrealize = idebus_unrealize;
     k->props = ide_props;
 }
 
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index a8aa36f5c0..0d14de08a6 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "qemu/osdep.h"
+#include "qemu/log.h"
 #include "hw/hw.h"
 #include "hw/input/ps2.h"
 #include "ui/console.h"
@@ -94,12 +95,10 @@ typedef struct {
 typedef struct {
     PS2State common;
     int scan_enabled;
-    /* QEMU uses translated PC scancodes internally.  To avoid multiple
-       conversions we do the translation (if any) in the PS/2 emulation
-       not the keyboard controller.  */
     int translate;
     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
     int ledstate;
+    bool need_high_bit;
 } PS2KbdState;
 
 typedef struct {
@@ -116,26 +115,430 @@ typedef struct {
     uint8_t mouse_buttons;
 } PS2MouseState;
 
-/* Table to convert from PC scancodes to raw scancodes.  */
-static const unsigned char ps2_raw_keycode[128] = {
-  0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
- 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
- 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
- 50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
- 11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
-114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
- 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
- 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+/* Table to convert from QEMU codes to scancodes.  */
+static const uint16_t qcode_to_keycode_set1[Q_KEY_CODE__MAX] = {
+    [0 ... Q_KEY_CODE__MAX - 1] = 0,
+
+    [Q_KEY_CODE_A] = 0x1e,
+    [Q_KEY_CODE_B] = 0x30,
+    [Q_KEY_CODE_C] = 0x2e,
+    [Q_KEY_CODE_D] = 0x20,
+    [Q_KEY_CODE_E] = 0x12,
+    [Q_KEY_CODE_F] = 0x21,
+    [Q_KEY_CODE_G] = 0x22,
+    [Q_KEY_CODE_H] = 0x23,
+    [Q_KEY_CODE_I] = 0x17,
+    [Q_KEY_CODE_J] = 0x24,
+    [Q_KEY_CODE_K] = 0x25,
+    [Q_KEY_CODE_L] = 0x26,
+    [Q_KEY_CODE_M] = 0x32,
+    [Q_KEY_CODE_N] = 0x31,
+    [Q_KEY_CODE_O] = 0x18,
+    [Q_KEY_CODE_P] = 0x19,
+    [Q_KEY_CODE_Q] = 0x10,
+    [Q_KEY_CODE_R] = 0x13,
+    [Q_KEY_CODE_S] = 0x1f,
+    [Q_KEY_CODE_T] = 0x14,
+    [Q_KEY_CODE_U] = 0x16,
+    [Q_KEY_CODE_V] = 0x2f,
+    [Q_KEY_CODE_W] = 0x11,
+    [Q_KEY_CODE_X] = 0x2d,
+    [Q_KEY_CODE_Y] = 0x15,
+    [Q_KEY_CODE_Z] = 0x2c,
+    [Q_KEY_CODE_0] = 0x0b,
+    [Q_KEY_CODE_1] = 0x02,
+    [Q_KEY_CODE_2] = 0x03,
+    [Q_KEY_CODE_3] = 0x04,
+    [Q_KEY_CODE_4] = 0x05,
+    [Q_KEY_CODE_5] = 0x06,
+    [Q_KEY_CODE_6] = 0x07,
+    [Q_KEY_CODE_7] = 0x08,
+    [Q_KEY_CODE_8] = 0x09,
+    [Q_KEY_CODE_9] = 0x0a,
+    [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
+    [Q_KEY_CODE_MINUS] = 0x0c,
+    [Q_KEY_CODE_EQUAL] = 0x0d,
+    [Q_KEY_CODE_BACKSLASH] = 0x2b,
+    [Q_KEY_CODE_BACKSPACE] = 0x0e,
+    [Q_KEY_CODE_SPC] = 0x39,
+    [Q_KEY_CODE_TAB] = 0x0f,
+    [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
+    [Q_KEY_CODE_SHIFT] = 0x2a,
+    [Q_KEY_CODE_CTRL] = 0x1d,
+    [Q_KEY_CODE_META_L] = 0xe05b,
+    [Q_KEY_CODE_ALT] = 0x38,
+    [Q_KEY_CODE_SHIFT_R] = 0x36,
+    [Q_KEY_CODE_CTRL_R] = 0xe01d,
+    [Q_KEY_CODE_META_R] = 0xe05c,
+    [Q_KEY_CODE_ALT_R] = 0xe038,
+    [Q_KEY_CODE_MENU] = 0xe05d,
+    [Q_KEY_CODE_RET] = 0x1c,
+    [Q_KEY_CODE_ESC] = 0x01,
+    [Q_KEY_CODE_F1] = 0x3b,
+    [Q_KEY_CODE_F2] = 0x3c,
+    [Q_KEY_CODE_F3] = 0x3d,
+    [Q_KEY_CODE_F4] = 0x3e,
+    [Q_KEY_CODE_F5] = 0x3f,
+    [Q_KEY_CODE_F6] = 0x40,
+    [Q_KEY_CODE_F7] = 0x41,
+    [Q_KEY_CODE_F8] = 0x42,
+    [Q_KEY_CODE_F9] = 0x43,
+    [Q_KEY_CODE_F10] = 0x44,
+    [Q_KEY_CODE_F11] = 0x57,
+    [Q_KEY_CODE_F12] = 0x58,
+    /* special handling for Q_KEY_CODE_PRINT */
+    [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
+    /* special handling for Q_KEY_CODE_PAUSE */
+    [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
+    [Q_KEY_CODE_INSERT] = 0xe052,
+    [Q_KEY_CODE_HOME] = 0xe047,
+    [Q_KEY_CODE_PGUP] = 0xe049,
+    [Q_KEY_CODE_DELETE] = 0xe053,
+    [Q_KEY_CODE_END] = 0xe04f,
+    [Q_KEY_CODE_PGDN] = 0xe051,
+    [Q_KEY_CODE_UP] = 0xe048,
+    [Q_KEY_CODE_LEFT] = 0xe04b,
+    [Q_KEY_CODE_DOWN] = 0xe050,
+    [Q_KEY_CODE_RIGHT] = 0xe04d,
+    [Q_KEY_CODE_NUM_LOCK] = 0x45,
+    [Q_KEY_CODE_KP_DIVIDE] = 0xe035,
+    [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
+    [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
+    [Q_KEY_CODE_KP_ADD] = 0x4e,
+    [Q_KEY_CODE_KP_ENTER] = 0xe01c,
+    [Q_KEY_CODE_KP_DECIMAL] = 0x53,
+    [Q_KEY_CODE_KP_0] = 0x52,
+    [Q_KEY_CODE_KP_1] = 0x4f,
+    [Q_KEY_CODE_KP_2] = 0x50,
+    [Q_KEY_CODE_KP_3] = 0x51,
+    [Q_KEY_CODE_KP_4] = 0x4b,
+    [Q_KEY_CODE_KP_5] = 0x4c,
+    [Q_KEY_CODE_KP_6] = 0x4d,
+    [Q_KEY_CODE_KP_7] = 0x47,
+    [Q_KEY_CODE_KP_8] = 0x48,
+    [Q_KEY_CODE_KP_9] = 0x49,
+    [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
+    [Q_KEY_CODE_SEMICOLON] = 0x27,
+    [Q_KEY_CODE_APOSTROPHE] = 0x28,
+    [Q_KEY_CODE_COMMA] = 0x33,
+    [Q_KEY_CODE_DOT] = 0x34,
+    [Q_KEY_CODE_SLASH] = 0x35,
+
+#if 0
+    [Q_KEY_CODE_POWER] = 0x0e5e,
+    [Q_KEY_CODE_SLEEP] = 0x0e5f,
+    [Q_KEY_CODE_WAKE] = 0x0e63,
+
+    [Q_KEY_CODE_AUDIONEXT] = 0xe019,
+    [Q_KEY_CODE_AUDIOPREV] = 0xe010,
+    [Q_KEY_CODE_AUDIOSTOP] = 0xe024,
+    [Q_KEY_CODE_AUDIOPLAY] = 0xe022,
+    [Q_KEY_CODE_AUDIOMUTE] = 0xe020,
+    [Q_KEY_CODE_VOLUMEUP] = 0xe030,
+    [Q_KEY_CODE_VOLUMEDOWN] = 0xe02e,
+    [Q_KEY_CODE_MEDIASELECT] = 0xe06d,
+    [Q_KEY_CODE_MAIL] = 0xe06c,
+    [Q_KEY_CODE_CALCULATOR] = 0xe021,
+    [Q_KEY_CODE_COMPUTER] = 0xe06b,
+    [Q_KEY_CODE_AC_SEARCH] = 0xe065,
+    [Q_KEY_CODE_AC_HOME] = 0xe032,
+    [Q_KEY_CODE_AC_BACK] = 0xe06a,
+    [Q_KEY_CODE_AC_FORWARD] = 0xe069,
+    [Q_KEY_CODE_AC_STOP] = 0xe068,
+    [Q_KEY_CODE_AC_REFRESH] = 0xe067,
+    [Q_KEY_CODE_AC_BOOKMARKS] = 0xe066,
+#endif
+
+    [Q_KEY_CODE_ASTERISK] = 0x37,
+    [Q_KEY_CODE_LESS] = 0x56,
+    [Q_KEY_CODE_RO] = 0x73,
+    [Q_KEY_CODE_KP_COMMA] = 0x7e,
 };
-static const unsigned char ps2_raw_keycode_set3[128] = {
-  0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
- 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
- 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
- 50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
- 47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
-114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
- 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
- 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+
+static const uint16_t qcode_to_keycode_set2[Q_KEY_CODE__MAX] = {
+    [0 ... Q_KEY_CODE__MAX - 1] = 0,
+
+    [Q_KEY_CODE_A] = 0x1c,
+    [Q_KEY_CODE_B] = 0x32,
+    [Q_KEY_CODE_C] = 0x21,
+    [Q_KEY_CODE_D] = 0x23,
+    [Q_KEY_CODE_E] = 0x24,
+    [Q_KEY_CODE_F] = 0x2b,
+    [Q_KEY_CODE_G] = 0x34,
+    [Q_KEY_CODE_H] = 0x33,
+    [Q_KEY_CODE_I] = 0x43,
+    [Q_KEY_CODE_J] = 0x3b,
+    [Q_KEY_CODE_K] = 0x42,
+    [Q_KEY_CODE_L] = 0x4b,
+    [Q_KEY_CODE_M] = 0x3a,
+    [Q_KEY_CODE_N] = 0x31,
+    [Q_KEY_CODE_O] = 0x44,
+    [Q_KEY_CODE_P] = 0x4d,
+    [Q_KEY_CODE_Q] = 0x15,
+    [Q_KEY_CODE_R] = 0x2d,
+    [Q_KEY_CODE_S] = 0x1b,
+    [Q_KEY_CODE_T] = 0x2c,
+    [Q_KEY_CODE_U] = 0x3c,
+    [Q_KEY_CODE_V] = 0x2a,
+    [Q_KEY_CODE_W] = 0x1d,
+    [Q_KEY_CODE_X] = 0x22,
+    [Q_KEY_CODE_Y] = 0x35,
+    [Q_KEY_CODE_Z] = 0x1a,
+    [Q_KEY_CODE_0] = 0x45,
+    [Q_KEY_CODE_1] = 0x16,
+    [Q_KEY_CODE_2] = 0x1e,
+    [Q_KEY_CODE_3] = 0x26,
+    [Q_KEY_CODE_4] = 0x25,
+    [Q_KEY_CODE_5] = 0x2e,
+    [Q_KEY_CODE_6] = 0x36,
+    [Q_KEY_CODE_7] = 0x3d,
+    [Q_KEY_CODE_8] = 0x3e,
+    [Q_KEY_CODE_9] = 0x46,
+    [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e,
+    [Q_KEY_CODE_MINUS] = 0x4e,
+    [Q_KEY_CODE_EQUAL] = 0x55,
+    [Q_KEY_CODE_BACKSLASH] = 0x5d,
+    [Q_KEY_CODE_BACKSPACE] = 0x66,
+    [Q_KEY_CODE_SPC] = 0x29,
+    [Q_KEY_CODE_TAB] = 0x0d,
+    [Q_KEY_CODE_CAPS_LOCK] = 0x58,
+    [Q_KEY_CODE_SHIFT] = 0x12,
+    [Q_KEY_CODE_CTRL] = 0x14,
+    [Q_KEY_CODE_META_L] = 0xe01f,
+    [Q_KEY_CODE_ALT] = 0x11,
+    [Q_KEY_CODE_SHIFT_R] = 0x59,
+    [Q_KEY_CODE_CTRL_R] = 0xe014,
+    [Q_KEY_CODE_META_R] = 0xe027,
+    [Q_KEY_CODE_ALT_R] = 0xe011,
+    [Q_KEY_CODE_MENU] = 0xe02f,
+    [Q_KEY_CODE_RET] = 0x5a,
+    [Q_KEY_CODE_ESC] = 0x76,
+    [Q_KEY_CODE_F1] = 0x05,
+    [Q_KEY_CODE_F2] = 0x06,
+    [Q_KEY_CODE_F3] = 0x04,
+    [Q_KEY_CODE_F4] = 0x0c,
+    [Q_KEY_CODE_F5] = 0x03,
+    [Q_KEY_CODE_F6] = 0x0b,
+    [Q_KEY_CODE_F7] = 0x83,
+    [Q_KEY_CODE_F8] = 0x0a,
+    [Q_KEY_CODE_F9] = 0x01,
+    [Q_KEY_CODE_F10] = 0x09,
+    [Q_KEY_CODE_F11] = 0x78,
+    [Q_KEY_CODE_F12] = 0x07,
+    /* special handling for Q_KEY_CODE_PRINT */
+    [Q_KEY_CODE_SCROLL_LOCK] = 0x7e,
+    /* special handling for Q_KEY_CODE_PAUSE */
+    [Q_KEY_CODE_BRACKET_LEFT] = 0x54,
+    [Q_KEY_CODE_INSERT] = 0xe070,
+    [Q_KEY_CODE_HOME] = 0xe06c,
+    [Q_KEY_CODE_PGUP] = 0xe07d,
+    [Q_KEY_CODE_DELETE] = 0xe071,
+    [Q_KEY_CODE_END] = 0xe069,
+    [Q_KEY_CODE_PGDN] = 0xe07a,
+    [Q_KEY_CODE_UP] = 0xe075,
+    [Q_KEY_CODE_LEFT] = 0xe06b,
+    [Q_KEY_CODE_DOWN] = 0xe072,
+    [Q_KEY_CODE_RIGHT] = 0xe074,
+    [Q_KEY_CODE_NUM_LOCK] = 0x77,
+    [Q_KEY_CODE_KP_DIVIDE] = 0xe04a,
+    [Q_KEY_CODE_KP_MULTIPLY] = 0x7c,
+    [Q_KEY_CODE_KP_SUBTRACT] = 0x7b,
+    [Q_KEY_CODE_KP_ADD] = 0x79,
+    [Q_KEY_CODE_KP_ENTER] = 0xe05a,
+    [Q_KEY_CODE_KP_DECIMAL] = 0x71,
+    [Q_KEY_CODE_KP_0] = 0x70,
+    [Q_KEY_CODE_KP_1] = 0x69,
+    [Q_KEY_CODE_KP_2] = 0x72,
+    [Q_KEY_CODE_KP_3] = 0x7a,
+    [Q_KEY_CODE_KP_4] = 0x6b,
+    [Q_KEY_CODE_KP_5] = 0x73,
+    [Q_KEY_CODE_KP_6] = 0x74,
+    [Q_KEY_CODE_KP_7] = 0x6c,
+    [Q_KEY_CODE_KP_8] = 0x75,
+    [Q_KEY_CODE_KP_9] = 0x7d,
+    [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b,
+    [Q_KEY_CODE_SEMICOLON] = 0x4c,
+    [Q_KEY_CODE_APOSTROPHE] = 0x52,
+    [Q_KEY_CODE_COMMA] = 0x41,
+    [Q_KEY_CODE_DOT] = 0x49,
+    [Q_KEY_CODE_SLASH] = 0x4a,
+
+#if 0
+    [Q_KEY_CODE_POWER] = 0x0e37,
+    [Q_KEY_CODE_SLEEP] = 0x0e3f,
+    [Q_KEY_CODE_WAKE] = 0x0e5e,
+
+    [Q_KEY_CODE_AUDIONEXT] = 0xe04d,
+    [Q_KEY_CODE_AUDIOPREV] = 0xe015,
+    [Q_KEY_CODE_AUDIOSTOP] = 0xe03b,
+    [Q_KEY_CODE_AUDIOPLAY] = 0xe034,
+    [Q_KEY_CODE_AUDIOMUTE] = 0xe023,
+    [Q_KEY_CODE_VOLUMEUP] = 0xe032,
+    [Q_KEY_CODE_VOLUMEDOWN] = 0xe021,
+    [Q_KEY_CODE_MEDIASELECT] = 0xe050,
+    [Q_KEY_CODE_MAIL] = 0xe048,
+    [Q_KEY_CODE_CALCULATOR] = 0xe02b,
+    [Q_KEY_CODE_COMPUTER] = 0xe040,
+    [Q_KEY_CODE_AC_SEARCH] = 0xe010,
+    [Q_KEY_CODE_AC_HOME] = 0xe03a,
+    [Q_KEY_CODE_AC_BACK] = 0xe038,
+    [Q_KEY_CODE_AC_FORWARD] = 0xe030,
+    [Q_KEY_CODE_AC_STOP] = 0xe028,
+    [Q_KEY_CODE_AC_REFRESH] = 0xe020,
+    [Q_KEY_CODE_AC_BOOKMARKS] = 0xe018,
+#endif
+
+    [Q_KEY_CODE_ALTGR] = 0x08,
+    [Q_KEY_CODE_ALTGR_R] = 0xe008,
+    [Q_KEY_CODE_ASTERISK] = 0x7c,
+    [Q_KEY_CODE_LESS] = 0x61,
+    [Q_KEY_CODE_SYSRQ] = 0x7f,
+    [Q_KEY_CODE_RO] = 0x51,
+    [Q_KEY_CODE_KP_COMMA] = 0x6d,
+};
+
+static const uint16_t qcode_to_keycode_set3[Q_KEY_CODE__MAX] = {
+    [0 ... Q_KEY_CODE__MAX - 1] = 0,
+
+    [Q_KEY_CODE_A] = 0x1c,
+    [Q_KEY_CODE_B] = 0x32,
+    [Q_KEY_CODE_C] = 0x21,
+    [Q_KEY_CODE_D] = 0x23,
+    [Q_KEY_CODE_E] = 0x24,
+    [Q_KEY_CODE_F] = 0x2b,
+    [Q_KEY_CODE_G] = 0x34,
+    [Q_KEY_CODE_H] = 0x33,
+    [Q_KEY_CODE_I] = 0x43,
+    [Q_KEY_CODE_J] = 0x3b,
+    [Q_KEY_CODE_K] = 0x42,
+    [Q_KEY_CODE_L] = 0x4b,
+    [Q_KEY_CODE_M] = 0x3a,
+    [Q_KEY_CODE_N] = 0x31,
+    [Q_KEY_CODE_O] = 0x44,
+    [Q_KEY_CODE_P] = 0x4d,
+    [Q_KEY_CODE_Q] = 0x15,
+    [Q_KEY_CODE_R] = 0x2d,
+    [Q_KEY_CODE_S] = 0x1b,
+    [Q_KEY_CODE_T] = 0x2c,
+    [Q_KEY_CODE_U] = 0x3c,
+    [Q_KEY_CODE_V] = 0x2a,
+    [Q_KEY_CODE_W] = 0x1d,
+    [Q_KEY_CODE_X] = 0x22,
+    [Q_KEY_CODE_Y] = 0x35,
+    [Q_KEY_CODE_Z] = 0x1a,
+    [Q_KEY_CODE_0] = 0x45,
+    [Q_KEY_CODE_1] = 0x16,
+    [Q_KEY_CODE_2] = 0x1e,
+    [Q_KEY_CODE_3] = 0x26,
+    [Q_KEY_CODE_4] = 0x25,
+    [Q_KEY_CODE_5] = 0x2e,
+    [Q_KEY_CODE_6] = 0x36,
+    [Q_KEY_CODE_7] = 0x3d,
+    [Q_KEY_CODE_8] = 0x3e,
+    [Q_KEY_CODE_9] = 0x46,
+    [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e,
+    [Q_KEY_CODE_MINUS] = 0x4e,
+    [Q_KEY_CODE_EQUAL] = 0x55,
+    [Q_KEY_CODE_BACKSLASH] = 0x5c,
+    [Q_KEY_CODE_BACKSPACE] = 0x66,
+    [Q_KEY_CODE_SPC] = 0x29,
+    [Q_KEY_CODE_TAB] = 0x0d,
+    [Q_KEY_CODE_CAPS_LOCK] = 0x14,
+    [Q_KEY_CODE_SHIFT] = 0x12,
+    [Q_KEY_CODE_CTRL] = 0x11,
+    [Q_KEY_CODE_META_L] = 0x8b,
+    [Q_KEY_CODE_ALT] = 0x19,
+    [Q_KEY_CODE_SHIFT_R] = 0x59,
+    [Q_KEY_CODE_CTRL_R] = 0x58,
+    [Q_KEY_CODE_META_R] = 0x8c,
+    [Q_KEY_CODE_ALT_R] = 0x39,
+    [Q_KEY_CODE_MENU] = 0x8d,
+    [Q_KEY_CODE_RET] = 0x5a,
+    [Q_KEY_CODE_ESC] = 0x08,
+    [Q_KEY_CODE_F1] = 0x07,
+    [Q_KEY_CODE_F2] = 0x0f,
+    [Q_KEY_CODE_F3] = 0x17,
+    [Q_KEY_CODE_F4] = 0x1f,
+    [Q_KEY_CODE_F5] = 0x27,
+    [Q_KEY_CODE_F6] = 0x2f,
+    [Q_KEY_CODE_F7] = 0x37,
+    [Q_KEY_CODE_F8] = 0x3f,
+    [Q_KEY_CODE_F9] = 0x47,
+    [Q_KEY_CODE_F10] = 0x4f,
+    [Q_KEY_CODE_F11] = 0x56,
+    [Q_KEY_CODE_F12] = 0x5e,
+    [Q_KEY_CODE_PRINT] = 0x57,
+    [Q_KEY_CODE_SCROLL_LOCK] = 0x5f,
+    [Q_KEY_CODE_PAUSE] = 0x62,
+    [Q_KEY_CODE_BRACKET_LEFT] = 0x54,
+    [Q_KEY_CODE_INSERT] = 0x67,
+    [Q_KEY_CODE_HOME] = 0x6e,
+    [Q_KEY_CODE_PGUP] = 0x6f,
+    [Q_KEY_CODE_DELETE] = 0x64,
+    [Q_KEY_CODE_END] = 0x65,
+    [Q_KEY_CODE_PGDN] = 0x6d,
+    [Q_KEY_CODE_UP] = 0x63,
+    [Q_KEY_CODE_LEFT] = 0x61,
+    [Q_KEY_CODE_DOWN] = 0x60,
+    [Q_KEY_CODE_RIGHT] = 0x6a,
+    [Q_KEY_CODE_NUM_LOCK] = 0x76,
+    [Q_KEY_CODE_KP_DIVIDE] = 0x4a,
+    [Q_KEY_CODE_KP_MULTIPLY] = 0x7e,
+    [Q_KEY_CODE_KP_SUBTRACT] = 0x4e,
+    [Q_KEY_CODE_KP_ADD] = 0x7c,
+    [Q_KEY_CODE_KP_ENTER] = 0x79,
+    [Q_KEY_CODE_KP_DECIMAL] = 0x71,
+    [Q_KEY_CODE_KP_0] = 0x70,
+    [Q_KEY_CODE_KP_1] = 0x69,
+    [Q_KEY_CODE_KP_2] = 0x72,
+    [Q_KEY_CODE_KP_3] = 0x7a,
+    [Q_KEY_CODE_KP_4] = 0x6b,
+    [Q_KEY_CODE_KP_5] = 0x73,
+    [Q_KEY_CODE_KP_6] = 0x74,
+    [Q_KEY_CODE_KP_7] = 0x6c,
+    [Q_KEY_CODE_KP_8] = 0x75,
+    [Q_KEY_CODE_KP_9] = 0x7d,
+    [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b,
+    [Q_KEY_CODE_SEMICOLON] = 0x4c,
+    [Q_KEY_CODE_APOSTROPHE] = 0x52,
+    [Q_KEY_CODE_COMMA] = 0x41,
+    [Q_KEY_CODE_DOT] = 0x49,
+    [Q_KEY_CODE_SLASH] = 0x4a,
+};
+
+static uint8_t translate_table[256] = {
+    0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
+    0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
+    0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
+    0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
+    0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
+    0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
+    0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
+    0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
+    0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
+    0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
+    0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
+    0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
+    0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
+    0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
+    0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
+    0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
+    0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
 };
 
 void ps2_queue(void *opaque, int b)
@@ -152,44 +555,130 @@ void ps2_queue(void *opaque, int b)
     s->update_irq(s->update_arg, 1);
 }
 
-/*
-   keycode is expressed as follow:
-   bit 7    - 0 key pressed, 1 = key released
-   bits 6-0 - translated scancode set 2
- */
+/* keycode is the untranslated scancode in the current scancode set. */
 static void ps2_put_keycode(void *opaque, int keycode)
 {
     PS2KbdState *s = opaque;
 
     trace_ps2_put_keycode(opaque, keycode);
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-    /* XXX: add support for scancode set 1 */
-    if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
-        if (keycode & 0x80) {
-            ps2_queue(&s->common, 0xf0);
-        }
-        if (s->scancode_set == 2) {
-            keycode = ps2_raw_keycode[keycode & 0x7f];
-        } else if (s->scancode_set == 3) {
-            keycode = ps2_raw_keycode_set3[keycode & 0x7f];
+
+    if (s->translate) {
+        if (keycode == 0xf0) {
+            s->need_high_bit = true;
+        } else if (s->need_high_bit) {
+            ps2_queue(&s->common, translate_table[keycode] | 0x80);
+            s->need_high_bit = false;
+        } else {
+            ps2_queue(&s->common, translate_table[keycode]);
         }
-      }
-    ps2_queue(&s->common, keycode);
+    } else {
+        ps2_queue(&s->common, keycode);
+    }
 }
 
 static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
                                InputEvent *evt)
 {
     PS2KbdState *s = (PS2KbdState *)dev;
-    int scancodes[3], i, count;
     InputKeyEvent *key = evt->u.key.data;
+    int qcode;
+    uint16_t keycode;
 
     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-    count = qemu_input_key_value_to_scancode(key->key,
-                                             key->down,
-                                             scancodes);
-    for (i = 0; i < count; i++) {
-        ps2_put_keycode(s, scancodes[i]);
+    assert(evt->type == INPUT_EVENT_KIND_KEY);
+    qcode = qemu_input_key_value_to_qcode(key->key);
+
+    if (s->scancode_set == 1) {
+        if (qcode == Q_KEY_CODE_PAUSE) {
+            if (key->down) {
+                ps2_put_keycode(s, 0xe1);
+                ps2_put_keycode(s, 0x1d);
+                ps2_put_keycode(s, 0x45);
+                ps2_put_keycode(s, 0x91);
+                ps2_put_keycode(s, 0x9d);
+                ps2_put_keycode(s, 0xc5);
+            }
+        } else if (qcode == Q_KEY_CODE_PRINT) {
+            if (key->down) {
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0x2a);
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0x37);
+            } else {
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0xb7);
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0xaa);
+            }
+        } else {
+            keycode = qcode_to_keycode_set1[qcode];
+            if (keycode) {
+                if (keycode & 0xff00) {
+                    ps2_put_keycode(s, keycode >> 8);
+                }
+                if (!key->down) {
+                    keycode |= 0x80;
+                }
+                ps2_put_keycode(s, keycode & 0xff);
+            } else {
+                qemu_log_mask(LOG_UNIMP,
+                              "ps2: ignoring key with qcode %d\n", qcode);
+            }
+        }
+    } else if (s->scancode_set == 2) {
+        if (qcode == Q_KEY_CODE_PAUSE) {
+            if (key->down) {
+                ps2_put_keycode(s, 0xe1);
+                ps2_put_keycode(s, 0x14);
+                ps2_put_keycode(s, 0x77);
+                ps2_put_keycode(s, 0xe1);
+                ps2_put_keycode(s, 0xf0);
+                ps2_put_keycode(s, 0x14);
+                ps2_put_keycode(s, 0xf0);
+                ps2_put_keycode(s, 0x77);
+            }
+        } else if (qcode == Q_KEY_CODE_PRINT) {
+            if (key->down) {
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0x12);
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0x7c);
+            } else {
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0xf0);
+                ps2_put_keycode(s, 0x7c);
+                ps2_put_keycode(s, 0xe0);
+                ps2_put_keycode(s, 0xf0);
+                ps2_put_keycode(s, 0x12);
+            }
+        } else {
+            keycode = qcode_to_keycode_set2[qcode];
+            if (keycode) {
+                if (keycode & 0xff00) {
+                    ps2_put_keycode(s, keycode >> 8);
+                }
+                if (!key->down) {
+                    ps2_put_keycode(s, 0xf0);
+                }
+                ps2_put_keycode(s, keycode & 0xff);
+            } else {
+                qemu_log_mask(LOG_UNIMP,
+                              "ps2: ignoring key with qcode %d\n", qcode);
+            }
+        }
+    } else if (s->scancode_set == 3) {
+        keycode = qcode_to_keycode_set3[qcode];
+        if (keycode) {
+            /* FIXME: break code should be configured on a key by key basis */
+            if (!key->down) {
+                ps2_put_keycode(s, 0xf0);
+            }
+            ps2_put_keycode(s, keycode);
+        } else {
+            qemu_log_mask(LOG_UNIMP,
+                          "ps2: ignoring key with qcode %d\n", qcode);
+        }
     }
 }
 
@@ -290,22 +779,19 @@ void ps2_write_keyboard(void *opaque, int val)
             ps2_queue(&s->common, KBD_REPLY_POR);
             break;
         default:
-            ps2_queue(&s->common, KBD_REPLY_ACK);
+            ps2_queue(&s->common, KBD_REPLY_RESEND);
             break;
         }
         break;
     case KBD_CMD_SCANCODE:
         if (val == 0) {
-            if (s->scancode_set == 1)
-                ps2_put_keycode(s, 0x43);
-            else if (s->scancode_set == 2)
-                ps2_put_keycode(s, 0x41);
-            else if (s->scancode_set == 3)
-                ps2_put_keycode(s, 0x3f);
-        } else {
-            if (val >= 1 && val <= 3)
-                s->scancode_set = val;
             ps2_queue(&s->common, KBD_REPLY_ACK);
+            ps2_put_keycode(s, s->scancode_set);
+        } else if (val >= 1 && val <= 3) {
+            s->scancode_set = val;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+        } else {
+            ps2_queue(&s->common, KBD_REPLY_RESEND);
         }
         s->common.write_cmd = -1;
         break;
@@ -690,6 +1176,23 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
     }
 };
 
+static bool ps2_keyboard_need_high_bit_needed(void *opaque)
+{
+    PS2KbdState *s = opaque;
+    return s->need_high_bit != 0; /* 0 is the usual state */
+}
+
+static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
+    .name = "ps2kbd/need_high_bit",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = ps2_keyboard_need_high_bit_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(need_high_bit, PS2KbdState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static int ps2_kbd_post_load(void* opaque, int version_id)
 {
     PS2KbdState *s = (PS2KbdState*)opaque;
@@ -726,6 +1229,7 @@ static const VMStateDescription vmstate_ps2_keyboard = {
     },
     .subsections = (const VMStateDescription*[]) {
         &vmstate_ps2_keyboard_ledstate,
+        &vmstate_ps2_keyboard_need_high_bit,
         NULL
     }
 };
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 31791b0986..fd9208fde0 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -416,7 +416,7 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
 }
 
 static Property ioapic_properties[] = {
-    DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x11),
+    DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x20),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/mem/trace-events b/hw/mem/trace-events
new file mode 100644
index 0000000000..323c3c10d5
--- /dev/null
+++ b/hw/mem/trace-events
@@ -0,0 +1,5 @@
+# See docs/trace-events.txt for syntax documentation.
+
+# hw/mem/pc-dimm.c
+mhp_pc_dimm_assigned_slot(int slot) "%d"
+mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index 22c584eb8d..8e16f651ea 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -54,11 +54,6 @@ typedef struct SpinState {
     SpinInfo spin[MAX_CPUS];
 } SpinState;
 
-typedef struct spin_kick {
-    PowerPCCPU *cpu;
-    SpinInfo *spin;
-} SpinKick;
-
 static void spin_reset(void *opaque)
 {
     SpinState *s = opaque;
@@ -89,16 +84,15 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
     env->tlb_dirty = true;
 }
 
-static void spin_kick(void *data)
+static void spin_kick(CPUState *cs, void *data)
 {
-    SpinKick *kick = data;
-    CPUState *cpu = CPU(kick->cpu);
-    CPUPPCState *env = &kick->cpu->env;
-    SpinInfo *curspin = kick->spin;
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+    SpinInfo *curspin = data;
     hwaddr map_size = 64 * 1024 * 1024;
     hwaddr map_start;
 
-    cpu_synchronize_state(cpu);
+    cpu_synchronize_state(cs);
     stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]);
     env->nip = ldq_p(&curspin->addr) & (map_size - 1);
     env->gpr[3] = ldq_p(&curspin->r3);
@@ -112,10 +106,10 @@ static void spin_kick(void *data)
     map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
     mmubooke_create_initial_mapping(env, 0, map_start, map_size);
 
-    cpu->halted = 0;
-    cpu->exception_index = -1;
-    cpu->stopped = false;
-    qemu_cpu_kick(cpu);
+    cs->halted = 0;
+    cs->exception_index = -1;
+    cs->stopped = false;
+    qemu_cpu_kick(cs);
 }
 
 static void spin_write(void *opaque, hwaddr addr, uint64_t value,
@@ -153,12 +147,7 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value,
 
     if (!(ldq_p(&curspin->addr) & 1)) {
         /* run CPU */
-        SpinKick kick = {
-            .cpu = POWERPC_CPU(cpu),
-            .spin = curspin,
-        };
-
-        run_on_cpu(cpu, spin_kick, &kick);
+        run_on_cpu(cpu, spin_kick, curspin);
     }
 }
 
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 648576e6bd..14b6821a94 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2132,10 +2132,8 @@ static void spapr_machine_finalizefn(Object *obj)
     g_free(spapr->kvm_type);
 }
 
-static void ppc_cpu_do_nmi_on_cpu(void *arg)
+static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, void *arg)
 {
-    CPUState *cs = arg;
-
     cpu_synchronize_state(cs);
     ppc_cpu_do_system_reset(cs);
 }
@@ -2145,7 +2143,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
     CPUState *cs;
 
     CPU_FOREACH(cs) {
-        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, cs);
+        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, NULL);
     }
 }
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 290a7122d4..c5e7e8c995 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -13,19 +13,18 @@
 #include "kvm_ppc.h"
 
 struct SPRSyncState {
-    CPUState *cs;
     int spr;
     target_ulong value;
     target_ulong mask;
 };
 
-static void do_spr_sync(void *arg)
+static void do_spr_sync(CPUState *cs, void *arg)
 {
     struct SPRSyncState *s = arg;
-    PowerPCCPU *cpu = POWERPC_CPU(s->cs);
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
-    cpu_synchronize_state(s->cs);
+    cpu_synchronize_state(cs);
     env->spr[s->spr] &= ~s->mask;
     env->spr[s->spr] |= s->value;
 }
@@ -34,7 +33,6 @@ static void set_spr(CPUState *cs, int spr, target_ulong value,
                     target_ulong mask)
 {
     struct SPRSyncState s = {
-        .cs = cs,
         .spr = spr,
         .value = value,
         .mask = mask
@@ -909,17 +907,17 @@ static target_ulong cas_get_option_vector(int vector, target_ulong table)
 }
 
 typedef struct {
-    PowerPCCPU *cpu;
     uint32_t cpu_version;
     Error *err;
 } SetCompatState;
 
-static void do_set_compat(void *arg)
+static void do_set_compat(CPUState *cs, void *arg)
 {
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
     SetCompatState *s = arg;
 
-    cpu_synchronize_state(CPU(s->cpu));
-    ppc_set_compat(s->cpu, s->cpu_version, &s->err);
+    cpu_synchronize_state(cs);
+    ppc_set_compat(cpu, s->cpu_version, &s->err);
 }
 
 #define get_compat_level(cpuver) ( \
@@ -1015,7 +1013,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
     if (old_cpu_version != cpu_version) {
         CPU_FOREACH(cs) {
             SetCompatState s = {
-                .cpu = POWERPC_CPU(cs),
                 .cpu_version = cpu_version,
                 .err = NULL,
             };
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index f20b0b884f..ae30bbe30f 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -156,14 +156,17 @@ static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu)
     return 1ULL << tcet->page_shift;
 }
 
-static void spapr_tce_notify_started(MemoryRegion *iommu)
+static void spapr_tce_notify_flag_changed(MemoryRegion *iommu,
+                                          IOMMUNotifierFlag old,
+                                          IOMMUNotifierFlag new)
 {
-    spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), true);
-}
+    struct sPAPRTCETable *tbl = container_of(iommu, sPAPRTCETable, iommu);
 
-static void spapr_tce_notify_stopped(MemoryRegion *iommu)
-{
-    spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), false);
+    if (old == IOMMU_NOTIFIER_NONE && new != IOMMU_NOTIFIER_NONE) {
+        spapr_tce_set_need_vfio(tbl, true);
+    } else if (old != IOMMU_NOTIFIER_NONE && new == IOMMU_NOTIFIER_NONE) {
+        spapr_tce_set_need_vfio(tbl, false);
+    }
 }
 
 static int spapr_tce_table_post_load(void *opaque, int version_id)
@@ -246,8 +249,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
 static MemoryRegionIOMMUOps spapr_iommu_ops = {
     .translate = spapr_tce_translate_iommu,
     .get_min_page_size = spapr_tce_get_min_page_size,
-    .notify_started = spapr_tce_notify_started,
-    .notify_stopped = spapr_tce_notify_stopped,
+    .notify_flag_changed = spapr_tce_notify_flag_changed,
 };
 
 static int spapr_tce_table_realize(DeviceState *dev)
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index b313e7c2c6..29188a12fc 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -293,11 +293,10 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section)
            section->offset_within_address_space & (1ULL << 63);
 }
 
-static void vfio_iommu_map_notify(Notifier *n, void *data)
+static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
 {
     VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
     VFIOContainer *container = giommu->container;
-    IOMMUTLBEntry *iotlb = data;
     hwaddr iova = iotlb->iova + giommu->iommu_offset;
     MemoryRegion *mr;
     hwaddr xlat;
@@ -454,6 +453,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
                                section->offset_within_region;
         giommu->container = container;
         giommu->n.notify = vfio_iommu_map_notify;
+        giommu->n.notifier_flags = IOMMU_NOTIFIER_ALL;
         QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
 
         memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 55184d33b3..8756cefa79 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -14,3 +14,8 @@ virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready"
 virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed"
 virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
 
+# hw/virtio/virtio-balloon.c
+virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64
+virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d"
+virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d"
+virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: %"PRIx64" num_pages: %d"