Patchwork [V10,06/15] xen: Add the Xen platform pci device

login
register
mail settings
Submitter Anthony PERARD
Date Feb. 2, 2011, 2:49 p.m.
Message ID <1296658172-16609-7-git-send-email-anthony.perard@citrix.com>
Download mbox | patch
Permalink /patch/81509/
State New
Headers show

Comments

Anthony PERARD - Feb. 2, 2011, 2:49 p.m.
From: Steven Smith <ssmith@xensource.com>

Introduce a new emulated PCI device, specific to fully virtualized Xen
guests.  The device is necessary for PV on HVM drivers to work.

Signed-off-by: Steven Smith <ssmith@xensource.com>
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target   |    1 +
 hw/hw.h           |    3 +
 hw/pc_piix.c      |    4 +
 hw/pci_ids.h      |    2 +
 hw/xen.h          |    2 +
 hw/xen_platform.c |  348 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 xen-stub.c        |    4 +
 7 files changed, 364 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_platform.c
Anthony Liguori - Feb. 24, 2011, 5:33 p.m.
On 02/02/2011 08:49 AM, anthony.perard@citrix.com wrote:
> From: Steven Smith<ssmith@xensource.com>
>
> Introduce a new emulated PCI device, specific to fully virtualized Xen
> guests.  The device is necessary for PV on HVM drivers to work.
>
> Signed-off-by: Steven Smith<ssmith@xensource.com>
> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com>
> ---
>   Makefile.target   |    1 +
>   hw/hw.h           |    3 +
>   hw/pc_piix.c      |    4 +
>   hw/pci_ids.h      |    2 +
>   hw/xen.h          |    2 +
>   hw/xen_platform.c |  348 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>   xen-stub.c        |    4 +
>   7 files changed, 364 insertions(+), 0 deletions(-)
>   create mode 100644 hw/xen_platform.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 00bb690..7a4fd72 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -215,6 +215,7 @@ obj-$(CONFIG_NO_XEN) += xen-stub.o
>   obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
>   obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
>   obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
> +obj-i386-$(CONFIG_XEN) += xen_platform.o
>
>   # Inter-VM PCI shared memory
>   obj-$(CONFIG_KVM) += ivshmem.o
> diff --git a/hw/hw.h b/hw/hw.h
> index dd993de..298df31 100644
> --- a/hw/hw.h
> +++ b/hw/hw.h
> @@ -672,6 +672,9 @@ extern const VMStateDescription vmstate_i2c_slave;
>   #define VMSTATE_INT32_LE(_f, _s)                                   \
>       VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
>
> +#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
> +    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
> +
>   #define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
>       VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
>
> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
> index 0ab8907..765877c 100644
> --- a/hw/pc_piix.c
> +++ b/hw/pc_piix.c
> @@ -120,6 +120,10 @@ static void pc_init1(ram_addr_t ram_size,
>
>       pc_vga_init(pci_enabled? pci_bus: NULL);
>
> +    if (xen_enabled()) {
> +        pci_xen_platform_init(pci_bus);
> +    }
> +
>       /* init basic PC hardware */
>       pc_basic_device_init(isa_irq,&floppy_controller,&rtc_state);
>
> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index ea3418c..6e9eabc 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -108,3 +108,5 @@
>   #define PCI_DEVICE_ID_INTEL_82371AB      0x7111
>   #define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
>   #define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
> +
> +#define PCI_VENDOR_ID_XENSOURCE          0x5853
> diff --git a/hw/xen.h b/hw/xen.h
> index 3984069..53a2ca4 100644
> --- a/hw/xen.h
> +++ b/hw/xen.h
> @@ -29,6 +29,8 @@ static inline int xen_enabled(void)
>   #endif
>   }
>
> +void pci_xen_platform_init(PCIBus *bus);
> +
>   int xen_init(int smp_cpus);
>
>   #if defined(CONFIG_XEN)&&  CONFIG_XEN_CTRL_INTERFACE_VERSION<  400
> diff --git a/hw/xen_platform.c b/hw/xen_platform.c
> new file mode 100644
> index 0000000..383cfcf
> --- /dev/null
> +++ b/hw/xen_platform.c
> @@ -0,0 +1,348 @@
> +/*
> + * XEN platform pci device, formerly known as the event channel device
> + *
> + * Copyright (c) 2003-2004 Intel Corp.
> + * Copyright (c) 2006 XenSource
> + *
> + * 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 "hw.h"
> +#include "pc.h"
> +#include "pci.h"
> +#include "irq.h"
> +#include "xen_common.h"
> +#include "net.h"
> +#include "xen_backend.h"
> +#include "qemu-log.h"
> +#include "rwhandler.h"
> +
> +#include<assert.h>
> +#include<xenguest.h>
> +
> +//#define DEBUG_PLATFORM
> +
> +#ifdef DEBUG_PLATFORM
> +#define DPRINTF(fmt, ...) do { \
> +    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
> +} while (0)
> +#else
> +#define DPRINTF(fmt, ...) do { } while (0)
> +#endif
> +
> +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
> +
> +typedef struct PCIXenPlatformState {
> +    PCIDevice  pci_dev;
> +    uint8_t flags; /* used only for version_id == 2 */
> +    int drivers_blacklisted;
> +    uint16_t driver_product_version;
> +
> +    /* Log from guest drivers */
> +    char log_buffer[4096];
> +    int log_buffer_off;
> +} PCIXenPlatformState;
> +
> +#define XEN_PLATFORM_IOPORT 0x10
> +
> +/* Send bytes to syslog */
> +static void log_writeb(PCIXenPlatformState *s, char val)
> +{
> +    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
> +        /* Flush buffer */
> +        s->log_buffer[s->log_buffer_off] = 0;
> +        DPRINTF("%s\n", s->log_buffer);
>    

This should go to a chardev.

Regards,

Anthony Liguori
Paolo Bonzini - Feb. 24, 2011, 5:36 p.m.
On 02/24/2011 06:33 PM, Anthony Liguori wrote:
> On 02/02/2011 08:49 AM, anthony.perard@citrix.com wrote:
>> From: Steven Smith<ssmith@xensource.com>
>>
>> Introduce a new emulated PCI device, specific to fully virtualized Xen
>> guests. The device is necessary for PV on HVM drivers to work.
>>
>> Signed-off-by: Steven Smith<ssmith@xensource.com>
>> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com>
>> Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com>
>> ---
>> Makefile.target | 1 +
>> hw/hw.h | 3 +
>> hw/pc_piix.c | 4 +
>> hw/pci_ids.h | 2 +
>> hw/xen.h | 2 +
>> hw/xen_platform.c | 348
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++
>> xen-stub.c | 4 +
>> 7 files changed, 364 insertions(+), 0 deletions(-)
>> create mode 100644 hw/xen_platform.c
>>
>> diff --git a/Makefile.target b/Makefile.target
>> index 00bb690..7a4fd72 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -215,6 +215,7 @@ obj-$(CONFIG_NO_XEN) += xen-stub.o
>> obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
>> obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
>> obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
>> +obj-i386-$(CONFIG_XEN) += xen_platform.o
>>
>> # Inter-VM PCI shared memory
>> obj-$(CONFIG_KVM) += ivshmem.o
>> diff --git a/hw/hw.h b/hw/hw.h
>> index dd993de..298df31 100644
>> --- a/hw/hw.h
>> +++ b/hw/hw.h
>> @@ -672,6 +672,9 @@ extern const VMStateDescription vmstate_i2c_slave;
>> #define VMSTATE_INT32_LE(_f, _s) \
>> VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
>>
>> +#define VMSTATE_UINT8_TEST(_f, _s, _t) \
>> + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
>> +
>> #define VMSTATE_UINT16_TEST(_f, _s, _t) \
>> VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
>>
>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
>> index 0ab8907..765877c 100644
>> --- a/hw/pc_piix.c
>> +++ b/hw/pc_piix.c
>> @@ -120,6 +120,10 @@ static void pc_init1(ram_addr_t ram_size,
>>
>> pc_vga_init(pci_enabled? pci_bus: NULL);
>>
>> + if (xen_enabled()) {
>> + pci_xen_platform_init(pci_bus);
>> + }
>> +
>> /* init basic PC hardware */
>> pc_basic_device_init(isa_irq,&floppy_controller,&rtc_state);
>>
>> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
>> index ea3418c..6e9eabc 100644
>> --- a/hw/pci_ids.h
>> +++ b/hw/pci_ids.h
>> @@ -108,3 +108,5 @@
>> #define PCI_DEVICE_ID_INTEL_82371AB 0x7111
>> #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
>> #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
>> +
>> +#define PCI_VENDOR_ID_XENSOURCE 0x5853
>> diff --git a/hw/xen.h b/hw/xen.h
>> index 3984069..53a2ca4 100644
>> --- a/hw/xen.h
>> +++ b/hw/xen.h
>> @@ -29,6 +29,8 @@ static inline int xen_enabled(void)
>> #endif
>> }
>>
>> +void pci_xen_platform_init(PCIBus *bus);
>> +
>> int xen_init(int smp_cpus);
>>
>> #if defined(CONFIG_XEN)&& CONFIG_XEN_CTRL_INTERFACE_VERSION< 400
>> diff --git a/hw/xen_platform.c b/hw/xen_platform.c
>> new file mode 100644
>> index 0000000..383cfcf
>> --- /dev/null
>> +++ b/hw/xen_platform.c
>> @@ -0,0 +1,348 @@
>> +/*
>> + * XEN platform pci device, formerly known as the event channel device
>> + *
>> + * Copyright (c) 2003-2004 Intel Corp.
>> + * Copyright (c) 2006 XenSource
>> + *
>> + * 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 "hw.h"
>> +#include "pc.h"
>> +#include "pci.h"
>> +#include "irq.h"
>> +#include "xen_common.h"
>> +#include "net.h"
>> +#include "xen_backend.h"
>> +#include "qemu-log.h"
>> +#include "rwhandler.h"
>> +
>> +#include<assert.h>
>> +#include<xenguest.h>
>> +
>> +//#define DEBUG_PLATFORM
>> +
>> +#ifdef DEBUG_PLATFORM
>> +#define DPRINTF(fmt, ...) do { \
>> + fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
>> +} while (0)
>> +#else
>> +#define DPRINTF(fmt, ...) do { } while (0)
>> +#endif
>> +
>> +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
>> +
>> +typedef struct PCIXenPlatformState {
>> + PCIDevice pci_dev;
>> + uint8_t flags; /* used only for version_id == 2 */
>> + int drivers_blacklisted;
>> + uint16_t driver_product_version;
>> +
>> + /* Log from guest drivers */
>> + char log_buffer[4096];
>> + int log_buffer_off;
>> +} PCIXenPlatformState;
>> +
>> +#define XEN_PLATFORM_IOPORT 0x10
>> +
>> +/* Send bytes to syslog */
>> +static void log_writeb(PCIXenPlatformState *s, char val)
>> +{
>> + if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
>> + /* Flush buffer */
>> + s->log_buffer[s->log_buffer_off] = 0;
>> + DPRINTF("%s\n", s->log_buffer);
>
> This should go to a chardev.

Or it should just go away.  Guests can already write to 0xe9 and see the 
output on the host's "xm dmesg" ring and serial console.

Paolo
Ian Campbell - Feb. 25, 2011, 9:58 a.m.
On Thu, 2011-02-24 at 17:36 +0000, Paolo Bonzini wrote:
> >> +/* Send bytes to syslog */
> >> +static void log_writeb(PCIXenPlatformState *s, char val)
> >> +{
> >> + if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) -
> 1) {
> >> + /* Flush buffer */
> >> + s->log_buffer[s->log_buffer_off] = 0;
> >> + DPRINTF("%s\n", s->log_buffer);
> >
> > This should go to a chardev.
> 
> Or it should just go away.  Guests can already write to 0xe9 and see
> the output on the host's "xm dmesg" ring and serial console. 

Only true if you have configured the guest log level to include debug
messages.

In any case host dmesg is not really the same as going to a file in dom0
from a supportability PoV.

Ian.
Paolo Bonzini - Feb. 25, 2011, 10:54 a.m.
On 02/25/2011 10:58 AM, Ian Campbell wrote:
> >  Or it should just go away.  Guests can already write to 0xe9 and see
> >  the output on the host's "xm dmesg" ring and serial console.
>
> Only true if you have configured the guest log level to include debug
> messages.

If you can recompile QEMU to add DEBUG_PLATFORM, you can usually do that 
too.  To avoid recompilation, rather than a chardev it would be even 
better to keep it as a trace event.

Paolo
Anthony PERARD - Feb. 25, 2011, 2:18 p.m.
On Fri, Feb 25, 2011 at 10:54, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 02/25/2011 10:58 AM, Ian Campbell wrote:
>>
>> >  Or it should just go away.  Guests can already write to 0xe9 and see
>> >  the output on the host's "xm dmesg" ring and serial console.
>>
>> Only true if you have configured the guest log level to include debug
>> messages.
>
> If you can recompile QEMU to add DEBUG_PLATFORM, you can usually do that
> too.  To avoid recompilation, rather than a chardev it would be even better
> to keep it as a trace event.

The trace event seems a good idea, let's go for that!

Regards,

Patch

diff --git a/Makefile.target b/Makefile.target
index 00bb690..7a4fd72 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -215,6 +215,7 @@  obj-$(CONFIG_NO_XEN) += xen-stub.o
 obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
 obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
 obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
+obj-i386-$(CONFIG_XEN) += xen_platform.o
 
 # Inter-VM PCI shared memory
 obj-$(CONFIG_KVM) += ivshmem.o
diff --git a/hw/hw.h b/hw/hw.h
index dd993de..298df31 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -672,6 +672,9 @@  extern const VMStateDescription vmstate_i2c_slave;
 #define VMSTATE_INT32_LE(_f, _s)                                   \
     VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
 
+#define VMSTATE_UINT8_TEST(_f, _s, _t)                               \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
 #define VMSTATE_UINT16_TEST(_f, _s, _t)                               \
     VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 0ab8907..765877c 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -120,6 +120,10 @@  static void pc_init1(ram_addr_t ram_size,
 
     pc_vga_init(pci_enabled? pci_bus: NULL);
 
+    if (xen_enabled()) {
+        pci_xen_platform_init(pci_bus);
+    }
+
     /* init basic PC hardware */
     pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
 
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index ea3418c..6e9eabc 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -108,3 +108,5 @@ 
 #define PCI_DEVICE_ID_INTEL_82371AB      0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
+
+#define PCI_VENDOR_ID_XENSOURCE          0x5853
diff --git a/hw/xen.h b/hw/xen.h
index 3984069..53a2ca4 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -29,6 +29,8 @@  static inline int xen_enabled(void)
 #endif
 }
 
+void pci_xen_platform_init(PCIBus *bus);
+
 int xen_init(int smp_cpus);
 
 #if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
new file mode 100644
index 0000000..383cfcf
--- /dev/null
+++ b/hw/xen_platform.c
@@ -0,0 +1,348 @@ 
+/*
+ * XEN platform pci device, formerly known as the event channel device
+ *
+ * Copyright (c) 2003-2004 Intel Corp.
+ * Copyright (c) 2006 XenSource
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "irq.h"
+#include "xen_common.h"
+#include "net.h"
+#include "xen_backend.h"
+#include "qemu-log.h"
+#include "rwhandler.h"
+
+#include <assert.h>
+#include <xenguest.h>
+
+//#define DEBUG_PLATFORM
+
+#ifdef DEBUG_PLATFORM
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState {
+    PCIDevice  pci_dev;
+    uint8_t flags; /* used only for version_id == 2 */
+    int drivers_blacklisted;
+    uint16_t driver_product_version;
+
+    /* Log from guest drivers */
+    char log_buffer[4096];
+    int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* Send bytes to syslog */
+static void log_writeb(PCIXenPlatformState *s, char val)
+{
+    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+        /* Flush buffer */
+        s->log_buffer[s->log_buffer_off] = 0;
+        DPRINTF("%s\n", s->log_buffer);
+        s->log_buffer_off = 0;
+    } else {
+        s->log_buffer[s->log_buffer_off++] = val;
+    }
+}
+
+/* Xen Platform, Fixed IOPort */
+
+static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        /* TODO: */
+        /* Unplug devices.  Value is a bitmask of which devices to
+           unplug, with bit 0 the IDE devices, bit 1 the network
+           devices, and bit 2 the non-primary-master IDE devices. */
+        break;
+    case 2:
+        switch (val) {
+        case 1:
+            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
+            break;
+        case 0:
+            DPRINTF("Guest claimed to be running PV product 0?\n");
+            break;
+        default:
+            DPRINTF("Unknown PV product %d loaded in guest\n", val);
+            break;
+        }
+        s->driver_product_version = val;
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
+                                         uint32_t val)
+{
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        /* PV driver version */
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0: /* Platform flags */ {
+        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
+            HVMMEM_ram_ro : HVMMEM_ram_rw;
+        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
+            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
+        } else {
+            s->flags = val & PFFLAG_ROM_LOCK;
+            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
+                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
+        }
+        break;
+    }
+    case 2:
+        log_writeb(s, val);
+        break;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        if (s->drivers_blacklisted) {
+            /* The drivers will recognise this magic number and refuse
+             * to do anything. */
+            return 0xd249;
+        } else {
+            /* Magic value so that you can identify the interface. */
+            return 0x49d2;
+        }
+    default:
+        return 0xffff;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr - XEN_PLATFORM_IOPORT) {
+    case 0:
+        /* Platform flags */
+        return s->flags;
+    case 2:
+        /* Version number */
+        return 1;
+    default:
+        return 0xff;
+    }
+}
+
+static void platform_fixed_ioport_reset(void *opaque)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, 0);
+}
+
+static void platform_fixed_ioport_init(PCIXenPlatformState* s)
+{
+    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 4, platform_fixed_ioport_writel, s);
+    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_writew, s);
+    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_writeb, s);
+    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_readw, s);
+    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_readb, s);
+}
+
+/* Xen Platform PCI Device */
+
+static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
+{
+    addr &= 0xff;
+
+    if (addr == 0) {
+        return platform_fixed_ioport_readb(opaque, XEN_PLATFORM_IOPORT);
+    } else {
+        return ~0u;
+    }
+}
+
+static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    addr &= 0xff;
+    val  &= 0xff;
+
+    switch (addr) {
+    case 0: /* Platform flags */
+        platform_fixed_ioport_writeb(opaque, XEN_PLATFORM_IOPORT, val);
+        break;
+    case 8:
+        log_writeb(s, val);
+        break;
+    default:
+        break;
+    }
+}
+
+static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type)
+{
+    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, pci_dev);
+
+    register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
+    register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
+}
+
+static uint32_t platform_mmio_read(ReadWriteHandler *handler, pcibus_t addr, int len)
+{
+    DPRINTF("Warning: attempted read from physical address "
+            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+
+    return 0;
+}
+
+static void platform_mmio_write(ReadWriteHandler *handler, pcibus_t addr,
+                                uint32_t val, int len)
+{
+    DPRINTF("Warning: attempted write of 0x%x to physical "
+            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+            val, addr);
+}
+
+static ReadWriteHandler platform_mmio_handler = {
+    .read = &platform_mmio_read,
+    .write = &platform_mmio_write,
+};
+
+static void platform_mmio_map(PCIDevice *d, int region_num,
+                              pcibus_t addr, pcibus_t size, int type)
+{
+    int mmio_io_addr;
+
+    mmio_io_addr = cpu_register_io_memory_simple(&platform_mmio_handler,
+                                                 DEVICE_NATIVE_ENDIAN);
+
+    cpu_register_physical_memory(addr, size, mmio_io_addr);
+}
+
+static int xen_platform_post_load(void *opaque, int version_id)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, s->flags);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_xen_platform = {
+    .name = "platform",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = xen_platform_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
+        VMSTATE_UINT8(flags, PCIXenPlatformState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int xen_platform_initfn(PCIDevice *dev)
+{
+    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = d->pci_dev.config;
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_XENSOURCE);
+    pci_config_set_device_id(pci_conf, 0x0001);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_XENSOURCE);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0001);
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    pci_config_set_revision(pci_conf, 1);
+    pci_config_set_prog_interface(pci_conf, 0);
+
+    pci_config_set_class(pci_conf, PCI_CLASS_OTHERS << 8 | 0x80);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+    pci_register_bar(&d->pci_dev, 0, 0x100,
+            PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
+
+    /* reserve 16MB mmio address for share memory*/
+    pci_register_bar(&d->pci_dev, 1, 0x1000000,
+            PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
+
+    platform_fixed_ioport_init(d);
+
+    return 0;
+}
+
+static void platform_reset(DeviceState *dev)
+{
+    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
+
+    platform_fixed_ioport_reset(s);
+}
+
+void pci_xen_platform_init(PCIBus *bus)
+{
+    PCIDevice *dev;
+
+    dev = pci_create(bus, -1, "xen-platform");
+
+    qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo xen_platform_info = {
+    .init = xen_platform_initfn,
+    .qdev.name = "xen-platform",
+    .qdev.desc = "XEN platform pci device",
+    .qdev.size = sizeof(PCIXenPlatformState),
+    .qdev.vmsd = &vmstate_xen_platform,
+    .qdev.reset = platform_reset,
+};
+
+static void xen_platform_register(void)
+{
+    pci_qdev_register(&xen_platform_info);
+}
+
+device_init(xen_platform_register);
diff --git a/xen-stub.c b/xen-stub.c
index 0fa9c51..a6d5850 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -11,6 +11,10 @@ 
 #include "qemu-common.h"
 #include "hw/xen.h"
 
+void pci_xen_platform_init(PCIBus *bus)
+{
+}
+
 int xen_init(int smp_cpus)
 {
     return -ENOSYS;