Merge remote-tracking branch 'stefanha/block-next' into staging

# By Stefan Hajnoczi
# Via Stefan Hajnoczi
* stefanha/block-next:
  aio: drop io_flush argument
  tests: drop event_active_cb()
  thread-pool: drop thread_pool_active()
  dataplane/virtio-blk: drop flush_true() and flush_io()
  block/ssh: drop return_true()
  block/sheepdog: drop have_co_req() and aio_flush_request()
  block/rbd: drop qemu_rbd_aio_flush_cb()
  block/nbd: drop nbd_have_request()
  block/linux-aio: drop qemu_laio_completion_cb()
  block/iscsi: drop iscsi_process_flush()
  block/gluster: drop qemu_gluster_aio_flush_cb()
  block/curl: drop curl_aio_flush()
  aio: stop using .io_flush()
  tests: adjust test-thread-pool to new aio_poll() semantics
  tests: adjust test-aio to new aio_poll() semantics
  dataplane/virtio-blk: check exit conditions before aio_poll()
  block: stop relying on io_flush() in bdrv_drain_all()
  block: ensure bdrv_drain_all() works during bdrv_delete()

Message-id: 1376921877-9576-1-git-send-email-stefanha@redhat.com
Signed-off-by: Anthony Liguori <anthony@codemonkey.ws>
diff --git a/.mailmap b/.mailmap
index 9797802..7b91a95 100644
--- a/.mailmap
+++ b/.mailmap
@@ -2,7 +2,7 @@
 # into proper addresses so that they are counted properly in git shortlog output.
 #
 Andrzej Zaborowski <balrogg@gmail.com> balrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
-Anthony Liguori <aliguori@us.ibm.com> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
+Anthony Liguori <anthony@codemonkey.ws> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
 Aurelien Jarno <aurelien@aurel32.net> aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
 Blue Swirl <blauwirbel@gmail.com> blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
 Edgar E. Iglesias <edgar.iglesias@gmail.com> edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>
diff --git a/MAINTAINERS b/MAINTAINERS
index 654e2cb..70a3370 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -50,7 +50,7 @@
 
 General Project Administration
 ------------------------------
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 M: Paul Brook <paul@codesourcery.com>
 
 Guest CPU cores (TCG):
@@ -509,7 +509,7 @@
 X86 Machines
 ------------
 PC
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 S: Supported
 F: hw/i386/pc.[ch]
 F: hw/i386/pc_piix.c
@@ -593,7 +593,7 @@
 F: hw/*/*vhost*
 
 virtio
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 S: Supported
 F: hw/*/virtio*
 
@@ -651,7 +651,7 @@
 F: hw/block/
 
 Character Devices
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 S: Maintained
 F: qemu-char.c
 
@@ -689,7 +689,7 @@
 F: hw/display/qxl*
 
 Graphics
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 S: Maintained
 F: ui/
 
@@ -699,7 +699,7 @@
 F: ui/cocoa.m
 
 Main loop
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 S: Supported
 F: vl.c
 
@@ -711,7 +711,7 @@
 F: hmp-commands.hx
 
 Network device layer
-M: Anthony Liguori <aliguori@us.ibm.com>
+M: Anthony Liguori <anthony@codemonkey.ws>
 M: Stefan Hajnoczi <stefanha@redhat.com>
 S: Maintained
 F: net/
diff --git a/cpus.c b/cpus.c
index 0f65e76..70cc617 100644
--- a/cpus.c
+++ b/cpus.c
@@ -62,12 +62,17 @@
 
 static CPUState *next_cpu;
 
+bool cpu_is_stopped(CPUState *cpu)
+{
+    return cpu->stopped || !runstate_is_running();
+}
+
 static bool cpu_thread_is_idle(CPUState *cpu)
 {
     if (cpu->stop || cpu->queued_work_first) {
         return false;
     }
-    if (cpu->stopped || !runstate_is_running()) {
+    if (cpu_is_stopped(cpu)) {
         return true;
     }
     if (!cpu->halted || qemu_cpu_has_work(cpu) ||
@@ -429,11 +434,6 @@
     }
 }
 
-bool cpu_is_stopped(CPUState *cpu)
-{
-    return !runstate_is_running() || cpu->stopped;
-}
-
 static int do_vm_stop(RunState state)
 {
     int ret = 0;
@@ -457,7 +457,7 @@
     if (cpu->stop) {
         return false;
     }
-    if (cpu->stopped || !runstate_is_running()) {
+    if (cpu_is_stopped(cpu)) {
         return false;
     }
     return true;
diff --git a/gdbstub.c b/gdbstub.c
index 1af25a6..9d067d6 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -621,6 +621,8 @@
         if (g_pos != s->base_reg) {
             fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n"
                     "Expected %d got %d\n", xml, g_pos, s->base_reg);
+        } else {
+            cpu->gdb_num_g_regs = cpu->gdb_num_regs;
         }
     }
 }
@@ -902,7 +904,7 @@
     case 'g':
         cpu_synchronize_state(s->g_cpu);
         len = 0;
-        for (addr = 0; addr < s->g_cpu->gdb_num_regs; addr++) {
+        for (addr = 0; addr < s->g_cpu->gdb_num_g_regs; addr++) {
             reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
             len += reg_size;
         }
@@ -914,7 +916,7 @@
         registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
-        for (addr = 0; addr < s->g_cpu->gdb_num_regs && len > 0; addr++) {
+        for (addr = 0; addr < s->g_cpu->gdb_num_g_regs && len > 0; addr++) {
             reg_size = gdb_write_register(s->g_cpu, registers, addr);
             len -= reg_size;
             registers += reg_size;
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index b7fb044..2450045 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -26,9 +26,9 @@
 } TyphoonCchip;
 
 typedef struct TyphoonWindow {
-    uint32_t base_addr;
-    uint32_t mask;
-    uint32_t translated_base_pfn;
+    uint64_t wba;
+    uint64_t wsm;
+    uint64_t tba;
 } TyphoonWindow;
  
 typedef struct TyphoonPchip {
@@ -37,6 +37,10 @@
     MemoryRegion reg_mem;
     MemoryRegion reg_io;
     MemoryRegion reg_conf;
+
+    AddressSpace iommu_as;
+    MemoryRegion iommu;
+
     uint64_t ctl;
     TyphoonWindow win[4];
 } TyphoonPchip;
@@ -209,53 +213,53 @@
     switch (addr) {
     case 0x0000:
         /* WSBA0: Window Space Base Address Register.  */
-        ret = s->pchip.win[0].base_addr;
+        ret = s->pchip.win[0].wba;
         break;
     case 0x0040:
         /* WSBA1 */
-        ret = s->pchip.win[1].base_addr;
+        ret = s->pchip.win[1].wba;
         break;
     case 0x0080:
         /* WSBA2 */
-        ret = s->pchip.win[2].base_addr;
+        ret = s->pchip.win[2].wba;
         break;
     case 0x00c0:
         /* WSBA3 */
-        ret = s->pchip.win[3].base_addr;
+        ret = s->pchip.win[3].wba;
         break;
 
     case 0x0100:
         /* WSM0: Window Space Mask Register.  */
-        ret = s->pchip.win[0].mask;
+        ret = s->pchip.win[0].wsm;
         break;
     case 0x0140:
         /* WSM1 */
-        ret = s->pchip.win[1].mask;
+        ret = s->pchip.win[1].wsm;
         break;
     case 0x0180:
         /* WSM2 */
-        ret = s->pchip.win[2].mask;
+        ret = s->pchip.win[2].wsm;
         break;
     case 0x01c0:
         /* WSM3 */
-        ret = s->pchip.win[3].mask;
+        ret = s->pchip.win[3].wsm;
         break;
 
     case 0x0200:
         /* TBA0: Translated Base Address Register.  */
-        ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10;
+        ret = s->pchip.win[0].tba;
         break;
     case 0x0240:
         /* TBA1 */
-        ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10;
+        ret = s->pchip.win[1].tba;
         break;
     case 0x0280:
         /* TBA2 */
-        ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10;
+        ret = s->pchip.win[2].tba;
         break;
     case 0x02c0:
         /* TBA3 */
-        ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10;
+        ret = s->pchip.win[3].tba;
         break;
 
     case 0x0300:
@@ -458,53 +462,53 @@
     switch (addr) {
     case 0x0000:
         /* WSBA0: Window Space Base Address Register.  */
-        s->pchip.win[0].base_addr = val;
+        s->pchip.win[0].wba = val & 0xfff00003u;
         break;
     case 0x0040:
         /* WSBA1 */
-        s->pchip.win[1].base_addr = val;
+        s->pchip.win[1].wba = val & 0xfff00003u;
         break;
     case 0x0080:
         /* WSBA2 */
-        s->pchip.win[2].base_addr = val;
+        s->pchip.win[2].wba = val & 0xfff00003u;
         break;
     case 0x00c0:
         /* WSBA3 */
-        s->pchip.win[3].base_addr = val;
+        s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
         break;
 
     case 0x0100:
         /* WSM0: Window Space Mask Register.  */
-        s->pchip.win[0].mask = val;
+        s->pchip.win[0].wsm = val & 0xfff00000u;
         break;
     case 0x0140:
         /* WSM1 */
-        s->pchip.win[1].mask = val;
+        s->pchip.win[1].wsm = val & 0xfff00000u;
         break;
     case 0x0180:
         /* WSM2 */
-        s->pchip.win[2].mask = val;
+        s->pchip.win[2].wsm = val & 0xfff00000u;
         break;
     case 0x01c0:
         /* WSM3 */
-        s->pchip.win[3].mask = val;
+        s->pchip.win[3].wsm = val & 0xfff00000u;
         break;
 
     case 0x0200:
         /* TBA0: Translated Base Address Register.  */
-        s->pchip.win[0].translated_base_pfn = val >> 10;
+        s->pchip.win[0].tba = val & 0x7fffffc00ull;
         break;
     case 0x0240:
         /* TBA1 */
-        s->pchip.win[1].translated_base_pfn = val >> 10;
+        s->pchip.win[1].tba = val & 0x7fffffc00ull;
         break;
     case 0x0280:
         /* TBA2 */
-        s->pchip.win[2].translated_base_pfn = val >> 10;
+        s->pchip.win[2].tba = val & 0x7fffffc00ull;
         break;
     case 0x02c0:
         /* TBA3 */
-        s->pchip.win[3].translated_base_pfn = val >> 10;
+        s->pchip.win[3].tba = val & 0x7fffffc00ull;
         break;
 
     case 0x0300:
@@ -512,7 +516,6 @@
         oldval = s->pchip.ctl;
         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
         oldval |= val & 0x00001cff0fc7ffull;
-
         s->pchip.ctl = oldval;
         break;
 
@@ -593,6 +596,140 @@
     },
 };
 
+/* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
+   using the given translated address and mask.  */
+static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
+{
+    *ret = (IOMMUTLBEntry) {
+        .target_as = &address_space_memory,
+        .translated_addr = taddr,
+        .addr_mask = mask,
+        .perm = IOMMU_RW,
+    };
+    return true;
+}
+
+/* A subroutine of typhoon_translate_iommu that handles scatter-gather
+   translation, given the address of the PTE.  */
+static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
+{
+    uint64_t pte = ldq_phys(pte_addr);
+
+    /* Check valid bit.  */
+    if ((pte & 1) == 0) {
+        return false;
+    }
+
+    return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
+}
+
+/* A subroutine of typhoon_translate_iommu that handles one of the
+   four single-address-cycle translation windows.  */
+static bool window_translate(TyphoonWindow *win, hwaddr addr,
+                             IOMMUTLBEntry *ret)
+{
+    uint32_t wba = win->wba;
+    uint64_t wsm = win->wsm;
+    uint64_t tba = win->tba;
+    uint64_t wsm_ext = wsm | 0xfffff;
+
+    /* Check for window disabled.  */
+    if ((wba & 1) == 0) {
+        return false;
+    }
+
+    /* Check for window hit.  */
+    if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
+        return false;
+    }
+
+    if (wba & 2) {
+        /* Scatter-gather translation.  */
+        hwaddr pte_addr;
+
+        /* See table 10-6, Generating PTE address for PCI DMA Address.  */
+        pte_addr  = tba & ~(wsm >> 10);
+        pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
+        return pte_translate(pte_addr, ret);
+    } else {
+	/* Direct-mapped translation.  */
+	return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
+    }
+}
+
+/* Handle PCI-to-system address translation.  */
+/* TODO: A translation failure here ought to set PCI error codes on the
+   Pchip and generate a machine check interrupt.  */
+static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr)
+{
+    TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
+    IOMMUTLBEntry ret;
+    int i;
+
+    if (addr <= 0xffffffffu) {
+        /* Single-address cycle.  */
+
+        /* Check for the Window Hole, inhibiting matching.  */
+        if ((pchip->ctl & 0x20)
+            && addr >= 0x80000
+            && addr <= 0xfffff) {
+            goto failure;
+        }
+
+        /* Check the first three windows.  */
+        for (i = 0; i < 3; ++i) {
+            if (window_translate(&pchip->win[i], addr, &ret)) {
+                goto success;
+            }
+        }
+
+        /* Check the fourth window for DAC disable.  */
+        if ((pchip->win[3].wba & 0x80000000000ull) == 0
+	    && window_translate(&pchip->win[3], addr, &ret)) {
+            goto success;
+        }
+    } else {
+        /* Double-address cycle.  */
+
+        if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
+            /* Check for the DMA monster window.  */
+            if (pchip->ctl & 0x40) {
+                /* See 10.1.4.4; in particular <39:35> is ignored.  */
+                make_iommu_tlbe(0, 0x007ffffffffull, &ret);
+		goto success;
+            }
+        }
+
+        if (addr >= 0x80000000000 && addr <= 0xfffffffffff) {
+            /* Check the fourth window for DAC enable and window enable.  */
+            if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
+                uint64_t pte_addr;
+
+                pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
+                pte_addr |= (addr & 0xffffe000u) >> 10;
+                if (pte_translate(pte_addr, &ret)) {
+			goto success;
+		}
+            }
+        }
+    }
+
+ failure:
+    ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
+ success:
+    return ret;
+}
+
+static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
+    .translate = typhoon_translate_iommu,
+};
+
+static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+    TyphoonState *s = opaque;
+    return &s->pchip.iommu_as;
+}
+
 static void typhoon_set_irq(void *opaque, int irq, int level)
 {
     TyphoonState *s = opaque;
@@ -688,6 +825,9 @@
     s = TYPHOON_PCI_HOST_BRIDGE(dev);
     phb = PCI_HOST_BRIDGE(dev);
 
+    s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
+    s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
+
     /* Remember the CPUs so that we can deliver interrupts to them.  */
     for (i = 0; i < 4; i++) {
         AlphaCPU *cpu = cpus[i];
@@ -746,6 +886,12 @@
                          0, 64, TYPE_PCI_BUS);
     phb->bus = b;
 
+    /* Host memory as seen from the PCI side, via the IOMMU.  */
+    memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
+                             "iommu-typhoon", UINT64_MAX);
+    address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci");
+    pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
+
     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
                           b, "pci0-iack", 64*MB);
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 9190a7e..758de9f 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -752,7 +752,6 @@
         }
         class = object_class_get_parent(class);
     } while (class != object_class_by_name(TYPE_DEVICE));
-    qdev_prop_set_globals(dev, &err);
     if (err != NULL) {
         qerror_report_err(err);
         error_free(err);
@@ -764,6 +763,15 @@
     assert_no_error(err);
 }
 
+static void device_post_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    Error *err = NULL;
+
+    qdev_prop_set_globals(dev, &err);
+    assert_no_error(err);
+}
+
 /* Unlink device from bus and free the structure.  */
 static void device_finalize(Object *obj)
 {
@@ -853,6 +861,7 @@
     .parent = TYPE_OBJECT,
     .instance_size = sizeof(DeviceState),
     .instance_init = device_initfn,
+    .instance_post_init = device_post_init,
     .instance_finalize = device_finalize,
     .class_base_init = device_class_base_init,
     .class_init = device_class_init,
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 0d6e95c..3e49936 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -152,6 +152,7 @@
  * @current_tb: Currently executing TB.
  * @gdb_regs: Additional GDB registers.
  * @gdb_num_regs: Number of total registers accessible to GDB.
+ * @gdb_num_g_regs: Number of registers in GDB 'g' packets.
  * @next_cpu: Next CPU sharing TB cache.
  * @kvm_fd: vCPU file descriptor for KVM.
  *
@@ -188,6 +189,7 @@
     struct TranslationBlock *current_tb;
     struct GDBRegisterState *gdb_regs;
     int gdb_num_regs;
+    int gdb_num_g_regs;
     CPUState *next_cpu;
 
     int kvm_fd;
diff --git a/include/qom/object.h b/include/qom/object.h
index 23fc048..9b69065 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -398,6 +398,8 @@
  * @instance_init: This function is called to initialize an object.  The parent
  *   class will have already been initialized so the type is only responsible
  *   for initializing its own members.
+ * @instance_post_init: This function is called to finish initialization of
+ *   an object, after all @instance_init functions were called.
  * @instance_finalize: This function is called during object destruction.  This
  *   is called before the parent @instance_finalize function has been called.
  *   An object should only free the members that are unique to its type in this
@@ -433,6 +435,7 @@
 
     size_t instance_size;
     void (*instance_init)(Object *obj);
+    void (*instance_post_init)(Object *obj);
     void (*instance_finalize)(Object *obj);
 
     bool abstract;
diff --git a/qom/cpu.c b/qom/cpu.c
index aa95108..e71e57b 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -240,7 +240,7 @@
     CPUState *cpu = CPU(obj);
     CPUClass *cc = CPU_GET_CLASS(obj);
 
-    cpu->gdb_num_regs = cc->gdb_num_core_regs;
+    cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs;
 }
 
 static int64_t cpu_common_get_arch_id(CPUState *cpu)
diff --git a/qom/object.c b/qom/object.c
index b2479d1..74fd241 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -51,6 +51,7 @@
     void *class_data;
 
     void (*instance_init)(Object *obj);
+    void (*instance_post_init)(Object *obj);
     void (*instance_finalize)(Object *obj);
 
     bool abstract;
@@ -111,6 +112,7 @@
     ti->class_data = info->class_data;
 
     ti->instance_init = info->instance_init;
+    ti->instance_post_init = info->instance_post_init;
     ti->instance_finalize = info->instance_finalize;
 
     ti->abstract = info->abstract;
@@ -298,6 +300,17 @@
     }
 }
 
+static void object_post_init_with_type(Object *obj, TypeImpl *ti)
+{
+    if (ti->instance_post_init) {
+        ti->instance_post_init(obj);
+    }
+
+    if (type_has_parent(ti)) {
+        object_post_init_with_type(obj, type_get_parent(ti));
+    }
+}
+
 void object_initialize_with_type(void *data, TypeImpl *type)
 {
     Object *obj = data;
@@ -313,6 +326,7 @@
     object_ref(obj);
     QTAILQ_INIT(&obj->properties);
     object_init_with_type(obj, type);
+    object_post_init_with_type(obj, type);
 }
 
 void object_initialize(void *data, const char *typename)
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 0e425cf..732b701 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -99,6 +99,7 @@
 
 #if !defined (CONFIG_USER_ONLY)
 DEF_HELPER_2(hw_ret, void, env, i64)
+DEF_HELPER_3(call_pal, void, env, i64, i64)
 
 DEF_HELPER_1(ldl_phys, i64, i64)
 DEF_HELPER_1(ldq_phys, i64, i64)
@@ -111,6 +112,7 @@
 
 DEF_HELPER_FLAGS_1(tbia, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_FLAGS_2(tbis, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_1(tb_flush, TCG_CALL_NO_RWG, void, env)
 
 DEF_HELPER_1(halt, void, i64);
 
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
index bd94597..97cf9eb 100644
--- a/target-alpha/sys_helper.c
+++ b/target-alpha/sys_helper.c
@@ -51,6 +51,17 @@
     }
 }
 
+void helper_call_pal(CPUAlphaState *env, uint64_t pc, uint64_t entry_ofs)
+{
+    int pal_mode = env->pal_mode;
+    env->exc_addr = pc | pal_mode;
+    env->pc = env->palbr + entry_ofs;
+    if (!pal_mode) {
+        env->pal_mode = 1;
+        swap_shadow_regs(env);
+    }
+}
+
 void helper_tbia(CPUAlphaState *env)
 {
     tlb_flush(env, 1);
@@ -61,6 +72,11 @@
     tlb_flush_page(env, p);
 }
 
+void helper_tb_flush(CPUAlphaState *env)
+{
+    tb_flush(env);
+}
+
 void helper_halt(uint64_t restart)
 {
     if (restart) {
@@ -91,4 +107,5 @@
         qemu_del_timer(cpu->alarm_timer);
     }
 }
+
 #endif /* CONFIG_USER_ONLY */
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 0efd559..309dea6 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -379,13 +379,26 @@
 #endif
 }
 
-static int use_goto_tb(DisasContext *ctx, uint64_t dest)
+static bool in_superpage(DisasContext *ctx, int64_t addr)
 {
-    /* Check for the dest on the same page as the start of the TB.  We
-       also want to suppress goto_tb in the case of single-steping and IO.  */
-    return (((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0
-            && !ctx->singlestep_enabled
-            && !(ctx->tb->cflags & CF_LAST_IO));
+    return ((ctx->tb->flags & TB_FLAGS_USER_MODE) == 0
+            && addr < 0
+            && ((addr >> 41) & 3) == 2
+            && addr >> TARGET_VIRT_ADDR_SPACE_BITS == addr >> 63);
+}
+
+static bool use_goto_tb(DisasContext *ctx, uint64_t dest)
+{
+    /* Suppress goto_tb in the case of single-steping and IO.  */
+    if (ctx->singlestep_enabled || (ctx->tb->cflags & CF_LAST_IO)) {
+        return false;
+    }
+    /* If the destination is in the superpage, the page perms can't change.  */
+    if (in_superpage(ctx, dest)) {
+        return true;
+    }
+    /* Check for the dest on the same page as the start of the TB.  */
+    return ((ctx->tb->pc ^ dest) & TARGET_PAGE_MASK) == 0;
 }
 
 static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp)
@@ -1521,7 +1534,8 @@
             tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
             break;
         default:
-            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
+            palcode &= 0xbf;
+            goto do_call_pal;
         }
         return NO_EXIT;
     }
@@ -1586,13 +1600,42 @@
             break;
 
         default:
-            return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
+            palcode &= 0x3f;
+            goto do_call_pal;
         }
         return NO_EXIT;
     }
 #endif
-
     return gen_invalid(ctx);
+
+ do_call_pal:
+#ifdef CONFIG_USER_ONLY
+    return gen_excp(ctx, EXCP_CALL_PAL, palcode);
+#else
+    {
+        TCGv pc = tcg_const_i64(ctx->pc);
+        TCGv entry = tcg_const_i64(palcode & 0x80
+                                   ? 0x2000 + (palcode - 0x80) * 64
+                                   : 0x1000 + palcode * 64);
+
+        gen_helper_call_pal(cpu_env, pc, entry);
+
+        tcg_temp_free(entry);
+        tcg_temp_free(pc);
+
+        /* Since the destination is running in PALmode, we don't really
+           need the page permissions check.  We'll see the existance of
+           the page when we create the TB, and we'll flush all TBs if
+           we change the PAL base register.  */
+        if (!ctx->singlestep_enabled && !(ctx->tb->cflags & CF_LAST_IO)) {
+            tcg_gen_goto_tb(0);
+            tcg_gen_exit_tb((tcg_target_long)ctx->tb);
+            return EXIT_GOTO_TB;
+        }
+
+        return EXIT_PC_UPDATED;
+    }
+#endif
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -1708,6 +1751,15 @@
         gen_helper_set_alarm(cpu_env, tmp);
         break;
 
+    case 7:
+        /* PALBR */
+        tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUAlphaState, palbr));
+        /* Changing the PAL base register implies un-chaining all of the TBs
+           that ended with a CALL_PAL.  Since the base register usually only
+           changes during boot, flushing everything works well.  */
+        gen_helper_tb_flush(cpu_env);
+        return EXIT_PC_STALE;
+
     default:
         /* The basic registers are data only, and unknown registers
            are read-zero, write-ignore.  */
@@ -3392,6 +3444,7 @@
     CPUAlphaState *env = &cpu->env;
     DisasContext ctx, *ctxp = &ctx;
     target_ulong pc_start;
+    target_ulong pc_mask;
     uint32_t insn;
     uint16_t *gen_opc_end;
     CPUBreakpoint *bp;
@@ -3421,8 +3474,15 @@
 
     num_insns = 0;
     max_insns = tb->cflags & CF_COUNT_MASK;
-    if (max_insns == 0)
+    if (max_insns == 0) {
         max_insns = CF_COUNT_MASK;
+    }
+
+    if (in_superpage(&ctx, pc_start)) {
+        pc_mask = (1ULL << 41) - 1;
+    } else {
+        pc_mask = ~TARGET_PAGE_MASK;
+    }
 
     gen_tb_start();
     do {
@@ -3460,7 +3520,7 @@
         /* If we reach a page boundary, are single stepping,
            or exhaust instruction count, stop generation.  */
         if (ret == NO_EXIT
-            && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
+            && ((ctx.pc & pc_mask) == 0
                 || tcg_ctx.gen_opc_ptr >= gen_opc_end
                 || num_insns >= max_insns
                 || singlestep
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 3b629d4d..da1fc40 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -3,7 +3,7 @@
 obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
 obj-y += gdbstub.o
 obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
-obj-$(CONFIG_KVM) += kvm.o hyperv.o
+obj-$(CONFIG_KVM) += kvm.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_LINUX_USER) += ioport-user.o
 obj-$(CONFIG_BSD_USER) += ioport-user.o
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 53b4c34..c4447c2 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -66,6 +66,10 @@
 
     CPUX86State env;
 
+    bool hyperv_vapic;
+    bool hyperv_relaxed_timing;
+    int hyperv_spinlock_attempts;
+
     /* Features that were filtered out because of missing host capabilities */
     uint32_t filtered_features[FEATURE_WORDS];
 
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 2efbeca..6e38252 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -35,8 +35,6 @@
 #include "qapi/visitor.h"
 #include "sysemu/arch_init.h"
 
-#include "hyperv.h"
-
 #include "hw/hw.h"
 #if defined(CONFIG_KVM)
 #include <linux/kvm_para.h>
@@ -1591,12 +1589,19 @@
                 object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp);
             } else if (!strcmp(featurestr, "hv-spinlocks")) {
                 char *err;
+                const int min = 0xFFF;
                 numvalue = strtoul(val, &err, 0);
                 if (!*val || *err) {
                     error_setg(errp, "bad numerical value %s", val);
                     goto out;
                 }
-                hyperv_set_spinlock_retries(numvalue);
+                if (numvalue < min) {
+                    fprintf(stderr, "hv-spinlocks value shall always be >= 0x%x"
+                            ", fixup will be removed in future versions\n",
+                            min);
+                    numvalue = min;
+                }
+                cpu->hyperv_spinlock_attempts = numvalue;
             } else {
                 error_setg(errp, "unrecognized feature %s", featurestr);
                 goto out;
@@ -1606,9 +1611,9 @@
         } else if (!strcmp(featurestr, "enforce")) {
             check_cpuid = enforce_cpuid = 1;
         } else if (!strcmp(featurestr, "hv_relaxed")) {
-            hyperv_enable_relaxed_timing(true);
+            cpu->hyperv_relaxed_timing = true;
         } else if (!strcmp(featurestr, "hv_vapic")) {
-            hyperv_enable_vapic_recommended(true);
+            cpu->hyperv_vapic = true;
         } else {
             error_setg(errp, "feature string `%s' not in format (+feature|"
                        "-feature|feature=xyz)", featurestr);
@@ -2489,6 +2494,7 @@
                         x86_cpu_get_feature_words,
                         NULL, NULL, (void *)cpu->filtered_features, NULL);
 
+    cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
     env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
 
     /* init various static tables used in TCG mode */
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index cedefdc..8a3d0fd 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -549,6 +549,10 @@
 #define CPUID_MWAIT_IBE     (1 << 1) /* Interrupts can exit capability */
 #define CPUID_MWAIT_EMX     (1 << 0) /* enumeration supported */
 
+#ifndef HYPERV_SPINLOCK_NEVER_RETRY
+#define HYPERV_SPINLOCK_NEVER_RETRY             0xFFFFFFFF
+#endif
+
 #define EXCP00_DIVZ	0
 #define EXCP01_DB	1
 #define EXCP02_NMI	2
diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c
deleted file mode 100644
index f284e99..0000000
--- a/target-i386/hyperv.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * QEMU Hyper-V support
- *
- * Copyright Red Hat, Inc. 2011
- *
- * Author: Vadim Rozenfeld     <vrozenfe@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "hyperv.h"
-
-static bool hyperv_vapic;
-static bool hyperv_relaxed_timing;
-static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
-
-void hyperv_enable_vapic_recommended(bool val)
-{
-    hyperv_vapic = val;
-}
-
-void hyperv_enable_relaxed_timing(bool val)
-{
-    hyperv_relaxed_timing = val;
-}
-
-void hyperv_set_spinlock_retries(int val)
-{
-    hyperv_spinlock_attempts = val;
-    if (hyperv_spinlock_attempts < 0xFFF) {
-        hyperv_spinlock_attempts = 0xFFF;
-    }
-}
-
-bool hyperv_enabled(void)
-{
-    return hyperv_hypercall_available() || hyperv_relaxed_timing_enabled();
-}
-
-bool hyperv_hypercall_available(void)
-{
-    if (hyperv_vapic ||
-        (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) {
-      return true;
-    }
-    return false;
-}
-
-bool hyperv_vapic_recommended(void)
-{
-    return hyperv_vapic;
-}
-
-bool hyperv_relaxed_timing_enabled(void)
-{
-    return hyperv_relaxed_timing;
-}
-
-int hyperv_get_spinlock_retries(void)
-{
-    return hyperv_spinlock_attempts;
-}
diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h
deleted file mode 100644
index bacb1d4..0000000
--- a/target-i386/hyperv.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * QEMU Hyper-V support
- *
- * Copyright Red Hat, Inc. 2011
- *
- * Author: Vadim Rozenfeld     <vrozenfe@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef QEMU_HW_HYPERV_H
-#define QEMU_HW_HYPERV_H 1
-
-#include "qemu-common.h"
-#ifdef CONFIG_KVM
-#include <asm/hyperv.h>
-#endif
-
-#ifndef HYPERV_SPINLOCK_NEVER_RETRY
-#define HYPERV_SPINLOCK_NEVER_RETRY             0xFFFFFFFF
-#endif
-
-#ifndef KVM_CPUID_SIGNATURE_NEXT
-#define KVM_CPUID_SIGNATURE_NEXT                0x40000100
-#endif
-
-#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_KVM)
-void hyperv_enable_vapic_recommended(bool val);
-void hyperv_enable_relaxed_timing(bool val);
-void hyperv_set_spinlock_retries(int val);
-#else
-static inline void hyperv_enable_vapic_recommended(bool val) { }
-static inline void hyperv_enable_relaxed_timing(bool val) { }
-static inline void hyperv_set_spinlock_retries(int val) { }
-#endif
-
-bool hyperv_enabled(void);
-bool hyperv_hypercall_available(void);
-bool hyperv_vapic_recommended(void);
-bool hyperv_relaxed_timing_enabled(void);
-int hyperv_get_spinlock_retries(void);
-
-#endif /* QEMU_HW_HYPERV_H */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 376fc70..0b6eb01 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -31,7 +31,7 @@
 #include "hw/i386/pc.h"
 #include "hw/i386/apic.h"
 #include "exec/ioport.h"
-#include "hyperv.h"
+#include <asm/hyperv.h>
 #include "hw/pci/pci.h"
 
 //#define DEBUG_KVM
@@ -420,6 +420,22 @@
     return cpu->env.cpuid_apic_id;
 }
 
+#ifndef KVM_CPUID_SIGNATURE_NEXT
+#define KVM_CPUID_SIGNATURE_NEXT                0x40000100
+#endif
+
+static bool hyperv_hypercall_available(X86CPU *cpu)
+{
+    return cpu->hyperv_vapic ||
+           (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY);
+}
+
+static bool hyperv_enabled(X86CPU *cpu)
+{
+    return hyperv_hypercall_available(cpu) ||
+           cpu->hyperv_relaxed_timing;
+}
+
 #define KVM_MAX_CPUID_ENTRIES  100
 
 int kvm_arch_init_vcpu(CPUState *cs)
@@ -442,7 +458,7 @@
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    if (!hyperv_enabled()) {
+    if (!hyperv_enabled(cpu)) {
         memcpy(signature, "KVMKVMKVM\0\0\0", 12);
         c->eax = 0;
     } else {
@@ -458,7 +474,7 @@
     c->function = KVM_CPUID_FEATURES;
     c->eax = env->features[FEAT_KVM];
 
-    if (hyperv_enabled()) {
+    if (hyperv_enabled(cpu)) {
         memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
         c->eax = signature[0];
 
@@ -471,10 +487,10 @@
         c = &cpuid_data.entries[cpuid_i++];
         memset(c, 0, sizeof(*c));
         c->function = HYPERV_CPUID_FEATURES;
-        if (hyperv_relaxed_timing_enabled()) {
+        if (cpu->hyperv_relaxed_timing) {
             c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
         }
-        if (hyperv_vapic_recommended()) {
+        if (cpu->hyperv_vapic) {
             c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
             c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
         }
@@ -482,13 +498,13 @@
         c = &cpuid_data.entries[cpuid_i++];
         memset(c, 0, sizeof(*c));
         c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
-        if (hyperv_relaxed_timing_enabled()) {
+        if (cpu->hyperv_relaxed_timing) {
             c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
         }
-        if (hyperv_vapic_recommended()) {
+        if (cpu->hyperv_vapic) {
             c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
         }
-        c->ebx = hyperv_get_spinlock_retries();
+        c->ebx = cpu->hyperv_spinlock_attempts;
 
         c = &cpuid_data.entries[cpuid_i++];
         memset(c, 0, sizeof(*c));
@@ -1114,11 +1130,11 @@
             kvm_msr_entry_set(&msrs[n++], MSR_KVM_STEAL_TIME,
                               env->steal_time_msr);
         }
-        if (hyperv_hypercall_available()) {
+        if (hyperv_hypercall_available(cpu)) {
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
         }
-        if (hyperv_vapic_recommended()) {
+        if (cpu->hyperv_vapic) {
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
         }
     }
diff --git a/tests/.gitignore b/tests/.gitignore
index fb05c2a..d11cc22 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -11,6 +11,7 @@
 test-mul64
 test-qapi-types.[ch]
 test-qapi-visit.[ch]
+test-qdev-global-props
 test-qmp-commands.h
 test-qmp-commands
 test-qmp-input-strict
diff --git a/tests/Makefile b/tests/Makefile
index d044908..b0200fd 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -48,6 +48,7 @@
 # all code tested by test-int128 is inside int128.h
 gcov-files-test-int128-y =
 check-unit-y += tests/test-bitops$(EXESUF)
+check-unit-y += tests/test-qdev-global-props$(EXESUF)
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -123,6 +124,12 @@
 tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuutil.a
 tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
 tests/test-int128$(EXESUF): tests/test-int128.o
+tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
+	hw/core/qdev.o hw/core/qdev-properties.o \
+	hw/core/irq.o \
+	qom/object.o qom/container.o qom/qom-qobject.o \
+	$(test-qapi-obj-y) \
+	libqemuutil.a libqemustub.a
 
 tests/test-qapi-types.c tests/test-qapi-types.h :\
 $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c
new file mode 100644
index 0000000..e4ad173
--- /dev/null
+++ b/tests/test-qdev-global-props.c
@@ -0,0 +1,180 @@
+/*
+ *  Test code for qdev global-properties handling
+ *
+ *  Copyright (c) 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <glib.h>
+#include <stdint.h>
+
+#include "hw/qdev.h"
+#include "qom/object.h"
+#include "qapi/visitor.h"
+
+
+#define TYPE_STATIC_PROPS "static_prop_type"
+#define STATIC_TYPE(obj) \
+    OBJECT_CHECK(MyType, (obj), TYPE_STATIC_PROPS)
+
+#define PROP_DEFAULT 100
+
+typedef struct MyType {
+    DeviceState parent_obj;
+
+    uint32_t prop1;
+    uint32_t prop2;
+} MyType;
+
+static Property static_props[] = {
+    DEFINE_PROP_UINT32("prop1", MyType, prop1, PROP_DEFAULT),
+    DEFINE_PROP_UINT32("prop2", MyType, prop2, PROP_DEFAULT),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void static_prop_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = NULL;
+    dc->props = static_props;
+}
+
+static const TypeInfo static_prop_type = {
+    .name = TYPE_STATIC_PROPS,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(MyType),
+    .class_init = static_prop_class_init,
+};
+
+/* Test simple static property setting to default value */
+static void test_static_prop(void)
+{
+    MyType *mt;
+
+    mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS));
+    qdev_init_nofail(DEVICE(mt));
+
+    g_assert_cmpuint(mt->prop1, ==, PROP_DEFAULT);
+}
+
+/* Test setting of static property using global properties */
+static void test_static_globalprop(void)
+{
+    MyType *mt;
+    static GlobalProperty props[] = {
+        { TYPE_STATIC_PROPS, "prop1", "200" },
+        {}
+    };
+
+    qdev_prop_register_global_list(props);
+
+    mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS));
+    qdev_init_nofail(DEVICE(mt));
+
+    g_assert_cmpuint(mt->prop1, ==, 200);
+    g_assert_cmpuint(mt->prop2, ==, PROP_DEFAULT);
+}
+
+#define TYPE_DYNAMIC_PROPS "dynamic-prop-type"
+#define DYNAMIC_TYPE(obj) \
+    OBJECT_CHECK(MyType, (obj), TYPE_DYNAMIC_PROPS)
+
+static void prop1_accessor(Object *obj,
+                           Visitor *v,
+                           void *opaque,
+                           const char *name,
+                           Error **errp)
+{
+    MyType *mt = DYNAMIC_TYPE(obj);
+
+    visit_type_uint32(v, &mt->prop1, name, errp);
+}
+
+static void prop2_accessor(Object *obj,
+                           Visitor *v,
+                           void *opaque,
+                           const char *name,
+                           Error **errp)
+{
+    MyType *mt = DYNAMIC_TYPE(obj);
+
+    visit_type_uint32(v, &mt->prop2, name, errp);
+}
+
+static void dynamic_instance_init(Object *obj)
+{
+    object_property_add(obj, "prop1", "uint32", prop1_accessor, prop1_accessor,
+                        NULL, NULL, NULL);
+    object_property_add(obj, "prop2", "uint32", prop2_accessor, prop2_accessor,
+                        NULL, NULL, NULL);
+}
+
+static void dynamic_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = NULL;
+}
+
+
+static const TypeInfo dynamic_prop_type = {
+    .name = TYPE_DYNAMIC_PROPS,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(MyType),
+    .instance_init = dynamic_instance_init,
+    .class_init = dynamic_class_init,
+};
+
+/* Test setting of static property using global properties */
+static void test_dynamic_globalprop(void)
+{
+    MyType *mt;
+    static GlobalProperty props[] = {
+        { TYPE_DYNAMIC_PROPS, "prop1", "101" },
+        { TYPE_DYNAMIC_PROPS, "prop2", "102" },
+        {}
+    };
+
+    qdev_prop_register_global_list(props);
+
+    mt = DYNAMIC_TYPE(object_new(TYPE_DYNAMIC_PROPS));
+    qdev_init_nofail(DEVICE(mt));
+
+    g_assert_cmpuint(mt->prop1, ==, 101);
+    g_assert_cmpuint(mt->prop2, ==, 102);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    module_call_init(MODULE_INIT_QOM);
+    type_register_static(&static_prop_type);
+    type_register_static(&dynamic_prop_type);
+
+    g_test_add_func("/qdev/properties/static/default", test_static_prop);
+    g_test_add_func("/qdev/properties/static/global", test_static_globalprop);
+    g_test_add_func("/qdev/properties/dynamic/global", test_dynamic_globalprop);
+
+    g_test_run();
+
+    return 0;
+}