All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support
@ 2010-08-23  9:49 ` Stefano Stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: Stefano Stabellini @ 2010-08-23  9:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, xen-devel, stefano.stabellini

Hi all,
this is the second version of the patch series that adds xen device
model support in qemu.
This is the list of changes we made on top of the last version:

- we modified the first patch to add support to the new libxc interface
without removing support for the old one;

- we converted the new xen platform device to VMState and qdev;

- we addressed the code style change requests;

- we removed the register functions in piix_pci and we are now calling
directly xen functions from there; we added a --enable-xen command line
option to enable these code paths.


As you can see we tried to address all the comments apart from removing
target-xen that is the next item on the todo list.



Anthony Perard (15):
    xen: Support new libxc calls from xen unstable.
    xen: Add xen_machine_fv
    xen: Add a new target to qemu: target-xen
    xen: xen_machine_fv, initialize xenctrl
    xen: add a 8259 Interrupt Controller
    xen: Add the Xen platform pci device
    xen: handle xenstore events
    xen: Read and write the state of the VM in xenstore
    xen: Initialize event channels and io rings
    xen: Introduce the Xen mapcache
    xen: Introduce --enable-xen command options.
    piix_pci: Introduces Xen specific call for irq.
    vl.c: Introduce getter for shutdown_requested and reset_requested.
    xen: destroy the VM when shutdown is requested
    xen: Add a Xen specific ACPI Implementation to target-xen

 Makefile.target                    |   34 ++
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   16 +-
 default-configs/xen-dm-softmmu.mak |   24 ++
 hw/hw.h                            |    3 +
 hw/pci_ids.h                       |    2 +
 hw/piix_pci.c                      |   19 +-
 hw/xen.h                           |   11 +
 hw/xen_acpi_piix4.c                |  424 +++++++++++++++++++
 hw/xen_backend.c                   |   10 +-
 hw/xen_backend.h                   |    2 +-
 hw/xen_common.h                    |   29 ++-
 hw/xen_disk.c                      |   12 +-
 hw/xen_domainbuild.c               |    2 +-
 hw/xen_machine_fv.c                |  199 +++++++++
 hw/xen_nic.c                       |   16 +-
 hw/xen_platform.c                  |  449 ++++++++++++++++++++
 hw/xen_platform.h                  |    8 +
 qemu-options.hx                    |    9 +
 sysemu.h                           |    2 +
 target-xen/cpu.h                   |  122 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |  424 +++++++++++++++++++
 target-xen/i8259-xen-stub.c        |   63 +++
 target-xen/qemu-xen.h              |   50 +++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |  261 ++++++++++++
 target-xen/xenstore.c              |  168 ++++++++
 target-xen/xenstore.h              |   12 +
 vl.c                               |   21 +
 xen-all.c                          |   25 ++
 xen-stub.c                         |    9 +
 33 files changed, 3235 insertions(+), 27 deletions(-)



A git tree is available here:

git://xenbits.xen.org/people/sstabellini/qemu-dm.git qemu-dm-v2.

Cheers,

Stefano


P.S.
Anthony is currently on vacation so the work will be on hold for a bit
and it might take some time for him to reply to your emails.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH 00/15] v2: RFC xen device model support
@ 2010-08-23  9:49 ` Stefano Stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: Stefano Stabellini @ 2010-08-23  9:49 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, xen-devel, Anthony Liguori, stefano.stabellini

Hi all,
this is the second version of the patch series that adds xen device
model support in qemu.
This is the list of changes we made on top of the last version:

- we modified the first patch to add support to the new libxc interface
without removing support for the old one;

- we converted the new xen platform device to VMState and qdev;

- we addressed the code style change requests;

- we removed the register functions in piix_pci and we are now calling
directly xen functions from there; we added a --enable-xen command line
option to enable these code paths.


As you can see we tried to address all the comments apart from removing
target-xen that is the next item on the todo list.



Anthony Perard (15):
    xen: Support new libxc calls from xen unstable.
    xen: Add xen_machine_fv
    xen: Add a new target to qemu: target-xen
    xen: xen_machine_fv, initialize xenctrl
    xen: add a 8259 Interrupt Controller
    xen: Add the Xen platform pci device
    xen: handle xenstore events
    xen: Read and write the state of the VM in xenstore
    xen: Initialize event channels and io rings
    xen: Introduce the Xen mapcache
    xen: Introduce --enable-xen command options.
    piix_pci: Introduces Xen specific call for irq.
    vl.c: Introduce getter for shutdown_requested and reset_requested.
    xen: destroy the VM when shutdown is requested
    xen: Add a Xen specific ACPI Implementation to target-xen

 Makefile.target                    |   34 ++
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   16 +-
 default-configs/xen-dm-softmmu.mak |   24 ++
 hw/hw.h                            |    3 +
 hw/pci_ids.h                       |    2 +
 hw/piix_pci.c                      |   19 +-
 hw/xen.h                           |   11 +
 hw/xen_acpi_piix4.c                |  424 +++++++++++++++++++
 hw/xen_backend.c                   |   10 +-
 hw/xen_backend.h                   |    2 +-
 hw/xen_common.h                    |   29 ++-
 hw/xen_disk.c                      |   12 +-
 hw/xen_domainbuild.c               |    2 +-
 hw/xen_machine_fv.c                |  199 +++++++++
 hw/xen_nic.c                       |   16 +-
 hw/xen_platform.c                  |  449 ++++++++++++++++++++
 hw/xen_platform.h                  |    8 +
 qemu-options.hx                    |    9 +
 sysemu.h                           |    2 +
 target-xen/cpu.h                   |  122 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |  424 +++++++++++++++++++
 target-xen/i8259-xen-stub.c        |   63 +++
 target-xen/qemu-xen.h              |   50 +++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |  261 ++++++++++++
 target-xen/xenstore.c              |  168 ++++++++
 target-xen/xenstore.h              |   12 +
 vl.c                               |   21 +
 xen-all.c                          |   25 ++
 xen-stub.c                         |    9 +
 33 files changed, 3235 insertions(+), 27 deletions(-)



A git tree is available here:

git://xenbits.xen.org/people/sstabellini/qemu-dm.git qemu-dm-v2.

Cheers,

Stefano


P.S.
Anthony is currently on vacation so the work will be on hold for a bit
and it might take some time for him to reply to your emails.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 01/15] xen: Support new libxc calls from xen unstable.
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Update the libxenctrl calls in Qemu to use the new interface, otherwise
Qemu wouldn't be able to build against new versions of the library.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 configure            |    5 +++++
 hw/xen_backend.c     |   10 +++++-----
 hw/xen_backend.h     |    2 +-
 hw/xen_common.h      |   23 ++++++++++++++++++++++-
 hw/xen_disk.c        |   12 ++++++------
 hw/xen_domainbuild.c |    2 +-
 hw/xen_nic.c         |   16 ++++++++--------
 7 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/configure b/configure
index a20371c..4c7c729 100755
--- a/configure
+++ b/configure
@@ -1102,7 +1102,12 @@ if test "$xen" != "no" ; then
   cat > $TMPC <<EOF
 #include <xenctrl.h>
 #include <xs.h>
+#include <xen/xen-compat.h>
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
 int main(void) { xs_daemon_open(); xc_interface_open(); return 0; }
+#else
+int main(void) { xs_daemon_open(); xc_interface_open(0, 0, 0); return 0; }
+#endif
 EOF
   if compile_prog "" "$xen_libs" ; then
     xen=yes
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index a2e408f..b23620f 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -43,7 +43,7 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-int xen_xc;
+qemu_xc_interface xen_xc = XC_HANDLER_INITIAL_VALUE;
 struct xs_handle *xenstore = NULL;
 const char *xen_protocol;
 
@@ -216,7 +216,7 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
     fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
 
     if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
-	xendev->gnttabdev = xc_gnttab_open();
+	xendev->gnttabdev = xc_gnttab_open(xen_xc);
 	if (xendev->gnttabdev < 0) {
 	    xen_be_printf(NULL, 0, "can't open gnttab device\n");
 	    xc_evtchn_close(xendev->evtchndev);
@@ -269,7 +269,7 @@ static struct XenDevice *xen_be_del_xendev(int dom, int dev)
 	if (xendev->evtchndev >= 0)
 	    xc_evtchn_close(xendev->evtchndev);
 	if (xendev->gnttabdev >= 0)
-	    xc_gnttab_close(xendev->gnttabdev);
+	    xc_gnttab_close(xen_xc, xendev->gnttabdev);
 
 	QTAILQ_REMOVE(&xendevs, xendev, next);
 	qemu_free(xendev);
@@ -627,8 +627,8 @@ int xen_be_init(void)
     if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
 	goto err;
 
-    xen_xc = xc_interface_open();
-    if (xen_xc == -1) {
+    xen_xc = xc_interface_open(NULL, NULL, 0);
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
 	xen_be_printf(NULL, 0, "can't open xen interface\n");
 	goto err;
     }
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index cc25f9d..4350df9 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -57,7 +57,7 @@ struct XenDevice {
 /* ------------------------------------------------------------- */
 
 /* variables */
-extern int xen_xc;
+extern qemu_xc_interface xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
 
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 8a55b44..2cbc376 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -16,7 +16,8 @@
  * tweaks needed to build with different xen versions
  *  0x00030205 -> 3.1.0
  *  0x00030207 -> 3.2.0
- *  0x00030208 -> unstable
+ *  0x00030209 -> 3.3.0
+ *  0x0003020a -> unstable
  */
 #include <xen/xen-compat.h>
 #if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030205
@@ -31,4 +32,24 @@
 # define xen_wmb() wmb()
 #endif
 
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
+typedef int qemu_xc_interface;
+# define XC_HANDLER_INITIAL_VALUE               -1
+# define xc_fd(xen_xc)                          xen_xc
+# define xc_interface_open(l, dl, f)            xc_interface_open()
+# define xc_gnttab_open(xc)                     xc_gnttab_open()
+# define xc_gnttab_map_grant_ref(xc, gnt, domid, ref, flags) \
+    xc_gnttab_map_grant_ref(gnt, domid, ref, flags)
+# define xc_gnttab_map_grant_refs(xc, gnt, count, domids, refs, flags) \
+    xc_gnttab_map_grant_refs(gnt, count, domids, refs, flags)
+# define xc_gnttab_munmap(xc, gnt, pages, niov) xc_gnttab_munmap(gnt, pages, niov)
+# define xc_gnttab_close(xc, dev)               xc_gnttab_close(dev)
+#else
+typedef xc_interface *qemu_xc_interface;
+# define XC_HANDLER_INITIAL_VALUE NULL
+/* FIXME The fd of xen_xc is now xen_xc->fd */
+/* fd is the first field, so this works */
+# define xc_fd(xen_xc)                          (*(int*)xen_xc)
+#endif
+
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9a466f3..3c1d3ef 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -242,7 +242,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
     if (batch_maps) {
 	if (!ioreq->pages)
 	    return;
-	if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0)
+	if (xc_gnttab_munmap(xen_xc, gnt, ioreq->pages, ioreq->v.niov) != 0)
 	    xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
 			  strerror(errno));
 	ioreq->blkdev->cnt_map -= ioreq->v.niov;
@@ -251,7 +251,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
 	for (i = 0; i < ioreq->v.niov; i++) {
 	    if (!ioreq->page[i])
 		continue;
-	    if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0)
+	    if (xc_gnttab_munmap(xen_xc, gnt, ioreq->page[i], 1) != 0)
 		xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
 			      strerror(errno));
 	    ioreq->blkdev->cnt_map--;
@@ -269,7 +269,7 @@ static int ioreq_map(struct ioreq *ioreq)
         return 0;
     if (batch_maps) {
 	ioreq->pages = xc_gnttab_map_grant_refs
-	    (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
+	    (xen_xc, gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
 	if (ioreq->pages == NULL) {
 	    xen_be_printf(&ioreq->blkdev->xendev, 0,
 			  "can't map %d grant refs (%s, %d maps)\n",
@@ -283,7 +283,7 @@ static int ioreq_map(struct ioreq *ioreq)
     } else  {
 	for (i = 0; i < ioreq->v.niov; i++) {
 	    ioreq->page[i] = xc_gnttab_map_grant_ref
-		(gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+		(xen_xc, gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
 	    if (ioreq->page[i] == NULL) {
 		xen_be_printf(&ioreq->blkdev->xendev, 0,
 			      "can't map grant ref %d (%s, %d maps)\n",
@@ -683,7 +683,7 @@ static int blk_connect(struct XenDevice *xendev)
             blkdev->protocol = BLKIF_PROTOCOL_X86_64;
     }
 
-    blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+    blkdev->sring = xc_gnttab_map_grant_ref(xen_xc, blkdev->xendev.gnttabdev,
 					    blkdev->xendev.dom,
 					    blkdev->ring_ref,
 					    PROT_READ | PROT_WRITE);
@@ -738,7 +738,7 @@ static void blk_disconnect(struct XenDevice *xendev)
     xen_be_unbind_evtchn(&blkdev->xendev);
 
     if (blkdev->sring) {
-	xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+	xc_gnttab_munmap(xen_xc, blkdev->xendev.gnttabdev, blkdev->sring, 1);
 	blkdev->cnt_map--;
 	blkdev->sring = NULL;
     }
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
index 7f1fd66..232a456 100644
--- a/hw/xen_domainbuild.c
+++ b/hw/xen_domainbuild.c
@@ -176,7 +176,7 @@ static int xen_domain_watcher(void)
     for (i = 3; i < n; i++) {
         if (i == fd[0])
             continue;
-        if (i == xen_xc)
+        if (i == xc_fd(xen_xc))
             continue;
         close(i);
     }
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index 08055b8..4f68850 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -166,7 +166,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
 			  (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
 			  (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
 
-	    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+	    page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 					   netdev->xendev.dom,
 					   txreq.gref, PROT_READ);
 	    if (page == NULL) {
@@ -185,7 +185,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
             } else {
                 qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size);
             }
-	    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+	    xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1);
 	    net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
 	}
 	if (!netdev->tx_work)
@@ -272,7 +272,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
     memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
     netdev->rx_ring.req_cons = ++rc;
 
-    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+    page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 				   netdev->xendev.dom,
 				   rxreq.gref, PROT_WRITE);
     if (page == NULL) {
@@ -282,7 +282,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
 	return -1;
     }
     memcpy(page + NET_IP_ALIGN, buf, size);
-    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+    xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1);
     net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
 
     return size;
@@ -350,11 +350,11 @@ static int net_connect(struct XenDevice *xendev)
 	return -1;
     }
 
-    netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+    netdev->txs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 					  netdev->xendev.dom,
 					  netdev->tx_ring_ref,
 					  PROT_READ | PROT_WRITE);
-    netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+    netdev->rxs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 					  netdev->xendev.dom,
 					  netdev->rx_ring_ref,
 					  PROT_READ | PROT_WRITE);
@@ -381,11 +381,11 @@ static void net_disconnect(struct XenDevice *xendev)
     xen_be_unbind_evtchn(&netdev->xendev);
 
     if (netdev->txs) {
-	xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+	xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->txs, 1);
 	netdev->txs = NULL;
     }
     if (netdev->rxs) {
-	xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+	xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->rxs, 1);
 	netdev->rxs = NULL;
     }
     if (netdev->nic) {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 01/15] xen: Support new libxc calls from xen unstable.
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Update the libxenctrl calls in Qemu to use the new interface, otherwise
Qemu wouldn't be able to build against new versions of the library.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 configure            |    5 +++++
 hw/xen_backend.c     |   10 +++++-----
 hw/xen_backend.h     |    2 +-
 hw/xen_common.h      |   23 ++++++++++++++++++++++-
 hw/xen_disk.c        |   12 ++++++------
 hw/xen_domainbuild.c |    2 +-
 hw/xen_nic.c         |   16 ++++++++--------
 7 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/configure b/configure
index a20371c..4c7c729 100755
--- a/configure
+++ b/configure
@@ -1102,7 +1102,12 @@ if test "$xen" != "no" ; then
   cat > $TMPC <<EOF
 #include <xenctrl.h>
 #include <xs.h>
+#include <xen/xen-compat.h>
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
 int main(void) { xs_daemon_open(); xc_interface_open(); return 0; }
+#else
+int main(void) { xs_daemon_open(); xc_interface_open(0, 0, 0); return 0; }
+#endif
 EOF
   if compile_prog "" "$xen_libs" ; then
     xen=yes
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index a2e408f..b23620f 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -43,7 +43,7 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-int xen_xc;
+qemu_xc_interface xen_xc = XC_HANDLER_INITIAL_VALUE;
 struct xs_handle *xenstore = NULL;
 const char *xen_protocol;
 
@@ -216,7 +216,7 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
     fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
 
     if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
-	xendev->gnttabdev = xc_gnttab_open();
+	xendev->gnttabdev = xc_gnttab_open(xen_xc);
 	if (xendev->gnttabdev < 0) {
 	    xen_be_printf(NULL, 0, "can't open gnttab device\n");
 	    xc_evtchn_close(xendev->evtchndev);
@@ -269,7 +269,7 @@ static struct XenDevice *xen_be_del_xendev(int dom, int dev)
 	if (xendev->evtchndev >= 0)
 	    xc_evtchn_close(xendev->evtchndev);
 	if (xendev->gnttabdev >= 0)
-	    xc_gnttab_close(xendev->gnttabdev);
+	    xc_gnttab_close(xen_xc, xendev->gnttabdev);
 
 	QTAILQ_REMOVE(&xendevs, xendev, next);
 	qemu_free(xendev);
@@ -627,8 +627,8 @@ int xen_be_init(void)
     if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
 	goto err;
 
-    xen_xc = xc_interface_open();
-    if (xen_xc == -1) {
+    xen_xc = xc_interface_open(NULL, NULL, 0);
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
 	xen_be_printf(NULL, 0, "can't open xen interface\n");
 	goto err;
     }
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index cc25f9d..4350df9 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -57,7 +57,7 @@ struct XenDevice {
 /* ------------------------------------------------------------- */
 
 /* variables */
-extern int xen_xc;
+extern qemu_xc_interface xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
 
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 8a55b44..2cbc376 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -16,7 +16,8 @@
  * tweaks needed to build with different xen versions
  *  0x00030205 -> 3.1.0
  *  0x00030207 -> 3.2.0
- *  0x00030208 -> unstable
+ *  0x00030209 -> 3.3.0
+ *  0x0003020a -> unstable
  */
 #include <xen/xen-compat.h>
 #if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030205
@@ -31,4 +32,24 @@
 # define xen_wmb() wmb()
 #endif
 
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
+typedef int qemu_xc_interface;
+# define XC_HANDLER_INITIAL_VALUE               -1
+# define xc_fd(xen_xc)                          xen_xc
+# define xc_interface_open(l, dl, f)            xc_interface_open()
+# define xc_gnttab_open(xc)                     xc_gnttab_open()
+# define xc_gnttab_map_grant_ref(xc, gnt, domid, ref, flags) \
+    xc_gnttab_map_grant_ref(gnt, domid, ref, flags)
+# define xc_gnttab_map_grant_refs(xc, gnt, count, domids, refs, flags) \
+    xc_gnttab_map_grant_refs(gnt, count, domids, refs, flags)
+# define xc_gnttab_munmap(xc, gnt, pages, niov) xc_gnttab_munmap(gnt, pages, niov)
+# define xc_gnttab_close(xc, dev)               xc_gnttab_close(dev)
+#else
+typedef xc_interface *qemu_xc_interface;
+# define XC_HANDLER_INITIAL_VALUE NULL
+/* FIXME The fd of xen_xc is now xen_xc->fd */
+/* fd is the first field, so this works */
+# define xc_fd(xen_xc)                          (*(int*)xen_xc)
+#endif
+
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9a466f3..3c1d3ef 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -242,7 +242,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
     if (batch_maps) {
 	if (!ioreq->pages)
 	    return;
-	if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0)
+	if (xc_gnttab_munmap(xen_xc, gnt, ioreq->pages, ioreq->v.niov) != 0)
 	    xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
 			  strerror(errno));
 	ioreq->blkdev->cnt_map -= ioreq->v.niov;
@@ -251,7 +251,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
 	for (i = 0; i < ioreq->v.niov; i++) {
 	    if (!ioreq->page[i])
 		continue;
-	    if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0)
+	    if (xc_gnttab_munmap(xen_xc, gnt, ioreq->page[i], 1) != 0)
 		xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
 			      strerror(errno));
 	    ioreq->blkdev->cnt_map--;
@@ -269,7 +269,7 @@ static int ioreq_map(struct ioreq *ioreq)
         return 0;
     if (batch_maps) {
 	ioreq->pages = xc_gnttab_map_grant_refs
-	    (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
+	    (xen_xc, gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
 	if (ioreq->pages == NULL) {
 	    xen_be_printf(&ioreq->blkdev->xendev, 0,
 			  "can't map %d grant refs (%s, %d maps)\n",
@@ -283,7 +283,7 @@ static int ioreq_map(struct ioreq *ioreq)
     } else  {
 	for (i = 0; i < ioreq->v.niov; i++) {
 	    ioreq->page[i] = xc_gnttab_map_grant_ref
-		(gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+		(xen_xc, gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
 	    if (ioreq->page[i] == NULL) {
 		xen_be_printf(&ioreq->blkdev->xendev, 0,
 			      "can't map grant ref %d (%s, %d maps)\n",
@@ -683,7 +683,7 @@ static int blk_connect(struct XenDevice *xendev)
             blkdev->protocol = BLKIF_PROTOCOL_X86_64;
     }
 
-    blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+    blkdev->sring = xc_gnttab_map_grant_ref(xen_xc, blkdev->xendev.gnttabdev,
 					    blkdev->xendev.dom,
 					    blkdev->ring_ref,
 					    PROT_READ | PROT_WRITE);
@@ -738,7 +738,7 @@ static void blk_disconnect(struct XenDevice *xendev)
     xen_be_unbind_evtchn(&blkdev->xendev);
 
     if (blkdev->sring) {
-	xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+	xc_gnttab_munmap(xen_xc, blkdev->xendev.gnttabdev, blkdev->sring, 1);
 	blkdev->cnt_map--;
 	blkdev->sring = NULL;
     }
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
index 7f1fd66..232a456 100644
--- a/hw/xen_domainbuild.c
+++ b/hw/xen_domainbuild.c
@@ -176,7 +176,7 @@ static int xen_domain_watcher(void)
     for (i = 3; i < n; i++) {
         if (i == fd[0])
             continue;
-        if (i == xen_xc)
+        if (i == xc_fd(xen_xc))
             continue;
         close(i);
     }
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index 08055b8..4f68850 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -166,7 +166,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
 			  (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
 			  (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
 
-	    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+	    page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 					   netdev->xendev.dom,
 					   txreq.gref, PROT_READ);
 	    if (page == NULL) {
@@ -185,7 +185,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
             } else {
                 qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size);
             }
-	    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+	    xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1);
 	    net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
 	}
 	if (!netdev->tx_work)
@@ -272,7 +272,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
     memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
     netdev->rx_ring.req_cons = ++rc;
 
-    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+    page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 				   netdev->xendev.dom,
 				   rxreq.gref, PROT_WRITE);
     if (page == NULL) {
@@ -282,7 +282,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
 	return -1;
     }
     memcpy(page + NET_IP_ALIGN, buf, size);
-    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+    xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1);
     net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
 
     return size;
@@ -350,11 +350,11 @@ static int net_connect(struct XenDevice *xendev)
 	return -1;
     }
 
-    netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+    netdev->txs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 					  netdev->xendev.dom,
 					  netdev->tx_ring_ref,
 					  PROT_READ | PROT_WRITE);
-    netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+    netdev->rxs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
 					  netdev->xendev.dom,
 					  netdev->rx_ring_ref,
 					  PROT_READ | PROT_WRITE);
@@ -381,11 +381,11 @@ static void net_disconnect(struct XenDevice *xendev)
     xen_be_unbind_evtchn(&netdev->xendev);
 
     if (netdev->txs) {
-	xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+	xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->txs, 1);
 	netdev->txs = NULL;
     }
     if (netdev->rxs) {
-	xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+	xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->rxs, 1);
 	netdev->rxs = NULL;
     }
     if (netdev->nic) {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Add the Xen FV (Fully Virtualized) machine to Qemu;
this is groundwork to add Xen device model support in Qemu.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target     |    3 +
 hw/xen_machine_fv.c |  156 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_machine_fv.c

diff --git a/Makefile.target b/Makefile.target
index 8a9c427..8fdc884 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,6 +183,9 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
+# xen full virtualized machine
+obj-$(CONFIG_XEN) += xen_machine_fv.o
+
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
new file mode 100644
index 0000000..8114460
--- /dev/null
+++ b/hw/xen_machine_fv.c
@@ -0,0 +1,156 @@
+/*
+ * QEMU Xen FV Machine
+ *
+ * Copyright (c) 2003-2007 Fabrice Bellard
+ * Copyright (c) 2007 Red Hat
+ *
+ * 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 "usb-uhci.h"
+#include "net.h"
+#include "boards.h"
+#include "ide.h"
+#include "sysemu.h"
+
+#include "xen/hvm/hvm_info_table.h"
+
+#define MAX_IDE_BUS 2
+
+static void xen_init_fv(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    int i;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
+    PCIBus *pci_bus;
+    PCII440FXState *i440fx_state;
+    int piix3_devfn = -1;
+    qemu_irq *cpu_irq;
+    qemu_irq *isa_irq;
+    qemu_irq *i8259;
+    qemu_irq *cmos_s3;
+    qemu_irq *smi_irq;
+    IsaIrqState *isa_irq_state;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    FDCtrl *floppy_controller;
+    BusState *idebus[MAX_IDE_BUS];
+    ISADevice *rtc_state;
+
+    CPUState *env;
+
+    /* Initialize a dummy CPU */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    env->halted = 1;
+
+    cpu_irq = pc_allocate_cpu_irq();
+    i8259 = i8259_init(cpu_irq[0]);
+    isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+    isa_irq_state->i8259 = i8259;
+
+    isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+
+    pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+    isa_bus_irqs(isa_irq);
+
+    pc_register_ferr_irq(isa_reserve_irq(13));
+
+    pc_vga_init(pci_bus);
+
+    /* init basic PC hardware */
+    pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (nd->model && strcmp(nd->model, "ne2k_isa") == 0)
+            pc_init_ne2k_isa(nd);
+        else
+            pci_nic_init_nofail(nd, "e1000", NULL);
+    }
+
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+    }
+
+    PCIDevice *dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+    idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+    idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+
+    pc_audio_init(pci_bus, isa_irq);
+
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        below_4g_mem_size = ram_size;
+    }
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+            idebus[0], idebus[1], floppy_controller, rtc_state);
+
+    if (usb_enabled) {
+        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+    }
+
+    if (acpi_enabled) {
+        cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+        piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+                isa_reserve_irq(9), *cmos_s3, *smi_irq,
+                0);
+    }
+
+    if (i440fx_state) {
+        i440fx_init_memory_mappings(i440fx_state);
+    }
+
+    pc_pci_device_init(pci_bus);
+}
+
+static QEMUMachine xenfv_machine = {
+    .name = "xenfv",
+    .desc = "Xen Fully-virtualized PC",
+    .init = xen_init_fv,
+    .max_cpus = HVM_MAX_VCPUS,
+};
+
+static void xenfv_machine_init(void)
+{
+    qemu_register_machine(&xenfv_machine);
+}
+
+machine_init(xenfv_machine_init);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Add the Xen FV (Fully Virtualized) machine to Qemu;
this is groundwork to add Xen device model support in Qemu.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target     |    3 +
 hw/xen_machine_fv.c |  156 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_machine_fv.c

diff --git a/Makefile.target b/Makefile.target
index 8a9c427..8fdc884 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,6 +183,9 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
+# xen full virtualized machine
+obj-$(CONFIG_XEN) += xen_machine_fv.o
+
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
new file mode 100644
index 0000000..8114460
--- /dev/null
+++ b/hw/xen_machine_fv.c
@@ -0,0 +1,156 @@
+/*
+ * QEMU Xen FV Machine
+ *
+ * Copyright (c) 2003-2007 Fabrice Bellard
+ * Copyright (c) 2007 Red Hat
+ *
+ * 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 "usb-uhci.h"
+#include "net.h"
+#include "boards.h"
+#include "ide.h"
+#include "sysemu.h"
+
+#include "xen/hvm/hvm_info_table.h"
+
+#define MAX_IDE_BUS 2
+
+static void xen_init_fv(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    int i;
+    ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
+    PCIBus *pci_bus;
+    PCII440FXState *i440fx_state;
+    int piix3_devfn = -1;
+    qemu_irq *cpu_irq;
+    qemu_irq *isa_irq;
+    qemu_irq *i8259;
+    qemu_irq *cmos_s3;
+    qemu_irq *smi_irq;
+    IsaIrqState *isa_irq_state;
+    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    FDCtrl *floppy_controller;
+    BusState *idebus[MAX_IDE_BUS];
+    ISADevice *rtc_state;
+
+    CPUState *env;
+
+    /* Initialize a dummy CPU */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+    env = cpu_init(cpu_model);
+    env->halted = 1;
+
+    cpu_irq = pc_allocate_cpu_irq();
+    i8259 = i8259_init(cpu_irq[0]);
+    isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+    isa_irq_state->i8259 = i8259;
+
+    isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+
+    pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+    isa_bus_irqs(isa_irq);
+
+    pc_register_ferr_irq(isa_reserve_irq(13));
+
+    pc_vga_init(pci_bus);
+
+    /* init basic PC hardware */
+    pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
+
+    for(i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (nd->model && strcmp(nd->model, "ne2k_isa") == 0)
+            pc_init_ne2k_isa(nd);
+        else
+            pci_nic_init_nofail(nd, "e1000", NULL);
+    }
+
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+    }
+
+    PCIDevice *dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+    idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+    idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+
+    pc_audio_init(pci_bus, isa_irq);
+
+    if (ram_size >= 0xe0000000 ) {
+        above_4g_mem_size = ram_size - 0xe0000000;
+        below_4g_mem_size = 0xe0000000;
+    } else {
+        below_4g_mem_size = ram_size;
+    }
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+            idebus[0], idebus[1], floppy_controller, rtc_state);
+
+    if (usb_enabled) {
+        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+    }
+
+    if (acpi_enabled) {
+        cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+        piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+                isa_reserve_irq(9), *cmos_s3, *smi_irq,
+                0);
+    }
+
+    if (i440fx_state) {
+        i440fx_init_memory_mappings(i440fx_state);
+    }
+
+    pc_pci_device_init(pci_bus);
+}
+
+static QEMUMachine xenfv_machine = {
+    .name = "xenfv",
+    .desc = "Xen Fully-virtualized PC",
+    .init = xen_init_fv,
+    .max_cpus = HVM_MAX_VCPUS,
+};
+
+static void xenfv_machine_init(void)
+{
+    qemu_register_machine(&xenfv_machine);
+}
+
+machine_init(xenfv_machine_init);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

This patch adds a new Xen device model target to Qemu, called
target-xen.
The new target makes use of the previously introduced xen_machine_fv.
In order to have a fully working Xen device model we still need
functionalities introduced by the following patches.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target                    |   31 ++-
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   11 +-
 default-configs/xen-dm-softmmu.mak |   24 ++
 target-xen/cpu.h                   |  116 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |   63 +++
 target-xen/qemu-xen.h              |   30 ++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |   14 +
 11 files changed, 1120 insertions(+), 5 deletions(-)
 create mode 100644 default-configs/xen-dm-softmmu.mak
 create mode 100644 target-xen/cpu.h
 create mode 100644 target-xen/exec-dm.c
 create mode 100644 target-xen/helper.c
 create mode 100644 target-xen/machine.c
 create mode 100644 target-xen/qemu-xen.h
 create mode 100644 target-xen/stub-functions.c
 create mode 100644 target-xen/xen_mapcache.c

diff --git a/Makefile.target b/Makefile.target
index 8fdc884..359a984 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
-# xen full virtualized machine
-obj-$(CONFIG_XEN) += xen_machine_fv.o
-
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
@@ -310,6 +307,34 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 
 endif # CONFIG_SOFTMMU
 
+# Xen Device Model
+# xen full virtualized machine
+
+# Remove some lib, because we don't want it for a xen target.
+ifeq ($(TARGET_BASE_ARCH), xen)
+bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
+bad-libobj-y += tcg%.o fpu/%.o
+bad-libobj-y += disas.o op_helper.o
+libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
+endif
+
+obj-xen-y += xen_machine_fv.o
+obj-xen-y += i8259.o
+obj-xen-y += pc.o
+obj-xen-y += piix_pci.o
+obj-xen-y += mc146818rtc.o
+
+obj-xen-y += xen_mapcache.o
+obj-xen-y += stub-functions.o
+
+obj-xen-y += vga.o
+obj-xen-y += hpet.o
+obj-xen-y += cirrus_vga.o
+obj-xen-y += smbios.o
+obj-xen-y += multiboot.o
+obj-xen-y += exec-dm.o
+obj-xen-y += lsi53c895a.o usb-ohci.o
+
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
diff --git a/arch_init.c b/arch_init.c
index 47bb4b2..ebc5cb6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -75,6 +75,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_SH4
 #elif defined(TARGET_SPARC)
 #define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XEN)
+#define QEMU_ARCH QEMU_ARCH_XEN
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 682890c..b5f8eb1 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -16,6 +16,7 @@ enum {
     QEMU_ARCH_S390X = 256,
     QEMU_ARCH_SH4 = 512,
     QEMU_ARCH_SPARC = 1024,
+    QEMU_ARCH_XEN = 2048,
 };
 
 extern const uint32_t arch_type;
diff --git a/configure b/configure
index 4c7c729..1ff6e80 100755
--- a/configure
+++ b/configure
@@ -2522,6 +2522,9 @@ case "$target" in
   ${target_arch2}-softmmu)
     target_softmmu="yes"
     ;;
+  ${target_arch2}-dm-softmmu)
+    target_softmmu="yes"
+    ;;
   ${target_arch2}-linux-user)
     if test "$linux" != "yes" ; then
       echo "ERROR: Target '$target' is only available on a Linux host"
@@ -2587,6 +2590,10 @@ case "$target_arch2" in
     TARGET_BASE_ARCH=i386
     target_phys_bits=64
   ;;
+  xen)
+    # This is use for xen mapcache
+    target_phys_bits=64
+  ;;
   alpha)
     target_phys_bits=64
     target_nptl="yes"
@@ -2698,7 +2705,7 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
 fi
 echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
 case "$target_arch2" in
-  i386|x86_64)
+  i386|x86_64|xen)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
       echo "CONFIG_XEN=y" >> $config_target_mak
     fi
@@ -2864,7 +2871,7 @@ if test "$target_softmmu" = "yes" ; then
   arm)
     cflags="-DHAS_AUDIO $cflags"
   ;;
-  i386|mips|ppc)
+  i386|mips|ppc|xen)
     cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
   ;;
   esac
diff --git a/default-configs/xen-dm-softmmu.mak b/default-configs/xen-dm-softmmu.mak
new file mode 100644
index 0000000..72fe141
--- /dev/null
+++ b/default-configs/xen-dm-softmmu.mak
@@ -0,0 +1,24 @@
+# Default configuration for xen-dm-softmmu
+
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_USB_UHCI=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_IDE_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_PIIX_PCI=y
+CONFIG_SOUND=y
+CONFIG_XEN=y
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
new file mode 100644
index 0000000..0e08ab3
--- /dev/null
+++ b/target-xen/cpu.h
@@ -0,0 +1,116 @@
+/*
+ * xen virtual CPU header
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_XEN_H
+#define CPU_XEN_H
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#ifdef TARGET_X86_64
+#define ELF_MACHINE     EM_X86_64
+#else
+#define ELF_MACHINE     EM_386
+#endif
+
+#define CPUState struct CPUXenState
+#define CPUX86State CPUXenState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+/* hidden flags - used internally by qemu to represent additional cpu
+   states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not
+   redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit
+   position to ease oring with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT         0
+#define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+
+#define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
+#define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+
+/* cpuid_features bits */
+#define CPUID_APIC (1 << 9)
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUXenState {
+    uint32_t hflags; /* TB flags, see HF_xxx constants. These flags
+                        are known at translation time. */
+    CPU_COMMON
+
+    /* processor features (e.g. for CPUID insn) */
+    uint32_t cpuid_features;
+    uint32_t cpuid_apic_id;
+
+    /* in order to simplify APIC support, we leave this pointer to the
+       user */
+    struct DeviceState *apic_state;
+} CPUXenState;
+
+CPUXenState *cpu_xen_init(const char *cpu_model);
+int cpu_xen_exec(CPUXenState *s);
+
+int cpu_get_pic_interrupt(CPUXenState *s);
+void cpu_set_ferr(CPUX86State *s);
+
+/* helper.c */
+void cpu_x86_set_a20(CPUXenState *env, int a20_state);
+
+/* hw/pc.c */
+void cpu_smm_update(CPUXenState *env);
+uint64_t cpu_get_tsc(CPUX86State *env);
+
+#define TARGET_PAGE_BITS 12
+
+#ifdef TARGET_X86_64
+#define TARGET_PHYS_ADDR_SPACE_BITS 52
+/* ??? This is really 48 bits, sign-extended, but the only thing
+   accessible to userland with bit 48 set is the VSYSCALL, and that
+   is handled via other mechanisms.  */
+#define TARGET_VIRT_ADDR_SPACE_BITS 47
+#else
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+#define cpu_init cpu_xen_init
+#define cpu_exec cpu_xen_exec
+
+/* MMU modes definitions */
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+}
+
+#endif /* CPU_XEN_H */
diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c
new file mode 100644
index 0000000..5af6330
--- /dev/null
+++ b/target-xen/exec-dm.c
@@ -0,0 +1,791 @@
+/*
+ *  virtual page mapping and translated block handling
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "config.h"
+
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "disas.h"
+#include "hw/xen_common.h"
+#include "qemu-xen.h"
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+int use_icount = 0;
+int64_t qemu_icount;
+
+RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
+
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+   cpu_exec() */
+CPUState *cpu_single_env;
+
+/* io memory support */
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+static int io_mem_nb = 1;
+
+/* log support */
+FILE *logfile;
+int loglevel;
+
+void cpu_exec_init_all(unsigned long tb_size)
+{
+}
+
+void cpu_exec_init(CPUState *env)
+{
+    CPUState **penv;
+    int cpu_index;
+
+    env->next_cpu = NULL;
+    penv = &first_cpu;
+    cpu_index = 0;
+    while (*penv != NULL) {
+        penv = (CPUState **)&(*penv)->next_cpu;
+        cpu_index++;
+    }
+    env->cpu_index = cpu_index;
+    *penv = env;
+}
+
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+    loglevel = log_flags;
+    if (!logfile) {
+        logfile = stderr;
+    }
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+    logfile = fopen(filename, "w");
+    if (!logfile) {
+        perror(filename);
+        _exit(1);
+    }
+#if !defined(CONFIG_SOFTMMU)
+    /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+    {
+        static uint8_t logfile_buf[4096];
+        setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+    }
+#else
+    setvbuf(logfile, NULL, _IOLBF, 0);
+#endif
+    dup2(fileno(logfile), 1);
+    dup2(fileno(logfile), 2);
+}
+
+/* mask must never be zero, except for A20 change call */
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+}
+
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request &= ~mask;
+}
+
+const CPULogItem cpu_log_items[] = {
+#ifdef DEBUG_IOPORT
+    { CPU_LOG_IOPORT, "ioport",
+      "show all i/o ports accesses" },
+#endif
+    { 0, NULL, NULL },
+};
+
+static int cmp1(const char *s1, int n, const char *s2)
+{
+    if (strlen(s2) != n)
+        return 0;
+    return memcmp(s1, s2, n) == 0;
+}
+
+/* takes a comma separated list of log masks. Return 0 if error. */
+int cpu_str_to_log_mask(const char *str)
+{
+    const CPULogItem *item;
+    int mask;
+    const char *p, *p1;
+
+    p = str;
+    mask = 0;
+    for(;;) {
+        p1 = strchr(p, ',');
+        if (!p1) {
+            p1 = p + strlen(p);
+        }
+        if(cmp1(p,p1-p,"all")) {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                mask |= item->mask;
+            }
+        } else {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                if (cmp1(p, p1 - p, item->name))
+                    goto found;
+            }
+            return 0;
+        }
+found:
+        mask |= item->mask;
+        if (*p1 != ',')
+            break;
+        p = p1 + 1;
+    }
+    return mask;
+}
+
+/* XXX: Simple implementation. Fix later */
+#define MAX_MMIO 1024
+static struct MMIOSpace {
+    target_phys_addr_t start;
+    unsigned long size;
+    unsigned long io_index;
+} mmio[MAX_MMIO];
+static unsigned long mmio_cnt;
+
+/* register physical memory. 'size' must be a multiple of the target
+   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+   io memory page */
+void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                         ram_addr_t size,
+                                         ram_addr_t phys_offset,
+                                         ram_addr_t region_offset)
+{
+    region_offset &= TARGET_PAGE_MASK;
+    start_addr += region_offset;
+
+    int i;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        if(mmio[i].start == start_addr) {
+            mmio[i].io_index = phys_offset;
+            mmio[i].size = size;
+            return;
+        }
+    }
+
+    if (mmio_cnt == MAX_MMIO) {
+        fprintf(stderr, "too many mmio regions\n");
+        exit(-1);
+    }
+
+    mmio[mmio_cnt].io_index = phys_offset;
+    mmio[mmio_cnt].start = start_addr;
+    mmio[mmio_cnt++].size = size;
+}
+
+/* mem_read and mem_write are arrays of functions containing the
+   function to access byte (index 0), word (index 1) and dword (index
+   2). All functions must be supplied. If io_index is non zero, the
+   corresponding io zone is modified. If it is zero, a new io zone is
+   allocated. The return value can be used with
+   cpu_register_physical_memory(). (-1) is returned if error. */
+int cpu_register_io_memory_fixed(int io_index,
+                           CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque)
+{
+    int i;
+
+    if (io_index <= 0) {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+        io_index = io_mem_nb++;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+    for(i = 0;i < 3; i++) {
+        io_mem_read[io_index][i] = mem_read[i];
+        io_mem_write[io_index][i] = mem_write[i];
+    }
+    io_mem_opaque[io_index] = opaque;
+    return io_index << IO_MEM_SHIFT;
+}
+
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque)
+{
+    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
+}
+
+void cpu_unregister_io_memory(int io_table_address)
+{
+    int i;
+    int io_index = io_table_address >> IO_MEM_SHIFT;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        if (mmio[i].size && mmio[i].io_index == io_index) {
+            mmio[i].start = mmio[i].size = 0;
+            break;
+        }
+    }
+
+    for (i=0;i < 3; i++) {
+        io_mem_read[io_index][i] = NULL;
+        io_mem_write[io_index][i] = NULL;
+    }
+    io_mem_opaque[io_index] = NULL;
+}
+
+int cpu_physical_memory_set_dirty_tracking(int enable)
+{
+    return 0;
+}
+
+#ifdef __ia64__
+
+#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i()   asm volatile (";; sync.i" ::: "memory")
+#define ia64_srlz_i()   asm volatile (";; srlz.i ;;" ::: "memory")
+
+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
+ * So to emulate right behavior that guest OS is assumed, we need to flush
+ * I/D cache here.
+ */
+static void sync_icache(uint8_t *address, int len)
+{
+    unsigned long addr = (unsigned long)address;
+    unsigned long end = addr + len;
+
+    for (addr &= ~(32UL-1); addr < end; addr += 32UL) {
+        __ia64_fc(addr);
+    }
+
+    ia64_sync_i();
+    ia64_srlz_i();
+}
+#endif
+
+static int iomem_index(target_phys_addr_t addr)
+{
+    int i;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        unsigned long start, end;
+
+        start = mmio[i].start;
+        end = mmio[i].start + mmio[i].size;
+
+        if ((addr >= start) && (addr < end)) {
+            return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        }
+    }
+    return 0;
+}
+
+unsigned int xen_logdirty_enable = 0;
+
+/*
+ * Replace the standard byte memcpy with a word memcpy for appropriately sized
+ * memory copy operations.  Some users (USB-UHCI) can not tolerate the possible
+ * word tearing that can result from a guest concurrently writing a memory
+ * structure while the qemu device model is modifying the same location.
+ * Forcing a word-sized read/write prevents the guest from seeing a partially
+ * written word-sized atom.
+ */
+#if defined(__x86_64__) || defined(__i386__)
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+    asm volatile (
+        "   movl %%edx,%%ecx \n"
+#ifdef __x86_64__
+        "   shrl $3,%%ecx    \n"
+        "   rep  movsq       \n"
+        "   test $4,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsl            \n"
+#else /* __i386__ */
+        "   shrl $2,%%ecx    \n"
+        "   rep  movsl       \n"
+#endif
+        "1: test $2,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsw            \n"
+        "1: test $1,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsb            \n"
+        "1:                  \n"
+        : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" );
+}
+#else
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+    /* Some architectures do not like unaligned accesses. */
+    if (((unsigned long)dst | (unsigned long)src) & 3) {
+        memcpy(dst, src, n);
+        return;
+    }
+
+    while (n >= sizeof(uint32_t)) {
+        *((uint32_t *)dst) = *((uint32_t *)src);
+        dst = ((uint32_t *)dst) + 1;
+        src = ((uint32_t *)src) + 1;
+        n -= sizeof(uint32_t);
+    }
+
+    if (n & 2) {
+        *((uint16_t *)dst) = *((uint16_t *)src);
+        dst = ((uint16_t *)dst) + 1;
+        src = ((uint16_t *)src) + 1;
+    }
+
+    if (n & 1) {
+        *((uint8_t *)dst) = *((uint8_t *)src);
+        dst = ((uint8_t *)dst) + 1;
+        src = ((uint8_t *)src) + 1;
+    }
+}
+#endif
+
+void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf,
+                            int _len, int is_write)
+{
+    target_phys_addr_t addr = _addr;
+    int len = _len;
+    int l, io_index;
+    uint8_t *ptr;
+    uint32_t val;
+
+    mapcache_lock();
+
+    while (len > 0) {
+        /* How much can we copy before the next page boundary? */
+        l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
+        if (l > len) {
+            l = len;
+        }
+
+        io_index = iomem_index(addr);
+        if (is_write) {
+            if (io_index) {
+                if (l >= 4 && ((addr & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = ldl_raw(buf);
+                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = lduw_raw(buf);
+                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+                    l = 2;
+                } else {
+                    /* 8 bit access */
+                    val = ldub_raw(buf);
+                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
+                    l = 1;
+                }
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+                /* Writing to RAM */
+                memcpy_words(ptr, buf, l);
+
+                if (xen_logdirty_enable) {
+                    xc_hvm_modified_memory(xen_xc,
+                            xen_domid,
+                            addr >> TARGET_PAGE_BITS,
+                            ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+                            - (addr >> TARGET_PAGE_BITS));
+                }
+#ifdef __ia64__
+                sync_icache(ptr, l);
+#endif
+            }
+        } else {
+            if (io_index) {
+                if (l >= 4 && ((addr & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+                    stl_raw(buf, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+                    stw_raw(buf, val);
+                    l = 2;
+                } else {
+                    /* 8 bit access */
+                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
+                    stb_raw(buf, val);
+                    l = 1;
+                }
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+                /* Reading from RAM */
+                memcpy_words(buf, ptr, l);
+            } else {
+                /* Neither RAM nor known MMIO space */
+                memset(buf, 0xff, len);
+            }
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+
+    mapcache_unlock();
+}
+
+/* virtual memory access for debug */
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+                        uint8_t *buf, int len, int is_write)
+{
+    int l;
+    target_ulong page, phys_addr;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        phys_addr = cpu_get_phys_page_debug(env, page);
+        /* if no physical page mapped, return an error */
+        if (phys_addr == -1)
+            return -1;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
+                               buf, l, is_write);
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+    return 0;
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+                                     int dirty_flags)
+{
+    unsigned long length;
+    int i, mask, len;
+    uint8_t *p;
+
+    start &= TARGET_PAGE_MASK;
+    end = TARGET_PAGE_ALIGN(end);
+
+    length = end - start;
+    if (length == 0)
+        return;
+    mask = ~dirty_flags;
+    p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+    len = length >> TARGET_PAGE_BITS;
+    for(i = 0; i < len; i++) {
+        p[i] &= mask;
+    }
+
+    return;
+}
+
+
+/* Unoptimised in Xen DM, nicked from git
+ *  aab33094073678d459ccaac5c60ea7533e8d1d8e */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+    uint8_t val;
+    cpu_physical_memory_read(addr, &val, 1);
+    return val;
+}
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+    uint16_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
+    return tswap16(val);
+}
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+    uint64_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
+    return tswap64(val);
+}
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t v = val;
+    cpu_physical_memory_write(addr, &v, 1);
+}
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint16_t v = tswap16(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
+}
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = tswap64(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+}
+
+/* stubs which we hope (think!) are OK for Xen DM */
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+    val = tswap32(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 4);
+}
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys(addr, val);
+}
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    uint32_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 4);
+    return tswap32(val);
+}
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+                                   const uint8_t *buf, int len)
+{
+    return cpu_physical_memory_write(addr,buf,len);
+}
+
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+
+/* stub out various functions for Xen DM */
+void dump_exec_info(FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+}
+
+void monitor_disas(Monitor *mon, CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags)
+{
+}
+
+/*
+ * This next section was clone-and-hacked from the version in exec.c
+ * :-(.  But the exec.c version is full of tcg-specific stuff and
+ * assumptions about phys_ram_base.
+ */
+
+typedef struct MapClient {
+    void *opaque;
+    void (*callback)(void *opaque);
+    QLIST_ENTRY(MapClient) link;
+} MapClient;
+
+static QLIST_HEAD(map_client_list, MapClient) map_client_list
+    = QLIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+    MapClient *client = qemu_malloc(sizeof(*client));
+
+    client->opaque = opaque;
+    client->callback = callback;
+    QLIST_INSERT_HEAD(&map_client_list, client, link);
+    return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+    MapClient *client = (MapClient *)_client;
+
+    QLIST_REMOVE(client, link);
+    qemu_free(client);
+}
+
+static void cpu_notify_map_clients(void)
+{
+    MapClient *client;
+
+    while (!QLIST_EMPTY(&map_client_list)) {
+        client = QLIST_FIRST(&map_client_list);
+        client->callback(client->opaque);
+        cpu_unregister_map_client(client);
+    }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write)
+{
+    unsigned long l = 0;
+#ifdef MAPCACHE
+    l = MCACHE_BUCKET_SIZE - (addr & (MCACHE_BUCKET_SIZE-1));
+    if ((*plen) > l) {
+        *plen = l;
+    }
+#endif
+    if (xen_logdirty_enable) {
+        xc_hvm_modified_memory(xen_xc, xen_domid, addr >> TARGET_PAGE_BITS,
+                ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+                    - (addr >> TARGET_PAGE_BITS));
+    }
+
+    return qemu_map_cache(addr, 1);
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1.  access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len)
+{
+    qemu_invalidate_entry(buffer);
+    cpu_notify_map_clients();
+}
+
+
+void cpu_exit(CPUState *env)
+{
+    env->exit_request = 1;
+}
+
+void qemu_flush_coalesced_mmio_buffer(void)
+{
+}
+
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr - block->offset < block->length) {
+            QLIST_REMOVE(block, next);
+            QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+            return block->host + (addr - block->offset);
+        }
+    }
+    return block->host + (addr - block->offset);
+
+    fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+    abort();
+
+    return NULL;
+}
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+    return 0;
+}
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static ram_addr_t find_ram_offset(ram_addr_t size)
+{
+    RAMBlock *block;
+    ram_addr_t last = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        last = MAX(last, block->offset + block->length);
+    }
+
+    return last;
+}
+
+ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
+{
+    RAMBlock *new_block;
+
+    size = TARGET_PAGE_ALIGN(size);
+    new_block = qemu_malloc(sizeof(*new_block));
+
+    if (mem_path) {
+#if defined (__linux__) && !defined(TARGET_S390X)
+        new_block->host = 0; // file_ram_alloc(size, mem_path);
+        if (!new_block->host) {
+            new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+            madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+        }
+#else
+        fprintf(stderr, "-mem-path option unsupported\n");
+        exit(1);
+#endif
+    } else {
+        new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+        madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+    }
+    new_block->offset = find_ram_offset(size);
+    new_block->length = size;
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+        (new_block->offset + size) >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, size >> TARGET_PAGE_BITS);
+
+    return new_block->offset;
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+}
+
+void tb_flush(CPUState *env1)
+{
+}
+
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint)
+{
+    return -ENOSYS;
+}
+
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags)
+{
+    return -ENOENT;
+}
+
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint)
+{
+    return -ENOSYS;
+}
+
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
+{
+    return -ENOSYS;
+}
+
+void cpu_breakpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+void cpu_single_step(CPUState *env, int enabled)
+{
+}
diff --git a/target-xen/helper.c b/target-xen/helper.c
new file mode 100644
index 0000000..f8512c8
--- /dev/null
+++ b/target-xen/helper.c
@@ -0,0 +1,63 @@
+/*
+ *  i386 helpers (without register variable usage)
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "cpu.h"
+
+CPUXenState *cpu_xen_init(const char *cpu_model)
+{
+    CPUXenState *env = NULL;
+    static int inited;
+
+    env = qemu_mallocz(sizeof(CPUXenState));
+    cpu_exec_init(env);
+
+    /* init various static tables */
+    if (!inited) {
+        inited = 1;
+
+        cpu_single_env = env;
+    }
+
+    return env;
+}
+
+int cpu_xen_exec(CPUState *env1)
+{
+    return 0;
+}
+
+void cpu_reset(CPUXenState *env)
+{
+}
+
+void cpu_dump_state(CPUState *env, FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+}
+
+void cpu_x86_set_a20(CPUXenState *env, int a20_state)
+{
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
diff --git a/target-xen/machine.c b/target-xen/machine.c
new file mode 100644
index 0000000..e69de29
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
new file mode 100644
index 0000000..d1910d6
--- /dev/null
+++ b/target-xen/qemu-xen.h
@@ -0,0 +1,30 @@
+#ifndef QEMU_XEN_H
+#define QEMU_XEN_H
+
+#include "hw/xen_common.h"
+
+/* vl.c */
+
+#if defined(__i386__) || defined(__x86_64__)
+#define phys_ram_addr(x) (qemu_map_cache(x, 0))
+#elif defined(__ia64__)
+#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL)
+#endif
+
+/* xen_mapcache.c */
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
+void     qemu_invalidate_entry(uint8_t *buffer);
+void     qemu_invalidate_map_cache(void);
+
+#define mapcache_lock()   ((void)0)
+#define mapcache_unlock() ((void)0)
+
+/* target-xen/exec-dm.c */
+
+int cpu_register_io_memory_fixed(int io_index,
+                           CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque);
+
+#endif /*QEMU_XEN_H*/
diff --git a/target-xen/stub-functions.c b/target-xen/stub-functions.c
new file mode 100644
index 0000000..0db6898
--- /dev/null
+++ b/target-xen/stub-functions.c
@@ -0,0 +1,42 @@
+#include "config.h"
+#include "disas.h"
+#include "hw/apic.h"
+#include "hw/pc.h"
+#include "cpu.h"
+
+/* disas */
+struct syminfo *syminfos = NULL;
+
+/* apic */
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+    return -1;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+    return 0;
+}
+
+/* vmmouse */
+void *vmmouse_init(void *m)
+{
+    return NULL;
+}
+
+/* cpu-exec */
+volatile sig_atomic_t exit_request;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+    return NULL;
+}
+
+int qemu_cpu_has_work(CPUState *env)
+{
+    return 0;
+}
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
new file mode 100644
index 0000000..39daae2
--- /dev/null
+++ b/target-xen/xen_mapcache.c
@@ -0,0 +1,14 @@
+#include "qemu-xen.h"
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+    return phys_ram_addr(phys_addr);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 03/15] xen: Add a new target to qemu: target-xen
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

This patch adds a new Xen device model target to Qemu, called
target-xen.
The new target makes use of the previously introduced xen_machine_fv.
In order to have a fully working Xen device model we still need
functionalities introduced by the following patches.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target                    |   31 ++-
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   11 +-
 default-configs/xen-dm-softmmu.mak |   24 ++
 target-xen/cpu.h                   |  116 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |   63 +++
 target-xen/qemu-xen.h              |   30 ++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |   14 +
 11 files changed, 1120 insertions(+), 5 deletions(-)
 create mode 100644 default-configs/xen-dm-softmmu.mak
 create mode 100644 target-xen/cpu.h
 create mode 100644 target-xen/exec-dm.c
 create mode 100644 target-xen/helper.c
 create mode 100644 target-xen/machine.c
 create mode 100644 target-xen/qemu-xen.h
 create mode 100644 target-xen/stub-functions.c
 create mode 100644 target-xen/xen_mapcache.c

diff --git a/Makefile.target b/Makefile.target
index 8fdc884..359a984 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
-# xen full virtualized machine
-obj-$(CONFIG_XEN) += xen_machine_fv.o
-
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
@@ -310,6 +307,34 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
 
 endif # CONFIG_SOFTMMU
 
+# Xen Device Model
+# xen full virtualized machine
+
+# Remove some lib, because we don't want it for a xen target.
+ifeq ($(TARGET_BASE_ARCH), xen)
+bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
+bad-libobj-y += tcg%.o fpu/%.o
+bad-libobj-y += disas.o op_helper.o
+libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
+endif
+
+obj-xen-y += xen_machine_fv.o
+obj-xen-y += i8259.o
+obj-xen-y += pc.o
+obj-xen-y += piix_pci.o
+obj-xen-y += mc146818rtc.o
+
+obj-xen-y += xen_mapcache.o
+obj-xen-y += stub-functions.o
+
+obj-xen-y += vga.o
+obj-xen-y += hpet.o
+obj-xen-y += cirrus_vga.o
+obj-xen-y += smbios.o
+obj-xen-y += multiboot.o
+obj-xen-y += exec-dm.o
+obj-xen-y += lsi53c895a.o usb-ohci.o
+
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
diff --git a/arch_init.c b/arch_init.c
index 47bb4b2..ebc5cb6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -75,6 +75,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_SH4
 #elif defined(TARGET_SPARC)
 #define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XEN)
+#define QEMU_ARCH QEMU_ARCH_XEN
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 682890c..b5f8eb1 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -16,6 +16,7 @@ enum {
     QEMU_ARCH_S390X = 256,
     QEMU_ARCH_SH4 = 512,
     QEMU_ARCH_SPARC = 1024,
+    QEMU_ARCH_XEN = 2048,
 };
 
 extern const uint32_t arch_type;
diff --git a/configure b/configure
index 4c7c729..1ff6e80 100755
--- a/configure
+++ b/configure
@@ -2522,6 +2522,9 @@ case "$target" in
   ${target_arch2}-softmmu)
     target_softmmu="yes"
     ;;
+  ${target_arch2}-dm-softmmu)
+    target_softmmu="yes"
+    ;;
   ${target_arch2}-linux-user)
     if test "$linux" != "yes" ; then
       echo "ERROR: Target '$target' is only available on a Linux host"
@@ -2587,6 +2590,10 @@ case "$target_arch2" in
     TARGET_BASE_ARCH=i386
     target_phys_bits=64
   ;;
+  xen)
+    # This is use for xen mapcache
+    target_phys_bits=64
+  ;;
   alpha)
     target_phys_bits=64
     target_nptl="yes"
@@ -2698,7 +2705,7 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
 fi
 echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
 case "$target_arch2" in
-  i386|x86_64)
+  i386|x86_64|xen)
     if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
       echo "CONFIG_XEN=y" >> $config_target_mak
     fi
@@ -2864,7 +2871,7 @@ if test "$target_softmmu" = "yes" ; then
   arm)
     cflags="-DHAS_AUDIO $cflags"
   ;;
-  i386|mips|ppc)
+  i386|mips|ppc|xen)
     cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
   ;;
   esac
diff --git a/default-configs/xen-dm-softmmu.mak b/default-configs/xen-dm-softmmu.mak
new file mode 100644
index 0000000..72fe141
--- /dev/null
+++ b/default-configs/xen-dm-softmmu.mak
@@ -0,0 +1,24 @@
+# Default configuration for xen-dm-softmmu
+
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_USB_UHCI=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_IDE_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_PIIX_PCI=y
+CONFIG_SOUND=y
+CONFIG_XEN=y
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
new file mode 100644
index 0000000..0e08ab3
--- /dev/null
+++ b/target-xen/cpu.h
@@ -0,0 +1,116 @@
+/*
+ * xen virtual CPU header
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_XEN_H
+#define CPU_XEN_H
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#ifdef TARGET_X86_64
+#define ELF_MACHINE     EM_X86_64
+#else
+#define ELF_MACHINE     EM_386
+#endif
+
+#define CPUState struct CPUXenState
+#define CPUX86State CPUXenState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+/* hidden flags - used internally by qemu to represent additional cpu
+   states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not
+   redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit
+   position to ease oring with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT         0
+#define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+
+#define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
+#define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+
+/* cpuid_features bits */
+#define CPUID_APIC (1 << 9)
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUXenState {
+    uint32_t hflags; /* TB flags, see HF_xxx constants. These flags
+                        are known at translation time. */
+    CPU_COMMON
+
+    /* processor features (e.g. for CPUID insn) */
+    uint32_t cpuid_features;
+    uint32_t cpuid_apic_id;
+
+    /* in order to simplify APIC support, we leave this pointer to the
+       user */
+    struct DeviceState *apic_state;
+} CPUXenState;
+
+CPUXenState *cpu_xen_init(const char *cpu_model);
+int cpu_xen_exec(CPUXenState *s);
+
+int cpu_get_pic_interrupt(CPUXenState *s);
+void cpu_set_ferr(CPUX86State *s);
+
+/* helper.c */
+void cpu_x86_set_a20(CPUXenState *env, int a20_state);
+
+/* hw/pc.c */
+void cpu_smm_update(CPUXenState *env);
+uint64_t cpu_get_tsc(CPUX86State *env);
+
+#define TARGET_PAGE_BITS 12
+
+#ifdef TARGET_X86_64
+#define TARGET_PHYS_ADDR_SPACE_BITS 52
+/* ??? This is really 48 bits, sign-extended, but the only thing
+   accessible to userland with bit 48 set is the VSYSCALL, and that
+   is handled via other mechanisms.  */
+#define TARGET_VIRT_ADDR_SPACE_BITS 47
+#else
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+#define cpu_init cpu_xen_init
+#define cpu_exec cpu_xen_exec
+
+/* MMU modes definitions */
+static inline int cpu_mmu_index (CPUState *env)
+{
+    return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+}
+
+#endif /* CPU_XEN_H */
diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c
new file mode 100644
index 0000000..5af6330
--- /dev/null
+++ b/target-xen/exec-dm.c
@@ -0,0 +1,791 @@
+/*
+ *  virtual page mapping and translated block handling
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "config.h"
+
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "disas.h"
+#include "hw/xen_common.h"
+#include "qemu-xen.h"
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+int use_icount = 0;
+int64_t qemu_icount;
+
+RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
+
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+   cpu_exec() */
+CPUState *cpu_single_env;
+
+/* io memory support */
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+static int io_mem_nb = 1;
+
+/* log support */
+FILE *logfile;
+int loglevel;
+
+void cpu_exec_init_all(unsigned long tb_size)
+{
+}
+
+void cpu_exec_init(CPUState *env)
+{
+    CPUState **penv;
+    int cpu_index;
+
+    env->next_cpu = NULL;
+    penv = &first_cpu;
+    cpu_index = 0;
+    while (*penv != NULL) {
+        penv = (CPUState **)&(*penv)->next_cpu;
+        cpu_index++;
+    }
+    env->cpu_index = cpu_index;
+    *penv = env;
+}
+
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+    loglevel = log_flags;
+    if (!logfile) {
+        logfile = stderr;
+    }
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+    logfile = fopen(filename, "w");
+    if (!logfile) {
+        perror(filename);
+        _exit(1);
+    }
+#if !defined(CONFIG_SOFTMMU)
+    /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+    {
+        static uint8_t logfile_buf[4096];
+        setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+    }
+#else
+    setvbuf(logfile, NULL, _IOLBF, 0);
+#endif
+    dup2(fileno(logfile), 1);
+    dup2(fileno(logfile), 2);
+}
+
+/* mask must never be zero, except for A20 change call */
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+}
+
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request &= ~mask;
+}
+
+const CPULogItem cpu_log_items[] = {
+#ifdef DEBUG_IOPORT
+    { CPU_LOG_IOPORT, "ioport",
+      "show all i/o ports accesses" },
+#endif
+    { 0, NULL, NULL },
+};
+
+static int cmp1(const char *s1, int n, const char *s2)
+{
+    if (strlen(s2) != n)
+        return 0;
+    return memcmp(s1, s2, n) == 0;
+}
+
+/* takes a comma separated list of log masks. Return 0 if error. */
+int cpu_str_to_log_mask(const char *str)
+{
+    const CPULogItem *item;
+    int mask;
+    const char *p, *p1;
+
+    p = str;
+    mask = 0;
+    for(;;) {
+        p1 = strchr(p, ',');
+        if (!p1) {
+            p1 = p + strlen(p);
+        }
+        if(cmp1(p,p1-p,"all")) {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                mask |= item->mask;
+            }
+        } else {
+            for(item = cpu_log_items; item->mask != 0; item++) {
+                if (cmp1(p, p1 - p, item->name))
+                    goto found;
+            }
+            return 0;
+        }
+found:
+        mask |= item->mask;
+        if (*p1 != ',')
+            break;
+        p = p1 + 1;
+    }
+    return mask;
+}
+
+/* XXX: Simple implementation. Fix later */
+#define MAX_MMIO 1024
+static struct MMIOSpace {
+    target_phys_addr_t start;
+    unsigned long size;
+    unsigned long io_index;
+} mmio[MAX_MMIO];
+static unsigned long mmio_cnt;
+
+/* register physical memory. 'size' must be a multiple of the target
+   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+   io memory page */
+void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                         ram_addr_t size,
+                                         ram_addr_t phys_offset,
+                                         ram_addr_t region_offset)
+{
+    region_offset &= TARGET_PAGE_MASK;
+    start_addr += region_offset;
+
+    int i;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        if(mmio[i].start == start_addr) {
+            mmio[i].io_index = phys_offset;
+            mmio[i].size = size;
+            return;
+        }
+    }
+
+    if (mmio_cnt == MAX_MMIO) {
+        fprintf(stderr, "too many mmio regions\n");
+        exit(-1);
+    }
+
+    mmio[mmio_cnt].io_index = phys_offset;
+    mmio[mmio_cnt].start = start_addr;
+    mmio[mmio_cnt++].size = size;
+}
+
+/* mem_read and mem_write are arrays of functions containing the
+   function to access byte (index 0), word (index 1) and dword (index
+   2). All functions must be supplied. If io_index is non zero, the
+   corresponding io zone is modified. If it is zero, a new io zone is
+   allocated. The return value can be used with
+   cpu_register_physical_memory(). (-1) is returned if error. */
+int cpu_register_io_memory_fixed(int io_index,
+                           CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque)
+{
+    int i;
+
+    if (io_index <= 0) {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+        io_index = io_mem_nb++;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
+
+    for(i = 0;i < 3; i++) {
+        io_mem_read[io_index][i] = mem_read[i];
+        io_mem_write[io_index][i] = mem_write[i];
+    }
+    io_mem_opaque[io_index] = opaque;
+    return io_index << IO_MEM_SHIFT;
+}
+
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque)
+{
+    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
+}
+
+void cpu_unregister_io_memory(int io_table_address)
+{
+    int i;
+    int io_index = io_table_address >> IO_MEM_SHIFT;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        if (mmio[i].size && mmio[i].io_index == io_index) {
+            mmio[i].start = mmio[i].size = 0;
+            break;
+        }
+    }
+
+    for (i=0;i < 3; i++) {
+        io_mem_read[io_index][i] = NULL;
+        io_mem_write[io_index][i] = NULL;
+    }
+    io_mem_opaque[io_index] = NULL;
+}
+
+int cpu_physical_memory_set_dirty_tracking(int enable)
+{
+    return 0;
+}
+
+#ifdef __ia64__
+
+#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i()   asm volatile (";; sync.i" ::: "memory")
+#define ia64_srlz_i()   asm volatile (";; srlz.i ;;" ::: "memory")
+
+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
+ * So to emulate right behavior that guest OS is assumed, we need to flush
+ * I/D cache here.
+ */
+static void sync_icache(uint8_t *address, int len)
+{
+    unsigned long addr = (unsigned long)address;
+    unsigned long end = addr + len;
+
+    for (addr &= ~(32UL-1); addr < end; addr += 32UL) {
+        __ia64_fc(addr);
+    }
+
+    ia64_sync_i();
+    ia64_srlz_i();
+}
+#endif
+
+static int iomem_index(target_phys_addr_t addr)
+{
+    int i;
+
+    for (i = 0; i < mmio_cnt; i++) {
+        unsigned long start, end;
+
+        start = mmio[i].start;
+        end = mmio[i].start + mmio[i].size;
+
+        if ((addr >= start) && (addr < end)) {
+            return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        }
+    }
+    return 0;
+}
+
+unsigned int xen_logdirty_enable = 0;
+
+/*
+ * Replace the standard byte memcpy with a word memcpy for appropriately sized
+ * memory copy operations.  Some users (USB-UHCI) can not tolerate the possible
+ * word tearing that can result from a guest concurrently writing a memory
+ * structure while the qemu device model is modifying the same location.
+ * Forcing a word-sized read/write prevents the guest from seeing a partially
+ * written word-sized atom.
+ */
+#if defined(__x86_64__) || defined(__i386__)
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+    asm volatile (
+        "   movl %%edx,%%ecx \n"
+#ifdef __x86_64__
+        "   shrl $3,%%ecx    \n"
+        "   rep  movsq       \n"
+        "   test $4,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsl            \n"
+#else /* __i386__ */
+        "   shrl $2,%%ecx    \n"
+        "   rep  movsl       \n"
+#endif
+        "1: test $2,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsw            \n"
+        "1: test $1,%%edx    \n"
+        "   jz   1f          \n"
+        "   movsb            \n"
+        "1:                  \n"
+        : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" );
+}
+#else
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+    /* Some architectures do not like unaligned accesses. */
+    if (((unsigned long)dst | (unsigned long)src) & 3) {
+        memcpy(dst, src, n);
+        return;
+    }
+
+    while (n >= sizeof(uint32_t)) {
+        *((uint32_t *)dst) = *((uint32_t *)src);
+        dst = ((uint32_t *)dst) + 1;
+        src = ((uint32_t *)src) + 1;
+        n -= sizeof(uint32_t);
+    }
+
+    if (n & 2) {
+        *((uint16_t *)dst) = *((uint16_t *)src);
+        dst = ((uint16_t *)dst) + 1;
+        src = ((uint16_t *)src) + 1;
+    }
+
+    if (n & 1) {
+        *((uint8_t *)dst) = *((uint8_t *)src);
+        dst = ((uint8_t *)dst) + 1;
+        src = ((uint8_t *)src) + 1;
+    }
+}
+#endif
+
+void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf,
+                            int _len, int is_write)
+{
+    target_phys_addr_t addr = _addr;
+    int len = _len;
+    int l, io_index;
+    uint8_t *ptr;
+    uint32_t val;
+
+    mapcache_lock();
+
+    while (len > 0) {
+        /* How much can we copy before the next page boundary? */
+        l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
+        if (l > len) {
+            l = len;
+        }
+
+        io_index = iomem_index(addr);
+        if (is_write) {
+            if (io_index) {
+                if (l >= 4 && ((addr & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = ldl_raw(buf);
+                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = lduw_raw(buf);
+                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+                    l = 2;
+                } else {
+                    /* 8 bit access */
+                    val = ldub_raw(buf);
+                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
+                    l = 1;
+                }
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+                /* Writing to RAM */
+                memcpy_words(ptr, buf, l);
+
+                if (xen_logdirty_enable) {
+                    xc_hvm_modified_memory(xen_xc,
+                            xen_domid,
+                            addr >> TARGET_PAGE_BITS,
+                            ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+                            - (addr >> TARGET_PAGE_BITS));
+                }
+#ifdef __ia64__
+                sync_icache(ptr, l);
+#endif
+            }
+        } else {
+            if (io_index) {
+                if (l >= 4 && ((addr & 3) == 0)) {
+                    /* 32 bit read access */
+                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+                    stl_raw(buf, val);
+                    l = 4;
+                } else if (l >= 2 && ((addr & 1) == 0)) {
+                    /* 16 bit read access */
+                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+                    stw_raw(buf, val);
+                    l = 2;
+                } else {
+                    /* 8 bit access */
+                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
+                    stb_raw(buf, val);
+                    l = 1;
+                }
+            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+                /* Reading from RAM */
+                memcpy_words(buf, ptr, l);
+            } else {
+                /* Neither RAM nor known MMIO space */
+                memset(buf, 0xff, len);
+            }
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+
+    mapcache_unlock();
+}
+
+/* virtual memory access for debug */
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+                        uint8_t *buf, int len, int is_write)
+{
+    int l;
+    target_ulong page, phys_addr;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        phys_addr = cpu_get_phys_page_debug(env, page);
+        /* if no physical page mapped, return an error */
+        if (phys_addr == -1)
+            return -1;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
+                               buf, l, is_write);
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+    return 0;
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+                                     int dirty_flags)
+{
+    unsigned long length;
+    int i, mask, len;
+    uint8_t *p;
+
+    start &= TARGET_PAGE_MASK;
+    end = TARGET_PAGE_ALIGN(end);
+
+    length = end - start;
+    if (length == 0)
+        return;
+    mask = ~dirty_flags;
+    p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+    len = length >> TARGET_PAGE_BITS;
+    for(i = 0; i < len; i++) {
+        p[i] &= mask;
+    }
+
+    return;
+}
+
+
+/* Unoptimised in Xen DM, nicked from git
+ *  aab33094073678d459ccaac5c60ea7533e8d1d8e */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+    uint8_t val;
+    cpu_physical_memory_read(addr, &val, 1);
+    return val;
+}
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+    uint16_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
+    return tswap16(val);
+}
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+    uint64_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
+    return tswap64(val);
+}
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t v = val;
+    cpu_physical_memory_write(addr, &v, 1);
+}
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint16_t v = tswap16(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
+}
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = tswap64(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+}
+
+/* stubs which we hope (think!) are OK for Xen DM */
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+    val = tswap32(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 4);
+}
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+    stl_phys(addr, val);
+}
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+    uint32_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 4);
+    return tswap32(val);
+}
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+                                   const uint8_t *buf, int len)
+{
+    return cpu_physical_memory_write(addr,buf,len);
+}
+
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+
+/* stub out various functions for Xen DM */
+void dump_exec_info(FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+}
+
+void monitor_disas(Monitor *mon, CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags)
+{
+}
+
+/*
+ * This next section was clone-and-hacked from the version in exec.c
+ * :-(.  But the exec.c version is full of tcg-specific stuff and
+ * assumptions about phys_ram_base.
+ */
+
+typedef struct MapClient {
+    void *opaque;
+    void (*callback)(void *opaque);
+    QLIST_ENTRY(MapClient) link;
+} MapClient;
+
+static QLIST_HEAD(map_client_list, MapClient) map_client_list
+    = QLIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+    MapClient *client = qemu_malloc(sizeof(*client));
+
+    client->opaque = opaque;
+    client->callback = callback;
+    QLIST_INSERT_HEAD(&map_client_list, client, link);
+    return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+    MapClient *client = (MapClient *)_client;
+
+    QLIST_REMOVE(client, link);
+    qemu_free(client);
+}
+
+static void cpu_notify_map_clients(void)
+{
+    MapClient *client;
+
+    while (!QLIST_EMPTY(&map_client_list)) {
+        client = QLIST_FIRST(&map_client_list);
+        client->callback(client->opaque);
+        cpu_unregister_map_client(client);
+    }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write)
+{
+    unsigned long l = 0;
+#ifdef MAPCACHE
+    l = MCACHE_BUCKET_SIZE - (addr & (MCACHE_BUCKET_SIZE-1));
+    if ((*plen) > l) {
+        *plen = l;
+    }
+#endif
+    if (xen_logdirty_enable) {
+        xc_hvm_modified_memory(xen_xc, xen_domid, addr >> TARGET_PAGE_BITS,
+                ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+                    - (addr >> TARGET_PAGE_BITS));
+    }
+
+    return qemu_map_cache(addr, 1);
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1.  access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len)
+{
+    qemu_invalidate_entry(buffer);
+    cpu_notify_map_clients();
+}
+
+
+void cpu_exit(CPUState *env)
+{
+    env->exit_request = 1;
+}
+
+void qemu_flush_coalesced_mmio_buffer(void)
+{
+}
+
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+    RAMBlock *block;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (addr - block->offset < block->length) {
+            QLIST_REMOVE(block, next);
+            QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+            return block->host + (addr - block->offset);
+        }
+    }
+    return block->host + (addr - block->offset);
+
+    fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+    abort();
+
+    return NULL;
+}
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+    return 0;
+}
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static ram_addr_t find_ram_offset(ram_addr_t size)
+{
+    RAMBlock *block;
+    ram_addr_t last = 0;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        last = MAX(last, block->offset + block->length);
+    }
+
+    return last;
+}
+
+ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
+{
+    RAMBlock *new_block;
+
+    size = TARGET_PAGE_ALIGN(size);
+    new_block = qemu_malloc(sizeof(*new_block));
+
+    if (mem_path) {
+#if defined (__linux__) && !defined(TARGET_S390X)
+        new_block->host = 0; // file_ram_alloc(size, mem_path);
+        if (!new_block->host) {
+            new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+            madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+        }
+#else
+        fprintf(stderr, "-mem-path option unsupported\n");
+        exit(1);
+#endif
+    } else {
+        new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+        madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+    }
+    new_block->offset = find_ram_offset(size);
+    new_block->length = size;
+
+    QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+    ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+        (new_block->offset + size) >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0xff, size >> TARGET_PAGE_BITS);
+
+    return new_block->offset;
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+}
+
+void tb_flush(CPUState *env1)
+{
+}
+
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint)
+{
+    return -ENOSYS;
+}
+
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags)
+{
+    return -ENOENT;
+}
+
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint)
+{
+    return -ENOSYS;
+}
+
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
+{
+    return -ENOSYS;
+}
+
+void cpu_breakpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+void cpu_single_step(CPUState *env, int enabled)
+{
+}
diff --git a/target-xen/helper.c b/target-xen/helper.c
new file mode 100644
index 0000000..f8512c8
--- /dev/null
+++ b/target-xen/helper.c
@@ -0,0 +1,63 @@
+/*
+ *  i386 helpers (without register variable usage)
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "cpu.h"
+
+CPUXenState *cpu_xen_init(const char *cpu_model)
+{
+    CPUXenState *env = NULL;
+    static int inited;
+
+    env = qemu_mallocz(sizeof(CPUXenState));
+    cpu_exec_init(env);
+
+    /* init various static tables */
+    if (!inited) {
+        inited = 1;
+
+        cpu_single_env = env;
+    }
+
+    return env;
+}
+
+int cpu_xen_exec(CPUState *env1)
+{
+    return 0;
+}
+
+void cpu_reset(CPUXenState *env)
+{
+}
+
+void cpu_dump_state(CPUState *env, FILE *f,
+                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                    int flags)
+{
+}
+
+void cpu_x86_set_a20(CPUXenState *env, int a20_state)
+{
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
diff --git a/target-xen/machine.c b/target-xen/machine.c
new file mode 100644
index 0000000..e69de29
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
new file mode 100644
index 0000000..d1910d6
--- /dev/null
+++ b/target-xen/qemu-xen.h
@@ -0,0 +1,30 @@
+#ifndef QEMU_XEN_H
+#define QEMU_XEN_H
+
+#include "hw/xen_common.h"
+
+/* vl.c */
+
+#if defined(__i386__) || defined(__x86_64__)
+#define phys_ram_addr(x) (qemu_map_cache(x, 0))
+#elif defined(__ia64__)
+#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL)
+#endif
+
+/* xen_mapcache.c */
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
+void     qemu_invalidate_entry(uint8_t *buffer);
+void     qemu_invalidate_map_cache(void);
+
+#define mapcache_lock()   ((void)0)
+#define mapcache_unlock() ((void)0)
+
+/* target-xen/exec-dm.c */
+
+int cpu_register_io_memory_fixed(int io_index,
+                           CPUReadMemoryFunc * const *mem_read,
+                           CPUWriteMemoryFunc * const *mem_write,
+                           void *opaque);
+
+#endif /*QEMU_XEN_H*/
diff --git a/target-xen/stub-functions.c b/target-xen/stub-functions.c
new file mode 100644
index 0000000..0db6898
--- /dev/null
+++ b/target-xen/stub-functions.c
@@ -0,0 +1,42 @@
+#include "config.h"
+#include "disas.h"
+#include "hw/apic.h"
+#include "hw/pc.h"
+#include "cpu.h"
+
+/* disas */
+struct syminfo *syminfos = NULL;
+
+/* apic */
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+    return -1;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+    return 0;
+}
+
+/* vmmouse */
+void *vmmouse_init(void *m)
+{
+    return NULL;
+}
+
+/* cpu-exec */
+volatile sig_atomic_t exit_request;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+    return NULL;
+}
+
+int qemu_cpu_has_work(CPUState *env)
+{
+    return 0;
+}
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
new file mode 100644
index 0000000..39daae2
--- /dev/null
+++ b/target-xen/xen_mapcache.c
@@ -0,0 +1,14 @@
+#include "qemu-xen.h"
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+    return phys_ram_addr(phys_addr);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenctrl
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce a xen_dm_init function that opens the xenctrl interface; call
xen_dm_init from xen_machine_fv.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target       |    1 +
 hw/xen_machine_fv.c   |    8 ++++++++
 target-xen/xenstore.c |   13 +++++++++++++
 target-xen/xenstore.h |    6 ++++++
 4 files changed, 28 insertions(+), 0 deletions(-)
 create mode 100644 target-xen/xenstore.c
 create mode 100644 target-xen/xenstore.h

diff --git a/Makefile.target b/Makefile.target
index 359a984..63dc7d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -323,6 +323,7 @@ obj-xen-y += i8259.o
 obj-xen-y += pc.o
 obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
+obj-xen-y += xenstore.o
 
 obj-xen-y += xen_mapcache.o
 obj-xen-y += stub-functions.o
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 8114460..5fef7de 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -32,6 +32,8 @@
 #include "ide.h"
 #include "sysemu.h"
 
+#include "xen_backend.h"
+#include "xenstore.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
@@ -61,6 +63,12 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     CPUState *env;
 
+    /* Initialize backend core & drivers */
+    if (xen_dm_init() != 0) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
+
     /* Initialize a dummy CPU */
     if (cpu_model == NULL) {
 #ifdef TARGET_X86_64
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
new file mode 100644
index 0000000..bd74787
--- /dev/null
+++ b/target-xen/xenstore.c
@@ -0,0 +1,13 @@
+#include "hw/xen_backend.h"
+#include "xenstore.h"
+
+int xen_dm_init(void)
+{
+    xen_xc = xc_interface_open(NULL, NULL, 0);
+    if (xen_xc == NULL) {
+        xen_be_printf(NULL, 0, "can't open xen interface\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
new file mode 100644
index 0000000..90baf79
--- /dev/null
+++ b/target-xen/xenstore.h
@@ -0,0 +1,6 @@
+#ifndef XENSTORE_H_
+#define XENSTORE_H_
+
+int xen_dm_init(void);
+
+#endif /* !XENSTORE_H_ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 04/15] xen: xen_machine_fv, initialize xenctrl
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce a xen_dm_init function that opens the xenctrl interface; call
xen_dm_init from xen_machine_fv.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target       |    1 +
 hw/xen_machine_fv.c   |    8 ++++++++
 target-xen/xenstore.c |   13 +++++++++++++
 target-xen/xenstore.h |    6 ++++++
 4 files changed, 28 insertions(+), 0 deletions(-)
 create mode 100644 target-xen/xenstore.c
 create mode 100644 target-xen/xenstore.h

diff --git a/Makefile.target b/Makefile.target
index 359a984..63dc7d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -323,6 +323,7 @@ obj-xen-y += i8259.o
 obj-xen-y += pc.o
 obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
+obj-xen-y += xenstore.o
 
 obj-xen-y += xen_mapcache.o
 obj-xen-y += stub-functions.o
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 8114460..5fef7de 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -32,6 +32,8 @@
 #include "ide.h"
 #include "sysemu.h"
 
+#include "xen_backend.h"
+#include "xenstore.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
@@ -61,6 +63,12 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     CPUState *env;
 
+    /* Initialize backend core & drivers */
+    if (xen_dm_init() != 0) {
+        fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+        exit(1);
+    }
+
     /* Initialize a dummy CPU */
     if (cpu_model == NULL) {
 #ifdef TARGET_X86_64
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
new file mode 100644
index 0000000..bd74787
--- /dev/null
+++ b/target-xen/xenstore.c
@@ -0,0 +1,13 @@
+#include "hw/xen_backend.h"
+#include "xenstore.h"
+
+int xen_dm_init(void)
+{
+    xen_xc = xc_interface_open(NULL, NULL, 0);
+    if (xen_xc == NULL) {
+        xen_be_printf(NULL, 0, "can't open xen interface\n");
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
new file mode 100644
index 0000000..90baf79
--- /dev/null
+++ b/target-xen/xenstore.h
@@ -0,0 +1,6 @@
+#ifndef XENSTORE_H_
+#define XENSTORE_H_
+
+int xen_dm_init(void);
+
+#endif /* !XENSTORE_H_ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce a 8259 Interrupt Controller for target-xen; every set_irq
call makes a Xen hypercall.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target             |    2 +-
 hw/xen_common.h             |    3 ++
 hw/xen_machine_fv.c         |    5 +--
 target-xen/i8259-xen-stub.c |   63 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+), 4 deletions(-)
 create mode 100644 target-xen/i8259-xen-stub.c

diff --git a/Makefile.target b/Makefile.target
index 63dc7d1..d1b63f2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -319,7 +319,7 @@ libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
 endif
 
 obj-xen-y += xen_machine_fv.o
-obj-xen-y += i8259.o
+obj-xen-y += i8259-xen-stub.o
 obj-xen-y += pc.o
 obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 2cbc376..c49358c 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -52,4 +52,7 @@ typedef xc_interface *qemu_xc_interface;
 # define xc_fd(xen_xc)                          (*(int*)xen_xc)
 #endif
 
+/* hw/i8259-xen-stub.c */
+qemu_irq *i8259_xen_init(void);
+
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 5fef7de..114addf 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -32,6 +32,7 @@
 #include "ide.h"
 #include "sysemu.h"
 
+#include "xen_common.h"
 #include "xen_backend.h"
 #include "xenstore.h"
 #include "xen/hvm/hvm_info_table.h"
@@ -50,7 +51,6 @@ static void xen_init_fv(ram_addr_t ram_size,
     PCIBus *pci_bus;
     PCII440FXState *i440fx_state;
     int piix3_devfn = -1;
-    qemu_irq *cpu_irq;
     qemu_irq *isa_irq;
     qemu_irq *i8259;
     qemu_irq *cmos_s3;
@@ -80,8 +80,7 @@ static void xen_init_fv(ram_addr_t ram_size,
     env = cpu_init(cpu_model);
     env->halted = 1;
 
-    cpu_irq = pc_allocate_cpu_irq();
-    i8259 = i8259_init(cpu_irq[0]);
+    i8259 = i8259_xen_init();
     isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
     isa_irq_state->i8259 = i8259;
 
diff --git a/target-xen/i8259-xen-stub.c b/target-xen/i8259-xen-stub.c
new file mode 100644
index 0000000..aa2aae1
--- /dev/null
+++ b/target-xen/i8259-xen-stub.c
@@ -0,0 +1,63 @@
+/* Xen 8259 stub for interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2005      Intel corperation
+ * Copyright (c) 2008      Citrix / 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/hw.h"
+#include "hw/pc.h"
+#include "monitor.h"
+#include "hw/xen_common.h"
+#include "hw/xen_backend.h"
+
+#include <xen/hvm/ioreq.h>
+
+PicState2 *isa_pic = NULL;
+
+void pic_update_irq(PicState2 *s)
+{
+}
+
+static void i8259_set_irq(void *opaque, int irq, int level)
+{
+    xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level);
+}
+
+int pic_read_irq(PicState2 *s)
+{
+    return -1;
+}
+
+void irq_info(Monitor *mon)
+{
+    monitor_printf(mon, "irq statistics not supported with Xen.\n");
+}
+
+void pic_info(Monitor *mon)
+{
+    monitor_printf(mon, "pic_info not supported with Xen .\n");
+}
+
+qemu_irq *i8259_xen_init(void)
+{
+    return qemu_allocate_irqs(i8259_set_irq, NULL, 16);
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 05/15] xen: add a 8259 Interrupt Controller
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce a 8259 Interrupt Controller for target-xen; every set_irq
call makes a Xen hypercall.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target             |    2 +-
 hw/xen_common.h             |    3 ++
 hw/xen_machine_fv.c         |    5 +--
 target-xen/i8259-xen-stub.c |   63 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+), 4 deletions(-)
 create mode 100644 target-xen/i8259-xen-stub.c

diff --git a/Makefile.target b/Makefile.target
index 63dc7d1..d1b63f2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -319,7 +319,7 @@ libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
 endif
 
 obj-xen-y += xen_machine_fv.o
-obj-xen-y += i8259.o
+obj-xen-y += i8259-xen-stub.o
 obj-xen-y += pc.o
 obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 2cbc376..c49358c 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -52,4 +52,7 @@ typedef xc_interface *qemu_xc_interface;
 # define xc_fd(xen_xc)                          (*(int*)xen_xc)
 #endif
 
+/* hw/i8259-xen-stub.c */
+qemu_irq *i8259_xen_init(void);
+
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 5fef7de..114addf 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -32,6 +32,7 @@
 #include "ide.h"
 #include "sysemu.h"
 
+#include "xen_common.h"
 #include "xen_backend.h"
 #include "xenstore.h"
 #include "xen/hvm/hvm_info_table.h"
@@ -50,7 +51,6 @@ static void xen_init_fv(ram_addr_t ram_size,
     PCIBus *pci_bus;
     PCII440FXState *i440fx_state;
     int piix3_devfn = -1;
-    qemu_irq *cpu_irq;
     qemu_irq *isa_irq;
     qemu_irq *i8259;
     qemu_irq *cmos_s3;
@@ -80,8 +80,7 @@ static void xen_init_fv(ram_addr_t ram_size,
     env = cpu_init(cpu_model);
     env->halted = 1;
 
-    cpu_irq = pc_allocate_cpu_irq();
-    i8259 = i8259_init(cpu_irq[0]);
+    i8259 = i8259_xen_init();
     isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
     isa_irq_state->i8259 = i8259;
 
diff --git a/target-xen/i8259-xen-stub.c b/target-xen/i8259-xen-stub.c
new file mode 100644
index 0000000..aa2aae1
--- /dev/null
+++ b/target-xen/i8259-xen-stub.c
@@ -0,0 +1,63 @@
+/* Xen 8259 stub for interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2005      Intel corperation
+ * Copyright (c) 2008      Citrix / 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/hw.h"
+#include "hw/pc.h"
+#include "monitor.h"
+#include "hw/xen_common.h"
+#include "hw/xen_backend.h"
+
+#include <xen/hvm/ioreq.h>
+
+PicState2 *isa_pic = NULL;
+
+void pic_update_irq(PicState2 *s)
+{
+}
+
+static void i8259_set_irq(void *opaque, int irq, int level)
+{
+    xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level);
+}
+
+int pic_read_irq(PicState2 *s)
+{
+    return -1;
+}
+
+void irq_info(Monitor *mon)
+{
+    monitor_printf(mon, "irq statistics not supported with Xen.\n");
+}
+
+void pic_info(Monitor *mon)
+{
+    monitor_printf(mon, "pic_info not supported with Xen .\n");
+}
+
+qemu_irq *i8259_xen_init(void)
+{
+    return qemu_allocate_irqs(i8259_set_irq, NULL, 16);
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.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: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target     |    1 +
 hw/hw.h             |    3 +
 hw/pci_ids.h        |    2 +
 hw/xen_machine_fv.c |    3 +
 hw/xen_platform.c   |  449 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_platform.h   |    8 +
 6 files changed, 466 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_platform.c
 create mode 100644 hw/xen_platform.h

diff --git a/Makefile.target b/Makefile.target
index d1b63f2..1984cdd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -324,6 +324,7 @@ obj-xen-y += pc.o
 obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
 obj-xen-y += xenstore.o
+obj-xen-y += xen_platform.o
 
 obj-xen-y += xen_mapcache.o
 obj-xen-y += stub-functions.o
diff --git a/hw/hw.h b/hw/hw.h
index e3c3db2..aa17aaf 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -651,6 +651,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/pci_ids.h b/hw/pci_ids.h
index 39e9f1d..1f2e0dd 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -105,3 +105,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_machine_fv.c b/hw/xen_machine_fv.c
index 114addf..12a7723 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -35,6 +35,7 @@
 #include "xen_common.h"
 #include "xen_backend.h"
 #include "xenstore.h"
+#include "xen_platform.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
@@ -93,6 +94,8 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     pc_vga_init(pci_bus);
 
+    pci_xen_platform_init(pci_bus);
+
     /* init basic PC hardware */
     pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
 
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
new file mode 100644
index 0000000..d843b3d
--- /dev/null
+++ b/hw/xen_platform.c
@@ -0,0 +1,449 @@
+/*
+ * 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_platform.h"
+#include "xen_backend.h"
+#include "qemu-log.h"
+
+#include <assert.h>
+#include <xenguest.h>
+
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+
+#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 */
+    int throttling_disabled;
+    char log_buffer[4096];
+    int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* We throttle access to dom0 syslog, to avoid DOS attacks.  This is
+   modelled as a token bucket, with one token for every byte of log.
+   The bucket size is 128KB (->1024 lines of 128 bytes each) and
+   refills at 256B/s.  It starts full.  The guest is blocked if no
+   tokens are available when it tries to generate a log message. */
+#define BUCKET_MAX_SIZE (128*1024)
+#define BUCKET_FILL_RATE 256
+
+static void throttle(PCIXenPlatformState *s, unsigned count)
+{
+    static unsigned available;
+    static struct timespec last_refil;
+    static int started;
+    static int warned;
+
+    struct timespec waiting_for, now;
+    double delay;
+    struct timespec ts;
+
+    if (s->throttling_disabled)
+        return;
+
+    if (!started) {
+        clock_gettime(CLOCK_MONOTONIC, &last_refil);
+        available = BUCKET_MAX_SIZE;
+        started = 1;
+    }
+
+    if (count > BUCKET_MAX_SIZE) {
+        DPRINTF("tried to get %d tokens, but bucket size is %d\n",
+                BUCKET_MAX_SIZE, count);
+        exit(1);
+    }
+
+    if (available < count) {
+        /* The bucket is empty.  Refil it */
+
+        /* When will it be full enough to handle this request? */
+        delay = (double)(count - available) / BUCKET_FILL_RATE;
+        waiting_for = last_refil;
+        waiting_for.tv_sec += delay;
+        waiting_for.tv_nsec += (delay - (int)delay) * 1e9;
+        if (waiting_for.tv_nsec >= 1000000000) {
+            waiting_for.tv_nsec -= 1000000000;
+            waiting_for.tv_sec++;
+        }
+
+        /* How long do we have to wait? (might be negative) */
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        ts.tv_sec = waiting_for.tv_sec - now.tv_sec;
+        ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec;
+        if (ts.tv_nsec < 0) {
+            ts.tv_sec--;
+            ts.tv_nsec += 1000000000;
+        }
+
+        /* Wait for it. */
+        if (ts.tv_sec > 0 ||
+            (ts.tv_sec == 0 && ts.tv_nsec > 0)) {
+            if (!warned) {
+                DPRINTF("throttling guest access to syslog");
+                warned = 1;
+            }
+            while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
+                ;
+        }
+
+        /* Refil */
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        delay = (now.tv_sec - last_refil.tv_sec) +
+            (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9;
+        available += BUCKET_FILL_RATE * delay;
+        if (available > BUCKET_MAX_SIZE)
+            available = BUCKET_MAX_SIZE;
+        last_refil = now;
+    }
+
+    assert(available >= count);
+
+    available -= count;
+}
+
+/* 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:
+        /* Send bytes to syslog */
+        if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+            /* Flush buffer */
+            s->log_buffer[s->log_buffer_off] = 0;
+            throttle(s, s->log_buffer_off);
+            DPRINTF("%s\n", s->log_buffer);
+            s->log_buffer_off = 0;
+            break;
+        }
+        s->log_buffer[s->log_buffer_off++] = 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:
+        {
+            if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+                /* Flush buffer */
+                s->log_buffer[s->log_buffer_off] = 0;
+                throttle(s, s->log_buffer_off);
+                DPRINTF("%s\n", s->log_buffer);
+                s->log_buffer_off = 0;
+                break;
+            }
+            s->log_buffer[s->log_buffer_off++] = 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(void *opaque, target_phys_addr_t addr)
+{
+    static int warnings = 0;
+
+    if (warnings < 5) {
+        DPRINTF("Warning: attempted read from physical address "
+                "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+        warnings++;
+    }
+    return 0;
+}
+
+static void platform_mmio_write(void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    static int warnings = 0;
+
+    if (warnings < 5) {
+        DPRINTF("Warning: attempted write of 0x%x to physical "
+                "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+                val, addr);
+        warnings++;
+    }
+}
+
+static CPUReadMemoryFunc * const platform_mmio_read_funcs[3] = {
+    platform_mmio_read,
+    platform_mmio_read,
+    platform_mmio_read,
+};
+
+static CPUWriteMemoryFunc * const platform_mmio_write_funcs[3] = {
+    platform_mmio_write,
+    platform_mmio_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(platform_mmio_read_funcs,
+                                          platform_mmio_write_funcs, NULL);
+
+    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_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_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+    /* Microsoft WHQL requires non-zero subsystem IDs. */
+    /* http://www.pcisig.com/reflector/msg02205.html.  */
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, pci_conf[PCI_VENDOR_ID]);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0001);
+
+    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/hw/xen_platform.h b/hw/xen_platform.h
new file mode 100644
index 0000000..574eecd
--- /dev/null
+++ b/hw/xen_platform.h
@@ -0,0 +1,8 @@
+#ifndef XEN_PLATFORM_H
+#define XEN_PLATFORM_H
+
+#include "hw/pci.h"
+
+void pci_xen_platform_init(PCIBus *bus);
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 06/15] xen: Add the Xen platform pci device
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.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: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target     |    1 +
 hw/hw.h             |    3 +
 hw/pci_ids.h        |    2 +
 hw/xen_machine_fv.c |    3 +
 hw/xen_platform.c   |  449 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_platform.h   |    8 +
 6 files changed, 466 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_platform.c
 create mode 100644 hw/xen_platform.h

diff --git a/Makefile.target b/Makefile.target
index d1b63f2..1984cdd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -324,6 +324,7 @@ obj-xen-y += pc.o
 obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
 obj-xen-y += xenstore.o
+obj-xen-y += xen_platform.o
 
 obj-xen-y += xen_mapcache.o
 obj-xen-y += stub-functions.o
diff --git a/hw/hw.h b/hw/hw.h
index e3c3db2..aa17aaf 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -651,6 +651,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/pci_ids.h b/hw/pci_ids.h
index 39e9f1d..1f2e0dd 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -105,3 +105,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_machine_fv.c b/hw/xen_machine_fv.c
index 114addf..12a7723 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -35,6 +35,7 @@
 #include "xen_common.h"
 #include "xen_backend.h"
 #include "xenstore.h"
+#include "xen_platform.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
@@ -93,6 +94,8 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     pc_vga_init(pci_bus);
 
+    pci_xen_platform_init(pci_bus);
+
     /* init basic PC hardware */
     pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
 
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
new file mode 100644
index 0000000..d843b3d
--- /dev/null
+++ b/hw/xen_platform.c
@@ -0,0 +1,449 @@
+/*
+ * 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_platform.h"
+#include "xen_backend.h"
+#include "qemu-log.h"
+
+#include <assert.h>
+#include <xenguest.h>
+
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+
+#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 */
+    int throttling_disabled;
+    char log_buffer[4096];
+    int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* We throttle access to dom0 syslog, to avoid DOS attacks.  This is
+   modelled as a token bucket, with one token for every byte of log.
+   The bucket size is 128KB (->1024 lines of 128 bytes each) and
+   refills at 256B/s.  It starts full.  The guest is blocked if no
+   tokens are available when it tries to generate a log message. */
+#define BUCKET_MAX_SIZE (128*1024)
+#define BUCKET_FILL_RATE 256
+
+static void throttle(PCIXenPlatformState *s, unsigned count)
+{
+    static unsigned available;
+    static struct timespec last_refil;
+    static int started;
+    static int warned;
+
+    struct timespec waiting_for, now;
+    double delay;
+    struct timespec ts;
+
+    if (s->throttling_disabled)
+        return;
+
+    if (!started) {
+        clock_gettime(CLOCK_MONOTONIC, &last_refil);
+        available = BUCKET_MAX_SIZE;
+        started = 1;
+    }
+
+    if (count > BUCKET_MAX_SIZE) {
+        DPRINTF("tried to get %d tokens, but bucket size is %d\n",
+                BUCKET_MAX_SIZE, count);
+        exit(1);
+    }
+
+    if (available < count) {
+        /* The bucket is empty.  Refil it */
+
+        /* When will it be full enough to handle this request? */
+        delay = (double)(count - available) / BUCKET_FILL_RATE;
+        waiting_for = last_refil;
+        waiting_for.tv_sec += delay;
+        waiting_for.tv_nsec += (delay - (int)delay) * 1e9;
+        if (waiting_for.tv_nsec >= 1000000000) {
+            waiting_for.tv_nsec -= 1000000000;
+            waiting_for.tv_sec++;
+        }
+
+        /* How long do we have to wait? (might be negative) */
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        ts.tv_sec = waiting_for.tv_sec - now.tv_sec;
+        ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec;
+        if (ts.tv_nsec < 0) {
+            ts.tv_sec--;
+            ts.tv_nsec += 1000000000;
+        }
+
+        /* Wait for it. */
+        if (ts.tv_sec > 0 ||
+            (ts.tv_sec == 0 && ts.tv_nsec > 0)) {
+            if (!warned) {
+                DPRINTF("throttling guest access to syslog");
+                warned = 1;
+            }
+            while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
+                ;
+        }
+
+        /* Refil */
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        delay = (now.tv_sec - last_refil.tv_sec) +
+            (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9;
+        available += BUCKET_FILL_RATE * delay;
+        if (available > BUCKET_MAX_SIZE)
+            available = BUCKET_MAX_SIZE;
+        last_refil = now;
+    }
+
+    assert(available >= count);
+
+    available -= count;
+}
+
+/* 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:
+        /* Send bytes to syslog */
+        if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+            /* Flush buffer */
+            s->log_buffer[s->log_buffer_off] = 0;
+            throttle(s, s->log_buffer_off);
+            DPRINTF("%s\n", s->log_buffer);
+            s->log_buffer_off = 0;
+            break;
+        }
+        s->log_buffer[s->log_buffer_off++] = 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:
+        {
+            if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+                /* Flush buffer */
+                s->log_buffer[s->log_buffer_off] = 0;
+                throttle(s, s->log_buffer_off);
+                DPRINTF("%s\n", s->log_buffer);
+                s->log_buffer_off = 0;
+                break;
+            }
+            s->log_buffer[s->log_buffer_off++] = 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(void *opaque, target_phys_addr_t addr)
+{
+    static int warnings = 0;
+
+    if (warnings < 5) {
+        DPRINTF("Warning: attempted read from physical address "
+                "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+        warnings++;
+    }
+    return 0;
+}
+
+static void platform_mmio_write(void *opaque, target_phys_addr_t addr,
+                                uint32_t val)
+{
+    static int warnings = 0;
+
+    if (warnings < 5) {
+        DPRINTF("Warning: attempted write of 0x%x to physical "
+                "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+                val, addr);
+        warnings++;
+    }
+}
+
+static CPUReadMemoryFunc * const platform_mmio_read_funcs[3] = {
+    platform_mmio_read,
+    platform_mmio_read,
+    platform_mmio_read,
+};
+
+static CPUWriteMemoryFunc * const platform_mmio_write_funcs[3] = {
+    platform_mmio_write,
+    platform_mmio_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(platform_mmio_read_funcs,
+                                          platform_mmio_write_funcs, NULL);
+
+    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_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_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+    /* Microsoft WHQL requires non-zero subsystem IDs. */
+    /* http://www.pcisig.com/reflector/msg02205.html.  */
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, pci_conf[PCI_VENDOR_ID]);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0001);
+
+    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/hw/xen_platform.h b/hw/xen_platform.h
new file mode 100644
index 0000000..574eecd
--- /dev/null
+++ b/hw/xen_platform.h
@@ -0,0 +1,8 @@
+#ifndef XEN_PLATFORM_H
+#define XEN_PLATFORM_H
+
+#include "hw/pci.h"
+
+void pci_xen_platform_init(PCIBus *bus);
+
+#endif
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 07/15] xen: handle xenstore events
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Add an handler to process xenstore events.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 target-xen/xenstore.c |   30 +++++++++++++++++++++++++++++-
 1 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index bd74787..331b25f 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -1,13 +1,41 @@
 #include "hw/xen_backend.h"
 #include "xenstore.h"
 
+static void xenstore_process_event(void *opaque)
+{
+    char **vec;
+    unsigned int num;
+
+    vec = xs_read_watch(xenstore, &num);
+    if (!vec)
+        return;
+
+    free(vec);
+}
+
 int xen_dm_init(void)
 {
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_process_event, NULL, NULL) < 0)
+        goto err;
+
     xen_xc = xc_interface_open(NULL, NULL, 0);
     if (xen_xc == NULL) {
         xen_be_printf(NULL, 0, "can't open xen interface\n");
-        return -1;
+        goto err;
     }
 
     return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
 }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 07/15] xen: handle xenstore events
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Add an handler to process xenstore events.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 target-xen/xenstore.c |   30 +++++++++++++++++++++++++++++-
 1 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index bd74787..331b25f 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -1,13 +1,41 @@
 #include "hw/xen_backend.h"
 #include "xenstore.h"
 
+static void xenstore_process_event(void *opaque)
+{
+    char **vec;
+    unsigned int num;
+
+    vec = xs_read_watch(xenstore, &num);
+    if (!vec)
+        return;
+
+    free(vec);
+}
+
 int xen_dm_init(void)
 {
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_process_event, NULL, NULL) < 0)
+        goto err;
+
     xen_xc = xc_interface_open(NULL, NULL, 0);
     if (xen_xc == NULL) {
         xen_be_printf(NULL, 0, "can't open xen interface\n");
-        return -1;
+        goto err;
     }
 
     return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
 }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce functions to read and write the state of the VM in xenstore.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c   |    9 ++++
 target-xen/helper.c   |    7 +++
 target-xen/qemu-xen.h |    3 +
 target-xen/xenstore.c |  127 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++
 5 files changed, 152 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 12a7723..f0c3c03 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -36,10 +36,17 @@
 #include "xen_backend.h"
 #include "xenstore.h"
 #include "xen_platform.h"
+#include "qemu-xen.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
 
+static void xen_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    if (running)
+        xen_main_loop_prepare();
+}
+
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -149,6 +156,8 @@ static void xen_init_fv(ram_addr_t ram_size,
     }
 
     pc_pci_device_init(pci_bus);
+
+    qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL);
 }
 
 static QEMUMachine xenfv_machine = {
diff --git a/target-xen/helper.c b/target-xen/helper.c
index f8512c8..b6b722b 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -19,6 +19,8 @@
  */
 
 #include "cpu.h"
+#include "qemu-xen.h"
+#include "xenstore.h"
 
 CPUXenState *cpu_xen_init(const char *cpu_model)
 {
@@ -61,3 +63,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
+
+void xen_main_loop_prepare(void)
+{
+    xenstore_record_dm_state("running");
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index d1910d6..091ae07 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -27,4 +27,7 @@ int cpu_register_io_memory_fixed(int io_index,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque);
 
+/* target-xen/helper.c */
+void xen_main_loop_prepare(void);
+
 #endif /*QEMU_XEN_H*/
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index 331b25f..6eb6a30 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -13,6 +13,60 @@ static void xenstore_process_event(void *opaque)
     free(vec);
 }
 
+static const char *xenstore_get_guest_uuid(void)
+{
+    static char *already_computed = NULL;
+
+    char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL;
+    unsigned int len;
+
+    if (already_computed)
+        return already_computed;
+
+    if (xen_xc == NULL)
+        return NULL;
+
+    domain_path = xs_get_domain_path(xenstore, xen_domid);
+    if (domain_path == NULL) {
+        fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid);
+        goto out;
+    }
+
+    if (asprintf(&vm_path, "%s/vm", domain_path) == -1) {
+        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+        goto out;
+    }
+    vm_value = xs_read(xenstore, XBT_NULL, vm_path, &len);
+    if (vm_value == NULL) {
+        fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path);
+        goto out;
+    }
+
+    if (strtok(vm_value, "/") == NULL) {
+        fprintf(stderr, "failed to parse guest uuid\n");
+        goto out;
+    }
+    p = strtok(NULL, "/");
+    if (p == NULL) {
+        fprintf(stderr, "failed to parse guest uuid\n");
+        goto out;
+    }
+
+    if (asprintf(&already_computed, "%s", p) == -1) {
+        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+        goto out;
+    }
+
+    fprintf(stderr, "Guest uuid = %s\n", already_computed);
+
+out:
+    free(domain_path);
+    free(vm_path);
+    free(vm_value);
+
+    return already_computed;
+}
+
 int xen_dm_init(void)
 {
     xenstore = xs_daemon_open();
@@ -39,3 +93,76 @@ err:
 
     return -1;
 }
+
+static char *xenstore_vm_key_path(int domid, const char *key) {
+    const char *uuid;
+    char *buf = NULL;
+
+    if (xenstore == NULL)
+        return NULL;
+
+    uuid = xenstore_get_guest_uuid();
+    if (!uuid)
+        return NULL;
+
+    if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
+        return NULL;
+
+    return buf;
+}
+
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len)
+{
+    char *path = NULL, *value = NULL;
+
+    path = xenstore_vm_key_path(domid, key);
+    if (!path)
+        return NULL;
+
+    value = xs_read(xenstore, XBT_NULL, path, len);
+    if (value == NULL) {
+        fprintf(stderr, "xs_read(%s): read error\n", path);
+    }
+
+    free(path);
+    return value;
+}
+
+int xenstore_vm_write(int domid, const char *key, const char *value)
+{
+    char *path = NULL;
+    int rc = -1;
+
+    path = xenstore_vm_key_path(domid, key);
+    if (!path)
+        return 0;
+
+    rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value));
+    if (rc == 0) {
+        fprintf(stderr, "xs_write(%s, %s): write error\n", path, key);
+    }
+
+    free(path);
+    return rc;
+}
+
+void xenstore_record_dm(const char *subpath, const char *state)
+{
+    char *path = NULL;
+
+    if (asprintf(&path,
+                 "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) {
+        fprintf(stderr, "out of memory recording dm\n");
+        goto out;
+    }
+    if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state)))
+        fprintf(stderr, "error recording dm\n");
+
+out:
+    free(path);
+}
+
+void xenstore_record_dm_state(const char *state)
+{
+    xenstore_record_dm("state", state);
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
index 90baf79..c8144ea 100644
--- a/target-xen/xenstore.h
+++ b/target-xen/xenstore.h
@@ -3,4 +3,10 @@
 
 int xen_dm_init(void);
 
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len);
+int xenstore_vm_write(int domid, const char *key, const char *value);
+
+void xenstore_record_dm(const char *subpath, const char *state);
+void xenstore_record_dm_state(const char *state);
+
 #endif /* !XENSTORE_H_ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce functions to read and write the state of the VM in xenstore.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c   |    9 ++++
 target-xen/helper.c   |    7 +++
 target-xen/qemu-xen.h |    3 +
 target-xen/xenstore.c |  127 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++
 5 files changed, 152 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 12a7723..f0c3c03 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -36,10 +36,17 @@
 #include "xen_backend.h"
 #include "xenstore.h"
 #include "xen_platform.h"
+#include "qemu-xen.h"
 #include "xen/hvm/hvm_info_table.h"
 
 #define MAX_IDE_BUS 2
 
+static void xen_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    if (running)
+        xen_main_loop_prepare();
+}
+
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -149,6 +156,8 @@ static void xen_init_fv(ram_addr_t ram_size,
     }
 
     pc_pci_device_init(pci_bus);
+
+    qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL);
 }
 
 static QEMUMachine xenfv_machine = {
diff --git a/target-xen/helper.c b/target-xen/helper.c
index f8512c8..b6b722b 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -19,6 +19,8 @@
  */
 
 #include "cpu.h"
+#include "qemu-xen.h"
+#include "xenstore.h"
 
 CPUXenState *cpu_xen_init(const char *cpu_model)
 {
@@ -61,3 +63,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
+
+void xen_main_loop_prepare(void)
+{
+    xenstore_record_dm_state("running");
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index d1910d6..091ae07 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -27,4 +27,7 @@ int cpu_register_io_memory_fixed(int io_index,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque);
 
+/* target-xen/helper.c */
+void xen_main_loop_prepare(void);
+
 #endif /*QEMU_XEN_H*/
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index 331b25f..6eb6a30 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -13,6 +13,60 @@ static void xenstore_process_event(void *opaque)
     free(vec);
 }
 
+static const char *xenstore_get_guest_uuid(void)
+{
+    static char *already_computed = NULL;
+
+    char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL;
+    unsigned int len;
+
+    if (already_computed)
+        return already_computed;
+
+    if (xen_xc == NULL)
+        return NULL;
+
+    domain_path = xs_get_domain_path(xenstore, xen_domid);
+    if (domain_path == NULL) {
+        fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid);
+        goto out;
+    }
+
+    if (asprintf(&vm_path, "%s/vm", domain_path) == -1) {
+        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+        goto out;
+    }
+    vm_value = xs_read(xenstore, XBT_NULL, vm_path, &len);
+    if (vm_value == NULL) {
+        fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path);
+        goto out;
+    }
+
+    if (strtok(vm_value, "/") == NULL) {
+        fprintf(stderr, "failed to parse guest uuid\n");
+        goto out;
+    }
+    p = strtok(NULL, "/");
+    if (p == NULL) {
+        fprintf(stderr, "failed to parse guest uuid\n");
+        goto out;
+    }
+
+    if (asprintf(&already_computed, "%s", p) == -1) {
+        fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+        goto out;
+    }
+
+    fprintf(stderr, "Guest uuid = %s\n", already_computed);
+
+out:
+    free(domain_path);
+    free(vm_path);
+    free(vm_value);
+
+    return already_computed;
+}
+
 int xen_dm_init(void)
 {
     xenstore = xs_daemon_open();
@@ -39,3 +93,76 @@ err:
 
     return -1;
 }
+
+static char *xenstore_vm_key_path(int domid, const char *key) {
+    const char *uuid;
+    char *buf = NULL;
+
+    if (xenstore == NULL)
+        return NULL;
+
+    uuid = xenstore_get_guest_uuid();
+    if (!uuid)
+        return NULL;
+
+    if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
+        return NULL;
+
+    return buf;
+}
+
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len)
+{
+    char *path = NULL, *value = NULL;
+
+    path = xenstore_vm_key_path(domid, key);
+    if (!path)
+        return NULL;
+
+    value = xs_read(xenstore, XBT_NULL, path, len);
+    if (value == NULL) {
+        fprintf(stderr, "xs_read(%s): read error\n", path);
+    }
+
+    free(path);
+    return value;
+}
+
+int xenstore_vm_write(int domid, const char *key, const char *value)
+{
+    char *path = NULL;
+    int rc = -1;
+
+    path = xenstore_vm_key_path(domid, key);
+    if (!path)
+        return 0;
+
+    rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value));
+    if (rc == 0) {
+        fprintf(stderr, "xs_write(%s, %s): write error\n", path, key);
+    }
+
+    free(path);
+    return rc;
+}
+
+void xenstore_record_dm(const char *subpath, const char *state)
+{
+    char *path = NULL;
+
+    if (asprintf(&path,
+                 "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) {
+        fprintf(stderr, "out of memory recording dm\n");
+        goto out;
+    }
+    if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state)))
+        fprintf(stderr, "error recording dm\n");
+
+out:
+    free(path);
+}
+
+void xenstore_record_dm_state(const char *state)
+{
+    xenstore_record_dm("state", state);
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
index 90baf79..c8144ea 100644
--- a/target-xen/xenstore.h
+++ b/target-xen/xenstore.h
@@ -3,4 +3,10 @@
 
 int xen_dm_init(void);
 
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len);
+int xenstore_vm_write(int domid, const char *key, const char *value);
+
+void xenstore_record_dm(const char *subpath, const char *state);
+void xenstore_record_dm_state(const char *state);
+
 #endif /* !XENSTORE_H_ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Open and bind event channels; map ioreq and buffered ioreq rings.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c   |   21 +++
 target-xen/cpu.h      |    6 +
 target-xen/helper.c   |  339 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/qemu-xen.h |    2 +
 4 files changed, 368 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index f0c3c03..bcf1101 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -22,6 +22,9 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "config.h"
+
+#include <sys/mman.h>
 
 #include "hw.h"
 #include "pc.h"
@@ -71,12 +74,30 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     CPUState *env;
 
+    unsigned long ioreq_pfn;
+
     /* Initialize backend core & drivers */
     if (xen_dm_init() != 0) {
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         exit(1);
     }
 
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
+    fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn);
+    shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+            PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (shared_page == NULL) {
+        hw_error("map shared IO page returned error %d handle=%p", errno, xen_xc);
+    }
+
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn);
+    fprintf(stderr, "buffered io page at pfn %lx\n", ioreq_pfn);
+    buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+                                            PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (buffered_io_page == NULL) {
+        hw_error("map buffered IO page returned error %d", errno);
+    }
+
     /* Initialize a dummy CPU */
     if (cpu_model == NULL) {
 #ifdef TARGET_X86_64
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
index 0e08ab3..26896e1 100644
--- a/target-xen/cpu.h
+++ b/target-xen/cpu.h
@@ -68,6 +68,7 @@ typedef struct CPUXenState {
 
 CPUXenState *cpu_xen_init(const char *cpu_model);
 int cpu_xen_exec(CPUXenState *s);
+void cpu_xen_close(CPUXenState *s);
 
 int cpu_get_pic_interrupt(CPUXenState *s);
 void cpu_set_ferr(CPUX86State *s);
@@ -113,4 +114,9 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 {
 }
 
+#include <xen/hvm/ioreq.h>
+
+extern shared_iopage_t *shared_page;
+extern buffered_iopage_t *buffered_io_page;
+
 #endif /* CPU_XEN_H */
diff --git a/target-xen/helper.c b/target-xen/helper.c
index b6b722b..c4339ce 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -18,23 +18,73 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "config.h"
+
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xen/hvm/ioreq.h>
+
 #include "cpu.h"
 #include "qemu-xen.h"
 #include "xenstore.h"
+#include "hw/xen_backend.h"
+
+long time_offset = 0;
+
+shared_iopage_t *shared_page = NULL;
+
+#define BUFFER_IO_MAX_DELAY  100
+buffered_iopage_t *buffered_io_page = NULL;
+QEMUTimer *buffered_io_timer;
+
+/* the evtchn fd for polling */
+int xce_handle = -1;
+
+/* which vcpu we are serving */
+int send_vcpu = 0;
+
+/* the evtchn port for polling the notification, */
+evtchn_port_t *ioreq_local_port;
 
 CPUXenState *cpu_xen_init(const char *cpu_model)
 {
     CPUXenState *env = NULL;
     static int inited;
+    int i, rc;
 
     env = qemu_mallocz(sizeof(CPUXenState));
     cpu_exec_init(env);
 
+    /* There is no shared_page for PV, we're done now */
+    if (shared_page == NULL)
+        return env;
+
+    ioreq_local_port =
+        (evtchn_port_t *)qemu_mallocz(smp_cpus * sizeof(evtchn_port_t));
+
     /* init various static tables */
     if (!inited) {
         inited = 1;
 
         cpu_single_env = env;
+
+        xce_handle = xc_evtchn_open();
+        if (xce_handle == -1) {
+            perror("open");
+            return NULL;
+        }
+
+        /* FIXME: how about if we overflow the page here? */
+        for (i = 0; i < smp_cpus; i++) {
+            rc = xc_evtchn_bind_interdomain(
+                    xce_handle, xen_domid, shared_page->vcpu_ioreq[i].vp_eport);
+            if (rc == -1) {
+                fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+                return NULL;
+            }
+            ioreq_local_port[i] = rc;
+        }
     }
 
     return env;
@@ -64,7 +114,296 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     return addr;
 }
 
+/* get the ioreq packets from share mem */
+static ioreq_t *cpu_get_ioreq_from_shared_memory(int vcpu)
+{
+    ioreq_t *req = &shared_page->vcpu_ioreq[vcpu];
+
+    if (req->state != STATE_IOREQ_READY) {
+        fprintf(stderr, "I/O request not ready: "
+                "%x, ptr: %x, port: %"PRIx64", "
+                "data: %"PRIx64", count: %u, size: %u\n",
+                req->state, req->data_is_ptr, req->addr,
+                req->data, req->count, req->size);
+        return NULL;
+    }
+
+    xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
+
+    req->state = STATE_IOREQ_INPROCESS;
+    return req;
+}
+
+/* use poll to get the port notification */
+/* ioreq_vec--out,the */
+/* retval--the number of ioreq packet */
+static ioreq_t *cpu_get_ioreq(void)
+{
+    int i;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xce_handle);
+    if (port != -1) {
+        for ( i = 0; i < smp_cpus; i++ )
+            if ( ioreq_local_port[i] == port )
+                break;
+
+        if ( i == smp_cpus ) {
+            fprintf(stderr, "Fatal error while trying to get io event!\n");
+            exit(1);
+        }
+
+        /* unmask the wanted port again */
+        xc_evtchn_unmask(xce_handle, port);
+
+        /* get the io packet from shared memory */
+        send_vcpu = i;
+        return cpu_get_ioreq_from_shared_memory(i);
+    }
+
+    /* read error or read nothing */
+    return NULL;
+}
+
+static uint32_t do_inp(CPUState *env, pio_addr_t addr, unsigned long size)
+{
+    switch(size) {
+        case 1:
+            return cpu_inb(addr);
+        case 2:
+            return cpu_inw(addr);
+        case 4:
+            return cpu_inl(addr);
+        default:
+            hw_error("inp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void do_outp(CPUState *env, pio_addr_t addr,
+        unsigned long size, uint32_t val)
+{
+    switch(size) {
+        case 1:
+            return cpu_outb(addr, val);
+        case 2:
+            return cpu_outw(addr, val);
+        case 4:
+            return cpu_outl(addr, val);
+        default:
+            hw_error("outp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void cpu_ioreq_pio(CPUState *env, ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (req->dir == IOREQ_READ) {
+        if (!req->data_is_ptr) {
+            req->data = do_inp(env, req->addr, req->size);
+        } else {
+            uint32_t tmp;
+
+            for (i = 0; i < req->count; i++) {
+                tmp = do_inp(env, req->addr, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        }
+    } else if (req->dir == IOREQ_WRITE) {
+        if (!req->data_is_ptr) {
+            do_outp(env, req->addr, req->size, req->data);
+        } else {
+            for (i = 0; i < req->count; i++) {
+                uint32_t tmp = 0;
+
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                do_outp(env, req->addr, req->size, tmp);
+            }
+        }
+    }
+}
+
+static void cpu_ioreq_move(CPUState *env, ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (!req->data_is_ptr) {
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t*) &req->data, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t*) &req->data, req->size);
+            }
+        }
+    } else {
+        target_ulong tmp;
+
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        }
+    }
+}
+
+static void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req)
+{
+    char b[64];
+
+    time_offset += (unsigned long)req->data;
+
+    fprintf(stderr, "Time offset set %ld, added offset %"PRId64"\n",
+            time_offset, req->data);
+    snprintf(b, 64, "%ld", time_offset);
+    xenstore_vm_write(xen_domid, "rtc/timeoffset", b);
+}
+
+static void handle_ioreq(CPUState *env, ioreq_t *req)
+{
+    if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
+            (req->size < sizeof(target_ulong)))
+        req->data &= ((target_ulong)1 << (8 * req->size)) - 1;
+
+    switch (req->type) {
+        case IOREQ_TYPE_PIO:
+            cpu_ioreq_pio(env, req);
+            break;
+        case IOREQ_TYPE_COPY:
+            cpu_ioreq_move(env, req);
+            break;
+        case IOREQ_TYPE_TIMEOFFSET:
+            cpu_ioreq_timeoffset(env, req);
+            break;
+        case IOREQ_TYPE_INVALIDATE:
+            qemu_invalidate_map_cache();
+            break;
+        default:
+            hw_error("Invalid ioreq type 0x%x\n", req->type);
+    }
+}
+
+static void handle_buffered_iopage(CPUState *env)
+{
+    buf_ioreq_t *buf_req = NULL;
+    ioreq_t req;
+    int qw;
+
+    if (!buffered_io_page)
+        return;
+
+    while (buffered_io_page->read_pointer !=
+            buffered_io_page->write_pointer) {
+        buf_req = &buffered_io_page->buf_ioreq[
+            buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
+        req.size = 1UL << buf_req->size;
+        req.count = 1;
+        req.addr = buf_req->addr;
+        req.data = buf_req->data;
+        req.state = STATE_IOREQ_READY;
+        req.dir = buf_req->dir;
+        req.df = 1;
+        req.type = buf_req->type;
+        req.data_is_ptr = 0;
+        qw = (req.size == 8);
+        if (qw) {
+            buf_req = &buffered_io_page->buf_ioreq[
+                (buffered_io_page->read_pointer+1) % IOREQ_BUFFER_SLOT_NUM];
+            req.data |= ((uint64_t)buf_req->data) << 32;
+        }
+
+        handle_ioreq(env, &req);
+
+        xen_mb();
+        buffered_io_page->read_pointer += qw ? 2 : 1;
+    }
+}
+
+static void handle_buffered_io(void *opaque)
+{
+    CPUState *env = opaque;
+
+    handle_buffered_iopage(env);
+    qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY +
+                   qemu_get_clock(rt_clock));
+}
+
+static void cpu_handle_ioreq(void *opaque)
+{
+    CPUState *env = opaque;
+    ioreq_t *req = cpu_get_ioreq();
+
+    handle_buffered_iopage(env);
+    if (req) {
+        handle_ioreq(env, req);
+
+        if (req->state != STATE_IOREQ_INPROCESS) {
+            fprintf(stderr, "Badness in I/O request ... not in service?!: "
+                    "%x, ptr: %x, port: %"PRIx64", "
+                    "data: %"PRIx64", count: %u, size: %u\n",
+                    req->state, req->data_is_ptr, req->addr,
+                    req->data, req->count, req->size);
+            destroy_hvm_domain();
+            return;
+        }
+
+        xen_wmb(); /* Update ioreq contents /then/ update state. */
+
+        req->state = STATE_IORESP_READY;
+        xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
+    }
+}
+
 void xen_main_loop_prepare(void)
 {
+    CPUState *env = cpu_single_env;
+
+    int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle);
+
+    buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io,
+                                       cpu_single_env);
+    qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock));
+
+    if (evtchn_fd != -1)
+        qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env);
+
     xenstore_record_dm_state("running");
 }
+
+void destroy_hvm_domain(void)
+{
+    xc_interface *xc_handle;
+    int sts;
+
+    xc_handle = xc_interface_open(NULL, NULL, 0);
+    if (!xc_handle)
+        fprintf(stderr, "Cannot acquire xenctrl handle\n");
+    else {
+        sts = xc_domain_shutdown(xc_handle, xen_domid, SHUTDOWN_poweroff);
+        if (sts != 0)
+            fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, "
+                    "sts %d, errno %d\n", sts, errno);
+        else
+            fprintf(stderr, "Issued domain %d poweroff\n", xen_domid);
+        xc_interface_close(xc_handle);
+    }
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index 091ae07..79a4638 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -22,12 +22,14 @@ void     qemu_invalidate_map_cache(void);
 
 /* target-xen/exec-dm.c */
 
+void destroy_hvm_domain(void);
 int cpu_register_io_memory_fixed(int io_index,
                            CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque);
 
 /* target-xen/helper.c */
+extern int xce_handle;
 void xen_main_loop_prepare(void);
 
 #endif /*QEMU_XEN_H*/
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 09/15] xen: Initialize event channels and io rings
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Open and bind event channels; map ioreq and buffered ioreq rings.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c   |   21 +++
 target-xen/cpu.h      |    6 +
 target-xen/helper.c   |  339 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/qemu-xen.h |    2 +
 4 files changed, 368 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index f0c3c03..bcf1101 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -22,6 +22,9 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "config.h"
+
+#include <sys/mman.h>
 
 #include "hw.h"
 #include "pc.h"
@@ -71,12 +74,30 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     CPUState *env;
 
+    unsigned long ioreq_pfn;
+
     /* Initialize backend core & drivers */
     if (xen_dm_init() != 0) {
         fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
         exit(1);
     }
 
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
+    fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn);
+    shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+            PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (shared_page == NULL) {
+        hw_error("map shared IO page returned error %d handle=%p", errno, xen_xc);
+    }
+
+    xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn);
+    fprintf(stderr, "buffered io page at pfn %lx\n", ioreq_pfn);
+    buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+                                            PROT_READ|PROT_WRITE, ioreq_pfn);
+    if (buffered_io_page == NULL) {
+        hw_error("map buffered IO page returned error %d", errno);
+    }
+
     /* Initialize a dummy CPU */
     if (cpu_model == NULL) {
 #ifdef TARGET_X86_64
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
index 0e08ab3..26896e1 100644
--- a/target-xen/cpu.h
+++ b/target-xen/cpu.h
@@ -68,6 +68,7 @@ typedef struct CPUXenState {
 
 CPUXenState *cpu_xen_init(const char *cpu_model);
 int cpu_xen_exec(CPUXenState *s);
+void cpu_xen_close(CPUXenState *s);
 
 int cpu_get_pic_interrupt(CPUXenState *s);
 void cpu_set_ferr(CPUX86State *s);
@@ -113,4 +114,9 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 {
 }
 
+#include <xen/hvm/ioreq.h>
+
+extern shared_iopage_t *shared_page;
+extern buffered_iopage_t *buffered_io_page;
+
 #endif /* CPU_XEN_H */
diff --git a/target-xen/helper.c b/target-xen/helper.c
index b6b722b..c4339ce 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -18,23 +18,73 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "config.h"
+
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xen/hvm/ioreq.h>
+
 #include "cpu.h"
 #include "qemu-xen.h"
 #include "xenstore.h"
+#include "hw/xen_backend.h"
+
+long time_offset = 0;
+
+shared_iopage_t *shared_page = NULL;
+
+#define BUFFER_IO_MAX_DELAY  100
+buffered_iopage_t *buffered_io_page = NULL;
+QEMUTimer *buffered_io_timer;
+
+/* the evtchn fd for polling */
+int xce_handle = -1;
+
+/* which vcpu we are serving */
+int send_vcpu = 0;
+
+/* the evtchn port for polling the notification, */
+evtchn_port_t *ioreq_local_port;
 
 CPUXenState *cpu_xen_init(const char *cpu_model)
 {
     CPUXenState *env = NULL;
     static int inited;
+    int i, rc;
 
     env = qemu_mallocz(sizeof(CPUXenState));
     cpu_exec_init(env);
 
+    /* There is no shared_page for PV, we're done now */
+    if (shared_page == NULL)
+        return env;
+
+    ioreq_local_port =
+        (evtchn_port_t *)qemu_mallocz(smp_cpus * sizeof(evtchn_port_t));
+
     /* init various static tables */
     if (!inited) {
         inited = 1;
 
         cpu_single_env = env;
+
+        xce_handle = xc_evtchn_open();
+        if (xce_handle == -1) {
+            perror("open");
+            return NULL;
+        }
+
+        /* FIXME: how about if we overflow the page here? */
+        for (i = 0; i < smp_cpus; i++) {
+            rc = xc_evtchn_bind_interdomain(
+                    xce_handle, xen_domid, shared_page->vcpu_ioreq[i].vp_eport);
+            if (rc == -1) {
+                fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+                return NULL;
+            }
+            ioreq_local_port[i] = rc;
+        }
     }
 
     return env;
@@ -64,7 +114,296 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     return addr;
 }
 
+/* get the ioreq packets from share mem */
+static ioreq_t *cpu_get_ioreq_from_shared_memory(int vcpu)
+{
+    ioreq_t *req = &shared_page->vcpu_ioreq[vcpu];
+
+    if (req->state != STATE_IOREQ_READY) {
+        fprintf(stderr, "I/O request not ready: "
+                "%x, ptr: %x, port: %"PRIx64", "
+                "data: %"PRIx64", count: %u, size: %u\n",
+                req->state, req->data_is_ptr, req->addr,
+                req->data, req->count, req->size);
+        return NULL;
+    }
+
+    xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
+
+    req->state = STATE_IOREQ_INPROCESS;
+    return req;
+}
+
+/* use poll to get the port notification */
+/* ioreq_vec--out,the */
+/* retval--the number of ioreq packet */
+static ioreq_t *cpu_get_ioreq(void)
+{
+    int i;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xce_handle);
+    if (port != -1) {
+        for ( i = 0; i < smp_cpus; i++ )
+            if ( ioreq_local_port[i] == port )
+                break;
+
+        if ( i == smp_cpus ) {
+            fprintf(stderr, "Fatal error while trying to get io event!\n");
+            exit(1);
+        }
+
+        /* unmask the wanted port again */
+        xc_evtchn_unmask(xce_handle, port);
+
+        /* get the io packet from shared memory */
+        send_vcpu = i;
+        return cpu_get_ioreq_from_shared_memory(i);
+    }
+
+    /* read error or read nothing */
+    return NULL;
+}
+
+static uint32_t do_inp(CPUState *env, pio_addr_t addr, unsigned long size)
+{
+    switch(size) {
+        case 1:
+            return cpu_inb(addr);
+        case 2:
+            return cpu_inw(addr);
+        case 4:
+            return cpu_inl(addr);
+        default:
+            hw_error("inp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void do_outp(CPUState *env, pio_addr_t addr,
+        unsigned long size, uint32_t val)
+{
+    switch(size) {
+        case 1:
+            return cpu_outb(addr, val);
+        case 2:
+            return cpu_outw(addr, val);
+        case 4:
+            return cpu_outl(addr, val);
+        default:
+            hw_error("outp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+    }
+}
+
+static void cpu_ioreq_pio(CPUState *env, ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (req->dir == IOREQ_READ) {
+        if (!req->data_is_ptr) {
+            req->data = do_inp(env, req->addr, req->size);
+        } else {
+            uint32_t tmp;
+
+            for (i = 0; i < req->count; i++) {
+                tmp = do_inp(env, req->addr, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        }
+    } else if (req->dir == IOREQ_WRITE) {
+        if (!req->data_is_ptr) {
+            do_outp(env, req->addr, req->size, req->data);
+        } else {
+            for (i = 0; i < req->count; i++) {
+                uint32_t tmp = 0;
+
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                do_outp(env, req->addr, req->size, tmp);
+            }
+        }
+    }
+}
+
+static void cpu_ioreq_move(CPUState *env, ioreq_t *req)
+{
+    int i, sign;
+
+    sign = req->df ? -1 : 1;
+
+    if (!req->data_is_ptr) {
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t*) &req->data, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t*) &req->data, req->size);
+            }
+        }
+    } else {
+        target_ulong tmp;
+
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                cpu_physical_memory_read(req->data + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+                cpu_physical_memory_write(req->addr + (sign * i * req->size),
+                        (uint8_t*) &tmp, req->size);
+            }
+        }
+    }
+}
+
+static void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req)
+{
+    char b[64];
+
+    time_offset += (unsigned long)req->data;
+
+    fprintf(stderr, "Time offset set %ld, added offset %"PRId64"\n",
+            time_offset, req->data);
+    snprintf(b, 64, "%ld", time_offset);
+    xenstore_vm_write(xen_domid, "rtc/timeoffset", b);
+}
+
+static void handle_ioreq(CPUState *env, ioreq_t *req)
+{
+    if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
+            (req->size < sizeof(target_ulong)))
+        req->data &= ((target_ulong)1 << (8 * req->size)) - 1;
+
+    switch (req->type) {
+        case IOREQ_TYPE_PIO:
+            cpu_ioreq_pio(env, req);
+            break;
+        case IOREQ_TYPE_COPY:
+            cpu_ioreq_move(env, req);
+            break;
+        case IOREQ_TYPE_TIMEOFFSET:
+            cpu_ioreq_timeoffset(env, req);
+            break;
+        case IOREQ_TYPE_INVALIDATE:
+            qemu_invalidate_map_cache();
+            break;
+        default:
+            hw_error("Invalid ioreq type 0x%x\n", req->type);
+    }
+}
+
+static void handle_buffered_iopage(CPUState *env)
+{
+    buf_ioreq_t *buf_req = NULL;
+    ioreq_t req;
+    int qw;
+
+    if (!buffered_io_page)
+        return;
+
+    while (buffered_io_page->read_pointer !=
+            buffered_io_page->write_pointer) {
+        buf_req = &buffered_io_page->buf_ioreq[
+            buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
+        req.size = 1UL << buf_req->size;
+        req.count = 1;
+        req.addr = buf_req->addr;
+        req.data = buf_req->data;
+        req.state = STATE_IOREQ_READY;
+        req.dir = buf_req->dir;
+        req.df = 1;
+        req.type = buf_req->type;
+        req.data_is_ptr = 0;
+        qw = (req.size == 8);
+        if (qw) {
+            buf_req = &buffered_io_page->buf_ioreq[
+                (buffered_io_page->read_pointer+1) % IOREQ_BUFFER_SLOT_NUM];
+            req.data |= ((uint64_t)buf_req->data) << 32;
+        }
+
+        handle_ioreq(env, &req);
+
+        xen_mb();
+        buffered_io_page->read_pointer += qw ? 2 : 1;
+    }
+}
+
+static void handle_buffered_io(void *opaque)
+{
+    CPUState *env = opaque;
+
+    handle_buffered_iopage(env);
+    qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY +
+                   qemu_get_clock(rt_clock));
+}
+
+static void cpu_handle_ioreq(void *opaque)
+{
+    CPUState *env = opaque;
+    ioreq_t *req = cpu_get_ioreq();
+
+    handle_buffered_iopage(env);
+    if (req) {
+        handle_ioreq(env, req);
+
+        if (req->state != STATE_IOREQ_INPROCESS) {
+            fprintf(stderr, "Badness in I/O request ... not in service?!: "
+                    "%x, ptr: %x, port: %"PRIx64", "
+                    "data: %"PRIx64", count: %u, size: %u\n",
+                    req->state, req->data_is_ptr, req->addr,
+                    req->data, req->count, req->size);
+            destroy_hvm_domain();
+            return;
+        }
+
+        xen_wmb(); /* Update ioreq contents /then/ update state. */
+
+        req->state = STATE_IORESP_READY;
+        xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
+    }
+}
+
 void xen_main_loop_prepare(void)
 {
+    CPUState *env = cpu_single_env;
+
+    int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle);
+
+    buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io,
+                                       cpu_single_env);
+    qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock));
+
+    if (evtchn_fd != -1)
+        qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env);
+
     xenstore_record_dm_state("running");
 }
+
+void destroy_hvm_domain(void)
+{
+    xc_interface *xc_handle;
+    int sts;
+
+    xc_handle = xc_interface_open(NULL, NULL, 0);
+    if (!xc_handle)
+        fprintf(stderr, "Cannot acquire xenctrl handle\n");
+    else {
+        sts = xc_domain_shutdown(xc_handle, xen_domid, SHUTDOWN_poweroff);
+        if (sts != 0)
+            fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, "
+                    "sts %d, errno %d\n", sts, errno);
+        else
+            fprintf(stderr, "Issued domain %d poweroff\n", xen_domid);
+        xc_interface_close(xc_handle);
+    }
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index 091ae07..79a4638 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -22,12 +22,14 @@ void     qemu_invalidate_map_cache(void);
 
 /* target-xen/exec-dm.c */
 
+void destroy_hvm_domain(void);
 int cpu_register_io_memory_fixed(int io_index,
                            CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque);
 
 /* target-xen/helper.c */
+extern int xce_handle;
 void xen_main_loop_prepare(void);
 
 #endif /*QEMU_XEN_H*/
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce a mapcache to handle the 64bit address space of the guest
from a 32bit userland process (Qemu).
The mapcache maps chucks of guest memory on demand, unmaps them when
they are not needed anymore.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c       |    7 ++
 target-xen/qemu-xen.h     |   15 +++
 target-xen/xen_mapcache.c |  247 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index bcf1101..cb40d22 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -82,6 +82,13 @@ static void xen_init_fv(ram_addr_t ram_size,
         exit(1);
     }
 
+#if defined(__i386__) || defined(__x86_64__)
+    if (qemu_map_cache_init()) {
+        fprintf(stderr, "qemu_map_cache_init returned: error %d\n", errno);
+        exit(-1);
+    }
+#endif
+
     xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
     fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn);
     shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index 79a4638..e4a7030 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -13,6 +13,21 @@
 
 /* xen_mapcache.c */
 
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(QEMU_TOOL)
+#define MAPCACHE
+
+#if defined(__i386__)
+#define MAX_MCACHE_SIZE    0x40000000 /* 1GB max for x86 */
+#define MCACHE_BUCKET_SHIFT 16
+#elif defined(__x86_64__)
+#define MAX_MCACHE_SIZE    0x1000000000 /* 64GB max for x86_64 */
+#define MCACHE_BUCKET_SHIFT 20
+#endif
+
+#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
+#endif
+
+int qemu_map_cache_init(void);
 uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
 void     qemu_invalidate_entry(uint8_t *buffer);
 void     qemu_invalidate_map_cache(void);
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
index 39daae2..5baaeb9 100644
--- a/target-xen/xen_mapcache.c
+++ b/target-xen/xen_mapcache.c
@@ -1,5 +1,251 @@
+#include "config.h"
+
+#include "hw/xen_backend.h"
 #include "qemu-xen.h"
 
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
+} while (0)
+
+#if defined(MAPCACHE)
+
+#define BITS_PER_LONG (sizeof(long)*8)
+#define BITS_TO_LONGS(bits) \
+    (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+    unsigned long name[BITS_TO_LONGS(bits)]
+#define test_bit(bit,map) \
+    (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG))))
+
+typedef struct MapCacheEntry {
+    unsigned long paddr_index;
+    uint8_t *vaddr_base;
+    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
+    uint8_t lock;
+    struct MapCacheEntry *next;
+} MapCacheEntry;
+
+typedef struct MapCacheRev {
+    uint8_t *vaddr_req;
+    unsigned long paddr_index;
+    QTAILQ_ENTRY(MapCacheRev) next;
+} MapCacheRev;
+
+typedef struct MapCache {
+    MapCacheEntry *entry;
+    unsigned long nr_buckets;
+    QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
+
+    /* For most cases (>99.9%), the page address is the same. */
+    unsigned long last_address_index;
+    uint8_t      *last_address_vaddr;
+} MapCache;
+
+static MapCache *mapcache;
+
+
+int qemu_map_cache_init(void)
+{
+    unsigned long size;
+
+    mapcache = qemu_mallocz(sizeof (MapCache));
+
+    QTAILQ_INIT(&mapcache->locked_entries);
+    mapcache->last_address_index = ~0UL;
+
+    mapcache->nr_buckets = (((MAX_MCACHE_SIZE >> XC_PAGE_SHIFT) +
+                   (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
+                  (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
+
+    /*
+     * Use mmap() directly: lets us allocate a big hash table with no up-front
+     * cost in storage space. The OS will allocate memory only for the buckets
+     * that we actually use. All others will contain all zeroes.
+     */
+    size = mapcache->nr_buckets * sizeof(MapCacheEntry);
+    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+    DPRINTF("qemu_map_cache_init, nr_buckets = %lx size %lu\n", mapcache->nr_buckets, size);
+    mapcache->entry = mmap(NULL, size, PROT_READ|PROT_WRITE,
+                          MAP_SHARED|MAP_ANON, -1, 0);
+    if (mapcache->entry == MAP_FAILED) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    return 0;
+}
+
+static void qemu_remap_bucket(MapCacheEntry *entry,
+                              unsigned long address_index)
+{
+    uint8_t *vaddr_base;
+    xen_pfn_t pfns[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT];
+    int err[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT];
+    unsigned int i, j;
+
+    if (entry->vaddr_base != NULL) {
+        errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+        if (errno) {
+            fprintf(stderr, "unmap fails %d\n", errno);
+            exit(-1);
+        }
+    }
+
+    for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i++) {
+        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
+    }
+
+    vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE,
+                                     pfns, err,
+                                     MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT);
+    if (vaddr_base == NULL) {
+        fprintf(stderr, "xc_map_foreign_bulk error %d\n", errno);
+        exit(-1);
+    }
+
+    entry->vaddr_base  = vaddr_base;
+    entry->paddr_index = address_index;
+
+    for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i += BITS_PER_LONG) {
+        unsigned long word = 0;
+        j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT)) ?
+            (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG;
+        while (j > 0) {
+            word = (word << 1) | !err[i + --j];
+        }
+        entry->valid_mapping[i / BITS_PER_LONG] = word;
+    }
+}
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+    MapCacheEntry *entry, *pentry = NULL;
+    unsigned long address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
+    unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1);
+
+    if (address_index == mapcache->last_address_index && !lock)
+        return mapcache->last_address_vaddr + address_offset;
+
+    entry = &mapcache->entry[address_index % mapcache->nr_buckets];
+
+    while (entry && entry->lock && entry->paddr_index != address_index && entry->vaddr_base) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        entry = qemu_mallocz(sizeof(MapCacheEntry));
+        pentry->next = entry;
+        qemu_remap_bucket(entry, address_index);
+    } else if (!entry->lock) {
+        if (!entry->vaddr_base || entry->paddr_index != address_index || !test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping))
+            qemu_remap_bucket(entry, address_index);
+    }
+
+    if (!test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) {
+        mapcache->last_address_index = ~0UL;
+        return NULL;
+    }
+
+    mapcache->last_address_index = address_index;
+    mapcache->last_address_vaddr = entry->vaddr_base;
+    if (lock) {
+        MapCacheRev *reventry = qemu_mallocz(sizeof(MapCacheRev));
+        entry->lock++;
+        reventry->vaddr_req = mapcache->last_address_vaddr + address_offset;
+        reventry->paddr_index = mapcache->last_address_index;
+        QTAILQ_INSERT_TAIL(&mapcache->locked_entries, reventry, next);
+    }
+
+    return mapcache->last_address_vaddr + address_offset;
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+    MapCacheEntry *entry = NULL, *pentry = NULL;
+    MapCacheRev *reventry;
+    unsigned long paddr_index;
+    int found = 0;
+
+    if (mapcache->last_address_vaddr == buffer)
+        mapcache->last_address_index =  ~0UL;
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        if (reventry->vaddr_req == buffer) {
+            paddr_index = reventry->paddr_index;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        DPRINTF("qemu_invalidate_entry, could not find %p\n", buffer);
+        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+            DPRINTF("   %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+        }
+        return;
+    }
+    QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
+    qemu_free(reventry);
+
+    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+    while (entry && entry->paddr_index != paddr_index) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
+        return;
+    }
+    entry->lock--;
+    if (entry->lock > 0 || pentry == NULL)
+        return;
+
+    pentry->next = entry->next;
+    errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+    if (errno) {
+        fprintf(stderr, "unmap fails %d\n", errno);
+        exit(-1);
+    }
+    qemu_free(entry);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+    unsigned long i;
+    MapCacheRev *reventry;
+
+    qemu_aio_flush();
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        DPRINTF("There should be no locked mappings at this time, but %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+    }
+
+    mapcache_lock();
+
+    for (i = 0; i < mapcache->nr_buckets; i++) {
+        MapCacheEntry *entry = &mapcache->entry[i];
+
+        if (entry->vaddr_base == NULL)
+            continue;
+
+        errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+        if (errno) {
+            fprintf(stderr, "unmap fails %d\n", errno);
+            exit(-1);
+        }
+
+        entry->paddr_index = 0;
+        entry->vaddr_base  = NULL;
+    }
+
+    mapcache->last_address_index =  ~0UL;
+    mapcache->last_address_vaddr = NULL;
+
+    mapcache_unlock();
+}
+#else
 uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
 {
     return phys_ram_addr(phys_addr);
@@ -12,3 +258,4 @@ void qemu_invalidate_map_cache(void)
 void qemu_invalidate_entry(uint8_t *buffer)
 {
 }
+#endif /* !MAPCACHE */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 10/15] xen: Introduce the Xen mapcache
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce a mapcache to handle the 64bit address space of the guest
from a 32bit userland process (Qemu).
The mapcache maps chucks of guest memory on demand, unmaps them when
they are not needed anymore.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/xen_machine_fv.c       |    7 ++
 target-xen/qemu-xen.h     |   15 +++
 target-xen/xen_mapcache.c |  247 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index bcf1101..cb40d22 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -82,6 +82,13 @@ static void xen_init_fv(ram_addr_t ram_size,
         exit(1);
     }
 
+#if defined(__i386__) || defined(__x86_64__)
+    if (qemu_map_cache_init()) {
+        fprintf(stderr, "qemu_map_cache_init returned: error %d\n", errno);
+        exit(-1);
+    }
+#endif
+
     xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
     fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn);
     shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index 79a4638..e4a7030 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -13,6 +13,21 @@
 
 /* xen_mapcache.c */
 
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(QEMU_TOOL)
+#define MAPCACHE
+
+#if defined(__i386__)
+#define MAX_MCACHE_SIZE    0x40000000 /* 1GB max for x86 */
+#define MCACHE_BUCKET_SHIFT 16
+#elif defined(__x86_64__)
+#define MAX_MCACHE_SIZE    0x1000000000 /* 64GB max for x86_64 */
+#define MCACHE_BUCKET_SHIFT 20
+#endif
+
+#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
+#endif
+
+int qemu_map_cache_init(void);
 uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
 void     qemu_invalidate_entry(uint8_t *buffer);
 void     qemu_invalidate_map_cache(void);
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
index 39daae2..5baaeb9 100644
--- a/target-xen/xen_mapcache.c
+++ b/target-xen/xen_mapcache.c
@@ -1,5 +1,251 @@
+#include "config.h"
+
+#include "hw/xen_backend.h"
 #include "qemu-xen.h"
 
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
+} while (0)
+
+#if defined(MAPCACHE)
+
+#define BITS_PER_LONG (sizeof(long)*8)
+#define BITS_TO_LONGS(bits) \
+    (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+    unsigned long name[BITS_TO_LONGS(bits)]
+#define test_bit(bit,map) \
+    (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG))))
+
+typedef struct MapCacheEntry {
+    unsigned long paddr_index;
+    uint8_t *vaddr_base;
+    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
+    uint8_t lock;
+    struct MapCacheEntry *next;
+} MapCacheEntry;
+
+typedef struct MapCacheRev {
+    uint8_t *vaddr_req;
+    unsigned long paddr_index;
+    QTAILQ_ENTRY(MapCacheRev) next;
+} MapCacheRev;
+
+typedef struct MapCache {
+    MapCacheEntry *entry;
+    unsigned long nr_buckets;
+    QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
+
+    /* For most cases (>99.9%), the page address is the same. */
+    unsigned long last_address_index;
+    uint8_t      *last_address_vaddr;
+} MapCache;
+
+static MapCache *mapcache;
+
+
+int qemu_map_cache_init(void)
+{
+    unsigned long size;
+
+    mapcache = qemu_mallocz(sizeof (MapCache));
+
+    QTAILQ_INIT(&mapcache->locked_entries);
+    mapcache->last_address_index = ~0UL;
+
+    mapcache->nr_buckets = (((MAX_MCACHE_SIZE >> XC_PAGE_SHIFT) +
+                   (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
+                  (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
+
+    /*
+     * Use mmap() directly: lets us allocate a big hash table with no up-front
+     * cost in storage space. The OS will allocate memory only for the buckets
+     * that we actually use. All others will contain all zeroes.
+     */
+    size = mapcache->nr_buckets * sizeof(MapCacheEntry);
+    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+    DPRINTF("qemu_map_cache_init, nr_buckets = %lx size %lu\n", mapcache->nr_buckets, size);
+    mapcache->entry = mmap(NULL, size, PROT_READ|PROT_WRITE,
+                          MAP_SHARED|MAP_ANON, -1, 0);
+    if (mapcache->entry == MAP_FAILED) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    return 0;
+}
+
+static void qemu_remap_bucket(MapCacheEntry *entry,
+                              unsigned long address_index)
+{
+    uint8_t *vaddr_base;
+    xen_pfn_t pfns[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT];
+    int err[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT];
+    unsigned int i, j;
+
+    if (entry->vaddr_base != NULL) {
+        errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+        if (errno) {
+            fprintf(stderr, "unmap fails %d\n", errno);
+            exit(-1);
+        }
+    }
+
+    for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i++) {
+        pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
+    }
+
+    vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE,
+                                     pfns, err,
+                                     MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT);
+    if (vaddr_base == NULL) {
+        fprintf(stderr, "xc_map_foreign_bulk error %d\n", errno);
+        exit(-1);
+    }
+
+    entry->vaddr_base  = vaddr_base;
+    entry->paddr_index = address_index;
+
+    for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i += BITS_PER_LONG) {
+        unsigned long word = 0;
+        j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT)) ?
+            (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG;
+        while (j > 0) {
+            word = (word << 1) | !err[i + --j];
+        }
+        entry->valid_mapping[i / BITS_PER_LONG] = word;
+    }
+}
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+    MapCacheEntry *entry, *pentry = NULL;
+    unsigned long address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
+    unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1);
+
+    if (address_index == mapcache->last_address_index && !lock)
+        return mapcache->last_address_vaddr + address_offset;
+
+    entry = &mapcache->entry[address_index % mapcache->nr_buckets];
+
+    while (entry && entry->lock && entry->paddr_index != address_index && entry->vaddr_base) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        entry = qemu_mallocz(sizeof(MapCacheEntry));
+        pentry->next = entry;
+        qemu_remap_bucket(entry, address_index);
+    } else if (!entry->lock) {
+        if (!entry->vaddr_base || entry->paddr_index != address_index || !test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping))
+            qemu_remap_bucket(entry, address_index);
+    }
+
+    if (!test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) {
+        mapcache->last_address_index = ~0UL;
+        return NULL;
+    }
+
+    mapcache->last_address_index = address_index;
+    mapcache->last_address_vaddr = entry->vaddr_base;
+    if (lock) {
+        MapCacheRev *reventry = qemu_mallocz(sizeof(MapCacheRev));
+        entry->lock++;
+        reventry->vaddr_req = mapcache->last_address_vaddr + address_offset;
+        reventry->paddr_index = mapcache->last_address_index;
+        QTAILQ_INSERT_TAIL(&mapcache->locked_entries, reventry, next);
+    }
+
+    return mapcache->last_address_vaddr + address_offset;
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+    MapCacheEntry *entry = NULL, *pentry = NULL;
+    MapCacheRev *reventry;
+    unsigned long paddr_index;
+    int found = 0;
+
+    if (mapcache->last_address_vaddr == buffer)
+        mapcache->last_address_index =  ~0UL;
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        if (reventry->vaddr_req == buffer) {
+            paddr_index = reventry->paddr_index;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        DPRINTF("qemu_invalidate_entry, could not find %p\n", buffer);
+        QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+            DPRINTF("   %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+        }
+        return;
+    }
+    QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
+    qemu_free(reventry);
+
+    entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+    while (entry && entry->paddr_index != paddr_index) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
+        return;
+    }
+    entry->lock--;
+    if (entry->lock > 0 || pentry == NULL)
+        return;
+
+    pentry->next = entry->next;
+    errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+    if (errno) {
+        fprintf(stderr, "unmap fails %d\n", errno);
+        exit(-1);
+    }
+    qemu_free(entry);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+    unsigned long i;
+    MapCacheRev *reventry;
+
+    qemu_aio_flush();
+
+    QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+        DPRINTF("There should be no locked mappings at this time, but %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+    }
+
+    mapcache_lock();
+
+    for (i = 0; i < mapcache->nr_buckets; i++) {
+        MapCacheEntry *entry = &mapcache->entry[i];
+
+        if (entry->vaddr_base == NULL)
+            continue;
+
+        errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+        if (errno) {
+            fprintf(stderr, "unmap fails %d\n", errno);
+            exit(-1);
+        }
+
+        entry->paddr_index = 0;
+        entry->vaddr_base  = NULL;
+    }
+
+    mapcache->last_address_index =  ~0UL;
+    mapcache->last_address_vaddr = NULL;
+
+    mapcache_unlock();
+}
+#else
 uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
 {
     return phys_ram_addr(phys_addr);
@@ -12,3 +258,4 @@ void qemu_invalidate_map_cache(void)
 void qemu_invalidate_entry(uint8_t *buffer)
 {
 }
+#endif /* !MAPCACHE */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 11/15] xen: Introduce --enable-xen command options.
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

This options will check if the target is build with Xen support.
---
 Makefile.target |    3 +++
 hw/xen.h        |    8 ++++++++
 qemu-options.hx |    9 +++++++++
 vl.c            |   11 +++++++++++
 4 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 xen-all.c
 create mode 100644 xen-stub.c

diff --git a/Makefile.target b/Makefile.target
index 1984cdd..840b87b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -2,6 +2,7 @@
 
 GENERATED_HEADERS = config-target.h
 CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
+CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
 
 include ../config-host.mak
 include config-devices.mak
@@ -182,6 +183,8 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
+obj-$(CONFIG_XEN) += xen-all.o
+obj-$(CONFIG_NO_XEN) += xen-stub.o
 
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
diff --git a/hw/xen.h b/hw/xen.h
index 780dcf7..f1d01d3 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -18,4 +18,12 @@ enum xen_mode {
 extern uint32_t xen_domid;
 extern enum xen_mode xen_mode;
 
+extern int xen_allowed;
+
+#if defined CONFIG_XEN
+#define xen_enabled() (xen_allowed)
+#else
+#define xen_enabled() (0)
+#endif
+
 #endif /* QEMU_HW_XEN_H */
diff --git a/qemu-options.hx b/qemu-options.hx
index db86feb..0abdfc4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1908,6 +1908,15 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+DEF("enable-xen", 0, QEMU_OPTION_enable_xen, \
+    "-enable-xen     enable Xen full virtualization support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-xen
+@findex -enable-xen
+Enable Xen full virtualization support. This option is only available
+if Xen support is enabled when compiling.
+ETEXI
+
 DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
     "-xen-domid id   specify xen guest domain id\n", QEMU_ARCH_ALL)
 DEF("xen-create", 0, QEMU_OPTION_xen_create,
diff --git a/vl.c b/vl.c
index b3e3676..dd88806 100644
--- a/vl.c
+++ b/vl.c
@@ -239,6 +239,7 @@ static NotifierList exit_notifiers =
     NOTIFIER_LIST_INITIALIZER(exit_notifiers);
 
 int kvm_allowed = 0;
+int xen_allowed = 0;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
 
@@ -2436,6 +2437,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_enable_kvm:
                 kvm_allowed = 1;
                 break;
+            case QEMU_OPTION_enable_xen:
+                xen_allowed = 1;
+                break;
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
                 break;
@@ -2730,6 +2734,13 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+    if (xen_allowed) {
+        if (!xen_available()) {
+            printf("Xen not supported for this target\n");
+            exit(1);
+        }
+    }
+
     if (qemu_init_main_loop()) {
         fprintf(stderr, "qemu_init_main_loop failed\n");
         exit(1);
diff --git a/xen-all.c b/xen-all.c
new file mode 100644
index 0000000..e69de29
diff --git a/xen-stub.c b/xen-stub.c
new file mode 100644
index 0000000..e69de29
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 11/15] xen: Introduce --enable-xen command options.
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

This options will check if the target is build with Xen support.
---
 Makefile.target |    3 +++
 hw/xen.h        |    8 ++++++++
 qemu-options.hx |    9 +++++++++
 vl.c            |   11 +++++++++++
 4 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 xen-all.c
 create mode 100644 xen-stub.c

diff --git a/Makefile.target b/Makefile.target
index 1984cdd..840b87b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -2,6 +2,7 @@
 
 GENERATED_HEADERS = config-target.h
 CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
+CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
 
 include ../config-host.mak
 include config-devices.mak
@@ -182,6 +183,8 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
+obj-$(CONFIG_XEN) += xen-all.o
+obj-$(CONFIG_NO_XEN) += xen-stub.o
 
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
diff --git a/hw/xen.h b/hw/xen.h
index 780dcf7..f1d01d3 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -18,4 +18,12 @@ enum xen_mode {
 extern uint32_t xen_domid;
 extern enum xen_mode xen_mode;
 
+extern int xen_allowed;
+
+#if defined CONFIG_XEN
+#define xen_enabled() (xen_allowed)
+#else
+#define xen_enabled() (0)
+#endif
+
 #endif /* QEMU_HW_XEN_H */
diff --git a/qemu-options.hx b/qemu-options.hx
index db86feb..0abdfc4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1908,6 +1908,15 @@ Enable KVM full virtualization support. This option is only available
 if KVM support is enabled when compiling.
 ETEXI
 
+DEF("enable-xen", 0, QEMU_OPTION_enable_xen, \
+    "-enable-xen     enable Xen full virtualization support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-xen
+@findex -enable-xen
+Enable Xen full virtualization support. This option is only available
+if Xen support is enabled when compiling.
+ETEXI
+
 DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
     "-xen-domid id   specify xen guest domain id\n", QEMU_ARCH_ALL)
 DEF("xen-create", 0, QEMU_OPTION_xen_create,
diff --git a/vl.c b/vl.c
index b3e3676..dd88806 100644
--- a/vl.c
+++ b/vl.c
@@ -239,6 +239,7 @@ static NotifierList exit_notifiers =
     NOTIFIER_LIST_INITIALIZER(exit_notifiers);
 
 int kvm_allowed = 0;
+int xen_allowed = 0;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
 
@@ -2436,6 +2437,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_enable_kvm:
                 kvm_allowed = 1;
                 break;
+            case QEMU_OPTION_enable_xen:
+                xen_allowed = 1;
+                break;
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
                 break;
@@ -2730,6 +2734,13 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+    if (xen_allowed) {
+        if (!xen_available()) {
+            printf("Xen not supported for this target\n");
+            exit(1);
+        }
+    }
+
     if (qemu_init_main_loop()) {
         fprintf(stderr, "qemu_init_main_loop failed\n");
         exit(1);
diff --git a/xen-all.c b/xen-all.c
new file mode 100644
index 0000000..e69de29
diff --git a/xen-stub.c b/xen-stub.c
new file mode 100644
index 0000000..e69de29
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq.
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

This patch introduces Xen specific call in piix_pci.

The specific part for Xen is in write_config, set_irq and get_pirq.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/piix_pci.c |   19 ++++++++++++++++---
 hw/xen.h      |    3 +++
 xen-all.c     |   25 +++++++++++++++++++++++++
 xen-stub.c    |    9 +++++++++
 4 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0f..994057f 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -28,6 +28,7 @@
 #include "pci_host.h"
 #include "isa.h"
 #include "sysbus.h"
+#include "xen.h"
 
 /*
  * I440FX chipset data sheet.
@@ -61,9 +62,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level);
    mapping. */
 static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
 {
-    int slot_addend;
-    slot_addend = (pci_dev->devfn >> 3) - 1;
-    return (irq_num + slot_addend) & 3;
+    if (!xen_enabled()) {
+        int slot_addend;
+        slot_addend = (pci_dev->devfn >> 3) - 1;
+        return (irq_num + slot_addend) & 3;
+    } else {
+        return irq_num + ((pci_dev->devfn >> 3) << 2);
+    }
 }
 
 static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
@@ -142,6 +147,9 @@ static void i440fx_write_config(PCIDevice *dev,
 {
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
+    if (xen_enabled())
+        xen_piix_pci_write_config_client(address, val, len);
+
     /* XXX: implement SMRAM.D_LOCK */
     pci_default_write_config(dev, address, val, len);
     if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
@@ -255,6 +263,11 @@ static void piix3_set_irq(void *opaque, int irq_num, int level)
     int i, pic_irq, pic_level;
     PIIX3State *piix3 = opaque;
 
+    if (xen_enabled()) {
+        xen_piix3_set_irq(irq_num, level);
+        return;
+    }
+
     piix3->pci_irq_levels[irq_num] = level;
 
     /* now we change the pic irq level according to the piix irq mappings */
diff --git a/hw/xen.h b/hw/xen.h
index f1d01d3..77012c2 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -26,4 +26,7 @@ extern int xen_allowed;
 #define xen_enabled() (0)
 #endif
 
+void xen_piix3_set_irq(int irq_num, int level);
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+
 #endif /* QEMU_HW_XEN_H */
diff --git a/xen-all.c b/xen-all.c
index e69de29..2d789ad 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -0,0 +1,25 @@
+#include "config.h"
+
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+void xen_piix3_set_irq(int irq_num, int level)
+{
+    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+            irq_num & 3, level);
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+    int i;
+
+    /* Scan for updates to PCI link routes (0x60-0x63). */
+    for (i = 0; i < len; i++) {
+        uint8_t v = (val >> (8*i)) & 0xff;
+        if (v & 0x80)
+            v = 0;
+        v &= 0xf;
+        if (((address+i) >= 0x60) && ((address+i) <= 0x63))
+            xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
+    }
+}
diff --git a/xen-stub.c b/xen-stub.c
index e69de29..38c64cf 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -0,0 +1,9 @@
+#include "hw/xen.h"
+
+void xen_piix3_set_irq(int irq_num, int level)
+{
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 12/15] piix_pci: Introduces Xen specific call for irq.
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

This patch introduces Xen specific call in piix_pci.

The specific part for Xen is in write_config, set_irq and get_pirq.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/piix_pci.c |   19 ++++++++++++++++---
 hw/xen.h      |    3 +++
 xen-all.c     |   25 +++++++++++++++++++++++++
 xen-stub.c    |    9 +++++++++
 4 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0f..994057f 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -28,6 +28,7 @@
 #include "pci_host.h"
 #include "isa.h"
 #include "sysbus.h"
+#include "xen.h"
 
 /*
  * I440FX chipset data sheet.
@@ -61,9 +62,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level);
    mapping. */
 static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
 {
-    int slot_addend;
-    slot_addend = (pci_dev->devfn >> 3) - 1;
-    return (irq_num + slot_addend) & 3;
+    if (!xen_enabled()) {
+        int slot_addend;
+        slot_addend = (pci_dev->devfn >> 3) - 1;
+        return (irq_num + slot_addend) & 3;
+    } else {
+        return irq_num + ((pci_dev->devfn >> 3) << 2);
+    }
 }
 
 static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
@@ -142,6 +147,9 @@ static void i440fx_write_config(PCIDevice *dev,
 {
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
+    if (xen_enabled())
+        xen_piix_pci_write_config_client(address, val, len);
+
     /* XXX: implement SMRAM.D_LOCK */
     pci_default_write_config(dev, address, val, len);
     if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
@@ -255,6 +263,11 @@ static void piix3_set_irq(void *opaque, int irq_num, int level)
     int i, pic_irq, pic_level;
     PIIX3State *piix3 = opaque;
 
+    if (xen_enabled()) {
+        xen_piix3_set_irq(irq_num, level);
+        return;
+    }
+
     piix3->pci_irq_levels[irq_num] = level;
 
     /* now we change the pic irq level according to the piix irq mappings */
diff --git a/hw/xen.h b/hw/xen.h
index f1d01d3..77012c2 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -26,4 +26,7 @@ extern int xen_allowed;
 #define xen_enabled() (0)
 #endif
 
+void xen_piix3_set_irq(int irq_num, int level);
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+
 #endif /* QEMU_HW_XEN_H */
diff --git a/xen-all.c b/xen-all.c
index e69de29..2d789ad 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -0,0 +1,25 @@
+#include "config.h"
+
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+void xen_piix3_set_irq(int irq_num, int level)
+{
+    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+            irq_num & 3, level);
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+    int i;
+
+    /* Scan for updates to PCI link routes (0x60-0x63). */
+    for (i = 0; i < len; i++) {
+        uint8_t v = (val >> (8*i)) & 0xff;
+        if (v & 0x80)
+            v = 0;
+        v &= 0xf;
+        if (((address+i) >= 0x60) && ((address+i) <= 0x63))
+            xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
+    }
+}
diff --git a/xen-stub.c b/xen-stub.c
index e69de29..38c64cf 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -0,0 +1,9 @@
+#include "hw/xen.h"
+
+void xen_piix3_set_irq(int irq_num, int level)
+{
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+}
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested.
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce two functions qemu_shutdown_requested_get and
qemu_reset_requested_get to get the value of shutdown/reset_requested
without reset it.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 sysemu.h |    2 ++
 vl.c     |   10 ++++++++++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/sysemu.h b/sysemu.h
index a1f6466..7facfae 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -51,6 +51,8 @@ void cpu_disable_ticks(void);
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
+int qemu_shutdown_requested_get(void);
+int qemu_reset_requested_get(void);
 int qemu_shutdown_requested(void);
 int qemu_reset_requested(void);
 int qemu_powerdown_requested(void);
diff --git a/vl.c b/vl.c
index dd88806..3316063 100644
--- a/vl.c
+++ b/vl.c
@@ -1130,6 +1130,16 @@ static int powerdown_requested;
 int debug_requested;
 int vmstop_requested;
 
+int qemu_shutdown_requested_get(void)
+{
+    return shutdown_requested;
+}
+
+int qemu_reset_requested_get(void)
+{
+    return reset_requested;
+}
+
 int qemu_shutdown_requested(void)
 {
     int r = shutdown_requested;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested.
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Introduce two functions qemu_shutdown_requested_get and
qemu_reset_requested_get to get the value of shutdown/reset_requested
without reset it.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 sysemu.h |    2 ++
 vl.c     |   10 ++++++++++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/sysemu.h b/sysemu.h
index a1f6466..7facfae 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -51,6 +51,8 @@ void cpu_disable_ticks(void);
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
+int qemu_shutdown_requested_get(void);
+int qemu_reset_requested_get(void);
 int qemu_shutdown_requested(void);
 int qemu_reset_requested(void);
 int qemu_powerdown_requested(void);
diff --git a/vl.c b/vl.c
index dd88806..3316063 100644
--- a/vl.c
+++ b/vl.c
@@ -1130,6 +1130,16 @@ static int powerdown_requested;
 int debug_requested;
 int vmstop_requested;
 
+int qemu_shutdown_requested_get(void)
+{
+    return shutdown_requested;
+}
+
+int qemu_reset_requested_get(void)
+{
+    return reset_requested;
+}
+
 int qemu_shutdown_requested(void)
 {
     int r = shutdown_requested;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Handle shutdown and reset requests in helper.c.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 target-xen/helper.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/target-xen/helper.c b/target-xen/helper.c
index c4339ce..d77d63e 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -368,6 +368,21 @@ static void cpu_handle_ioreq(void *opaque)
 
         xen_wmb(); /* Update ioreq contents /then/ update state. */
 
+        /*
+         * We do this before we send the response so that the tools
+         * have the opportunity to pick up on the reset before the
+         * guest resumes and does a hlt with interrupts disabled which
+         * causes Xen to powerdown the domain.
+         */
+        if (vm_running) {
+            if (qemu_shutdown_requested_get()) {
+                destroy_hvm_domain();
+            }
+            if (qemu_reset_requested_get()) {
+                qemu_system_reset();
+            }
+        }
+
         req->state = STATE_IORESP_READY;
         xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
     }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 14/15] xen: destroy the VM when shutdown is requested
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Handle shutdown and reset requests in helper.c.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 target-xen/helper.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/target-xen/helper.c b/target-xen/helper.c
index c4339ce..d77d63e 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -368,6 +368,21 @@ static void cpu_handle_ioreq(void *opaque)
 
         xen_wmb(); /* Update ioreq contents /then/ update state. */
 
+        /*
+         * We do this before we send the response so that the tools
+         * have the opportunity to pick up on the reset before the
+         * guest resumes and does a hlt with interrupts disabled which
+         * causes Xen to powerdown the domain.
+         */
+        if (vm_running) {
+            if (qemu_shutdown_requested_get()) {
+                destroy_hvm_domain();
+            }
+            if (qemu_reset_requested_get()) {
+                qemu_system_reset();
+            }
+        }
+
         req->state = STATE_IORESP_READY;
         xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
     }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-23  9:49 ` Stefano Stabellini
@ 2010-08-23  9:50   ` stefano.stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Xen currently uses a different BIOS (hvmloader + rombios) therefore the
Qemu acpi_piix4 implementation wouldn't work correctly with Xen.
We plan on fixing this properly but at the moment we are just adding a
new Xen specific acpi_piix4 implementation.
This patch is optional; without it the VM boots but it cannot shutdown
properly or go to S3.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target     |    1 +
 hw/xen_acpi_piix4.c |  424 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_common.h     |    3 +
 hw/xen_machine_fv.c |    6 +-
 4 files changed, 429 insertions(+), 5 deletions(-)
 create mode 100644 hw/xen_acpi_piix4.c

diff --git a/Makefile.target b/Makefile.target
index 840b87b..e815937 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -328,6 +328,7 @@ obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
 obj-xen-y += xenstore.o
 obj-xen-y += xen_platform.o
+obj-xen-y += xen_acpi_piix4.o
 
 obj-xen-y += xen_mapcache.o
 obj-xen-y += stub-functions.o
diff --git a/hw/xen_acpi_piix4.c b/hw/xen_acpi_piix4.c
new file mode 100644
index 0000000..3c65963
--- /dev/null
+++ b/hw/xen_acpi_piix4.c
@@ -0,0 +1,424 @@
+ /*
+ * PIIX4 ACPI controller emulation
+ *
+ * Winston liwen Wang, winston.l.wang@intel.com
+ * Copyright (c) 2006 , Intel Corporation.
+ *
+ * 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 "sysemu.h"
+#include "acpi.h"
+
+#include "xen_backend.h"
+#include "xen_common.h"
+#include "qemu-log.h"
+
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+
+#define PIIX4ACPI_LOG_ERROR 0
+#define PIIX4ACPI_LOG_INFO 1
+#define PIIX4ACPI_LOG_DEBUG 2
+#define PIIX4ACPI_LOGLEVEL PIIX4ACPI_LOG_INFO
+#define PIIX4ACPI_LOG(level, fmt, ...) do { if (level <= PIIX4ACPI_LOGLEVEL) qemu_log(fmt, ## __VA_ARGS__); } while (0)
+
+/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */
+/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */
+#define SLP_TYP_S4        (6 << 10)
+#define SLP_TYP_S3        (5 << 10)
+#define SLP_TYP_S5        (7 << 10)
+
+#define ACPI_DBG_IO_ADDR  0xb044
+#define ACPI_PHP_IO_ADDR  0x10c0
+
+#define PHP_EVT_ADD     0x0
+#define PHP_EVT_REMOVE  0x3
+
+/* The bit in GPE0_STS/EN to notify the pci hotplug event */
+#define ACPI_PHP_GPE_BIT 3
+
+#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn >> 1)
+#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg << 1) | hilo)
+
+/* ioport to monitor cpu add/remove status */
+#define PROC_BASE 0xaf00
+
+typedef struct PCIAcpiState {
+    PCIDevice dev;
+    uint16_t pm1_control; /* pm1a_ECNT_BLK */
+    qemu_irq irq;
+    qemu_irq cmos_s3;
+} PCIAcpiState;
+
+typedef struct GPEState {
+    /* GPE0 block */
+    uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2];
+    uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2];
+
+    /* CPU bitmap */
+    uint8_t cpus_sts[32];
+
+    /* SCI IRQ level */
+    uint8_t sci_asserted;
+
+} GPEState;
+
+static GPEState gpe_state;
+
+static qemu_irq sci_irq;
+
+typedef struct AcpiDeviceState AcpiDeviceState;
+AcpiDeviceState *acpi_device_table;
+
+static const VMStateDescription vmstate_acpi = {
+    .name = "PIIX4 ACPI",
+    .version_id = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIAcpiState),
+        VMSTATE_UINT16(pm1_control, PCIAcpiState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAcpiState *s = opaque;
+    s->pm1_control = (s->pm1_control & 0xff00) | (val & 0xff);
+}
+
+static uint32_t acpiPm1Control_readb(void *opaque, uint32_t addr)
+{
+    PCIAcpiState *s = opaque;
+    /* Mask out the write-only bits */
+    return (uint8_t)(s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE));
+}
+
+static void acpi_shutdown(PCIAcpiState *s, uint32_t val)
+{
+    if (!(val & ACPI_BITMASK_SLEEP_ENABLE))
+        return;
+
+    switch (val & ACPI_BITMASK_SLEEP_TYPE) {
+    case SLP_TYP_S3:
+        qemu_system_reset();
+        qemu_irq_raise(s->cmos_s3);
+        xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
+        break;
+    case SLP_TYP_S4:
+    case SLP_TYP_S5:
+        qemu_system_shutdown_request();
+        break;
+    default:
+        break;
+    }
+}
+
+static void acpiPm1ControlP1_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAcpiState *s = opaque;
+
+    val <<= 8;
+    s->pm1_control = ((s->pm1_control & 0xff) | val) & ~ACPI_BITMASK_SLEEP_ENABLE;
+
+    acpi_shutdown(s, val);
+}
+
+static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr)
+{
+    PCIAcpiState *s = opaque;
+    /* Mask out the write-only bits */
+    return (uint8_t)((s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)) >> 8);
+}
+
+static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAcpiState *s = opaque;
+
+    s->pm1_control = val & ~ACPI_BITMASK_SLEEP_ENABLE;
+
+    acpi_shutdown(s, val);
+}
+
+static uint32_t acpiPm1Control_readw(void *opaque, uint32_t addr)
+{
+    PCIAcpiState *s = opaque;
+    /* Mask out the write-only bits */
+    return (s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE));
+}
+
+static void acpi_map(PCIDevice *pci_dev, int region_num,
+                     uint32_t addr, uint32_t size, int type)
+{
+    PCIAcpiState *d = (PCIAcpiState *)pci_dev;
+
+    /* Byte access */
+    register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d);
+    register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d);
+    register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d);
+    register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d);
+
+    /* Word access */
+    register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d);
+    register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
+}
+
+static inline int test_bit(uint8_t *map, int bit)
+{
+    return ( map[bit / 8] & (1 << (bit % 8)) );
+}
+
+static inline void set_bit(uint8_t *map, int bit)
+{
+    map[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline void clear_bit(uint8_t *map, int bit)
+{
+    map[bit / 8] &= ~(1 << (bit % 8));
+}
+
+static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "ACPI: DBG: 0x%08x\n", val);
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val);
+}
+
+/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */
+static uint32_t gpe_sts_read(void *opaque, uint32_t addr)
+{
+    GPEState *s = opaque;
+
+    return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS];
+}
+
+/* write 1 to clear specific GPE bits */
+static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    GPEState *s = opaque;
+    int hotplugged = 0;
+
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val);
+
+    hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT);
+    s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val;
+    if ( s->sci_asserted &&
+         hotplugged &&
+         !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) {
+        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n");
+        qemu_irq_lower(sci_irq);
+    }
+
+}
+
+static uint32_t gpe_en_read(void *opaque, uint32_t addr)
+{
+    GPEState *s = opaque;
+
+    return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)];
+}
+
+/* write 0 to clear en bit */
+static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    GPEState *s = opaque;
+    int reg_count;
+
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val);
+    reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2);
+    s->gpe0_en[reg_count] = val;
+    /* If disable GPE bit right after generating SCI on it,
+     * need deassert the intr to avoid redundant intrs
+     */
+    if ( s->sci_asserted &&
+         reg_count == (ACPI_PHP_GPE_BIT / 8) &&
+         !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) {
+        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "deassert due to disable GPE bit.\n");
+        s->sci_asserted = 0;
+        qemu_irq_lower(sci_irq);
+    }
+
+}
+
+static void gpe_save(QEMUFile* f, void* opaque)
+{
+    GPEState *s = (GPEState*)opaque;
+    int i;
+
+    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+        qemu_put_8s(f, &s->gpe0_sts[i]);
+        qemu_put_8s(f, &s->gpe0_en[i]);
+    }
+
+    qemu_put_8s(f, &s->sci_asserted);
+    if ( s->sci_asserted ) {
+        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
+    }
+}
+
+static int gpe_load(QEMUFile* f, void* opaque, int version_id)
+{
+    GPEState *s = (GPEState*)opaque;
+    int i;
+    if (version_id != 1)
+        return -EINVAL;
+
+    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+        qemu_get_8s(f, &s->gpe0_sts[i]);
+        qemu_get_8s(f, &s->gpe0_en[i]);
+    }
+
+    qemu_get_8s(f, &s->sci_asserted);
+    return 0;
+}
+
+static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr)
+{
+    uint32_t val = 0;
+    GPEState *g = opaque;
+
+    switch (addr) {
+        case PROC_BASE ... PROC_BASE+31:
+            val = g->cpus_sts[addr - PROC_BASE];
+        default:
+            break;
+    }
+
+    return val;
+}
+
+static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    /* GPEState *g = opaque; */
+
+    switch (addr) {
+        case PROC_BASE ... PROC_BASE + 31:
+            /* don't allow to change cpus_sts from inside a guest */
+            break;
+        default:
+            break;
+    }
+}
+
+static void gpe_acpi_init(void)
+{
+    GPEState *s = &gpe_state;
+    memset(s, 0, sizeof(GPEState));
+
+    s->cpus_sts[0] = 1;
+
+    register_ioport_read(PROC_BASE, 32, 1,  gpe_cpus_readb, s);
+    register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s);
+
+    register_ioport_read(ACPI_GPE0_BLK_ADDRESS,
+                         ACPI_GPE0_BLK_LEN / 2,
+                         1,
+                         gpe_sts_read,
+                         s);
+    register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
+                         ACPI_GPE0_BLK_LEN / 2,
+                         1,
+                         gpe_en_read,
+                         s);
+
+    register_ioport_write(ACPI_GPE0_BLK_ADDRESS,
+                          ACPI_GPE0_BLK_LEN / 2,
+                          1,
+                          gpe_sts_write,
+                          s);
+    register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
+                          ACPI_GPE0_BLK_LEN / 2,
+                          1,
+                          gpe_en_write,
+                          s);
+
+    register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
+}
+
+static int piix4_pm_xen_initfn(PCIDevice *dev)
+{
+    PCIAcpiState *s = DO_UPCAST(PCIAcpiState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3);
+    pci_conf[0x08] = 0x01;  /* B0 stepping */
+    pci_conf[0x09] = 0x00;  /* base class */
+    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
+    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
+    pci_conf[0x3d] = 0x01;  /* Hardwired to PIRQA is used */
+
+    /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40
+     * to make shutdown work for IPF, due to IPF Guest Firmware
+     * will enumerate pci devices.
+     *
+     * TODO:  if Guest Firmware or Guest OS will change this PMBA,
+     * More logic will be added.
+     */
+    pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */
+    pci_conf[0x41] = 0x1f;
+    pci_conf[0x42] = 0x00;
+    pci_conf[0x43] = 0x00;
+
+    s->pm1_control = ACPI_BITMASK_SCI_ENABLE;
+
+    acpi_map((PCIDevice *)s, 0, 0x1f40, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+
+    gpe_acpi_init();
+
+    register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
+
+    return 0;
+}
+
+void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3)
+{
+    PCIDevice *dev;
+    PCIAcpiState *s;
+
+    sci_irq = sci_irq_spec;
+
+    dev = pci_create(bus, devfn, "PIIX4 ACPI");
+
+    s = DO_UPCAST(PCIAcpiState, dev, dev);
+
+    s->irq = sci_irq_spec;
+    s->cmos_s3 = cmos_s3;
+
+    qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo piix4_pm_xen_info = {
+    .qdev.name    = "PIIX4 ACPI",
+    .qdev.desc    = "dm",
+    .qdev.size    = sizeof(PCIAcpiState),
+    .qdev.vmsd    = &vmstate_acpi,
+    .init         = piix4_pm_xen_initfn,
+};
+
+static void piix4_pm_xen_register(void)
+{
+    pci_qdev_register(&piix4_pm_xen_info);
+}
+
+device_init(piix4_pm_xen_register);
diff --git a/hw/xen_common.h b/hw/xen_common.h
index c49358c..cd62097 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -55,4 +55,7 @@ typedef xc_interface *qemu_xc_interface;
 /* hw/i8259-xen-stub.c */
 qemu_irq *i8259_xen_init(void);
 
+/* hw/xen_acpi_piix4.c */
+void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3);
+
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index cb40d22..5132c97 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -65,7 +65,6 @@ static void xen_init_fv(ram_addr_t ram_size,
     qemu_irq *isa_irq;
     qemu_irq *i8259;
     qemu_irq *cmos_s3;
-    qemu_irq *smi_irq;
     IsaIrqState *isa_irq_state;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     FDCtrl *floppy_controller;
@@ -173,10 +172,7 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     if (acpi_enabled) {
         cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
-        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
-        piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
-                isa_reserve_irq(9), *cmos_s3, *smi_irq,
-                0);
+        piix4_pm_xen_init(pci_bus, piix3_devfn + 3, isa_reserve_irq(9), *cmos_s3);
     }
 
     if (i440fx_state) {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
@ 2010-08-23  9:50   ` stefano.stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: stefano.stabellini @ 2010-08-23  9:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, anthony, stefano.stabellini

From: Anthony PERARD <anthony.perard@citrix.com>

Xen currently uses a different BIOS (hvmloader + rombios) therefore the
Qemu acpi_piix4 implementation wouldn't work correctly with Xen.
We plan on fixing this properly but at the moment we are just adding a
new Xen specific acpi_piix4 implementation.
This patch is optional; without it the VM boots but it cannot shutdown
properly or go to S3.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 Makefile.target     |    1 +
 hw/xen_acpi_piix4.c |  424 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_common.h     |    3 +
 hw/xen_machine_fv.c |    6 +-
 4 files changed, 429 insertions(+), 5 deletions(-)
 create mode 100644 hw/xen_acpi_piix4.c

diff --git a/Makefile.target b/Makefile.target
index 840b87b..e815937 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -328,6 +328,7 @@ obj-xen-y += piix_pci.o
 obj-xen-y += mc146818rtc.o
 obj-xen-y += xenstore.o
 obj-xen-y += xen_platform.o
+obj-xen-y += xen_acpi_piix4.o
 
 obj-xen-y += xen_mapcache.o
 obj-xen-y += stub-functions.o
diff --git a/hw/xen_acpi_piix4.c b/hw/xen_acpi_piix4.c
new file mode 100644
index 0000000..3c65963
--- /dev/null
+++ b/hw/xen_acpi_piix4.c
@@ -0,0 +1,424 @@
+ /*
+ * PIIX4 ACPI controller emulation
+ *
+ * Winston liwen Wang, winston.l.wang@intel.com
+ * Copyright (c) 2006 , Intel Corporation.
+ *
+ * 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 "sysemu.h"
+#include "acpi.h"
+
+#include "xen_backend.h"
+#include "xen_common.h"
+#include "qemu-log.h"
+
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+
+#define PIIX4ACPI_LOG_ERROR 0
+#define PIIX4ACPI_LOG_INFO 1
+#define PIIX4ACPI_LOG_DEBUG 2
+#define PIIX4ACPI_LOGLEVEL PIIX4ACPI_LOG_INFO
+#define PIIX4ACPI_LOG(level, fmt, ...) do { if (level <= PIIX4ACPI_LOGLEVEL) qemu_log(fmt, ## __VA_ARGS__); } while (0)
+
+/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */
+/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */
+#define SLP_TYP_S4        (6 << 10)
+#define SLP_TYP_S3        (5 << 10)
+#define SLP_TYP_S5        (7 << 10)
+
+#define ACPI_DBG_IO_ADDR  0xb044
+#define ACPI_PHP_IO_ADDR  0x10c0
+
+#define PHP_EVT_ADD     0x0
+#define PHP_EVT_REMOVE  0x3
+
+/* The bit in GPE0_STS/EN to notify the pci hotplug event */
+#define ACPI_PHP_GPE_BIT 3
+
+#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn >> 1)
+#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg << 1) | hilo)
+
+/* ioport to monitor cpu add/remove status */
+#define PROC_BASE 0xaf00
+
+typedef struct PCIAcpiState {
+    PCIDevice dev;
+    uint16_t pm1_control; /* pm1a_ECNT_BLK */
+    qemu_irq irq;
+    qemu_irq cmos_s3;
+} PCIAcpiState;
+
+typedef struct GPEState {
+    /* GPE0 block */
+    uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2];
+    uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2];
+
+    /* CPU bitmap */
+    uint8_t cpus_sts[32];
+
+    /* SCI IRQ level */
+    uint8_t sci_asserted;
+
+} GPEState;
+
+static GPEState gpe_state;
+
+static qemu_irq sci_irq;
+
+typedef struct AcpiDeviceState AcpiDeviceState;
+AcpiDeviceState *acpi_device_table;
+
+static const VMStateDescription vmstate_acpi = {
+    .name = "PIIX4 ACPI",
+    .version_id = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIAcpiState),
+        VMSTATE_UINT16(pm1_control, PCIAcpiState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAcpiState *s = opaque;
+    s->pm1_control = (s->pm1_control & 0xff00) | (val & 0xff);
+}
+
+static uint32_t acpiPm1Control_readb(void *opaque, uint32_t addr)
+{
+    PCIAcpiState *s = opaque;
+    /* Mask out the write-only bits */
+    return (uint8_t)(s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE));
+}
+
+static void acpi_shutdown(PCIAcpiState *s, uint32_t val)
+{
+    if (!(val & ACPI_BITMASK_SLEEP_ENABLE))
+        return;
+
+    switch (val & ACPI_BITMASK_SLEEP_TYPE) {
+    case SLP_TYP_S3:
+        qemu_system_reset();
+        qemu_irq_raise(s->cmos_s3);
+        xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
+        break;
+    case SLP_TYP_S4:
+    case SLP_TYP_S5:
+        qemu_system_shutdown_request();
+        break;
+    default:
+        break;
+    }
+}
+
+static void acpiPm1ControlP1_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAcpiState *s = opaque;
+
+    val <<= 8;
+    s->pm1_control = ((s->pm1_control & 0xff) | val) & ~ACPI_BITMASK_SLEEP_ENABLE;
+
+    acpi_shutdown(s, val);
+}
+
+static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr)
+{
+    PCIAcpiState *s = opaque;
+    /* Mask out the write-only bits */
+    return (uint8_t)((s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)) >> 8);
+}
+
+static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIAcpiState *s = opaque;
+
+    s->pm1_control = val & ~ACPI_BITMASK_SLEEP_ENABLE;
+
+    acpi_shutdown(s, val);
+}
+
+static uint32_t acpiPm1Control_readw(void *opaque, uint32_t addr)
+{
+    PCIAcpiState *s = opaque;
+    /* Mask out the write-only bits */
+    return (s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE));
+}
+
+static void acpi_map(PCIDevice *pci_dev, int region_num,
+                     uint32_t addr, uint32_t size, int type)
+{
+    PCIAcpiState *d = (PCIAcpiState *)pci_dev;
+
+    /* Byte access */
+    register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d);
+    register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d);
+    register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d);
+    register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d);
+
+    /* Word access */
+    register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d);
+    register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
+}
+
+static inline int test_bit(uint8_t *map, int bit)
+{
+    return ( map[bit / 8] & (1 << (bit % 8)) );
+}
+
+static inline void set_bit(uint8_t *map, int bit)
+{
+    map[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline void clear_bit(uint8_t *map, int bit)
+{
+    map[bit / 8] &= ~(1 << (bit % 8));
+}
+
+static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "ACPI: DBG: 0x%08x\n", val);
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val);
+}
+
+/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */
+static uint32_t gpe_sts_read(void *opaque, uint32_t addr)
+{
+    GPEState *s = opaque;
+
+    return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS];
+}
+
+/* write 1 to clear specific GPE bits */
+static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    GPEState *s = opaque;
+    int hotplugged = 0;
+
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val);
+
+    hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT);
+    s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val;
+    if ( s->sci_asserted &&
+         hotplugged &&
+         !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) {
+        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n");
+        qemu_irq_lower(sci_irq);
+    }
+
+}
+
+static uint32_t gpe_en_read(void *opaque, uint32_t addr)
+{
+    GPEState *s = opaque;
+
+    return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)];
+}
+
+/* write 0 to clear en bit */
+static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    GPEState *s = opaque;
+    int reg_count;
+
+    PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val);
+    reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2);
+    s->gpe0_en[reg_count] = val;
+    /* If disable GPE bit right after generating SCI on it,
+     * need deassert the intr to avoid redundant intrs
+     */
+    if ( s->sci_asserted &&
+         reg_count == (ACPI_PHP_GPE_BIT / 8) &&
+         !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) {
+        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "deassert due to disable GPE bit.\n");
+        s->sci_asserted = 0;
+        qemu_irq_lower(sci_irq);
+    }
+
+}
+
+static void gpe_save(QEMUFile* f, void* opaque)
+{
+    GPEState *s = (GPEState*)opaque;
+    int i;
+
+    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+        qemu_put_8s(f, &s->gpe0_sts[i]);
+        qemu_put_8s(f, &s->gpe0_en[i]);
+    }
+
+    qemu_put_8s(f, &s->sci_asserted);
+    if ( s->sci_asserted ) {
+        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
+    }
+}
+
+static int gpe_load(QEMUFile* f, void* opaque, int version_id)
+{
+    GPEState *s = (GPEState*)opaque;
+    int i;
+    if (version_id != 1)
+        return -EINVAL;
+
+    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+        qemu_get_8s(f, &s->gpe0_sts[i]);
+        qemu_get_8s(f, &s->gpe0_en[i]);
+    }
+
+    qemu_get_8s(f, &s->sci_asserted);
+    return 0;
+}
+
+static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr)
+{
+    uint32_t val = 0;
+    GPEState *g = opaque;
+
+    switch (addr) {
+        case PROC_BASE ... PROC_BASE+31:
+            val = g->cpus_sts[addr - PROC_BASE];
+        default:
+            break;
+    }
+
+    return val;
+}
+
+static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    /* GPEState *g = opaque; */
+
+    switch (addr) {
+        case PROC_BASE ... PROC_BASE + 31:
+            /* don't allow to change cpus_sts from inside a guest */
+            break;
+        default:
+            break;
+    }
+}
+
+static void gpe_acpi_init(void)
+{
+    GPEState *s = &gpe_state;
+    memset(s, 0, sizeof(GPEState));
+
+    s->cpus_sts[0] = 1;
+
+    register_ioport_read(PROC_BASE, 32, 1,  gpe_cpus_readb, s);
+    register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s);
+
+    register_ioport_read(ACPI_GPE0_BLK_ADDRESS,
+                         ACPI_GPE0_BLK_LEN / 2,
+                         1,
+                         gpe_sts_read,
+                         s);
+    register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
+                         ACPI_GPE0_BLK_LEN / 2,
+                         1,
+                         gpe_en_read,
+                         s);
+
+    register_ioport_write(ACPI_GPE0_BLK_ADDRESS,
+                          ACPI_GPE0_BLK_LEN / 2,
+                          1,
+                          gpe_sts_write,
+                          s);
+    register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
+                          ACPI_GPE0_BLK_LEN / 2,
+                          1,
+                          gpe_en_write,
+                          s);
+
+    register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
+}
+
+static int piix4_pm_xen_initfn(PCIDevice *dev)
+{
+    PCIAcpiState *s = DO_UPCAST(PCIAcpiState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3);
+    pci_conf[0x08] = 0x01;  /* B0 stepping */
+    pci_conf[0x09] = 0x00;  /* base class */
+    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
+    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
+    pci_conf[0x3d] = 0x01;  /* Hardwired to PIRQA is used */
+
+    /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40
+     * to make shutdown work for IPF, due to IPF Guest Firmware
+     * will enumerate pci devices.
+     *
+     * TODO:  if Guest Firmware or Guest OS will change this PMBA,
+     * More logic will be added.
+     */
+    pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */
+    pci_conf[0x41] = 0x1f;
+    pci_conf[0x42] = 0x00;
+    pci_conf[0x43] = 0x00;
+
+    s->pm1_control = ACPI_BITMASK_SCI_ENABLE;
+
+    acpi_map((PCIDevice *)s, 0, 0x1f40, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+
+    gpe_acpi_init();
+
+    register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
+
+    return 0;
+}
+
+void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3)
+{
+    PCIDevice *dev;
+    PCIAcpiState *s;
+
+    sci_irq = sci_irq_spec;
+
+    dev = pci_create(bus, devfn, "PIIX4 ACPI");
+
+    s = DO_UPCAST(PCIAcpiState, dev, dev);
+
+    s->irq = sci_irq_spec;
+    s->cmos_s3 = cmos_s3;
+
+    qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo piix4_pm_xen_info = {
+    .qdev.name    = "PIIX4 ACPI",
+    .qdev.desc    = "dm",
+    .qdev.size    = sizeof(PCIAcpiState),
+    .qdev.vmsd    = &vmstate_acpi,
+    .init         = piix4_pm_xen_initfn,
+};
+
+static void piix4_pm_xen_register(void)
+{
+    pci_qdev_register(&piix4_pm_xen_info);
+}
+
+device_init(piix4_pm_xen_register);
diff --git a/hw/xen_common.h b/hw/xen_common.h
index c49358c..cd62097 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -55,4 +55,7 @@ typedef xc_interface *qemu_xc_interface;
 /* hw/i8259-xen-stub.c */
 qemu_irq *i8259_xen_init(void);
 
+/* hw/xen_acpi_piix4.c */
+void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3);
+
 #endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index cb40d22..5132c97 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -65,7 +65,6 @@ static void xen_init_fv(ram_addr_t ram_size,
     qemu_irq *isa_irq;
     qemu_irq *i8259;
     qemu_irq *cmos_s3;
-    qemu_irq *smi_irq;
     IsaIrqState *isa_irq_state;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     FDCtrl *floppy_controller;
@@ -173,10 +172,7 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     if (acpi_enabled) {
         cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
-        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
-        piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
-                isa_reserve_irq(9), *cmos_s3, *smi_irq,
-                0);
+        piix4_pm_xen_init(pci_bus, piix3_devfn + 3, isa_reserve_irq(9), *cmos_s3);
     }
 
     if (i440fx_state) {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [Qemu-devel] Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-23  9:50   ` stefano.stabellini
@ 2010-08-23 11:09     ` Juan Quintela
  -1 siblings, 0 replies; 41+ messages in thread
From: Juan Quintela @ 2010-08-23 11:09 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> This patch adds a new Xen device model target to Qemu, called
> target-xen.
> The new target makes use of the previously introduced xen_machine_fv.
> In order to have a fully working Xen device model we still need
> functionalities introduced by the following patches.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

....

> diff --git a/Makefile.target b/Makefile.target
> index 8fdc884..359a984 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
>  # xen backend driver support

....

> +# Xen Device Model
> +# xen full virtualized machine
> +
> +# Remove some lib, because we don't want it for a xen target.
> +ifeq ($(TARGET_BASE_ARCH), xen)
> +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
> +bad-libobj-y += tcg%.o fpu/%.o
> +bad-libobj-y += disas.o op_helper.o
> +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
> +endif

This is a hack (to call it something).  Can we have a proper fix for
this?  Just putting that files under tcg-libobj-y (or something like
that), and add it only to some targets.  There is (another similar bad
hack) on qemu-kvm.git to disable them for ia64.  Can we get something
saner here?

Later, Juan.

PD. No, this is not xen specific, disabling compilation of tcg on qemu
    is basically imposible.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
@ 2010-08-23 11:09     ` Juan Quintela
  0 siblings, 0 replies; 41+ messages in thread
From: Juan Quintela @ 2010-08-23 11:09 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> This patch adds a new Xen device model target to Qemu, called
> target-xen.
> The new target makes use of the previously introduced xen_machine_fv.
> In order to have a fully working Xen device model we still need
> functionalities introduced by the following patches.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

....

> diff --git a/Makefile.target b/Makefile.target
> index 8fdc884..359a984 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
>  # xen backend driver support

....

> +# Xen Device Model
> +# xen full virtualized machine
> +
> +# Remove some lib, because we don't want it for a xen target.
> +ifeq ($(TARGET_BASE_ARCH), xen)
> +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
> +bad-libobj-y += tcg%.o fpu/%.o
> +bad-libobj-y += disas.o op_helper.o
> +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
> +endif

This is a hack (to call it something).  Can we have a proper fix for
this?  Just putting that files under tcg-libobj-y (or something like
that), and add it only to some targets.  There is (another similar bad
hack) on qemu-kvm.git to disable them for ia64.  Can we get something
saner here?

Later, Juan.

PD. No, this is not xen specific, disabling compilation of tcg on qemu
    is basically imposible.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-23  9:50   ` stefano.stabellini
@ 2010-08-23 11:15     ` Juan Quintela
  -1 siblings, 0 replies; 41+ messages in thread
From: Juan Quintela @ 2010-08-23 11:15 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> Xen currently uses a different BIOS (hvmloader + rombios) therefore the
> Qemu acpi_piix4 implementation wouldn't work correctly with Xen.
> We plan on fixing this properly but at the moment we are just adding a
> new Xen specific acpi_piix4 implementation.
> This patch is optional; without it the VM boots but it cannot shutdown
> properly or go to S3.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

> +static void gpe_save(QEMUFile* f, void* opaque)
> +{
> +    GPEState *s = (GPEState*)opaque;
> +    int i;
> +
> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_put_8s(f, &s->gpe0_sts[i]);
> +        qemu_put_8s(f, &s->gpe0_en[i]);
> +    }
> +
> +    qemu_put_8s(f, &s->sci_asserted);
> +    if ( s->sci_asserted ) {
> +        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
> +    }
> +}
> +
> +static int gpe_load(QEMUFile* f, void* opaque, int version_id)
> +{
> +    GPEState *s = (GPEState*)opaque;
> +    int i;
> +    if (version_id != 1)
> +        return -EINVAL;
> +
> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_get_8s(f, &s->gpe0_sts[i]);
> +        qemu_get_8s(f, &s->gpe0_en[i]);
> +    }
> +
> +    qemu_get_8s(f, &s->sci_asserted);
> +    return 0;
> +}
....
> +    register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);

Please port this to VMSTATE.

If possible (i.e. not problems with backwards compatibility), something like:

> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_get_8s(f, &s->gpe0_sts[i]);
> +    }
> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_get_8s(f, &s->gpe0_en[i]);
> +    }

Would be easier to put in vmstate.

Later, Juan.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
@ 2010-08-23 11:15     ` Juan Quintela
  0 siblings, 0 replies; 41+ messages in thread
From: Juan Quintela @ 2010-08-23 11:15 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> Xen currently uses a different BIOS (hvmloader + rombios) therefore the
> Qemu acpi_piix4 implementation wouldn't work correctly with Xen.
> We plan on fixing this properly but at the moment we are just adding a
> new Xen specific acpi_piix4 implementation.
> This patch is optional; without it the VM boots but it cannot shutdown
> properly or go to S3.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

> +static void gpe_save(QEMUFile* f, void* opaque)
> +{
> +    GPEState *s = (GPEState*)opaque;
> +    int i;
> +
> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_put_8s(f, &s->gpe0_sts[i]);
> +        qemu_put_8s(f, &s->gpe0_en[i]);
> +    }
> +
> +    qemu_put_8s(f, &s->sci_asserted);
> +    if ( s->sci_asserted ) {
> +        PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
> +    }
> +}
> +
> +static int gpe_load(QEMUFile* f, void* opaque, int version_id)
> +{
> +    GPEState *s = (GPEState*)opaque;
> +    int i;
> +    if (version_id != 1)
> +        return -EINVAL;
> +
> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_get_8s(f, &s->gpe0_sts[i]);
> +        qemu_get_8s(f, &s->gpe0_en[i]);
> +    }
> +
> +    qemu_get_8s(f, &s->sci_asserted);
> +    return 0;
> +}
....
> +    register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);

Please port this to VMSTATE.

If possible (i.e. not problems with backwards compatibility), something like:

> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_get_8s(f, &s->gpe0_sts[i]);
> +    }
> +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> +        qemu_get_8s(f, &s->gpe0_en[i]);
> +    }

Would be easier to put in vmstate.

Later, Juan.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-23 11:09     ` Juan Quintela
@ 2010-08-23 11:16       ` Stefano Stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: Stefano Stabellini @ 2010-08-23 11:16 UTC (permalink / raw)
  To: Juan Quintela; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 23 Aug 2010, Juan Quintela wrote:
> > +# Xen Device Model
> > +# xen full virtualized machine
> > +
> > +# Remove some lib, because we don't want it for a xen target.
> > +ifeq ($(TARGET_BASE_ARCH), xen)
> > +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
> > +bad-libobj-y += tcg%.o fpu/%.o
> > +bad-libobj-y += disas.o op_helper.o
> > +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
> > +endif
> 
> This is a hack (to call it something).  Can we have a proper fix for
> this?  Just putting that files under tcg-libobj-y (or something like
> that), and add it only to some targets.  There is (another similar bad
> hack) on qemu-kvm.git to disable them for ia64.  Can we get something
> saner here?
> 
 
As I mentioned in the introduction email to the series, we haven't tried
to remove target-xen yet, but it is the next item on our todo list.
Removing the new target will remove this hack too.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
@ 2010-08-23 11:16       ` Stefano Stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: Stefano Stabellini @ 2010-08-23 11:16 UTC (permalink / raw)
  To: Juan Quintela; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 23 Aug 2010, Juan Quintela wrote:
> > +# Xen Device Model
> > +# xen full virtualized machine
> > +
> > +# Remove some lib, because we don't want it for a xen target.
> > +ifeq ($(TARGET_BASE_ARCH), xen)
> > +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
> > +bad-libobj-y += tcg%.o fpu/%.o
> > +bad-libobj-y += disas.o op_helper.o
> > +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
> > +endif
> 
> This is a hack (to call it something).  Can we have a proper fix for
> this?  Just putting that files under tcg-libobj-y (or something like
> that), and add it only to some targets.  There is (another similar bad
> hack) on qemu-kvm.git to disable them for ia64.  Can we get something
> saner here?
> 
 
As I mentioned in the introduction email to the series, we haven't tried
to remove target-xen yet, but it is the next item on our todo list.
Removing the new target will remove this hack too.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [Qemu-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-23 11:15     ` Juan Quintela
@ 2010-08-23 13:15       ` Stefano Stabellini
  -1 siblings, 0 replies; 41+ messages in thread
From: Stefano Stabellini @ 2010-08-23 13:15 UTC (permalink / raw)
  To: Juan Quintela; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 23 Aug 2010, Juan Quintela wrote:
> > +    register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
> 
> Please port this to VMSTATE.
> 
> If possible (i.e. not problems with backwards compatibility), something like:
> 
> > +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> > +        qemu_get_8s(f, &s->gpe0_sts[i]);
> > +    }
> > +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> > +        qemu_get_8s(f, &s->gpe0_en[i]);
> > +    }
> 
> Would be easier to put in vmstate.
> 
 
Ok, will do.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
@ 2010-08-23 13:15       ` Stefano Stabellini
  0 siblings, 0 replies; 41+ messages in thread
From: Stefano Stabellini @ 2010-08-23 13:15 UTC (permalink / raw)
  To: Juan Quintela; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 23 Aug 2010, Juan Quintela wrote:
> > +    register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
> 
> Please port this to VMSTATE.
> 
> If possible (i.e. not problems with backwards compatibility), something like:
> 
> > +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> > +        qemu_get_8s(f, &s->gpe0_sts[i]);
> > +    }
> > +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> > +        qemu_get_8s(f, &s->gpe0_en[i]);
> > +    }
> 
> Would be easier to put in vmstate.
> 
 
Ok, will do.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq.
  2010-08-23  9:50   ` stefano.stabellini
  (?)
@ 2010-08-24 11:20   ` Isaku Yamahata
  -1 siblings, 0 replies; 41+ messages in thread
From: Isaku Yamahata @ 2010-08-24 11:20 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Mon, Aug 23, 2010 at 10:50:49AM +0100, stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
> 
> This patch introduces Xen specific call in piix_pci.
> 
> The specific part for Xen is in write_config, set_irq and get_pirq.
> 
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
>  hw/piix_pci.c |   19 ++++++++++++++++---
>  hw/xen.h      |    3 +++
>  xen-all.c     |   25 +++++++++++++++++++++++++
>  xen-stub.c    |    9 +++++++++
>  4 files changed, 53 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/piix_pci.c b/hw/piix_pci.c
> index f152a0f..994057f 100644
> --- a/hw/piix_pci.c
> +++ b/hw/piix_pci.c
> @@ -28,6 +28,7 @@
>  #include "pci_host.h"
>  #include "isa.h"
>  #include "sysbus.h"
> +#include "xen.h"
>  
>  /*
>   * I440FX chipset data sheet.
> @@ -61,9 +62,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level);
>     mapping. */
>  static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
>  {
> -    int slot_addend;
> -    slot_addend = (pci_dev->devfn >> 3) - 1;
> -    return (irq_num + slot_addend) & 3;
> +    if (!xen_enabled()) {
> +        int slot_addend;
> +        slot_addend = (pci_dev->devfn >> 3) - 1;
> +        return (irq_num + slot_addend) & 3;
> +    } else {
> +        return irq_num + ((pci_dev->devfn >> 3) << 2);
> +    }
>  }
>  
>  static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)

pci_slot_get_pirq() is passed to pci_bus_irqs() in i440fx_init().
It would be better to pass xen specific function to pci_bus_irqs() instead of
dynamic check.


> @@ -142,6 +147,9 @@ static void i440fx_write_config(PCIDevice *dev,
>  {
>      PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
>  
> +    if (xen_enabled())
> +        xen_piix_pci_write_config_client(address, val, len);
> +
>      /* XXX: implement SMRAM.D_LOCK */
>      pci_default_write_config(dev, address, val, len);
>      if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||

Maybe do we want another PCIDeviceInfo whose difference is .write_config?
I'm not sure which is better, though.


> @@ -255,6 +263,11 @@ static void piix3_set_irq(void *opaque, int irq_num, int level)
>      int i, pic_irq, pic_level;
>      PIIX3State *piix3 = opaque;
>  
> +    if (xen_enabled()) {
> +        xen_piix3_set_irq(irq_num, level);
> +        return;
> +    }
> +
>      piix3->pci_irq_levels[irq_num] = level;

Ditto. Pass xen_piix3_set_irq() to pci_bus_irqs()?

thanks,

>  
>      /* now we change the pic irq level according to the piix irq mappings */
> diff --git a/hw/xen.h b/hw/xen.h
> index f1d01d3..77012c2 100644
> --- a/hw/xen.h
> +++ b/hw/xen.h
> @@ -26,4 +26,7 @@ extern int xen_allowed;
>  #define xen_enabled() (0)
>  #endif
>  
> +void xen_piix3_set_irq(int irq_num, int level);
> +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
> +
>  #endif /* QEMU_HW_XEN_H */
> diff --git a/xen-all.c b/xen-all.c
> index e69de29..2d789ad 100644
> --- a/xen-all.c
> +++ b/xen-all.c
> @@ -0,0 +1,25 @@
> +#include "config.h"
> +
> +#include "hw/xen.h"
> +#include "hw/xen_backend.h"
> +
> +void xen_piix3_set_irq(int irq_num, int level)
> +{
> +    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
> +            irq_num & 3, level);
> +}
> +
> +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
> +{
> +    int i;
> +
> +    /* Scan for updates to PCI link routes (0x60-0x63). */
> +    for (i = 0; i < len; i++) {
> +        uint8_t v = (val >> (8*i)) & 0xff;
> +        if (v & 0x80)
> +            v = 0;
> +        v &= 0xf;
> +        if (((address+i) >= 0x60) && ((address+i) <= 0x63))
> +            xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
> +    }
> +}
> diff --git a/xen-stub.c b/xen-stub.c
> index e69de29..38c64cf 100644
> --- a/xen-stub.c
> +++ b/xen-stub.c
> @@ -0,0 +1,9 @@
> +#include "hw/xen.h"
> +
> +void xen_piix3_set_irq(int irq_num, int level)
> +{
> +}
> +
> +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
> +{
> +}
> -- 
> 1.7.0.4
> 
> 

-- 
yamahata

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2010-08-24 11:10 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-23  9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
2010-08-23  9:49 ` Stefano Stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 01/15] xen: Support new libxc calls from xen unstable stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23 11:09   ` [Qemu-devel] " Juan Quintela
2010-08-23 11:09     ` Juan Quintela
2010-08-23 11:16     ` [Qemu-devel] " Stefano Stabellini
2010-08-23 11:16       ` Stefano Stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenctrl stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 07/15] xen: handle xenstore events stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 11/15] xen: Introduce --enable-xen command options stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-24 11:20   ` [Qemu-devel] " Isaku Yamahata
2010-08-23  9:50 ` [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23  9:50 ` [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen stefano.stabellini
2010-08-23  9:50   ` stefano.stabellini
2010-08-23 11:15   ` [Qemu-devel] " Juan Quintela
2010-08-23 11:15     ` Juan Quintela
2010-08-23 13:15     ` [Qemu-devel] " Stefano Stabellini
2010-08-23 13:15       ` Stefano Stabellini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.