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

Hi all,
this is the long awaited patch series to add xen device model support in
qemu; the main author is Anthony Perard.
Developing this series we tried to come up with the cleanest possible
solution from the qemu point of view, limiting the amount of changes to
common code as much as possible. The end result still requires a couple
of hooks in piix_pci but overall the impact should be very limited.
The current series gives you an upstream qemu device model able to boot
a Linux or a Windows HVM guest; some features are still missing
compared to the current qemu-xen, among which vga dirty bits, pci
passthrough and stubdomain support.

For any of you that want to try it, this is the step by step guide:

- clone a fresh copy of xen-unstable.hg, make and install;
note that the xen-unstable make system will clone a linux tree and a
qemu-xen tree by default: you can avoid the former just executing 'make
xen' and 'make tools' instead of 'make world';

- configure qemu using xen-dm-softmmu as target and extra-ldflags and
extra-cflags pointing at the xen-unstable build directory, something
like this should work:

./configure --target-list=xen-dm-softmmu --extra-cflags="-I$HOME/xen-unstable/dist/install/usr/include" --extra-ldflags="-L$HOME/xen-unstable/dist/install/usr/lib" --enable-xen

- build qemu and install the newly compiled binary
(xen-dm-softmmu/qemu-system-xen);

- edit your VM config file and modify device_model to point at it.


Currently only xl (not xend) knows how to spawn the new qemu device model
with the right command line options.
As you can see the build and test procedures are not straightforward
yet, but in the near future we plan to provide a way to select an
upstream qemu tree for use as xen device model directly from the
xen-unstable build system.

The patch series adds a new target with the whole xen device model
machinery; each patch contains a detailed description.
This is the full list of patches and the diffstat:

Anthony Perard (15):
    xen: Update libxc calls   
    xen: Add xen_machine_fv                                                                   
    xen: Add a new target to qemu: target-xen                                                 
    xen: xen_machine_fv, initialize xenstore                                                  
    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                                                           
    piix3: introduce register_set_irq and register_map_irq                                    
    piix_pci: introduce a write_config notifier                                               
    vl.c: Introduce getter for shutdown_requested and reset_requested.                        
    xen: destroy the VM when shutdown is requested                                            

 Makefile.target                    |   31 ++
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   12 +-
 default-configs/xen-dm-softmmu.mak |   24 +
 hw/pc.h                            |    4 +
 hw/piix_pci.c                      |   45 ++-
 hw/xen_acpi_piix4.c                |  424 ++++++++++++++++++
 hw/xen_backend.c                   |   10 +-
 hw/xen_backend.h                   |    2 +-
 hw/xen_common.h                    |    6 +
 hw/xen_disk.c                      |   12 +-
 hw/xen_domainbuild.c               |    4 +-
 hw/xen_machine_fv.c                |  234 ++++++++++
 hw/xen_nic.c                       |   16 +-
 hw/xen_platform.c                  |  452 ++++++++++++++++++++
 hw/xen_platform.h                  |    9 +
 sysemu.h                           |    2 +
 target-xen/cpu.h                   |  121 ++++++
 target-xen/exec-dm.c               |  826 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |  455 ++++++++++++++++++++
 target-xen/i8259-xen-stub.c        |   63 +++
 target-xen/qemu-xen.h              |   50 +++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |  247 +++++++++++
 target-xen/xenstore.c              |  168 ++++++++
 target-xen/xenstore.h              |   12 +
 vl.c                               |   10 +
 28 files changed, 3259 insertions(+), 25 deletions(-)


A git tree is available here:

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

branch name qemu-dm-v1.


We are committed in providing the best solution for both qemu and xen
developers and users communities; we greatly appreciate any help you can
give us to improve the quality of this series, including comments,
critics, suggestions and of course patches :)

Happy Hacking,

Stefano

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

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

Hi all,
this is the long awaited patch series to add xen device model support in
qemu; the main author is Anthony Perard.
Developing this series we tried to come up with the cleanest possible
solution from the qemu point of view, limiting the amount of changes to
common code as much as possible. The end result still requires a couple
of hooks in piix_pci but overall the impact should be very limited.
The current series gives you an upstream qemu device model able to boot
a Linux or a Windows HVM guest; some features are still missing
compared to the current qemu-xen, among which vga dirty bits, pci
passthrough and stubdomain support.

For any of you that want to try it, this is the step by step guide:

- clone a fresh copy of xen-unstable.hg, make and install;
note that the xen-unstable make system will clone a linux tree and a
qemu-xen tree by default: you can avoid the former just executing 'make
xen' and 'make tools' instead of 'make world';

- configure qemu using xen-dm-softmmu as target and extra-ldflags and
extra-cflags pointing at the xen-unstable build directory, something
like this should work:

./configure --target-list=xen-dm-softmmu --extra-cflags="-I$HOME/xen-unstable/dist/install/usr/include" --extra-ldflags="-L$HOME/xen-unstable/dist/install/usr/lib" --enable-xen

- build qemu and install the newly compiled binary
(xen-dm-softmmu/qemu-system-xen);

- edit your VM config file and modify device_model to point at it.


Currently only xl (not xend) knows how to spawn the new qemu device model
with the right command line options.
As you can see the build and test procedures are not straightforward
yet, but in the near future we plan to provide a way to select an
upstream qemu tree for use as xen device model directly from the
xen-unstable build system.

The patch series adds a new target with the whole xen device model
machinery; each patch contains a detailed description.
This is the full list of patches and the diffstat:

Anthony Perard (15):
    xen: Update libxc calls   
    xen: Add xen_machine_fv                                                                   
    xen: Add a new target to qemu: target-xen                                                 
    xen: xen_machine_fv, initialize xenstore                                                  
    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                                                           
    piix3: introduce register_set_irq and register_map_irq                                    
    piix_pci: introduce a write_config notifier                                               
    vl.c: Introduce getter for shutdown_requested and reset_requested.                        
    xen: destroy the VM when shutdown is requested                                            

 Makefile.target                    |   31 ++
 arch_init.c                        |    2 +
 arch_init.h                        |    1 +
 configure                          |   12 +-
 default-configs/xen-dm-softmmu.mak |   24 +
 hw/pc.h                            |    4 +
 hw/piix_pci.c                      |   45 ++-
 hw/xen_acpi_piix4.c                |  424 ++++++++++++++++++
 hw/xen_backend.c                   |   10 +-
 hw/xen_backend.h                   |    2 +-
 hw/xen_common.h                    |    6 +
 hw/xen_disk.c                      |   12 +-
 hw/xen_domainbuild.c               |    4 +-
 hw/xen_machine_fv.c                |  234 ++++++++++
 hw/xen_nic.c                       |   16 +-
 hw/xen_platform.c                  |  452 ++++++++++++++++++++
 hw/xen_platform.h                  |    9 +
 sysemu.h                           |    2 +
 target-xen/cpu.h                   |  121 ++++++
 target-xen/exec-dm.c               |  826 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |  455 ++++++++++++++++++++
 target-xen/i8259-xen-stub.c        |   63 +++
 target-xen/qemu-xen.h              |   50 +++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |  247 +++++++++++
 target-xen/xenstore.c              |  168 ++++++++
 target-xen/xenstore.h              |   12 +
 vl.c                               |   10 +
 28 files changed, 3259 insertions(+), 25 deletions(-)


A git tree is available here:

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

branch name qemu-dm-v1.


We are committed in providing the best solution for both qemu and xen
developers and users communities; we greatly appreciate any help you can
give us to improve the quality of this series, including comments,
critics, suggestions and of course patches :)

Happy Hacking,

Stefano

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

* [Qemu-devel] [PATCH 01/15] xen: Update libxc calls
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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            |    2 +-
 hw/xen_backend.c     |   10 +++++-----
 hw/xen_backend.h     |    2 +-
 hw/xen_disk.c        |   12 ++++++------
 hw/xen_domainbuild.c |    4 +++-
 hw/xen_nic.c         |   16 ++++++++--------
 6 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/configure b/configure
index a20371c..89d9b44 100755
--- a/configure
+++ b/configure
@@ -1102,7 +1102,7 @@ if test "$xen" != "no" ; then
   cat > $TMPC <<EOF
 #include <xenctrl.h>
 #include <xs.h>
-int main(void) { xs_daemon_open(); xc_interface_open(); return 0; }
+int main(void) { xs_daemon_open(); xc_interface_open(0, 0, 0); return 0; }
 EOF
   if compile_prog "" "$xen_libs" ; then
     xen=yes
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index a2e408f..b2d302b 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -43,7 +43,7 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-int xen_xc;
+xc_interface *xen_xc = NULL;
 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 == NULL) {
 	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..385e851 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -57,7 +57,7 @@ struct XenDevice {
 /* ------------------------------------------------------------- */
 
 /* variables */
-extern int xen_xc;
+extern xc_interface *xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
 
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..1620312 100644
--- a/hw/xen_domainbuild.c
+++ b/hw/xen_domainbuild.c
@@ -176,7 +176,9 @@ static int xen_domain_watcher(void)
     for (i = 3; i < n; i++) {
         if (i == fd[0])
             continue;
-        if (i == xen_xc)
+        // FIXME The fd of xen_xc is now xen_xc->fd
+        // fd is the first field, so this works
+        if (i == *(int*)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] 106+ messages in thread

* [PATCH 01/15] xen: Update libxc calls
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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            |    2 +-
 hw/xen_backend.c     |   10 +++++-----
 hw/xen_backend.h     |    2 +-
 hw/xen_disk.c        |   12 ++++++------
 hw/xen_domainbuild.c |    4 +++-
 hw/xen_nic.c         |   16 ++++++++--------
 6 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/configure b/configure
index a20371c..89d9b44 100755
--- a/configure
+++ b/configure
@@ -1102,7 +1102,7 @@ if test "$xen" != "no" ; then
   cat > $TMPC <<EOF
 #include <xenctrl.h>
 #include <xs.h>
-int main(void) { xs_daemon_open(); xc_interface_open(); return 0; }
+int main(void) { xs_daemon_open(); xc_interface_open(0, 0, 0); return 0; }
 EOF
   if compile_prog "" "$xen_libs" ; then
     xen=yes
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index a2e408f..b2d302b 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -43,7 +43,7 @@
 /* ------------------------------------------------------------- */
 
 /* public */
-int xen_xc;
+xc_interface *xen_xc = NULL;
 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 == NULL) {
 	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..385e851 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -57,7 +57,7 @@ struct XenDevice {
 /* ------------------------------------------------------------- */
 
 /* variables */
-extern int xen_xc;
+extern xc_interface *xen_xc;
 extern struct xs_handle *xenstore;
 extern const char *xen_protocol;
 
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..1620312 100644
--- a/hw/xen_domainbuild.c
+++ b/hw/xen_domainbuild.c
@@ -176,7 +176,9 @@ static int xen_domain_watcher(void)
     for (i = 3; i < n; i++) {
         if (i == fd[0])
             continue;
-        if (i == xen_xc)
+        // FIXME The fd of xen_xc is now xen_xc->fd
+        // fd is the first field, so this works
+        if (i == *(int*)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] 106+ messages in thread

* [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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] 106+ messages in thread

* [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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] 106+ messages in thread

* [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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                   |  120 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |   69 ++++
 target-xen/qemu-xen.h              |   30 ++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |   14 +
 11 files changed, 1130 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 89d9b44..c3f52ce 100755
--- a/configure
+++ b/configure
@@ -2517,6 +2517,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"
@@ -2582,6 +2585,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"
@@ -2693,7 +2700,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
@@ -2859,7 +2866,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..5a45d1c
--- /dev/null
+++ b/target-xen/cpu.h
@@ -0,0 +1,120 @@
+/*
+ * 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"
+
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#else
+#define TARGET_LONG_BITS 32
+#endif
+
+#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..3d64695
--- /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 mmio_space {
+    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..d588e64
--- /dev/null
+++ b/target-xen/helper.c
@@ -0,0 +1,69 @@
+/*
+ *  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));
+    if (!env)
+        return NULL;
+    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)
+{
+}
+
+/***********************************************************/
+/* x86 mmu */
+/* XXX: add PGE support */
+
+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] 106+ messages in thread

* [PATCH 03/15] xen: Add a new target to qemu: target-xen
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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                   |  120 ++++++
 target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
 target-xen/helper.c                |   69 ++++
 target-xen/qemu-xen.h              |   30 ++
 target-xen/stub-functions.c        |   42 ++
 target-xen/xen_mapcache.c          |   14 +
 11 files changed, 1130 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 89d9b44..c3f52ce 100755
--- a/configure
+++ b/configure
@@ -2517,6 +2517,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"
@@ -2582,6 +2585,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"
@@ -2693,7 +2700,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
@@ -2859,7 +2866,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..5a45d1c
--- /dev/null
+++ b/target-xen/cpu.h
@@ -0,0 +1,120 @@
+/*
+ * 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"
+
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#else
+#define TARGET_LONG_BITS 32
+#endif
+
+#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..3d64695
--- /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 mmio_space {
+    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..d588e64
--- /dev/null
+++ b/target-xen/helper.c
@@ -0,0 +1,69 @@
+/*
+ *  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));
+    if (!env)
+        return NULL;
+    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)
+{
+}
+
+/***********************************************************/
+/* x86 mmu */
+/* XXX: add PGE support */
+
+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] 106+ messages in thread

* [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenstore
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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 a new xenstore connection
and 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 |   24 ++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++++++
 4 files changed, 39 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..c202f66
--- /dev/null
+++ b/target-xen/xenstore.c
@@ -0,0 +1,24 @@
+#include "hw/xen_backend.h"
+#include "xenstore.h"
+
+int xen_dm_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    xen_xc = xc_interface_open(NULL, NULL, 0);
+    if (xen_xc == NULL) {
+        xen_be_printf(NULL, 0, "can't open xen interface\n");
+        goto err;
+    }
+    return 0;
+
+err:
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
+}
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] 106+ messages in thread

* [PATCH 04/15] xen: xen_machine_fv, initialize xenstore
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	Stefano Stabellini

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

Introduce a xen_dm_init function that opens a new xenstore connection
and 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 |   24 ++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++++++
 4 files changed, 39 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..c202f66
--- /dev/null
+++ b/target-xen/xenstore.c
@@ -0,0 +1,24 @@
+#include "hw/xen_backend.h"
+#include "xenstore.h"
+
+int xen_dm_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    xen_xc = xc_interface_open(NULL, NULL, 0);
+    if (xen_xc == NULL) {
+        xen_be_printf(NULL, 0, "can't open xen interface\n");
+        goto err;
+    }
+    return 0;
+
+err:
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
+}
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] 106+ messages in thread

* [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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 8a55b44..020fdd7 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -31,4 +31,7 @@
 # define xen_wmb() wmb()
 #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] 106+ messages in thread

* [PATCH 05/15] xen: add a 8259 Interrupt Controller
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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 8a55b44..020fdd7 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -31,4 +31,7 @@
 # define xen_wmb() wmb()
 #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] 106+ messages in thread

* [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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/xen_machine_fv.c |    4 +
 hw/xen_platform.c   |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_platform.h   |    9 +
 4 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/xen_machine_fv.c b/hw/xen_machine_fv.c
index 114addf..ec826e7 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,9 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     pc_vga_init(pci_bus);
 
+    pci_xen_platform_init(pci_bus);
+    platform_fixed_ioport_init();
+
     /* 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..85d3f8b
--- /dev/null
+++ b/hw/xen_platform.c
@@ -0,0 +1,452 @@
+/*
+ * 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>
+
+static int drivers_blacklisted;
+static uint16_t driver_product_version;
+static int throttling_disabled;
+static char log_buffer[4096];
+static int log_buffer_off;
+
+static uint8_t platform_flags;
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState
+{
+    PCIDevice  pci_dev;
+} PCIXenPlatformState;
+
+
+/* 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(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 (throttling_disabled)
+        return;
+
+    if (!started) {
+        clock_gettime(CLOCK_MONOTONIC, &last_refil);
+        available = BUCKET_MAX_SIZE;
+        started = 1;
+    }
+
+    if (count > BUCKET_MAX_SIZE) {
+        fprintf(stderr, "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) {
+                fprintf(stderr, "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;
+}
+
+#define UNPLUG_ALL_IDE_DISKS 1
+#define UNPLUG_ALL_NICS 2
+#define UNPLUG_AUX_IDE_DISKS 4
+
+static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val)
+{
+    switch (addr - 0x10) {
+    case 0:
+        /* 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:
+            fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n");
+            break;
+        case 0:
+            fprintf(stderr, "Guest claimed to be running PV product 0?\n");
+            break;
+        default:
+            fprintf(stderr, "Unknown PV product %d loaded in guest\n", val);
+            break;
+        }
+        driver_product_version = val;
+        break;
+    }
+}
+
+static void platform_fixed_ioport_write4(void *opaque, uint32_t addr,
+                                         uint32_t val)
+{
+    switch (addr - 0x10) {
+    case 0:
+        /* PV driver version */
+        break;
+    }
+}
+
+static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val)
+{
+    switch (addr - 0x10) {
+    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))
+            fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw "
+                    "state of ROM memory area!\n");
+        else {
+            platform_flags = val & PFFLAG_ROM_LOCK;
+            fprintf(stderr,"platform_fixed_ioport: 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' || log_buffer_off == sizeof(log_buffer) - 1) {
+            /* Flush buffer */
+            log_buffer[log_buffer_off] = 0;
+            throttle(log_buffer_off);
+            fprintf(stderr, "%s\n", log_buffer);
+            log_buffer_off = 0;
+            break;
+        }
+        log_buffer[log_buffer_off++] = val;
+        break;
+    }
+}
+
+static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr)
+{
+    switch (addr - 0x10) {
+    case 0:
+        if (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_read1(void *opaque, uint32_t addr)
+{
+    switch (addr - 0x10) {
+    case 0:
+        /* Platform flags */
+        return platform_flags;
+    case 2:
+        /* Version number */
+        return 1;
+    default:
+        return 0xff;
+    }
+}
+
+static void platform_fixed_ioport_save(QEMUFile *f, void *opaque)
+{
+    qemu_put_8s(f, &platform_flags);
+}
+
+static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id)
+{
+    uint8_t flags;
+
+    if (version_id > 1)
+        return -EINVAL;
+
+    qemu_get_8s(f, &flags);
+    platform_fixed_ioport_write1(NULL, 0x10, flags);
+
+    return 0;
+}
+
+void platform_fixed_ioport_init(void)
+{
+    register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save,
+                    platform_fixed_ioport_load, NULL);
+
+    register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL);
+    register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL);
+    register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL);
+    register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL);
+    register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL);
+
+    platform_fixed_ioport_write1(NULL, 0x10, 0);
+}
+
+static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
+{
+    addr &= 0xff;
+
+    return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u;
+}
+
+static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    addr &= 0xff;
+    val  &= 0xff;
+
+    switch (addr) {
+    case 0: /* Platform flags */
+        platform_fixed_ioport_write1(NULL, 0x10, val);
+        break;
+    case 8:
+        {
+            if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
+                /* Flush buffer */
+                log_buffer[log_buffer_off] = 0;
+                throttle(log_buffer_off);
+                fprintf(stderr, "%s\n", log_buffer);
+                log_buffer_off = 0;
+                break;
+            }
+            log_buffer[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 = (PCIXenPlatformState *)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) {
+        fprintf(stderr, "Warning: attempted read from physical address "
+                "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)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) {
+        fprintf(stderr, "Warning: attempted write of 0x%x to physical "
+                "address 0x%"PRIx64" in xen platform mmio space\n",
+                val, (uint64_t)addr);
+        warnings++;
+    }
+    return;
+}
+
+static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = {
+    platform_mmio_read,
+    platform_mmio_read,
+    platform_mmio_read,
+};
+
+static CPUWriteMemoryFunc *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, 0x1000000, mmio_io_addr);
+}
+
+struct pci_config_header {
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t command;
+    uint16_t status;
+    uint8_t  revision;
+    uint8_t  api;
+    uint8_t  subclass;
+    uint8_t  class;
+    uint8_t  cache_line_size; /* Units of 32 bit words */
+    uint8_t  latency_timer; /* In units of bus cycles */
+    uint8_t  header_type; /* Should be 0 */
+    uint8_t  bist; /* Built in self test */
+    uint32_t base_address_regs[6];
+    uint32_t reserved1;
+    uint16_t subsystem_vendor_id;
+    uint16_t subsystem_id;
+    uint32_t rom_addr;
+    uint32_t reserved3;
+    uint32_t reserved4;
+    uint8_t  interrupt_line;
+    uint8_t  interrupt_pin;
+    uint8_t  min_gnt;
+    uint8_t  max_lat;
+};
+
+static void xen_pci_save(QEMUFile *f, void *opaque)
+{
+    PCIXenPlatformState *d = opaque;
+    uint64_t t = 0;
+
+    pci_device_save(&d->pci_dev, f);
+    qemu_put_be64s(f, &t);
+}
+
+static int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PCIXenPlatformState *d = opaque;
+    int ret;
+
+    if (version_id > 3)
+        return -EINVAL;
+
+    ret = pci_device_load(&d->pci_dev, f);
+    if (ret < 0)
+        return ret;
+
+    if (version_id >= 2) {
+        if (version_id == 2) {
+            uint8_t flags;
+            qemu_get_8s(f, &flags);
+            xen_platform_ioport_writeb(d, 0, flags);
+        }
+        qemu_get_be64(f);
+    }
+
+    return 0;
+}
+
+void pci_xen_platform_init(PCIBus *bus)
+{
+    PCIXenPlatformState *d;
+    struct pci_config_header *pch;
+
+    printf("Register xen platform.\n");
+    d = (PCIXenPlatformState *)pci_register_device(
+        bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL);
+    pch = (struct pci_config_header *)d->pci_dev.config;
+    pch->vendor_id = 0x5853;
+    pch->device_id = 0x0001;
+    pch->command = 3; /* IO and memory access */
+    pch->revision = 1;
+    pch->api = 0;
+    pch->subclass = 0x80; /* Other */
+    pch->class = 0xff; /* Unclassified device class */
+    pch->header_type = 0;
+    pch->interrupt_pin = 1;
+
+    /* Microsoft WHQL requires non-zero subsystem IDs. */
+    /* http://www.pcisig.com/reflector/msg02205.html.  */
+    pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id.  */
+    pch->subsystem_id        = 0x0001;         /* Hardcode sub-id as 1. */
+
+    pci_register_bar(&d->pci_dev, 0, 0x100,
+                           PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
+
+    /* reserve 16MB mmio address for share memory*/
+    pci_register_bar(&d->pci_dev, 1, 0x1000000,
+                           PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
+
+    register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d);
+    printf("Done register platform.\n");
+}
+
diff --git a/hw/xen_platform.h b/hw/xen_platform.h
new file mode 100644
index 0000000..6eeff22
--- /dev/null
+++ b/hw/xen_platform.h
@@ -0,0 +1,9 @@
+#ifndef XEN_PLATFORM_H
+#define XEN_PLATFORM_H
+
+#include "hw/pci.h"
+
+void pci_xen_platform_init(PCIBus *bus);
+void platform_fixed_ioport_init(void);
+
+#endif
-- 
1.7.0.4

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

* [PATCH 06/15] xen: Add the Xen platform pci device
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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/xen_machine_fv.c |    4 +
 hw/xen_platform.c   |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_platform.h   |    9 +
 4 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/xen_machine_fv.c b/hw/xen_machine_fv.c
index 114addf..ec826e7 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,9 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     pc_vga_init(pci_bus);
 
+    pci_xen_platform_init(pci_bus);
+    platform_fixed_ioport_init();
+
     /* 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..85d3f8b
--- /dev/null
+++ b/hw/xen_platform.c
@@ -0,0 +1,452 @@
+/*
+ * 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>
+
+static int drivers_blacklisted;
+static uint16_t driver_product_version;
+static int throttling_disabled;
+static char log_buffer[4096];
+static int log_buffer_off;
+
+static uint8_t platform_flags;
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState
+{
+    PCIDevice  pci_dev;
+} PCIXenPlatformState;
+
+
+/* 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(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 (throttling_disabled)
+        return;
+
+    if (!started) {
+        clock_gettime(CLOCK_MONOTONIC, &last_refil);
+        available = BUCKET_MAX_SIZE;
+        started = 1;
+    }
+
+    if (count > BUCKET_MAX_SIZE) {
+        fprintf(stderr, "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) {
+                fprintf(stderr, "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;
+}
+
+#define UNPLUG_ALL_IDE_DISKS 1
+#define UNPLUG_ALL_NICS 2
+#define UNPLUG_AUX_IDE_DISKS 4
+
+static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val)
+{
+    switch (addr - 0x10) {
+    case 0:
+        /* 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:
+            fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n");
+            break;
+        case 0:
+            fprintf(stderr, "Guest claimed to be running PV product 0?\n");
+            break;
+        default:
+            fprintf(stderr, "Unknown PV product %d loaded in guest\n", val);
+            break;
+        }
+        driver_product_version = val;
+        break;
+    }
+}
+
+static void platform_fixed_ioport_write4(void *opaque, uint32_t addr,
+                                         uint32_t val)
+{
+    switch (addr - 0x10) {
+    case 0:
+        /* PV driver version */
+        break;
+    }
+}
+
+static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val)
+{
+    switch (addr - 0x10) {
+    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))
+            fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw "
+                    "state of ROM memory area!\n");
+        else {
+            platform_flags = val & PFFLAG_ROM_LOCK;
+            fprintf(stderr,"platform_fixed_ioport: 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' || log_buffer_off == sizeof(log_buffer) - 1) {
+            /* Flush buffer */
+            log_buffer[log_buffer_off] = 0;
+            throttle(log_buffer_off);
+            fprintf(stderr, "%s\n", log_buffer);
+            log_buffer_off = 0;
+            break;
+        }
+        log_buffer[log_buffer_off++] = val;
+        break;
+    }
+}
+
+static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr)
+{
+    switch (addr - 0x10) {
+    case 0:
+        if (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_read1(void *opaque, uint32_t addr)
+{
+    switch (addr - 0x10) {
+    case 0:
+        /* Platform flags */
+        return platform_flags;
+    case 2:
+        /* Version number */
+        return 1;
+    default:
+        return 0xff;
+    }
+}
+
+static void platform_fixed_ioport_save(QEMUFile *f, void *opaque)
+{
+    qemu_put_8s(f, &platform_flags);
+}
+
+static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id)
+{
+    uint8_t flags;
+
+    if (version_id > 1)
+        return -EINVAL;
+
+    qemu_get_8s(f, &flags);
+    platform_fixed_ioport_write1(NULL, 0x10, flags);
+
+    return 0;
+}
+
+void platform_fixed_ioport_init(void)
+{
+    register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save,
+                    platform_fixed_ioport_load, NULL);
+
+    register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL);
+    register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL);
+    register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL);
+    register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL);
+    register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL);
+
+    platform_fixed_ioport_write1(NULL, 0x10, 0);
+}
+
+static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
+{
+    addr &= 0xff;
+
+    return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u;
+}
+
+static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    addr &= 0xff;
+    val  &= 0xff;
+
+    switch (addr) {
+    case 0: /* Platform flags */
+        platform_fixed_ioport_write1(NULL, 0x10, val);
+        break;
+    case 8:
+        {
+            if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
+                /* Flush buffer */
+                log_buffer[log_buffer_off] = 0;
+                throttle(log_buffer_off);
+                fprintf(stderr, "%s\n", log_buffer);
+                log_buffer_off = 0;
+                break;
+            }
+            log_buffer[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 = (PCIXenPlatformState *)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) {
+        fprintf(stderr, "Warning: attempted read from physical address "
+                "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)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) {
+        fprintf(stderr, "Warning: attempted write of 0x%x to physical "
+                "address 0x%"PRIx64" in xen platform mmio space\n",
+                val, (uint64_t)addr);
+        warnings++;
+    }
+    return;
+}
+
+static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = {
+    platform_mmio_read,
+    platform_mmio_read,
+    platform_mmio_read,
+};
+
+static CPUWriteMemoryFunc *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, 0x1000000, mmio_io_addr);
+}
+
+struct pci_config_header {
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t command;
+    uint16_t status;
+    uint8_t  revision;
+    uint8_t  api;
+    uint8_t  subclass;
+    uint8_t  class;
+    uint8_t  cache_line_size; /* Units of 32 bit words */
+    uint8_t  latency_timer; /* In units of bus cycles */
+    uint8_t  header_type; /* Should be 0 */
+    uint8_t  bist; /* Built in self test */
+    uint32_t base_address_regs[6];
+    uint32_t reserved1;
+    uint16_t subsystem_vendor_id;
+    uint16_t subsystem_id;
+    uint32_t rom_addr;
+    uint32_t reserved3;
+    uint32_t reserved4;
+    uint8_t  interrupt_line;
+    uint8_t  interrupt_pin;
+    uint8_t  min_gnt;
+    uint8_t  max_lat;
+};
+
+static void xen_pci_save(QEMUFile *f, void *opaque)
+{
+    PCIXenPlatformState *d = opaque;
+    uint64_t t = 0;
+
+    pci_device_save(&d->pci_dev, f);
+    qemu_put_be64s(f, &t);
+}
+
+static int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PCIXenPlatformState *d = opaque;
+    int ret;
+
+    if (version_id > 3)
+        return -EINVAL;
+
+    ret = pci_device_load(&d->pci_dev, f);
+    if (ret < 0)
+        return ret;
+
+    if (version_id >= 2) {
+        if (version_id == 2) {
+            uint8_t flags;
+            qemu_get_8s(f, &flags);
+            xen_platform_ioport_writeb(d, 0, flags);
+        }
+        qemu_get_be64(f);
+    }
+
+    return 0;
+}
+
+void pci_xen_platform_init(PCIBus *bus)
+{
+    PCIXenPlatformState *d;
+    struct pci_config_header *pch;
+
+    printf("Register xen platform.\n");
+    d = (PCIXenPlatformState *)pci_register_device(
+        bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL);
+    pch = (struct pci_config_header *)d->pci_dev.config;
+    pch->vendor_id = 0x5853;
+    pch->device_id = 0x0001;
+    pch->command = 3; /* IO and memory access */
+    pch->revision = 1;
+    pch->api = 0;
+    pch->subclass = 0x80; /* Other */
+    pch->class = 0xff; /* Unclassified device class */
+    pch->header_type = 0;
+    pch->interrupt_pin = 1;
+
+    /* Microsoft WHQL requires non-zero subsystem IDs. */
+    /* http://www.pcisig.com/reflector/msg02205.html.  */
+    pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id.  */
+    pch->subsystem_id        = 0x0001;         /* Hardcode sub-id as 1. */
+
+    pci_register_bar(&d->pci_dev, 0, 0x100,
+                           PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
+
+    /* reserve 16MB mmio address for share memory*/
+    pci_register_bar(&d->pci_dev, 1, 0x1000000,
+                           PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
+
+    register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d);
+    printf("Done register platform.\n");
+}
+
diff --git a/hw/xen_platform.h b/hw/xen_platform.h
new file mode 100644
index 0000000..6eeff22
--- /dev/null
+++ b/hw/xen_platform.h
@@ -0,0 +1,9 @@
+#ifndef XEN_PLATFORM_H
+#define XEN_PLATFORM_H
+
+#include "hw/pci.h"
+
+void pci_xen_platform_init(PCIBus *bus);
+void platform_fixed_ioport_init(void);
+
+#endif
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH 07/15] xen: handle xenstore events
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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 |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index c202f66..9f2e1ea 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -1,6 +1,18 @@
 #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();
@@ -9,6 +21,9 @@ int xen_dm_init(void)
         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");
@@ -17,6 +32,7 @@ int xen_dm_init(void)
     return 0;
 
 err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
     xs_daemon_close(xenstore);
     xenstore = NULL;
 
-- 
1.7.0.4

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

* [PATCH 07/15] xen: handle xenstore events
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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 |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index c202f66..9f2e1ea 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -1,6 +1,18 @@
 #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();
@@ -9,6 +21,9 @@ int xen_dm_init(void)
         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");
@@ -17,6 +32,7 @@ int xen_dm_init(void)
     return 0;
 
 err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
     xs_daemon_close(xenstore);
     xenstore = NULL;
 
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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 |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++
 5 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index ec826e7..a6e778a 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,
@@ -150,6 +157,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 d588e64..8cb7771 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)
 {
@@ -67,3 +69,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 9f2e1ea..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();
@@ -29,6 +83,7 @@ int xen_dm_init(void)
         xen_be_printf(NULL, 0, "can't open xen interface\n");
         goto err;
     }
+
     return 0;
 
 err:
@@ -38,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] 106+ messages in thread

* [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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 |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/xenstore.h |    6 ++
 5 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index ec826e7..a6e778a 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,
@@ -150,6 +157,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 d588e64..8cb7771 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)
 {
@@ -67,3 +69,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 9f2e1ea..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();
@@ -29,6 +83,7 @@ int xen_dm_init(void)
         xen_be_printf(NULL, 0, "can't open xen interface\n");
         goto err;
     }
+
     return 0;
 
 err:
@@ -38,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] 106+ messages in thread

* [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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   |   25 ++++
 target-xen/cpu.h      |    1 +
 target-xen/helper.c   |  362 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/qemu-xen.h |    2 +
 4 files changed, 390 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index a6e778a..b1bc88d 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,34 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     CPUState *env;
 
+    unsigned long ioreq_pfn;
+    extern void *shared_page;
+    extern void *buffered_io_page;
+
     /* 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) {
+        fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc);
+        exit(-1);
+    }
+
+    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) {
+        fprintf(logfile, "map buffered IO page returned error %d\n", errno);
+        exit(-1);
+    }
+
     /* 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 5a45d1c..573241f 100644
--- a/target-xen/cpu.h
+++ b/target-xen/cpu.h
@@ -72,6 +72,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);
diff --git a/target-xen/helper.c b/target-xen/helper.c
index 8cb7771..4571ac0 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -18,25 +18,77 @@
  * 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));
     if (!env)
         return NULL;
     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));
+    if (!ioreq_local_port)
+        return NULL;
+
     /* 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;
@@ -70,7 +122,317 @@ 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(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(i);
+    }
+
+    // read error or read nothing
+    return NULL;
+}
+
+static unsigned long do_inp(CPUState *env, unsigned long 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:
+            fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size);
+            exit(-1);
+    }
+}
+
+static void do_outp(CPUState *env, unsigned long addr,
+        unsigned long size, unsigned long 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:
+            fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size);
+            exit(-1);
+    }
+}
+
+static inline void read_physical(uint64_t addr, unsigned long size, void *val)
+{
+    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
+}
+
+static inline void write_physical(uint64_t addr, unsigned long size, void *val)
+{
+    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
+}
+
+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 {
+            unsigned long tmp;
+
+            for (i = 0; i < req->count; i++) {
+                tmp = do_inp(env, req->addr, req->size);
+                write_physical((target_phys_addr_t) req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+            }
+        }
+    } 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++) {
+                unsigned long tmp = 0;
+
+                read_physical((target_phys_addr_t) req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+                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++) {
+                read_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &req->data);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                write_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &req->data);
+            }
+        }
+    } else {
+        target_ulong tmp;
+
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                read_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+                write_physical((target_phys_addr_t )req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                read_physical((target_phys_addr_t) req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+                write_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+            }
+        }
+    }
+}
+
+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);
+    sprintf(b, "%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 *xcHandle;
+    int sts;
+
+    xcHandle = xc_interface_open(NULL, NULL, 0);
+    if (xcHandle < 0)
+        fprintf(stderr, "Cannot acquire xenctrl handle\n");
+    else {
+        sts = xc_domain_shutdown(xcHandle, 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(xcHandle);
+    }
+}
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] 106+ messages in thread

* [PATCH 09/15] xen: Initialize event channels and io rings
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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   |   25 ++++
 target-xen/cpu.h      |    1 +
 target-xen/helper.c   |  362 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-xen/qemu-xen.h |    2 +
 4 files changed, 390 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index a6e778a..b1bc88d 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,34 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     CPUState *env;
 
+    unsigned long ioreq_pfn;
+    extern void *shared_page;
+    extern void *buffered_io_page;
+
     /* 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) {
+        fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc);
+        exit(-1);
+    }
+
+    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) {
+        fprintf(logfile, "map buffered IO page returned error %d\n", errno);
+        exit(-1);
+    }
+
     /* 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 5a45d1c..573241f 100644
--- a/target-xen/cpu.h
+++ b/target-xen/cpu.h
@@ -72,6 +72,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);
diff --git a/target-xen/helper.c b/target-xen/helper.c
index 8cb7771..4571ac0 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -18,25 +18,77 @@
  * 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));
     if (!env)
         return NULL;
     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));
+    if (!ioreq_local_port)
+        return NULL;
+
     /* 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;
@@ -70,7 +122,317 @@ 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(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(i);
+    }
+
+    // read error or read nothing
+    return NULL;
+}
+
+static unsigned long do_inp(CPUState *env, unsigned long 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:
+            fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size);
+            exit(-1);
+    }
+}
+
+static void do_outp(CPUState *env, unsigned long addr,
+        unsigned long size, unsigned long 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:
+            fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size);
+            exit(-1);
+    }
+}
+
+static inline void read_physical(uint64_t addr, unsigned long size, void *val)
+{
+    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
+}
+
+static inline void write_physical(uint64_t addr, unsigned long size, void *val)
+{
+    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
+}
+
+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 {
+            unsigned long tmp;
+
+            for (i = 0; i < req->count; i++) {
+                tmp = do_inp(env, req->addr, req->size);
+                write_physical((target_phys_addr_t) req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+            }
+        }
+    } 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++) {
+                unsigned long tmp = 0;
+
+                read_physical((target_phys_addr_t) req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+                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++) {
+                read_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &req->data);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                write_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &req->data);
+            }
+        }
+    } else {
+        target_ulong tmp;
+
+        if (req->dir == IOREQ_READ) {
+            for (i = 0; i < req->count; i++) {
+                read_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+                write_physical((target_phys_addr_t )req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+            }
+        } else if (req->dir == IOREQ_WRITE) {
+            for (i = 0; i < req->count; i++) {
+                read_physical((target_phys_addr_t) req->data
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+                write_physical(req->addr
+                        + (sign * i * req->size),
+                        req->size, &tmp);
+            }
+        }
+    }
+}
+
+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);
+    sprintf(b, "%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 *xcHandle;
+    int sts;
+
+    xcHandle = xc_interface_open(NULL, NULL, 0);
+    if (xcHandle < 0)
+        fprintf(stderr, "Cannot acquire xenctrl handle\n");
+    else {
+        sts = xc_domain_shutdown(xcHandle, 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(xcHandle);
+    }
+}
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] 106+ messages in thread

* [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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 |  233 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 255 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index b1bc88d..58237d6 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -84,6 +84,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..efe036c 100644
--- a/target-xen/xen_mapcache.c
+++ b/target-xen/xen_mapcache.c
@@ -1,5 +1,237 @@
+#include "config.h"
+
+#include "hw/xen_backend.h"
 #include "qemu-xen.h"
 
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#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))))
+
+struct map_cache {
+    unsigned long paddr_index;
+    uint8_t      *vaddr_base;
+    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
+    uint8_t lock;
+    struct map_cache *next;
+};
+
+struct map_cache_rev {
+    uint8_t      *vaddr_req;
+    unsigned long paddr_index;
+    QTAILQ_ENTRY(map_cache_rev) next;
+};
+
+static struct map_cache *mapcache_entry;
+static unsigned long nr_buckets;
+QTAILQ_HEAD(map_cache_head, map_cache_rev) locked_entries = QTAILQ_HEAD_INITIALIZER(locked_entries);
+
+/* For most cases (>99.9%), the page address is the same. */
+static unsigned long last_address_index = ~0UL;
+static uint8_t      *last_address_vaddr;
+
+int qemu_map_cache_init(void)
+{
+    unsigned long size;
+
+    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 = nr_buckets * sizeof(struct map_cache);
+    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+    fprintf(stderr, "qemu_map_cache_init nr_buckets = %lx size %lu\n", 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(struct map_cache *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)
+{
+    struct map_cache *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 == last_address_index && !lock)
+        return last_address_vaddr + address_offset;
+
+    entry = &mapcache_entry[address_index % 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(struct map_cache));
+        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)) {
+        last_address_index = ~0UL;
+        return NULL;
+    }
+
+    last_address_index = address_index;
+    last_address_vaddr = entry->vaddr_base;
+    if (lock) {
+        struct map_cache_rev *reventry = qemu_mallocz(sizeof(struct map_cache_rev));
+        entry->lock++;
+        reventry->vaddr_req = last_address_vaddr + address_offset;
+        reventry->paddr_index = last_address_index;
+        QTAILQ_INSERT_TAIL(&locked_entries, reventry, next);
+    }
+
+    return last_address_vaddr + address_offset;
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+    struct map_cache *entry = NULL, *pentry = NULL;
+    struct map_cache_rev *reventry;
+    unsigned long paddr_index;
+    int found = 0;
+
+    if (last_address_vaddr == buffer)
+        last_address_index =  ~0UL;
+
+    QTAILQ_FOREACH(reventry, &locked_entries, next) {
+        if (reventry->vaddr_req == buffer) {
+            paddr_index = reventry->paddr_index;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        fprintf(stderr, "qemu_invalidate_entry: could not find %p\n", buffer);
+        QTAILQ_FOREACH(reventry, &locked_entries, next) {
+            fprintf(stderr, "   %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+        }
+        return;
+    }
+    QTAILQ_REMOVE(&locked_entries, reventry, next);
+    qemu_free(reventry);
+
+    entry = &mapcache_entry[paddr_index % nr_buckets];
+    while (entry && entry->paddr_index != paddr_index) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        fprintf(stderr, "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;
+    struct map_cache_rev *reventry;
+
+    qemu_aio_flush();
+
+    QTAILQ_FOREACH(reventry, &locked_entries, next) {
+        fprintf(stderr, "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 < nr_buckets; i++) {
+        struct map_cache *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;
+    }
+
+    last_address_index =  ~0UL;
+    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 +244,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] 106+ messages in thread

* [PATCH 10/15] xen: Introduce the Xen mapcache
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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 |  233 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 255 insertions(+), 0 deletions(-)

diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index b1bc88d..58237d6 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -84,6 +84,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..efe036c 100644
--- a/target-xen/xen_mapcache.c
+++ b/target-xen/xen_mapcache.c
@@ -1,5 +1,237 @@
+#include "config.h"
+
+#include "hw/xen_backend.h"
 #include "qemu-xen.h"
 
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#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))))
+
+struct map_cache {
+    unsigned long paddr_index;
+    uint8_t      *vaddr_base;
+    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
+    uint8_t lock;
+    struct map_cache *next;
+};
+
+struct map_cache_rev {
+    uint8_t      *vaddr_req;
+    unsigned long paddr_index;
+    QTAILQ_ENTRY(map_cache_rev) next;
+};
+
+static struct map_cache *mapcache_entry;
+static unsigned long nr_buckets;
+QTAILQ_HEAD(map_cache_head, map_cache_rev) locked_entries = QTAILQ_HEAD_INITIALIZER(locked_entries);
+
+/* For most cases (>99.9%), the page address is the same. */
+static unsigned long last_address_index = ~0UL;
+static uint8_t      *last_address_vaddr;
+
+int qemu_map_cache_init(void)
+{
+    unsigned long size;
+
+    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 = nr_buckets * sizeof(struct map_cache);
+    size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+    fprintf(stderr, "qemu_map_cache_init nr_buckets = %lx size %lu\n", 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(struct map_cache *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)
+{
+    struct map_cache *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 == last_address_index && !lock)
+        return last_address_vaddr + address_offset;
+
+    entry = &mapcache_entry[address_index % 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(struct map_cache));
+        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)) {
+        last_address_index = ~0UL;
+        return NULL;
+    }
+
+    last_address_index = address_index;
+    last_address_vaddr = entry->vaddr_base;
+    if (lock) {
+        struct map_cache_rev *reventry = qemu_mallocz(sizeof(struct map_cache_rev));
+        entry->lock++;
+        reventry->vaddr_req = last_address_vaddr + address_offset;
+        reventry->paddr_index = last_address_index;
+        QTAILQ_INSERT_TAIL(&locked_entries, reventry, next);
+    }
+
+    return last_address_vaddr + address_offset;
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+    struct map_cache *entry = NULL, *pentry = NULL;
+    struct map_cache_rev *reventry;
+    unsigned long paddr_index;
+    int found = 0;
+
+    if (last_address_vaddr == buffer)
+        last_address_index =  ~0UL;
+
+    QTAILQ_FOREACH(reventry, &locked_entries, next) {
+        if (reventry->vaddr_req == buffer) {
+            paddr_index = reventry->paddr_index;
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        fprintf(stderr, "qemu_invalidate_entry: could not find %p\n", buffer);
+        QTAILQ_FOREACH(reventry, &locked_entries, next) {
+            fprintf(stderr, "   %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+        }
+        return;
+    }
+    QTAILQ_REMOVE(&locked_entries, reventry, next);
+    qemu_free(reventry);
+
+    entry = &mapcache_entry[paddr_index % nr_buckets];
+    while (entry && entry->paddr_index != paddr_index) {
+        pentry = entry;
+        entry = entry->next;
+    }
+    if (!entry) {
+        fprintf(stderr, "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;
+    struct map_cache_rev *reventry;
+
+    qemu_aio_flush();
+
+    QTAILQ_FOREACH(reventry, &locked_entries, next) {
+        fprintf(stderr, "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 < nr_buckets; i++) {
+        struct map_cache *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;
+    }
+
+    last_address_index =  ~0UL;
+    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 +244,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] 106+ messages in thread

* [Qemu-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 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 a generic function registration mechanism for
set_irq and map_irq in piix3, so that the two calls can be
overridden with platform specific functions whenever needed.
The patch also implements and registers the Xen specific version of the
functions.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/pc.h             |    3 +++
 hw/piix_pci.c       |   17 ++++++++++++++++-
 hw/xen_machine_fv.c |   14 ++++++++++++++
 3 files changed, 33 insertions(+), 1 deletions(-)

diff --git a/hw/pc.h b/hw/pc.h
index 63b0249..ee562cd 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -5,6 +5,7 @@
 #include "ioport.h"
 #include "isa.h"
 #include "fdc.h"
+#include "pci.h"
 
 /* PC-style peripherals (also used by other machines).  */
 
@@ -138,6 +139,8 @@ int pcspk_audio_init(qemu_irq *pic);
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
 
+void piix3_register_set_irq(pci_set_irq_fn set_irq);
+void piix3_register_map_irq(pci_map_irq_fn map_irq);
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
 void i440fx_init_memory_mappings(PCII440FXState *d);
 
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0f..56e3f61 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -55,6 +55,21 @@ struct PCII440FXState {
 #define I440FX_SMRAM    0x72
 
 static void piix3_set_irq(void *opaque, int irq_num, int level);
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
+
+static pci_set_irq_fn piix3_set_irq_handler = piix3_set_irq;
+static pci_map_irq_fn piix3_map_irq_handler = pci_slot_get_pirq;
+
+/* Must be called before call i440fx_init() */
+void piix3_register_set_irq(pci_set_irq_fn set_irq)
+{
+    piix3_set_irq_handler = set_irq;
+}
+
+void piix3_register_map_irq(pci_map_irq_fn map_irq)
+{
+    piix3_map_irq_handler = map_irq;
+}
 
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
@@ -235,7 +250,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
     piix3 = DO_UPCAST(PIIX3State, dev,
                       pci_create_simple_multifunction(b, -1, true, "PIIX3"));
     piix3->pic = pic;
-    pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
+    pci_bus_irqs(b, piix3_set_irq_handler, piix3_map_irq_handler, piix3, 4);
     (*pi440fx_state)->piix3 = piix3;
 
     *piix3_devfn = piix3->dev.devfn;
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 58237d6..5d553b6 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -50,6 +50,18 @@ static void xen_vm_change_state_handler(void *opaque, int running, int reason)
         xen_main_loop_prepare();
 }
 
+static int xen_piix3_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return irq_num + ((pci_dev->devfn >> 3) << 2);
+}
+
+static void xen_piix3_set_irq(void *opaque, int irq_num, int level)
+{
+    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+            irq_num & 3, level);
+}
+
+
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -126,6 +138,8 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
 
+    piix3_register_set_irq(xen_piix3_set_irq);
+    piix3_register_map_irq(xen_piix3_map_irq);
     pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
     isa_bus_irqs(isa_irq);
 
-- 
1.7.0.4

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

* [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	Stefano Stabellini

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

This patch introduces a generic function registration mechanism for
set_irq and map_irq in piix3, so that the two calls can be
overridden with platform specific functions whenever needed.
The patch also implements and registers the Xen specific version of the
functions.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/pc.h             |    3 +++
 hw/piix_pci.c       |   17 ++++++++++++++++-
 hw/xen_machine_fv.c |   14 ++++++++++++++
 3 files changed, 33 insertions(+), 1 deletions(-)

diff --git a/hw/pc.h b/hw/pc.h
index 63b0249..ee562cd 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -5,6 +5,7 @@
 #include "ioport.h"
 #include "isa.h"
 #include "fdc.h"
+#include "pci.h"
 
 /* PC-style peripherals (also used by other machines).  */
 
@@ -138,6 +139,8 @@ int pcspk_audio_init(qemu_irq *pic);
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
 
+void piix3_register_set_irq(pci_set_irq_fn set_irq);
+void piix3_register_map_irq(pci_map_irq_fn map_irq);
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
 void i440fx_init_memory_mappings(PCII440FXState *d);
 
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0f..56e3f61 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -55,6 +55,21 @@ struct PCII440FXState {
 #define I440FX_SMRAM    0x72
 
 static void piix3_set_irq(void *opaque, int irq_num, int level);
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
+
+static pci_set_irq_fn piix3_set_irq_handler = piix3_set_irq;
+static pci_map_irq_fn piix3_map_irq_handler = pci_slot_get_pirq;
+
+/* Must be called before call i440fx_init() */
+void piix3_register_set_irq(pci_set_irq_fn set_irq)
+{
+    piix3_set_irq_handler = set_irq;
+}
+
+void piix3_register_map_irq(pci_map_irq_fn map_irq)
+{
+    piix3_map_irq_handler = map_irq;
+}
 
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
@@ -235,7 +250,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
     piix3 = DO_UPCAST(PIIX3State, dev,
                       pci_create_simple_multifunction(b, -1, true, "PIIX3"));
     piix3->pic = pic;
-    pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
+    pci_bus_irqs(b, piix3_set_irq_handler, piix3_map_irq_handler, piix3, 4);
     (*pi440fx_state)->piix3 = piix3;
 
     *piix3_devfn = piix3->dev.devfn;
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 58237d6..5d553b6 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -50,6 +50,18 @@ static void xen_vm_change_state_handler(void *opaque, int running, int reason)
         xen_main_loop_prepare();
 }
 
+static int xen_piix3_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return irq_num + ((pci_dev->devfn >> 3) << 2);
+}
+
+static void xen_piix3_set_irq(void *opaque, int irq_num, int level)
+{
+    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+            irq_num & 3, level);
+}
+
+
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
                         const char *kernel_filename,
@@ -126,6 +138,8 @@ static void xen_init_fv(ram_addr_t ram_size,
 
     isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
 
+    piix3_register_set_irq(xen_piix3_set_irq);
+    piix3_register_map_irq(xen_piix3_map_irq);
     pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
     isa_bus_irqs(isa_irq);
 
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:09   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, Stefano Stabellini

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

Introduce a write config notifier in piix_pci, so that clients can be
notified every time a pci config write happens.
The patch also makes use of the notification mechanism in
xen_machine_fv.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/pc.h             |    1 +
 hw/piix_pci.c       |   28 ++++++++++++++++++++++++++++
 hw/xen_machine_fv.c |   16 ++++++++++++++++
 3 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/hw/pc.h b/hw/pc.h
index ee562cd..3a745ae 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -141,6 +141,7 @@ typedef struct PCII440FXState PCII440FXState;
 
 void piix3_register_set_irq(pci_set_irq_fn set_irq);
 void piix3_register_map_irq(pci_map_irq_fn map_irq);
+void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config);
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
 void i440fx_init_memory_mappings(PCII440FXState *d);
 
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 56e3f61..afa9e9d 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -49,6 +49,13 @@ struct PCII440FXState {
     PIIX3State *piix3;
 };
 
+typedef struct PCII440FXWriteConfigNotifier {
+    PCIConfigWriteFunc *write_config;
+    QLIST_ENTRY(PCII440FXWriteConfigNotifier) next;
+} PCII440FXWriteConfigNotifier;
+
+static QLIST_HEAD(write_config_list, PCII440FXWriteConfigNotifier) write_config_list
+    = QLIST_HEAD_INITIALIZER(write_config_list);
 
 #define I440FX_PAM      0x59
 #define I440FX_PAM_SIZE 7
@@ -71,6 +78,25 @@ void piix3_register_map_irq(pci_map_irq_fn map_irq)
     piix3_map_irq_handler = map_irq;
 }
 
+void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config)
+{
+    PCII440FXWriteConfigNotifier *new_notifier;
+
+    assert(write_config);
+    new_notifier = qemu_mallocz(sizeof(PCII440FXWriteConfigNotifier));
+    new_notifier->write_config = write_config;
+    QLIST_INSERT_HEAD(&write_config_list, new_notifier, next);
+}
+
+static void piix_pci_notify_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len)
+{
+    PCII440FXWriteConfigNotifier *notifier;
+
+    QLIST_FOREACH(notifier, &write_config_list, next) {
+        notifier->write_config(dev, address, val, len);
+    }
+}
+
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
    mapping. */
@@ -157,6 +183,8 @@ static void i440fx_write_config(PCIDevice *dev,
 {
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
+    piix_pci_notify_write_config(dev, 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) ||
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 5d553b6..77563db 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -61,6 +61,21 @@ static void xen_piix3_set_irq(void *opaque, int irq_num, int level)
             irq_num & 3, level);
 }
 
+static void xen_piix_pci_write_config_client(PCIDevice *dev,
+        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);
+    }
+}
 
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
@@ -141,6 +156,7 @@ static void xen_init_fv(ram_addr_t ram_size,
     piix3_register_set_irq(xen_piix3_set_irq);
     piix3_register_map_irq(xen_piix3_map_irq);
     pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+    piix_pci_register_write_config_notifier(i440fx_state, xen_piix_pci_write_config_client);
     isa_bus_irqs(isa_irq);
 
     pc_register_ferr_irq(isa_reserve_irq(13));
-- 
1.7.0.4

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

* [PATCH 12/15] piix_pci: introduce a write_config notifier
@ 2010-08-12 14:09   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	Stefano Stabellini

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

Introduce a write config notifier in piix_pci, so that clients can be
notified every time a pci config write happens.
The patch also makes use of the notification mechanism in
xen_machine_fv.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 hw/pc.h             |    1 +
 hw/piix_pci.c       |   28 ++++++++++++++++++++++++++++
 hw/xen_machine_fv.c |   16 ++++++++++++++++
 3 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/hw/pc.h b/hw/pc.h
index ee562cd..3a745ae 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -141,6 +141,7 @@ typedef struct PCII440FXState PCII440FXState;
 
 void piix3_register_set_irq(pci_set_irq_fn set_irq);
 void piix3_register_map_irq(pci_map_irq_fn map_irq);
+void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config);
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
 void i440fx_init_memory_mappings(PCII440FXState *d);
 
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 56e3f61..afa9e9d 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -49,6 +49,13 @@ struct PCII440FXState {
     PIIX3State *piix3;
 };
 
+typedef struct PCII440FXWriteConfigNotifier {
+    PCIConfigWriteFunc *write_config;
+    QLIST_ENTRY(PCII440FXWriteConfigNotifier) next;
+} PCII440FXWriteConfigNotifier;
+
+static QLIST_HEAD(write_config_list, PCII440FXWriteConfigNotifier) write_config_list
+    = QLIST_HEAD_INITIALIZER(write_config_list);
 
 #define I440FX_PAM      0x59
 #define I440FX_PAM_SIZE 7
@@ -71,6 +78,25 @@ void piix3_register_map_irq(pci_map_irq_fn map_irq)
     piix3_map_irq_handler = map_irq;
 }
 
+void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config)
+{
+    PCII440FXWriteConfigNotifier *new_notifier;
+
+    assert(write_config);
+    new_notifier = qemu_mallocz(sizeof(PCII440FXWriteConfigNotifier));
+    new_notifier->write_config = write_config;
+    QLIST_INSERT_HEAD(&write_config_list, new_notifier, next);
+}
+
+static void piix_pci_notify_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len)
+{
+    PCII440FXWriteConfigNotifier *notifier;
+
+    QLIST_FOREACH(notifier, &write_config_list, next) {
+        notifier->write_config(dev, address, val, len);
+    }
+}
+
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
    mapping. */
@@ -157,6 +183,8 @@ static void i440fx_write_config(PCIDevice *dev,
 {
     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
+    piix_pci_notify_write_config(dev, 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) ||
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 5d553b6..77563db 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -61,6 +61,21 @@ static void xen_piix3_set_irq(void *opaque, int irq_num, int level)
             irq_num & 3, level);
 }
 
+static void xen_piix_pci_write_config_client(PCIDevice *dev,
+        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);
+    }
+}
 
 static void xen_init_fv(ram_addr_t ram_size,
                         const char *boot_device,
@@ -141,6 +156,7 @@ static void xen_init_fv(ram_addr_t ram_size,
     piix3_register_set_irq(xen_piix3_set_irq);
     piix3_register_map_irq(xen_piix3_map_irq);
     pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+    piix_pci_register_write_config_notifier(i440fx_state, xen_piix_pci_write_config_client);
     isa_bus_irqs(isa_irq);
 
     pc_register_ferr_irq(isa_reserve_irq(13));
-- 
1.7.0.4

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

* [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested.
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:10   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:10 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 b3e3676..1ff727f 100644
--- a/vl.c
+++ b/vl.c
@@ -1129,6 +1129,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] 106+ messages in thread

* [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested.
@ 2010-08-12 14:10   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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 b3e3676..1ff727f 100644
--- a/vl.c
+++ b/vl.c
@@ -1129,6 +1129,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] 106+ messages in thread

* [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:10   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:10 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 |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/target-xen/helper.c b/target-xen/helper.c
index 4571ac0..16e628c 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -397,6 +397,23 @@ 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()) {
+                fprintf(stderr, "shutdown requested in cpu_handle_ioreq\n");
+                destroy_hvm_domain();
+            }
+            if (qemu_reset_requested_get()) {
+                fprintf(stderr, "reset requested in cpu_handle_ioreq.\n");
+                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] 106+ messages in thread

* [PATCH 14/15] xen: destroy the VM when shutdown is requested
@ 2010-08-12 14:10   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:10 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 |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/target-xen/helper.c b/target-xen/helper.c
index 4571ac0..16e628c 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -397,6 +397,23 @@ 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()) {
+                fprintf(stderr, "shutdown requested in cpu_handle_ioreq\n");
+                destroy_hvm_domain();
+            }
+            if (qemu_reset_requested_get()) {
+                fprintf(stderr, "reset requested in cpu_handle_ioreq.\n");
+                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] 106+ messages in thread

* [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-12 14:10   ` stefano.stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:10 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 1984cdd..a2d9217 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -325,6 +325,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 020fdd7..e1f07ba 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -34,4 +34,7 @@
 /* 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 77563db..bfda944 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -92,7 +92,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;
@@ -208,10 +207,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] 106+ messages in thread

* [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
@ 2010-08-12 14:10   ` stefano.stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: stefano.stabellini @ 2010-08-12 14:10 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony.Perard, Anthony PERARD, xen-devel, Anthony Liguori,
	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 1984cdd..a2d9217 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -325,6 +325,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 020fdd7..e1f07ba 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -34,4 +34,7 @@
 /* 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 77563db..bfda944 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -92,7 +92,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;
@@ -208,10 +207,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] 106+ messages in thread

* [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
  2010-08-12 14:09   ` stefano.stabellini
@ 2010-08-12 14:19     ` Paolo Bonzini
  -1 siblings, 0 replies; 106+ messages in thread
From: Paolo Bonzini @ 2010-08-12 14:19 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:
> 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.

What's the earliest version of libxc that will be supported after this 
patch?

Thanks!

Paolo

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

* Re: [PATCH 01/15] xen: Update libxc calls
@ 2010-08-12 14:19     ` Paolo Bonzini
  0 siblings, 0 replies; 106+ messages in thread
From: Paolo Bonzini @ 2010-08-12 14:19 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:
> 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.

What's the earliest version of libxc that will be supported after this 
patch?

Thanks!

Paolo

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

* [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
  2010-08-12 14:19     ` Paolo Bonzini
@ 2010-08-12 14:28       ` Stefano Stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-12 14:28 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Thu, 12 Aug 2010, Paolo Bonzini wrote:
> On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:
> > 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.
> 
> What's the earliest version of libxc that will be supported after this 
> patch?
 
xen-unstable only at the moment.

We can probably add some #define so that qemu can work with both (old
and new versions of libxc).

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

* Re: [PATCH 01/15] xen: Update libxc calls
@ 2010-08-12 14:28       ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-12 14:28 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Anthony Perard, xen-devel, qemu-devel, Anthony Liguori,
	Stefano Stabellini

On Thu, 12 Aug 2010, Paolo Bonzini wrote:
> On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:
> > 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.
> 
> What's the earliest version of libxc that will be supported after this 
> patch?
 
xen-unstable only at the moment.

We can probably add some #define so that qemu can work with both (old
and new versions of libxc).

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

* [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
  2010-08-12 14:28       ` Stefano Stabellini
@ 2010-08-12 14:29         ` Stefano Stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-12 14:29 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, qemu-devel, Anthony, Anthony Perard, Paolo Bonzini

On Thu, 12 Aug 2010, Stefano Stabellini wrote:
> On Thu, 12 Aug 2010, Paolo Bonzini wrote:
> > On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:
> > > 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.
> > 
> > What's the earliest version of libxc that will be supported after this 
> > patch?
>  
> xen-unstable only at the moment.
> 
> We can probably add some #define so that qemu can work with both (old
> and new versions of libxc).
> 

I mean we can add them to libxc so that there is no need for this patch
anymore.

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

* Re: [PATCH 01/15] xen: Update libxc calls
@ 2010-08-12 14:29         ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-12 14:29 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, qemu-devel, Anthony, Liguori, Anthony Perard, Paolo Bonzini

On Thu, 12 Aug 2010, Stefano Stabellini wrote:
> On Thu, 12 Aug 2010, Paolo Bonzini wrote:
> > On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:
> > > 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.
> > 
> > What's the earliest version of libxc that will be supported after this 
> > patch?
>  
> xen-unstable only at the moment.
> 
> We can probably add some #define so that qemu can work with both (old
> and new versions of libxc).
> 

I mean we can add them to libxc so that there is no need for this patch
anymore.

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

* Re: [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
  2010-08-12 14:09   ` stefano.stabellini
  (?)
@ 2010-08-12 18:26   ` Blue Swirl
  2010-08-13 13:09     ` Stefano Stabellini
  -1 siblings, 1 reply; 106+ messages in thread
From: Blue Swirl @ 2010-08-12 18:26 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> 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.

The code should be converted to qdev and VMState.

>
> 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 |    4 +
>  hw/xen_platform.c   |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/xen_platform.h   |    9 +
>  4 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/xen_machine_fv.c b/hw/xen_machine_fv.c
> index 114addf..ec826e7 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,9 @@ static void xen_init_fv(ram_addr_t ram_size,
>
>     pc_vga_init(pci_bus);
>
> +    pci_xen_platform_init(pci_bus);
> +    platform_fixed_ioport_init();
> +
>     /* 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..85d3f8b
> --- /dev/null
> +++ b/hw/xen_platform.c
> @@ -0,0 +1,452 @@
> +/*
> + * 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>
> +
> +static int drivers_blacklisted;
> +static uint16_t driver_product_version;
> +static int throttling_disabled;
> +static char log_buffer[4096];
> +static int log_buffer_off;
> +
> +static uint8_t platform_flags;

A lot of static variables. Could you put these to PCIXenPlatformState?

> +
> +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
> +
> +typedef struct PCIXenPlatformState
> +{
> +    PCIDevice  pci_dev;
> +} PCIXenPlatformState;
> +
> +
> +/* 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(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 (throttling_disabled)
> +        return;
> +
> +    if (!started) {
> +        clock_gettime(CLOCK_MONOTONIC, &last_refil);
> +        available = BUCKET_MAX_SIZE;
> +        started = 1;
> +    }
> +
> +    if (count > BUCKET_MAX_SIZE) {
> +        fprintf(stderr, "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) {
> +                fprintf(stderr, "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;
> +}
> +
> +#define UNPLUG_ALL_IDE_DISKS 1
> +#define UNPLUG_ALL_NICS 2
> +#define UNPLUG_AUX_IDE_DISKS 4

These should go to the top of the file. Are they even used, the
function below doesn't?

> +
> +static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    switch (addr - 0x10) {

0x10 should be a #define, which should be used...

> +    case 0:
> +        /* 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:
> +            fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n");
> +            break;
> +        case 0:
> +            fprintf(stderr, "Guest claimed to be running PV product 0?\n");
> +            break;
> +        default:
> +            fprintf(stderr, "Unknown PV product %d loaded in guest\n", val);
> +            break;
> +        }
> +        driver_product_version = val;
> +        break;
> +    }
> +}
> +
> +static void platform_fixed_ioport_write4(void *opaque, uint32_t addr,
> +                                         uint32_t val)
> +{
> +    switch (addr - 0x10) {

... here ...

> +    case 0:
> +        /* PV driver version */
> +        break;
> +    }
> +}
> +
> +static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    switch (addr - 0x10) {

... here ...

> +    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))
> +            fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw "
> +                    "state of ROM memory area!\n");

Please introduce a macro (DPRINTF) and use that.

> +        else {
> +            platform_flags = val & PFFLAG_ROM_LOCK;
> +            fprintf(stderr,"platform_fixed_ioport: 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' || log_buffer_off == sizeof(log_buffer) - 1) {
> +            /* Flush buffer */
> +            log_buffer[log_buffer_off] = 0;
> +            throttle(log_buffer_off);
> +            fprintf(stderr, "%s\n", log_buffer);
> +            log_buffer_off = 0;
> +            break;
> +        }
> +        log_buffer[log_buffer_off++] = val;
> +        break;
> +    }
> +}
> +
> +static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr)
> +{
> +    switch (addr - 0x10) {

... here ...

> +    case 0:
> +        if (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_read1(void *opaque, uint32_t addr)
> +{
> +    switch (addr - 0x10) {

... here ...

> +    case 0:
> +        /* Platform flags */
> +        return platform_flags;
> +    case 2:
> +        /* Version number */
> +        return 1;
> +    default:
> +        return 0xff;
> +    }
> +}
> +
> +static void platform_fixed_ioport_save(QEMUFile *f, void *opaque)
> +{
> +    qemu_put_8s(f, &platform_flags);
> +}
> +
> +static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id)
> +{
> +    uint8_t flags;
> +
> +    if (version_id > 1)
> +        return -EINVAL;
> +
> +    qemu_get_8s(f, &flags);
> +    platform_fixed_ioport_write1(NULL, 0x10, flags);
> +
> +    return 0;
> +}
> +
> +void platform_fixed_ioport_init(void)
> +{
> +    register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save,
> +                    platform_fixed_ioport_load, NULL);

Please use VMState instead.

> +
> +    register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL);

and here and below. In fact, just s/0x10/XEN_PLATFORM_IOPORT/g.

> +    register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL);
> +    register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL);
> +    register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL);
> +    register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL);
> +
> +    platform_fixed_ioport_write1(NULL, 0x10, 0);

Introduce a reset function which performs something similar.

> +}
> +
> +static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
> +{
> +    addr &= 0xff;
> +
> +    return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u;

Just use if.

> +}
> +
> +static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    addr &= 0xff;
> +    val  &= 0xff;
> +
> +    switch (addr) {
> +    case 0: /* Platform flags */
> +        platform_fixed_ioport_write1(NULL, 0x10, val);
> +        break;
> +    case 8:
> +        {
> +            if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
> +                /* Flush buffer */
> +                log_buffer[log_buffer_off] = 0;
> +                throttle(log_buffer_off);
> +                fprintf(stderr, "%s\n", log_buffer);
> +                log_buffer_off = 0;
> +                break;
> +            }
> +            log_buffer[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 = (PCIXenPlatformState *)pci_dev;

Useless cast in C. Moreover, you should use DO_UPCAST or container_of.

> +    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) {
> +        fprintf(stderr, "Warning: attempted read from physical address "
> +                "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)addr);

Instead of the cast, you should use TARGET_FMT_plx.

> +        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) {
> +        fprintf(stderr, "Warning: attempted write of 0x%x to physical "
> +                "address 0x%"PRIx64" in xen platform mmio space\n",
> +                val, (uint64_t)addr);
> +        warnings++;
> +    }
> +    return;
> +}
> +
> +static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = {

These should be 'const'.

> +    platform_mmio_read,
> +    platform_mmio_read,
> +    platform_mmio_read,
> +};
> +
> +static CPUWriteMemoryFunc *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, 0x1000000, mmio_io_addr);
> +}
> +
> +struct pci_config_header {
> +    uint16_t vendor_id;
> +    uint16_t device_id;
> +    uint16_t command;
> +    uint16_t status;
> +    uint8_t  revision;
> +    uint8_t  api;
> +    uint8_t  subclass;
> +    uint8_t  class;
> +    uint8_t  cache_line_size; /* Units of 32 bit words */
> +    uint8_t  latency_timer; /* In units of bus cycles */
> +    uint8_t  header_type; /* Should be 0 */
> +    uint8_t  bist; /* Built in self test */
> +    uint32_t base_address_regs[6];
> +    uint32_t reserved1;
> +    uint16_t subsystem_vendor_id;
> +    uint16_t subsystem_id;
> +    uint32_t rom_addr;
> +    uint32_t reserved3;
> +    uint32_t reserved4;
> +    uint8_t  interrupt_line;
> +    uint8_t  interrupt_pin;
> +    uint8_t  min_gnt;
> +    uint8_t  max_lat;
> +};

Why can't you use the facilities from pci.h?

> +
> +static void xen_pci_save(QEMUFile *f, void *opaque)
> +{
> +    PCIXenPlatformState *d = opaque;
> +    uint64_t t = 0;
> +
> +    pci_device_save(&d->pci_dev, f);
> +    qemu_put_be64s(f, &t);
> +}
> +
> +static int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
> +{
> +    PCIXenPlatformState *d = opaque;
> +    int ret;
> +
> +    if (version_id > 3)
> +        return -EINVAL;
> +
> +    ret = pci_device_load(&d->pci_dev, f);
> +    if (ret < 0)
> +        return ret;
> +
> +    if (version_id >= 2) {
> +        if (version_id == 2) {
> +            uint8_t flags;
> +            qemu_get_8s(f, &flags);
> +            xen_platform_ioport_writeb(d, 0, flags);
> +        }
> +        qemu_get_be64(f);
> +    }
> +
> +    return 0;
> +}
> +
> +void pci_xen_platform_init(PCIBus *bus)
> +{
> +    PCIXenPlatformState *d;
> +    struct pci_config_header *pch;
> +
> +    printf("Register xen platform.\n");
> +    d = (PCIXenPlatformState *)pci_register_device(
> +        bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL);
> +    pch = (struct pci_config_header *)d->pci_dev.config;
> +    pch->vendor_id = 0x5853;

You should use pci_set_word etc. Please add 0x5853 to pci_ids.h.

> +    pch->device_id = 0x0001;
> +    pch->command = 3; /* IO and memory access */
> +    pch->revision = 1;
> +    pch->api = 0;
> +    pch->subclass = 0x80; /* Other */
> +    pch->class = 0xff; /* Unclassified device class */
> +    pch->header_type = 0;
> +    pch->interrupt_pin = 1;
> +
> +    /* Microsoft WHQL requires non-zero subsystem IDs. */
> +    /* http://www.pcisig.com/reflector/msg02205.html.  */
> +    pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id.  */
> +    pch->subsystem_id        = 0x0001;         /* Hardcode sub-id as 1. */
> +
> +    pci_register_bar(&d->pci_dev, 0, 0x100,
> +                           PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
> +
> +    /* reserve 16MB mmio address for share memory*/
> +    pci_register_bar(&d->pci_dev, 1, 0x1000000,
> +                           PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
> +
> +    register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d);
> +    printf("Done register platform.\n");
> +}
> +
> diff --git a/hw/xen_platform.h b/hw/xen_platform.h
> new file mode 100644
> index 0000000..6eeff22
> --- /dev/null
> +++ b/hw/xen_platform.h
> @@ -0,0 +1,9 @@
> +#ifndef XEN_PLATFORM_H
> +#define XEN_PLATFORM_H
> +
> +#include "hw/pci.h"
> +
> +void pci_xen_platform_init(PCIBus *bus);
> +void platform_fixed_ioport_init(void);
> +
> +#endif
> --
> 1.7.0.4
>
>
>

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

* Re: [Qemu-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier
  2010-08-12 14:09   ` stefano.stabellini
  (?)
@ 2010-08-12 18:35   ` Blue Swirl
  2010-08-13 13:10     ` Stefano Stabellini
  -1 siblings, 1 reply; 106+ messages in thread
From: Blue Swirl @ 2010-08-12 18:35 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> Introduce a write config notifier in piix_pci, so that clients can be
> notified every time a pci config write happens.
> The patch also makes use of the notification mechanism in
> xen_machine_fv.

Will the mechanism be used elsewhere? If not, I'd just add a call to
xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded
by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and
friends.

>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
>  hw/pc.h             |    1 +
>  hw/piix_pci.c       |   28 ++++++++++++++++++++++++++++
>  hw/xen_machine_fv.c |   16 ++++++++++++++++
>  3 files changed, 45 insertions(+), 0 deletions(-)
>
> diff --git a/hw/pc.h b/hw/pc.h
> index ee562cd..3a745ae 100644
> --- a/hw/pc.h
> +++ b/hw/pc.h
> @@ -141,6 +141,7 @@ typedef struct PCII440FXState PCII440FXState;
>
>  void piix3_register_set_irq(pci_set_irq_fn set_irq);
>  void piix3_register_map_irq(pci_map_irq_fn map_irq);
> +void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config);
>  PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
>  void i440fx_init_memory_mappings(PCII440FXState *d);
>
> diff --git a/hw/piix_pci.c b/hw/piix_pci.c
> index 56e3f61..afa9e9d 100644
> --- a/hw/piix_pci.c
> +++ b/hw/piix_pci.c
> @@ -49,6 +49,13 @@ struct PCII440FXState {
>     PIIX3State *piix3;
>  };
>
> +typedef struct PCII440FXWriteConfigNotifier {
> +    PCIConfigWriteFunc *write_config;
> +    QLIST_ENTRY(PCII440FXWriteConfigNotifier) next;
> +} PCII440FXWriteConfigNotifier;
> +
> +static QLIST_HEAD(write_config_list, PCII440FXWriteConfigNotifier) write_config_list
> +    = QLIST_HEAD_INITIALIZER(write_config_list);
>
>  #define I440FX_PAM      0x59
>  #define I440FX_PAM_SIZE 7
> @@ -71,6 +78,25 @@ void piix3_register_map_irq(pci_map_irq_fn map_irq)
>     piix3_map_irq_handler = map_irq;
>  }
>
> +void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config)
> +{
> +    PCII440FXWriteConfigNotifier *new_notifier;
> +
> +    assert(write_config);
> +    new_notifier = qemu_mallocz(sizeof(PCII440FXWriteConfigNotifier));
> +    new_notifier->write_config = write_config;
> +    QLIST_INSERT_HEAD(&write_config_list, new_notifier, next);
> +}
> +
> +static void piix_pci_notify_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len)
> +{
> +    PCII440FXWriteConfigNotifier *notifier;
> +
> +    QLIST_FOREACH(notifier, &write_config_list, next) {
> +        notifier->write_config(dev, address, val, len);
> +    }
> +}
> +
>  /* return the global irq number corresponding to a given device irq
>    pin. We could also use the bus number to have a more precise
>    mapping. */
> @@ -157,6 +183,8 @@ static void i440fx_write_config(PCIDevice *dev,
>  {
>     PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
>
> +    piix_pci_notify_write_config(dev, 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) ||
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index 5d553b6..77563db 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -61,6 +61,21 @@ static void xen_piix3_set_irq(void *opaque, int irq_num, int level)
>             irq_num & 3, level);
>  }
>
> +static void xen_piix_pci_write_config_client(PCIDevice *dev,
> +        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);
> +    }
> +}
>
>  static void xen_init_fv(ram_addr_t ram_size,
>                         const char *boot_device,
> @@ -141,6 +156,7 @@ static void xen_init_fv(ram_addr_t ram_size,
>     piix3_register_set_irq(xen_piix3_set_irq);
>     piix3_register_map_irq(xen_piix3_map_irq);
>     pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
> +    piix_pci_register_write_config_notifier(i440fx_state, xen_piix_pci_write_config_client);
>     isa_bus_irqs(isa_irq);
>
>     pc_register_ferr_irq(isa_reserve_irq(13));
> --
> 1.7.0.4
>
>
>

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

* Re: [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
  2010-08-12 14:09   ` stefano.stabellini
  (?)
@ 2010-08-12 18:42   ` Blue Swirl
  2010-08-13 13:10     ` Stefano Stabellini
  -1 siblings, 1 reply; 106+ messages in thread
From: Blue Swirl @ 2010-08-12 18:42 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> 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   |   25 ++++
>  target-xen/cpu.h      |    1 +
>  target-xen/helper.c   |  362 +++++++++++++++++++++++++++++++++++++++++++++++++
>  target-xen/qemu-xen.h |    2 +
>  4 files changed, 390 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index a6e778a..b1bc88d 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,34 @@ static void xen_init_fv(ram_addr_t ram_size,
>
>     CPUState *env;
>
> +    unsigned long ioreq_pfn;
> +    extern void *shared_page;
> +    extern void *buffered_io_page;

These should be defined in a header file.

> +
>     /* 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) {
> +        fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc);

hw_error()?

> +        exit(-1);
> +    }
> +
> +    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) {
> +        fprintf(logfile, "map buffered IO page returned error %d\n", errno);
> +        exit(-1);
> +    }
> +
>     /* 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 5a45d1c..573241f 100644
> --- a/target-xen/cpu.h
> +++ b/target-xen/cpu.h
> @@ -72,6 +72,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);
> diff --git a/target-xen/helper.c b/target-xen/helper.c
> index 8cb7771..4571ac0 100644
> --- a/target-xen/helper.c
> +++ b/target-xen/helper.c
> @@ -18,25 +18,77 @@
>  * 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));
>     if (!env)
>         return NULL;
>     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));
> +    if (!ioreq_local_port)
> +        return NULL;
> +
>     /* 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;
> @@ -70,7 +122,317 @@ 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(int vcpu)

Don't use names with leading underscores.

> +{
> +    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(i);
> +    }
> +
> +    // read error or read nothing
> +    return NULL;
> +}
> +
> +static unsigned long do_inp(CPUState *env, unsigned long 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:
> +            fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size);
> +            exit(-1);
> +    }
> +}
> +
> +static void do_outp(CPUState *env, unsigned long addr,
> +        unsigned long size, unsigned long 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:
> +            fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size);
> +            exit(-1);
> +    }
> +}
> +
> +static inline void read_physical(uint64_t addr, unsigned long size, void *val)
> +{
> +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
> +}
> +
> +static inline void write_physical(uint64_t addr, unsigned long size, void *val)
> +{
> +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
> +}

Useless redirection?

> +
> +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 {
> +            unsigned long tmp;
> +
> +            for (i = 0; i < req->count; i++) {
> +                tmp = do_inp(env, req->addr, req->size);
> +                write_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size, &tmp);
> +            }
> +        }
> +    } 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++) {
> +                unsigned long tmp = 0;
> +
> +                read_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size, &tmp);
> +                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++) {
> +                read_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size, &req->data);
> +            }
> +        } else if (req->dir == IOREQ_WRITE) {
> +            for (i = 0; i < req->count; i++) {
> +                write_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size, &req->data);
> +            }
> +        }
> +    } else {
> +        target_ulong tmp;
> +
> +        if (req->dir == IOREQ_READ) {
> +            for (i = 0; i < req->count; i++) {
> +                read_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size, &tmp);
> +                write_physical((target_phys_addr_t )req->data
> +                        + (sign * i * req->size),
> +                        req->size, &tmp);
> +            }
> +        } else if (req->dir == IOREQ_WRITE) {
> +            for (i = 0; i < req->count; i++) {
> +                read_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size, &tmp);
> +                write_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size, &tmp);
> +            }
> +        }
> +    }
> +}
> +
> +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);
> +    sprintf(b, "%ld", time_offset);

snprintf

> +    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 *xcHandle;

xc_handle or something.

> +    int sts;
> +
> +    xcHandle = xc_interface_open(NULL, NULL, 0);
> +    if (xcHandle < 0)
> +        fprintf(stderr, "Cannot acquire xenctrl handle\n");
> +    else {
> +        sts = xc_domain_shutdown(xcHandle, 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(xcHandle);
> +    }
> +}
> 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	[flat|nested] 106+ messages in thread

* Re: [Qemu-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
  2010-08-12 14:09   ` stefano.stabellini
  (?)
@ 2010-08-12 18:44   ` Blue Swirl
  2010-08-13 13:10     ` Stefano Stabellini
  -1 siblings, 1 reply; 106+ messages in thread
From: Blue Swirl @ 2010-08-12 18:44 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> This patch introduces a generic function registration mechanism for
> set_irq and map_irq in piix3, so that the two calls can be
> overridden with platform specific functions whenever needed.
> The patch also implements and registers the Xen specific version of the
> functions.

I'd avoid the registration, see my comments for the other registration patch.

>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
>  hw/pc.h             |    3 +++
>  hw/piix_pci.c       |   17 ++++++++++++++++-
>  hw/xen_machine_fv.c |   14 ++++++++++++++
>  3 files changed, 33 insertions(+), 1 deletions(-)
>
> diff --git a/hw/pc.h b/hw/pc.h
> index 63b0249..ee562cd 100644
> --- a/hw/pc.h
> +++ b/hw/pc.h
> @@ -5,6 +5,7 @@
>  #include "ioport.h"
>  #include "isa.h"
>  #include "fdc.h"
> +#include "pci.h"
>
>  /* PC-style peripherals (also used by other machines).  */
>
> @@ -138,6 +139,8 @@ int pcspk_audio_init(qemu_irq *pic);
>  struct PCII440FXState;
>  typedef struct PCII440FXState PCII440FXState;
>
> +void piix3_register_set_irq(pci_set_irq_fn set_irq);
> +void piix3_register_map_irq(pci_map_irq_fn map_irq);
>  PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
>  void i440fx_init_memory_mappings(PCII440FXState *d);
>
> diff --git a/hw/piix_pci.c b/hw/piix_pci.c
> index f152a0f..56e3f61 100644
> --- a/hw/piix_pci.c
> +++ b/hw/piix_pci.c
> @@ -55,6 +55,21 @@ struct PCII440FXState {
>  #define I440FX_SMRAM    0x72
>
>  static void piix3_set_irq(void *opaque, int irq_num, int level);
> +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
> +
> +static pci_set_irq_fn piix3_set_irq_handler = piix3_set_irq;
> +static pci_map_irq_fn piix3_map_irq_handler = pci_slot_get_pirq;
> +
> +/* Must be called before call i440fx_init() */
> +void piix3_register_set_irq(pci_set_irq_fn set_irq)
> +{
> +    piix3_set_irq_handler = set_irq;
> +}
> +
> +void piix3_register_map_irq(pci_map_irq_fn map_irq)
> +{
> +    piix3_map_irq_handler = map_irq;
> +}
>
>  /* return the global irq number corresponding to a given device irq
>    pin. We could also use the bus number to have a more precise
> @@ -235,7 +250,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
>     piix3 = DO_UPCAST(PIIX3State, dev,
>                       pci_create_simple_multifunction(b, -1, true, "PIIX3"));
>     piix3->pic = pic;
> -    pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
> +    pci_bus_irqs(b, piix3_set_irq_handler, piix3_map_irq_handler, piix3, 4);
>     (*pi440fx_state)->piix3 = piix3;
>
>     *piix3_devfn = piix3->dev.devfn;
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index 58237d6..5d553b6 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -50,6 +50,18 @@ static void xen_vm_change_state_handler(void *opaque, int running, int reason)
>         xen_main_loop_prepare();
>  }
>
> +static int xen_piix3_map_irq(PCIDevice *pci_dev, int irq_num)
> +{
> +    return irq_num + ((pci_dev->devfn >> 3) << 2);
> +}
> +
> +static void xen_piix3_set_irq(void *opaque, int irq_num, int level)
> +{
> +    xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
> +            irq_num & 3, level);
> +}
> +
> +
>  static void xen_init_fv(ram_addr_t ram_size,
>                         const char *boot_device,
>                         const char *kernel_filename,
> @@ -126,6 +138,8 @@ static void xen_init_fv(ram_addr_t ram_size,
>
>     isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
>
> +    piix3_register_set_irq(xen_piix3_set_irq);
> +    piix3_register_map_irq(xen_piix3_map_irq);
>     pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
>     isa_bus_irqs(isa_irq);
>
> --
> 1.7.0.4
>
>
>

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

* Re: [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-12 14:10   ` stefano.stabellini
  (?)
@ 2010-08-12 18:46   ` Blue Swirl
  2010-08-13 13:10       ` Stefano Stabellini
  -1 siblings, 1 reply; 106+ messages in thread
From: Blue Swirl @ 2010-08-12 18:46 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Thu, Aug 12, 2010 at 2:10 PM,  <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.

I'd suppose the proper fix is to modify acpi_piix4 instead of copy&paste.

> 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 1984cdd..a2d9217 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -325,6 +325,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 020fdd7..e1f07ba 100644
> --- a/hw/xen_common.h
> +++ b/hw/xen_common.h
> @@ -34,4 +34,7 @@
>  /* 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 77563db..bfda944 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -92,7 +92,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;
> @@ -208,10 +207,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	[flat|nested] 106+ messages in thread

* Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-12 14:09   ` stefano.stabellini
  (?)
@ 2010-08-12 18:56   ` Blue Swirl
  2010-08-13 12:47       ` Ian Jackson
  2010-08-13 13:10     ` Stefano Stabellini
  -1 siblings, 2 replies; 106+ messages in thread
From: Blue Swirl @ 2010-08-12 18:56 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On Thu, Aug 12, 2010 at 2:09 PM,  <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.

I don't understand why it would be a target, QEMU calls CPU
architectures targets. Isn't it possible to have Xen for Sparc, PPC or
ARM? It should really be just a machine, not copy&paste from x86
target.

> 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                   |  120 ++++++
>  target-xen/exec-dm.c               |  791 ++++++++++++++++++++++++++++++++++++
>  target-xen/helper.c                |   69 ++++
>  target-xen/qemu-xen.h              |   30 ++
>  target-xen/stub-functions.c        |   42 ++
>  target-xen/xen_mapcache.c          |   14 +
>  11 files changed, 1130 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 89d9b44..c3f52ce 100755
> --- a/configure
> +++ b/configure
> @@ -2517,6 +2517,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"
> @@ -2582,6 +2585,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"
> @@ -2693,7 +2700,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
> @@ -2859,7 +2866,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..5a45d1c
> --- /dev/null
> +++ b/target-xen/cpu.h
> @@ -0,0 +1,120 @@
> +/*
> + * 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"
> +
> +#ifdef TARGET_X86_64
> +#define TARGET_LONG_BITS 64
> +#else
> +#define TARGET_LONG_BITS 32
> +#endif
> +
> +#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..3d64695
> --- /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

Please use the URL version. The address is ancient.

> + */
> +#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 mmio_space {
> +    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.

Then fix those assumptions and introduce xen specific hooks, like KVM.

> + */
> +
> +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..d588e64
> --- /dev/null
> +++ b/target-xen/helper.c
> @@ -0,0 +1,69 @@
> +/*
> + *  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));
> +    if (!env)

qemu_mallocz won't return NULL.

> +        return NULL;
> +    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)
> +{
> +}
> +
> +/***********************************************************/
> +/* x86 mmu */
> +/* XXX: add PGE support */
> +
> +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	[flat|nested] 106+ messages in thread

* [Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-12 18:56   ` [Qemu-devel] " Blue Swirl
@ 2010-08-13 12:47       ` Ian Jackson
  2010-08-13 13:10     ` Stefano Stabellini
  1 sibling, 0 replies; 106+ messages in thread
From: Ian Jackson @ 2010-08-13 12:47 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony.Perard, xen-devel, qemu-devel, stefano.stabellini

Blue Swirl writes ("[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen"):
> I don't understand why it would be a target, QEMU calls CPU
> architectures targets. Isn't it possible to have Xen for Sparc, PPC or
> ARM? It should really be just a machine, not copy&paste from x86
> target.

Qemu's targets include much more of Qemu's system emulation than is
appropriate for Xen, because the hypervisor is doing more of the
work.  For example, there is no representation of the guest CPU state
outside the hypervisor so Qemu doesn't see that at all.

So it makes sense to do Xen emulation in Qemu as a new target than
just as a machine.

Yes, in principle Xen for Sparc, PPC and ARM are possible; some of
these have existed in the past although targets other than i386,
itanium and amd64 aren't currently supported by xen-unstable.  So
perhaps the currently-introduced xen target should be called
target-i386-xen.  However, in practice since in a Xen system Qemu
doesn't deal with CPU instructions these other targets will be much
more like each other than (say) i386 is close to m68k.

Or to put it all another way: from the point of view of Qemu, Xen is
a weird kind of cpu architecture whose instruction emulation is done
"by magic" and Qemu doesn't need to care vary much about that.

Ian.

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

* Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
@ 2010-08-13 12:47       ` Ian Jackson
  0 siblings, 0 replies; 106+ messages in thread
From: Ian Jackson @ 2010-08-13 12:47 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony.Perard, xen-devel, qemu-devel, stefano.stabellini

Blue Swirl writes ("[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen"):
> I don't understand why it would be a target, QEMU calls CPU
> architectures targets. Isn't it possible to have Xen for Sparc, PPC or
> ARM? It should really be just a machine, not copy&paste from x86
> target.

Qemu's targets include much more of Qemu's system emulation than is
appropriate for Xen, because the hypervisor is doing more of the
work.  For example, there is no representation of the guest CPU state
outside the hypervisor so Qemu doesn't see that at all.

So it makes sense to do Xen emulation in Qemu as a new target than
just as a machine.

Yes, in principle Xen for Sparc, PPC and ARM are possible; some of
these have existed in the past although targets other than i386,
itanium and amd64 aren't currently supported by xen-unstable.  So
perhaps the currently-introduced xen target should be called
target-i386-xen.  However, in practice since in a Xen system Qemu
doesn't deal with CPU instructions these other targets will be much
more like each other than (say) i386 is close to m68k.

Or to put it all another way: from the point of view of Qemu, Xen is
a weird kind of cpu architecture whose instruction emulation is done
"by magic" and Qemu doesn't need to care vary much about that.

Ian.

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

* Re: [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
  2010-08-12 18:26   ` [Qemu-devel] " Blue Swirl
@ 2010-08-13 13:09     ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 13:09 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

Thanks for the very detailed review, all the comments make perfect
sense, we'll address them in the next version of the series.

On Thu, 12 Aug 2010, Blue Swirl wrote:
> On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> > 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.
> 
> The code should be converted to qdev and VMState.
> 
> >
> > 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 |    4 +
> >  hw/xen_platform.c   |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  hw/xen_platform.h   |    9 +
> >  4 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/xen_machine_fv.c b/hw/xen_machine_fv.c
> > index 114addf..ec826e7 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,9 @@ static void xen_init_fv(ram_addr_t ram_size,
> >
> >     pc_vga_init(pci_bus);
> >
> > +    pci_xen_platform_init(pci_bus);
> > +    platform_fixed_ioport_init();
> > +
> >     /* 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..85d3f8b
> > --- /dev/null
> > +++ b/hw/xen_platform.c
> > @@ -0,0 +1,452 @@
> > +/*
> > + * 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>
> > +
> > +static int drivers_blacklisted;
> > +static uint16_t driver_product_version;
> > +static int throttling_disabled;
> > +static char log_buffer[4096];
> > +static int log_buffer_off;
> > +
> > +static uint8_t platform_flags;
> 
> A lot of static variables. Could you put these to PCIXenPlatformState?
> 
> > +
> > +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
> > +
> > +typedef struct PCIXenPlatformState
> > +{
> > +    PCIDevice  pci_dev;
> > +} PCIXenPlatformState;
> > +
> > +
> > +/* 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(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 (throttling_disabled)
> > +        return;
> > +
> > +    if (!started) {
> > +        clock_gettime(CLOCK_MONOTONIC, &last_refil);
> > +        available = BUCKET_MAX_SIZE;
> > +        started = 1;
> > +    }
> > +
> > +    if (count > BUCKET_MAX_SIZE) {
> > +        fprintf(stderr, "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) {
> > +                fprintf(stderr, "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;
> > +}
> > +
> > +#define UNPLUG_ALL_IDE_DISKS 1
> > +#define UNPLUG_ALL_NICS 2
> > +#define UNPLUG_AUX_IDE_DISKS 4
> 
> These should go to the top of the file. Are they even used, the
> function below doesn't?
> 
> > +
> > +static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val)
> > +{
> > +    switch (addr - 0x10) {
> 
> 0x10 should be a #define, which should be used...
> 
> > +    case 0:
> > +        /* 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:
> > +            fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n");
> > +            break;
> > +        case 0:
> > +            fprintf(stderr, "Guest claimed to be running PV product 0?\n");
> > +            break;
> > +        default:
> > +            fprintf(stderr, "Unknown PV product %d loaded in guest\n", val);
> > +            break;
> > +        }
> > +        driver_product_version = val;
> > +        break;
> > +    }
> > +}
> > +
> > +static void platform_fixed_ioport_write4(void *opaque, uint32_t addr,
> > +                                         uint32_t val)
> > +{
> > +    switch (addr - 0x10) {
> 
> ... here ...
> 
> > +    case 0:
> > +        /* PV driver version */
> > +        break;
> > +    }
> > +}
> > +
> > +static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val)
> > +{
> > +    switch (addr - 0x10) {
> 
> ... here ...
> 
> > +    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))
> > +            fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw "
> > +                    "state of ROM memory area!\n");
> 
> Please introduce a macro (DPRINTF) and use that.
> 
> > +        else {
> > +            platform_flags = val & PFFLAG_ROM_LOCK;
> > +            fprintf(stderr,"platform_fixed_ioport: 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' || log_buffer_off == sizeof(log_buffer) - 1) {
> > +            /* Flush buffer */
> > +            log_buffer[log_buffer_off] = 0;
> > +            throttle(log_buffer_off);
> > +            fprintf(stderr, "%s\n", log_buffer);
> > +            log_buffer_off = 0;
> > +            break;
> > +        }
> > +        log_buffer[log_buffer_off++] = val;
> > +        break;
> > +    }
> > +}
> > +
> > +static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr)
> > +{
> > +    switch (addr - 0x10) {
> 
> ... here ...
> 
> > +    case 0:
> > +        if (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_read1(void *opaque, uint32_t addr)
> > +{
> > +    switch (addr - 0x10) {
> 
> ... here ...
> 
> > +    case 0:
> > +        /* Platform flags */
> > +        return platform_flags;
> > +    case 2:
> > +        /* Version number */
> > +        return 1;
> > +    default:
> > +        return 0xff;
> > +    }
> > +}
> > +
> > +static void platform_fixed_ioport_save(QEMUFile *f, void *opaque)
> > +{
> > +    qemu_put_8s(f, &platform_flags);
> > +}
> > +
> > +static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id)
> > +{
> > +    uint8_t flags;
> > +
> > +    if (version_id > 1)
> > +        return -EINVAL;
> > +
> > +    qemu_get_8s(f, &flags);
> > +    platform_fixed_ioport_write1(NULL, 0x10, flags);
> > +
> > +    return 0;
> > +}
> > +
> > +void platform_fixed_ioport_init(void)
> > +{
> > +    register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save,
> > +                    platform_fixed_ioport_load, NULL);
> 
> Please use VMState instead.
> 
> > +
> > +    register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL);
> 
> and here and below. In fact, just s/0x10/XEN_PLATFORM_IOPORT/g.
> 
> > +    register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL);
> > +    register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL);
> > +    register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL);
> > +    register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL);
> > +
> > +    platform_fixed_ioport_write1(NULL, 0x10, 0);
> 
> Introduce a reset function which performs something similar.
> 
> > +}
> > +
> > +static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
> > +{
> > +    addr &= 0xff;
> > +
> > +    return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u;
> 
> Just use if.
> 
> > +}
> > +
> > +static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
> > +{
> > +    addr &= 0xff;
> > +    val  &= 0xff;
> > +
> > +    switch (addr) {
> > +    case 0: /* Platform flags */
> > +        platform_fixed_ioport_write1(NULL, 0x10, val);
> > +        break;
> > +    case 8:
> > +        {
> > +            if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
> > +                /* Flush buffer */
> > +                log_buffer[log_buffer_off] = 0;
> > +                throttle(log_buffer_off);
> > +                fprintf(stderr, "%s\n", log_buffer);
> > +                log_buffer_off = 0;
> > +                break;
> > +            }
> > +            log_buffer[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 = (PCIXenPlatformState *)pci_dev;
> 
> Useless cast in C. Moreover, you should use DO_UPCAST or container_of.
> 
> > +    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) {
> > +        fprintf(stderr, "Warning: attempted read from physical address "
> > +                "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)addr);
> 
> Instead of the cast, you should use TARGET_FMT_plx.
> 
> > +        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) {
> > +        fprintf(stderr, "Warning: attempted write of 0x%x to physical "
> > +                "address 0x%"PRIx64" in xen platform mmio space\n",
> > +                val, (uint64_t)addr);
> > +        warnings++;
> > +    }
> > +    return;
> > +}
> > +
> > +static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = {
> 
> These should be 'const'.
> 
> > +    platform_mmio_read,
> > +    platform_mmio_read,
> > +    platform_mmio_read,
> > +};
> > +
> > +static CPUWriteMemoryFunc *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, 0x1000000, mmio_io_addr);
> > +}
> > +
> > +struct pci_config_header {
> > +    uint16_t vendor_id;
> > +    uint16_t device_id;
> > +    uint16_t command;
> > +    uint16_t status;
> > +    uint8_t  revision;
> > +    uint8_t  api;
> > +    uint8_t  subclass;
> > +    uint8_t  class;
> > +    uint8_t  cache_line_size; /* Units of 32 bit words */
> > +    uint8_t  latency_timer; /* In units of bus cycles */
> > +    uint8_t  header_type; /* Should be 0 */
> > +    uint8_t  bist; /* Built in self test */
> > +    uint32_t base_address_regs[6];
> > +    uint32_t reserved1;
> > +    uint16_t subsystem_vendor_id;
> > +    uint16_t subsystem_id;
> > +    uint32_t rom_addr;
> > +    uint32_t reserved3;
> > +    uint32_t reserved4;
> > +    uint8_t  interrupt_line;
> > +    uint8_t  interrupt_pin;
> > +    uint8_t  min_gnt;
> > +    uint8_t  max_lat;
> > +};
> 
> Why can't you use the facilities from pci.h?
> 
> > +
> > +static void xen_pci_save(QEMUFile *f, void *opaque)
> > +{
> > +    PCIXenPlatformState *d = opaque;
> > +    uint64_t t = 0;
> > +
> > +    pci_device_save(&d->pci_dev, f);
> > +    qemu_put_be64s(f, &t);
> > +}
> > +
> > +static int xen_pci_load(QEMUFile *f, void *opaque, int version_id)
> > +{
> > +    PCIXenPlatformState *d = opaque;
> > +    int ret;
> > +
> > +    if (version_id > 3)
> > +        return -EINVAL;
> > +
> > +    ret = pci_device_load(&d->pci_dev, f);
> > +    if (ret < 0)
> > +        return ret;
> > +
> > +    if (version_id >= 2) {
> > +        if (version_id == 2) {
> > +            uint8_t flags;
> > +            qemu_get_8s(f, &flags);
> > +            xen_platform_ioport_writeb(d, 0, flags);
> > +        }
> > +        qemu_get_be64(f);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +void pci_xen_platform_init(PCIBus *bus)
> > +{
> > +    PCIXenPlatformState *d;
> > +    struct pci_config_header *pch;
> > +
> > +    printf("Register xen platform.\n");
> > +    d = (PCIXenPlatformState *)pci_register_device(
> > +        bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL);
> > +    pch = (struct pci_config_header *)d->pci_dev.config;
> > +    pch->vendor_id = 0x5853;
> 
> You should use pci_set_word etc. Please add 0x5853 to pci_ids.h.
> 
> > +    pch->device_id = 0x0001;
> > +    pch->command = 3; /* IO and memory access */
> > +    pch->revision = 1;
> > +    pch->api = 0;
> > +    pch->subclass = 0x80; /* Other */
> > +    pch->class = 0xff; /* Unclassified device class */
> > +    pch->header_type = 0;
> > +    pch->interrupt_pin = 1;
> > +
> > +    /* Microsoft WHQL requires non-zero subsystem IDs. */
> > +    /* http://www.pcisig.com/reflector/msg02205.html.  */
> > +    pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id.  */
> > +    pch->subsystem_id        = 0x0001;         /* Hardcode sub-id as 1. */
> > +
> > +    pci_register_bar(&d->pci_dev, 0, 0x100,
> > +                           PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
> > +
> > +    /* reserve 16MB mmio address for share memory*/
> > +    pci_register_bar(&d->pci_dev, 1, 0x1000000,
> > +                           PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
> > +
> > +    register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d);
> > +    printf("Done register platform.\n");
> > +}
> > +
> > diff --git a/hw/xen_platform.h b/hw/xen_platform.h
> > new file mode 100644
> > index 0000000..6eeff22
> > --- /dev/null
> > +++ b/hw/xen_platform.h
> > @@ -0,0 +1,9 @@
> > +#ifndef XEN_PLATFORM_H
> > +#define XEN_PLATFORM_H
> > +
> > +#include "hw/pci.h"
> > +
> > +void pci_xen_platform_init(PCIBus *bus);
> > +void platform_fixed_ioport_init(void);
> > +
> > +#endif
> > --
> > 1.7.0.4
> >
> >
> >
> 

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

* Re: [Qemu-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier
  2010-08-12 18:35   ` [Qemu-devel] " Blue Swirl
@ 2010-08-13 13:10     ` Stefano Stabellini
  2010-09-05  7:34         ` Michael S. Tsirkin
  0 siblings, 1 reply; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 13:10 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Thu, 12 Aug 2010, Blue Swirl wrote:
> On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> > From: Anthony PERARD <anthony.perard@citrix.com>
> >
> > Introduce a write config notifier in piix_pci, so that clients can be
> > notified every time a pci config write happens.
> > The patch also makes use of the notification mechanism in
> > xen_machine_fv.
> 
> Will the mechanism be used elsewhere? If not, I'd just add a call to
> xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded
> by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and
> friends.
> 

we were trying to avoid ifdef's in piix_pci, but if you are OK with just a
couple of them we'll gladly remove the hook.

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

* Re: [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
  2010-08-12 18:42   ` [Qemu-devel] " Blue Swirl
@ 2010-08-13 13:10     ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 13:10 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Thu, 12 Aug 2010, Blue Swirl wrote:
> > +static inline void read_physical(uint64_t addr, unsigned long size, void *val)
> > +{
> > +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
> > +}
> > +
> > +static inline void write_physical(uint64_t addr, unsigned long size, void *val)
> > +{
> > +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
> > +}
> 
> Useless redirection?
> 

I guess we can just use cpu_physical_memory_read/write instead of
read_physical and write_physical here.
Ok also to all the other comments.

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

* Re: [Qemu-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
  2010-08-12 18:44   ` [Qemu-devel] " Blue Swirl
@ 2010-08-13 13:10     ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 13:10 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Thu, 12 Aug 2010, Blue Swirl wrote:
> On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> > From: Anthony PERARD <anthony.perard@citrix.com>
> >
> > This patch introduces a generic function registration mechanism for
> > set_irq and map_irq in piix3, so that the two calls can be
> > overridden with platform specific functions whenever needed.
> > The patch also implements and registers the Xen specific version of the
> > functions.
> 
> I'd avoid the registration, see my comments for the other registration patch.

sure

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

* Re: [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-12 18:46   ` [Qemu-devel] " Blue Swirl
@ 2010-08-13 13:10       ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 13:10 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Thu, 12 Aug 2010, Blue Swirl wrote:
> On Thu, Aug 12, 2010 at 2:10 PM,  <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.
> 
> I'd suppose the proper fix is to modify acpi_piix4 instead of copy&paste.
> 

Yes, but we would need few xen specific hooks in acpi_piix4 to make the S
state transitions work correctly; if you are OK with it we'll proceed
in that direction.

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

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

On Thu, 12 Aug 2010, Blue Swirl wrote:
> On Thu, Aug 12, 2010 at 2:10 PM,  <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.
> 
> I'd suppose the proper fix is to modify acpi_piix4 instead of copy&paste.
> 

Yes, but we would need few xen specific hooks in acpi_piix4 to make the S
state transitions work correctly; if you are OK with it we'll proceed
in that direction.

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

* Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-12 18:56   ` [Qemu-devel] " Blue Swirl
  2010-08-13 12:47       ` Ian Jackson
@ 2010-08-13 13:10     ` Stefano Stabellini
  2010-08-13 17:46       ` Blue Swirl
  1 sibling, 1 reply; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 13:10 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Thu, 12 Aug 2010, Blue Swirl wrote:
> On Thu, Aug 12, 2010 at 2:09 PM,  <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.
> 
> I don't understand why it would be a target, QEMU calls CPU
> architectures targets. Isn't it possible to have Xen for Sparc, PPC or
> ARM? It should really be just a machine, not copy&paste from x86
> target.
> 

It is not possible to have Xen device models for Sparc, PPC or ARM: the
only architecture that supports Xen HVM guests is x86 and x86_64.
Also most of the x86 copy and paste are definitions or stubs that
haven't really changed in a very long time.


> > +/*
> > + * 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.
> 
> Then fix those assumptions and introduce xen specific hooks, like KVM.
> 

That comment goes back to the very first qemu-xen integration, it is not
so relevant anymore.
I don't know kvm hooks well enough to be sure that something similar
could work well for Xen too and honestly I don't see many benefits in
doing so.
In particular I am afraid that taking that route might cause a much
heavier impact on common code and APIs and ultimately could cause more
problems than it solves. As you can see the current approach has the
benefit of being self-contained and considering that the xen device
model use case works only on x86, doesn't do any cpu emulation and needs
a specific set of emulated hardware, I think it makes sense to have its
own target. 

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

* Re: [Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-13 12:47       ` Ian Jackson
@ 2010-08-13 17:35         ` Blue Swirl
  -1 siblings, 0 replies; 106+ messages in thread
From: Blue Swirl @ 2010-08-13 17:35 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Anthony.Perard, xen-devel, qemu-devel, stefano.stabellini

On Fri, Aug 13, 2010 at 12:47 PM, Ian Jackson <Ian.Jackson@eu.citrix.com> wrote:
> Blue Swirl writes ("[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen"):
>> I don't understand why it would be a target, QEMU calls CPU
>> architectures targets. Isn't it possible to have Xen for Sparc, PPC or
>> ARM? It should really be just a machine, not copy&paste from x86
>> target.
>
> Qemu's targets include much more of Qemu's system emulation than is
> appropriate for Xen, because the hypervisor is doing more of the
> work.  For example, there is no representation of the guest CPU state
> outside the hypervisor so Qemu doesn't see that at all.

But you could easily ignore QEMU's CPU state, or even better would be
to support some kind of CPU state synchronization. KVM also manages
the CPU when it is charge, but at the transition points the state is
synched with QEMU state. For example, what should happen to CPU on
system reset on Xen? In this version, reset is completely ignored.

About the other changes, for example cpu_physical_memory_map() seems
to do very different things on Xen than QEMU. But this can be handled
easily by adding some kind of indirection to exec.c or just:
if (xen_enabled()) {
    xen_func();
} else {
    tcg_func();
}

or add stubs for non-Xen case and then:

xen_func();

if (!xen_enabled()) {
    tcg_func();
}

> So it makes sense to do Xen emulation in Qemu as a new target than
> just as a machine.

It's also possible to add a new x86 CPU model like 'xen-x86'.

> Yes, in principle Xen for Sparc, PPC and ARM are possible; some of
> these have existed in the past although targets other than i386,
> itanium and amd64 aren't currently supported by xen-unstable.  So
> perhaps the currently-introduced xen target should be called
> target-i386-xen.  However, in practice since in a Xen system Qemu
> doesn't deal with CPU instructions these other targets will be much
> more like each other than (say) i386 is close to m68k.
>
> Or to put it all another way: from the point of view of Qemu, Xen is
> a weird kind of cpu architecture whose instruction emulation is done
> "by magic" and Qemu doesn't need to care vary much about that.

I don't see how this is so different from KVM, which is integrated to
QEMU cleanly. Even if the changes would be more invasive that way
(like the memory changes which KVM hasn't done so far), I'd still
think that would be better for everyone than having two versions of
the same code with some changes. They would eventually drift apart.

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

* Re: Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
@ 2010-08-13 17:35         ` Blue Swirl
  0 siblings, 0 replies; 106+ messages in thread
From: Blue Swirl @ 2010-08-13 17:35 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Anthony.Perard, xen-devel, qemu-devel, stefano.stabellini

On Fri, Aug 13, 2010 at 12:47 PM, Ian Jackson <Ian.Jackson@eu.citrix.com> wrote:
> Blue Swirl writes ("[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen"):
>> I don't understand why it would be a target, QEMU calls CPU
>> architectures targets. Isn't it possible to have Xen for Sparc, PPC or
>> ARM? It should really be just a machine, not copy&paste from x86
>> target.
>
> Qemu's targets include much more of Qemu's system emulation than is
> appropriate for Xen, because the hypervisor is doing more of the
> work.  For example, there is no representation of the guest CPU state
> outside the hypervisor so Qemu doesn't see that at all.

But you could easily ignore QEMU's CPU state, or even better would be
to support some kind of CPU state synchronization. KVM also manages
the CPU when it is charge, but at the transition points the state is
synched with QEMU state. For example, what should happen to CPU on
system reset on Xen? In this version, reset is completely ignored.

About the other changes, for example cpu_physical_memory_map() seems
to do very different things on Xen than QEMU. But this can be handled
easily by adding some kind of indirection to exec.c or just:
if (xen_enabled()) {
    xen_func();
} else {
    tcg_func();
}

or add stubs for non-Xen case and then:

xen_func();

if (!xen_enabled()) {
    tcg_func();
}

> So it makes sense to do Xen emulation in Qemu as a new target than
> just as a machine.

It's also possible to add a new x86 CPU model like 'xen-x86'.

> Yes, in principle Xen for Sparc, PPC and ARM are possible; some of
> these have existed in the past although targets other than i386,
> itanium and amd64 aren't currently supported by xen-unstable.  So
> perhaps the currently-introduced xen target should be called
> target-i386-xen.  However, in practice since in a Xen system Qemu
> doesn't deal with CPU instructions these other targets will be much
> more like each other than (say) i386 is close to m68k.
>
> Or to put it all another way: from the point of view of Qemu, Xen is
> a weird kind of cpu architecture whose instruction emulation is done
> "by magic" and Qemu doesn't need to care vary much about that.

I don't see how this is so different from KVM, which is integrated to
QEMU cleanly. Even if the changes would be more invasive that way
(like the memory changes which KVM hasn't done so far), I'd still
think that would be better for everyone than having two versions of
the same code with some changes. They would eventually drift apart.

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

* Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
  2010-08-13 13:10     ` Stefano Stabellini
@ 2010-08-13 17:46       ` Blue Swirl
  0 siblings, 0 replies; 106+ messages in thread
From: Blue Swirl @ 2010-08-13 17:46 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel

On Fri, Aug 13, 2010 at 1:10 PM, Stefano Stabellini
<stefano.stabellini@eu.citrix.com> wrote:
> On Thu, 12 Aug 2010, Blue Swirl wrote:
>> On Thu, Aug 12, 2010 at 2:09 PM,  <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.
>>
>> I don't understand why it would be a target, QEMU calls CPU
>> architectures targets. Isn't it possible to have Xen for Sparc, PPC or
>> ARM? It should really be just a machine, not copy&paste from x86
>> target.
>>
>
> It is not possible to have Xen device models for Sparc, PPC or ARM: the
> only architecture that supports Xen HVM guests is x86 and x86_64.
> Also most of the x86 copy and paste are definitions or stubs that
> haven't really changed in a very long time.

What about Itanium? The patch already adds some conditional code.

>> > +/*
>> > + * 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.
>>
>> Then fix those assumptions and introduce xen specific hooks, like KVM.
>>
>
> That comment goes back to the very first qemu-xen integration, it is not
> so relevant anymore.
> I don't know kvm hooks well enough to be sure that something similar
> could work well for Xen too and honestly I don't see many benefits in
> doing so.

In Makefile.target we have just these lines:
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o

The stub functions return -ENOSYS.

The benefit is that Xen code would then be fully integrated with QEMU.
Xen would benefit from improvements to the shared code, vice versa for
QEMU.

> In particular I am afraid that taking that route might cause a much
> heavier impact on common code and APIs and ultimately could cause more
> problems than it solves. As you can see the current approach has the
> benefit of being self-contained and considering that the xen device
> model use case works only on x86, doesn't do any cpu emulation and needs
> a specific set of emulated hardware, I think it makes sense to have its
> own target.

I'm not afraid of the impact, from an architectural standpoint the
completely integrated version would be much more preferable.
Self-contained solution is not unlike out-of-tree version, it will
bitrot and die.

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

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

On 08/12/2010 09:09 AM, 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.
>    

A xen specific target is definitely the wrong approach.

I understand the desire to avoid the TCG code.  We would like to 
(optionally) do the same in KVM.

The right way to do this though is to make it possible to build without 
TCG by wrapping the common interfaces in a function pointer table.


> diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c
> new file mode 100644
> index 0000000..3d64695
> --- /dev/null
> +++ b/target-xen/exec-dm.c
>    

This takes a non-target specific file and makes it target specific.  
This is not a reasonable approach.  What's the issue with the existing 
exec.c?

Regards,

Anthony Liguori

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

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

On 08/12/2010 09:09 AM, 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.
>    

A xen specific target is definitely the wrong approach.

I understand the desire to avoid the TCG code.  We would like to 
(optionally) do the same in KVM.

The right way to do this though is to make it possible to build without 
TCG by wrapping the common interfaces in a function pointer table.


> diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c
> new file mode 100644
> index 0000000..3d64695
> --- /dev/null
> +++ b/target-xen/exec-dm.c
>    

This takes a non-target specific file and makes it target specific.  
This is not a reasonable approach.  What's the issue with the existing 
exec.c?

Regards,

Anthony Liguori

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

* [Qemu-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-12 14:09   ` stefano.stabellini
@ 2010-08-13 18:53     ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:53 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD<anthony.perard@citrix.com>
>
> Introduce functions to read and write the state of the VM in xenstore.
>    

This basically creates a new management interface for QEMU via the xenstore.

Our management interface is QMP.  If you want to maintain compatibility, 
you'll need to write a QMP -> xenstore daemon that maps events 
appropriately.

Regards,

Anthony Liguori

> 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 |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
>   target-xen/xenstore.h |    6 ++
>   5 files changed, 153 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index ec826e7..a6e778a 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,
> @@ -150,6 +157,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 d588e64..8cb7771 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)
>   {
> @@ -67,3 +69,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 9f2e1ea..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();
> @@ -29,6 +83,7 @@ int xen_dm_init(void)
>           xen_be_printf(NULL, 0, "can't open xen interface\n");
>           goto err;
>       }
> +
>       return 0;
>
>   err:
> @@ -38,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_ */
>    

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

* Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-13 18:53     ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:53 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD<anthony.perard@citrix.com>
>
> Introduce functions to read and write the state of the VM in xenstore.
>    

This basically creates a new management interface for QEMU via the xenstore.

Our management interface is QMP.  If you want to maintain compatibility, 
you'll need to write a QMP -> xenstore daemon that maps events 
appropriately.

Regards,

Anthony Liguori

> 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 |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
>   target-xen/xenstore.h |    6 ++
>   5 files changed, 153 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index ec826e7..a6e778a 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,
> @@ -150,6 +157,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 d588e64..8cb7771 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)
>   {
> @@ -67,3 +69,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 9f2e1ea..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();
> @@ -29,6 +83,7 @@ int xen_dm_init(void)
>           xen_be_printf(NULL, 0, "can't open xen interface\n");
>           goto err;
>       }
> +
>       return 0;
>
>   err:
> @@ -38,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_ */
>    

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

* [Qemu-devel] Re: [PATCH 09/15] xen: Initialize event channels and io rings
  2010-08-12 14:09   ` stefano.stabellini
@ 2010-08-13 18:54     ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:54 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> 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   |   25 ++++
>   target-xen/cpu.h      |    1 +
>   target-xen/helper.c   |  362 +++++++++++++++++++++++++++++++++++++++++++++++++
>   target-xen/qemu-xen.h |    2 +
>   4 files changed, 390 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index a6e778a..b1bc88d 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,34 @@ static void xen_init_fv(ram_addr_t ram_size,
>
>       CPUState *env;
>
> +    unsigned long ioreq_pfn;
> +    extern void *shared_page;
> +    extern void *buffered_io_page;
> +
>       /* 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) {
> +        fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc);
> +        exit(-1);
> +    }
> +
> +    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) {
> +        fprintf(logfile, "map buffered IO page returned error %d\n", errno);
> +        exit(-1);
> +    }
> +
>       /* 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 5a45d1c..573241f 100644
> --- a/target-xen/cpu.h
> +++ b/target-xen/cpu.h
> @@ -72,6 +72,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);
> diff --git a/target-xen/helper.c b/target-xen/helper.c
> index 8cb7771..4571ac0 100644
> --- a/target-xen/helper.c
> +++ b/target-xen/helper.c
> @@ -18,25 +18,77 @@
>    * 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));
>       if (!env)
>           return NULL;
>       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));
> +    if (!ioreq_local_port)
> +        return NULL;
> +
>    

You don't need to check for NULL.  There's numerous CODING_STYLE issues 
in this file too (like C99 comments).

Regards,

Anthony Liguori

>       /* 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;
> @@ -70,7 +122,317 @@ 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(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(i);
> +    }
> +
> +    // read error or read nothing
> +    return NULL;
> +}
> +
> +static unsigned long do_inp(CPUState *env, unsigned long 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:
> +            fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size);
> +            exit(-1);
> +    }
> +}
> +
> +static void do_outp(CPUState *env, unsigned long addr,
> +        unsigned long size, unsigned long 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:
> +            fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size);
> +            exit(-1);
> +    }
> +}
> +
> +static inline void read_physical(uint64_t addr, unsigned long size, void *val)
> +{
> +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
> +}
> +
> +static inline void write_physical(uint64_t addr, unsigned long size, void *val)
> +{
> +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
> +}
> +
> +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 {
> +            unsigned long tmp;
> +
> +            for (i = 0; i<  req->count; i++) {
> +                tmp = do_inp(env, req->addr, req->size);
> +                write_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +            }
> +        }
> +    } 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++) {
> +                unsigned long tmp = 0;
> +
> +                read_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +                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++) {
> +                read_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&req->data);
> +            }
> +        } else if (req->dir == IOREQ_WRITE) {
> +            for (i = 0; i<  req->count; i++) {
> +                write_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&req->data);
> +            }
> +        }
> +    } else {
> +        target_ulong tmp;
> +
> +        if (req->dir == IOREQ_READ) {
> +            for (i = 0; i<  req->count; i++) {
> +                read_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +                write_physical((target_phys_addr_t )req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +            }
> +        } else if (req->dir == IOREQ_WRITE) {
> +            for (i = 0; i<  req->count; i++) {
> +                read_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +                write_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +            }
> +        }
> +    }
> +}
> +
> +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);
> +    sprintf(b, "%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 *xcHandle;
> +    int sts;
> +
> +    xcHandle = xc_interface_open(NULL, NULL, 0);
> +    if (xcHandle<  0)
> +        fprintf(stderr, "Cannot acquire xenctrl handle\n");
> +    else {
> +        sts = xc_domain_shutdown(xcHandle, 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(xcHandle);
> +    }
> +}
> 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*/
>    

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

* Re: [PATCH 09/15] xen: Initialize event channels and io rings
@ 2010-08-13 18:54     ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:54 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> 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   |   25 ++++
>   target-xen/cpu.h      |    1 +
>   target-xen/helper.c   |  362 +++++++++++++++++++++++++++++++++++++++++++++++++
>   target-xen/qemu-xen.h |    2 +
>   4 files changed, 390 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index a6e778a..b1bc88d 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,34 @@ static void xen_init_fv(ram_addr_t ram_size,
>
>       CPUState *env;
>
> +    unsigned long ioreq_pfn;
> +    extern void *shared_page;
> +    extern void *buffered_io_page;
> +
>       /* 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) {
> +        fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc);
> +        exit(-1);
> +    }
> +
> +    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) {
> +        fprintf(logfile, "map buffered IO page returned error %d\n", errno);
> +        exit(-1);
> +    }
> +
>       /* 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 5a45d1c..573241f 100644
> --- a/target-xen/cpu.h
> +++ b/target-xen/cpu.h
> @@ -72,6 +72,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);
> diff --git a/target-xen/helper.c b/target-xen/helper.c
> index 8cb7771..4571ac0 100644
> --- a/target-xen/helper.c
> +++ b/target-xen/helper.c
> @@ -18,25 +18,77 @@
>    * 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));
>       if (!env)
>           return NULL;
>       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));
> +    if (!ioreq_local_port)
> +        return NULL;
> +
>    

You don't need to check for NULL.  There's numerous CODING_STYLE issues 
in this file too (like C99 comments).

Regards,

Anthony Liguori

>       /* 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;
> @@ -70,7 +122,317 @@ 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(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(i);
> +    }
> +
> +    // read error or read nothing
> +    return NULL;
> +}
> +
> +static unsigned long do_inp(CPUState *env, unsigned long 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:
> +            fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size);
> +            exit(-1);
> +    }
> +}
> +
> +static void do_outp(CPUState *env, unsigned long addr,
> +        unsigned long size, unsigned long 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:
> +            fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size);
> +            exit(-1);
> +    }
> +}
> +
> +static inline void read_physical(uint64_t addr, unsigned long size, void *val)
> +{
> +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0);
> +}
> +
> +static inline void write_physical(uint64_t addr, unsigned long size, void *val)
> +{
> +    return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1);
> +}
> +
> +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 {
> +            unsigned long tmp;
> +
> +            for (i = 0; i<  req->count; i++) {
> +                tmp = do_inp(env, req->addr, req->size);
> +                write_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +            }
> +        }
> +    } 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++) {
> +                unsigned long tmp = 0;
> +
> +                read_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +                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++) {
> +                read_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&req->data);
> +            }
> +        } else if (req->dir == IOREQ_WRITE) {
> +            for (i = 0; i<  req->count; i++) {
> +                write_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&req->data);
> +            }
> +        }
> +    } else {
> +        target_ulong tmp;
> +
> +        if (req->dir == IOREQ_READ) {
> +            for (i = 0; i<  req->count; i++) {
> +                read_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +                write_physical((target_phys_addr_t )req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +            }
> +        } else if (req->dir == IOREQ_WRITE) {
> +            for (i = 0; i<  req->count; i++) {
> +                read_physical((target_phys_addr_t) req->data
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +                write_physical(req->addr
> +                        + (sign * i * req->size),
> +                        req->size,&tmp);
> +            }
> +        }
> +    }
> +}
> +
> +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);
> +    sprintf(b, "%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 *xcHandle;
> +    int sts;
> +
> +    xcHandle = xc_interface_open(NULL, NULL, 0);
> +    if (xcHandle<  0)
> +        fprintf(stderr, "Cannot acquire xenctrl handle\n");
> +    else {
> +        sts = xc_domain_shutdown(xcHandle, 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(xcHandle);
> +    }
> +}
> 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*/
>    

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

* [Qemu-devel] Re: [PATCH 10/15] xen: Introduce the Xen mapcache
  2010-08-12 14:09   ` stefano.stabellini
@ 2010-08-13 18:55     ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:55 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> 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 |  233 +++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 255 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index b1bc88d..58237d6 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -84,6 +84,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..efe036c 100644
> --- a/target-xen/xen_mapcache.c
> +++ b/target-xen/xen_mapcache.c
> @@ -1,5 +1,237 @@
> +#include "config.h"
> +
> +#include "hw/xen_backend.h"
>   #include "qemu-xen.h"
>
> +#include<xen/hvm/params.h>
> +#include<sys/mman.h>
> +
> +#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))))
> +
> +struct map_cache {
> +    unsigned long paddr_index;
> +    uint8_t      *vaddr_base;
> +    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
> +    uint8_t lock;
> +    struct map_cache *next;
> +};
> +
> +struct map_cache_rev {
> +    uint8_t      *vaddr_req;
> +    unsigned long paddr_index;
> +    QTAILQ_ENTRY(map_cache_rev) next;
> +};
>
>    

CODING_STYLE

> +static struct map_cache *mapcache_entry;
> +static unsigned long nr_buckets;
> +QTAILQ_HEAD(map_cache_head, map_cache_rev) locked_entries = QTAILQ_HEAD_INITIALIZER(locked_entries);
> +
> +/* For most cases (>99.9%), the page address is the same. */
> +static unsigned long last_address_index = ~0UL;
> +static uint8_t      *last_address_vaddr;
>    

Should refactor away global state.

> +int qemu_map_cache_init(void)
> +{
> +    unsigned long size;
> +
> +    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 = nr_buckets * sizeof(struct map_cache);
> +    size = (size + XC_PAGE_SIZE - 1)&  ~(XC_PAGE_SIZE - 1);
> +    fprintf(stderr, "qemu_map_cache_init nr_buckets = %lx size %lu\n", 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(struct map_cache *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)
> +{
> +    struct map_cache *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 == last_address_index&&  !lock)
> +        return last_address_vaddr + address_offset;
> +
> +    entry =&mapcache_entry[address_index % 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(struct map_cache));
> +        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)) {
> +        last_address_index = ~0UL;
> +        return NULL;
> +    }
> +
> +    last_address_index = address_index;
> +    last_address_vaddr = entry->vaddr_base;
> +    if (lock) {
> +        struct map_cache_rev *reventry = qemu_mallocz(sizeof(struct map_cache_rev));
> +        entry->lock++;
> +        reventry->vaddr_req = last_address_vaddr + address_offset;
> +        reventry->paddr_index = last_address_index;
> +        QTAILQ_INSERT_TAIL(&locked_entries, reventry, next);
> +    }
> +
> +    return last_address_vaddr + address_offset;
> +}
> +
> +void qemu_invalidate_entry(uint8_t *buffer)
> +{
> +    struct map_cache *entry = NULL, *pentry = NULL;
> +    struct map_cache_rev *reventry;
> +    unsigned long paddr_index;
> +    int found = 0;
> +
> +    if (last_address_vaddr == buffer)
> +        last_address_index =  ~0UL;
> +
> +    QTAILQ_FOREACH(reventry,&locked_entries, next) {
> +        if (reventry->vaddr_req == buffer) {
> +            paddr_index = reventry->paddr_index;
> +            found = 1;
> +            break;
> +        }
> +    }
> +    if (!found) {
> +        fprintf(stderr, "qemu_invalidate_entry: could not find %p\n", buffer);
> +        QTAILQ_FOREACH(reventry,&locked_entries, next) {
> +            fprintf(stderr, "   %lx ->  %p is present\n", reventry->paddr_index, reventry->vaddr_req);
> +        }
> +        return;
> +    }
> +    QTAILQ_REMOVE(&locked_entries, reventry, next);
> +    qemu_free(reventry);
> +
> +    entry =&mapcache_entry[paddr_index % nr_buckets];
> +    while (entry&&  entry->paddr_index != paddr_index) {
> +        pentry = entry;
> +        entry = entry->next;
> +    }
> +    if (!entry) {
> +        fprintf(stderr, "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;
> +    struct map_cache_rev *reventry;
> +
> +    qemu_aio_flush();
> +
> +    QTAILQ_FOREACH(reventry,&locked_entries, next) {
> +        fprintf(stderr, "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<  nr_buckets; i++) {
> +        struct map_cache *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;
> +    }
> +
> +    last_address_index =  ~0UL;
> +    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 +244,4 @@ void qemu_invalidate_map_cache(void)
>   void qemu_invalidate_entry(uint8_t *buffer)
>   {
>   }
> +#endif /* !MAPCACHE */
>    

This should really tie into the RAMBlock infrastructure.

Regards,

Anthony Liguori

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

* Re: [PATCH 10/15] xen: Introduce the Xen mapcache
@ 2010-08-13 18:55     ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:55 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> 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 |  233 +++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 255 insertions(+), 0 deletions(-)
>
> diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
> index b1bc88d..58237d6 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -84,6 +84,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..efe036c 100644
> --- a/target-xen/xen_mapcache.c
> +++ b/target-xen/xen_mapcache.c
> @@ -1,5 +1,237 @@
> +#include "config.h"
> +
> +#include "hw/xen_backend.h"
>   #include "qemu-xen.h"
>
> +#include<xen/hvm/params.h>
> +#include<sys/mman.h>
> +
> +#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))))
> +
> +struct map_cache {
> +    unsigned long paddr_index;
> +    uint8_t      *vaddr_base;
> +    DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
> +    uint8_t lock;
> +    struct map_cache *next;
> +};
> +
> +struct map_cache_rev {
> +    uint8_t      *vaddr_req;
> +    unsigned long paddr_index;
> +    QTAILQ_ENTRY(map_cache_rev) next;
> +};
>
>    

CODING_STYLE

> +static struct map_cache *mapcache_entry;
> +static unsigned long nr_buckets;
> +QTAILQ_HEAD(map_cache_head, map_cache_rev) locked_entries = QTAILQ_HEAD_INITIALIZER(locked_entries);
> +
> +/* For most cases (>99.9%), the page address is the same. */
> +static unsigned long last_address_index = ~0UL;
> +static uint8_t      *last_address_vaddr;
>    

Should refactor away global state.

> +int qemu_map_cache_init(void)
> +{
> +    unsigned long size;
> +
> +    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 = nr_buckets * sizeof(struct map_cache);
> +    size = (size + XC_PAGE_SIZE - 1)&  ~(XC_PAGE_SIZE - 1);
> +    fprintf(stderr, "qemu_map_cache_init nr_buckets = %lx size %lu\n", 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(struct map_cache *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)
> +{
> +    struct map_cache *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 == last_address_index&&  !lock)
> +        return last_address_vaddr + address_offset;
> +
> +    entry =&mapcache_entry[address_index % 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(struct map_cache));
> +        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)) {
> +        last_address_index = ~0UL;
> +        return NULL;
> +    }
> +
> +    last_address_index = address_index;
> +    last_address_vaddr = entry->vaddr_base;
> +    if (lock) {
> +        struct map_cache_rev *reventry = qemu_mallocz(sizeof(struct map_cache_rev));
> +        entry->lock++;
> +        reventry->vaddr_req = last_address_vaddr + address_offset;
> +        reventry->paddr_index = last_address_index;
> +        QTAILQ_INSERT_TAIL(&locked_entries, reventry, next);
> +    }
> +
> +    return last_address_vaddr + address_offset;
> +}
> +
> +void qemu_invalidate_entry(uint8_t *buffer)
> +{
> +    struct map_cache *entry = NULL, *pentry = NULL;
> +    struct map_cache_rev *reventry;
> +    unsigned long paddr_index;
> +    int found = 0;
> +
> +    if (last_address_vaddr == buffer)
> +        last_address_index =  ~0UL;
> +
> +    QTAILQ_FOREACH(reventry,&locked_entries, next) {
> +        if (reventry->vaddr_req == buffer) {
> +            paddr_index = reventry->paddr_index;
> +            found = 1;
> +            break;
> +        }
> +    }
> +    if (!found) {
> +        fprintf(stderr, "qemu_invalidate_entry: could not find %p\n", buffer);
> +        QTAILQ_FOREACH(reventry,&locked_entries, next) {
> +            fprintf(stderr, "   %lx ->  %p is present\n", reventry->paddr_index, reventry->vaddr_req);
> +        }
> +        return;
> +    }
> +    QTAILQ_REMOVE(&locked_entries, reventry, next);
> +    qemu_free(reventry);
> +
> +    entry =&mapcache_entry[paddr_index % nr_buckets];
> +    while (entry&&  entry->paddr_index != paddr_index) {
> +        pentry = entry;
> +        entry = entry->next;
> +    }
> +    if (!entry) {
> +        fprintf(stderr, "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;
> +    struct map_cache_rev *reventry;
> +
> +    qemu_aio_flush();
> +
> +    QTAILQ_FOREACH(reventry,&locked_entries, next) {
> +        fprintf(stderr, "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<  nr_buckets; i++) {
> +        struct map_cache *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;
> +    }
> +
> +    last_address_index =  ~0UL;
> +    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 +244,4 @@ void qemu_invalidate_map_cache(void)
>   void qemu_invalidate_entry(uint8_t *buffer)
>   {
>   }
> +#endif /* !MAPCACHE */
>    

This should really tie into the RAMBlock infrastructure.

Regards,

Anthony Liguori

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

* [Qemu-devel] Re: [PATCH 14/15] xen: destroy the VM when shutdown is requested
  2010-08-12 14:10   ` stefano.stabellini
@ 2010-08-13 18:56     ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:56 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote:
> 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 |   17 +++++++++++++++++
>   1 files changed, 17 insertions(+), 0 deletions(-)
>
> diff --git a/target-xen/helper.c b/target-xen/helper.c
> index 4571ac0..16e628c 100644
> --- a/target-xen/helper.c
> +++ b/target-xen/helper.c
> @@ -397,6 +397,23 @@ 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()) {
> +                fprintf(stderr, "shutdown requested in cpu_handle_ioreq\n");
> +                destroy_hvm_domain();
> +            }
>    

The patches should not introduce fprintfs in expected paths.

Regards,

Anthony Liguori

> +            if (qemu_reset_requested_get()) {
> +                fprintf(stderr, "reset requested in cpu_handle_ioreq.\n");
> +                qemu_system_reset();
> +            }
> +        }
> +
>           req->state = STATE_IORESP_READY;
>           xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
>       }
>    

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

* Re: [PATCH 14/15] xen: destroy the VM when shutdown is requested
@ 2010-08-13 18:56     ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:56 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote:
> 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 |   17 +++++++++++++++++
>   1 files changed, 17 insertions(+), 0 deletions(-)
>
> diff --git a/target-xen/helper.c b/target-xen/helper.c
> index 4571ac0..16e628c 100644
> --- a/target-xen/helper.c
> +++ b/target-xen/helper.c
> @@ -397,6 +397,23 @@ 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()) {
> +                fprintf(stderr, "shutdown requested in cpu_handle_ioreq\n");
> +                destroy_hvm_domain();
> +            }
>    

The patches should not introduce fprintfs in expected paths.

Regards,

Anthony Liguori

> +            if (qemu_reset_requested_get()) {
> +                fprintf(stderr, "reset requested in cpu_handle_ioreq.\n");
> +                qemu_system_reset();
> +            }
> +        }
> +
>           req->state = STATE_IORESP_READY;
>           xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
>       }
>    

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

* [Qemu-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
  2010-08-12 14:10   ` stefano.stabellini
@ 2010-08-13 18:57     ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 18:57 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

On 08/12/2010 09:10 AM, 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.
>    

What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt 
your BIOS to cope with our ACPI implementation?

Regards,

Anthony Liguori

> 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 1984cdd..a2d9217 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -325,6 +325,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 020fdd7..e1f07ba 100644
> --- a/hw/xen_common.h
> +++ b/hw/xen_common.h
> @@ -34,4 +34,7 @@
>   /* 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 77563db..bfda944 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -92,7 +92,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;
> @@ -208,10 +207,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) {
>    

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

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

On 08/12/2010 09:10 AM, 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.
>    

What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt 
your BIOS to cope with our ACPI implementation?

Regards,

Anthony Liguori

> 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 1984cdd..a2d9217 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -325,6 +325,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 020fdd7..e1f07ba 100644
> --- a/hw/xen_common.h
> +++ b/hw/xen_common.h
> @@ -34,4 +34,7 @@
>   /* 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 77563db..bfda944 100644
> --- a/hw/xen_machine_fv.c
> +++ b/hw/xen_machine_fv.c
> @@ -92,7 +92,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;
> @@ -208,10 +207,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) {
>    

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

* [Qemu-devel] Re: [PATCH 00/15] RFC xen device model support
  2010-08-12 14:08 ` Stefano Stabellini
@ 2010-08-13 19:09   ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 19:09 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

Hi Stefano/Anthony,

On 08/12/2010 09:08 AM, Stefano Stabellini wrote:
> Hi all,
> this is the long awaited patch series to add xen device model support in
> qemu; the main author is Anthony Perard.
>    

Thanks for sending this out.  Overall, the series looks pretty good.  I 
think there's just a couple issues we need to address to get it into a 
mergable state.

We definitely need to resolve the various CODING_STYLE issues.

We should limit XenStore interactions to strictly be device model 
setup.  Any management operations should be done through QMP.  The main 
reason to take this approach is to ensure that we don't end up with a 
more powerful interface via xenstore verses QMP or vice versa.

The target changes are probably the most contentious.  Fortunately, we 
have a very similar set of goals with KVM so I think we'll be able to 
come up with a common solution to the problem.

Regards,

Anthony Liguori

> Developing this series we tried to come up with the cleanest possible
> solution from the qemu point of view, limiting the amount of changes to
> common code as much as possible. The end result still requires a couple
> of hooks in piix_pci but overall the impact should be very limited.
> The current series gives you an upstream qemu device model able to boot
> a Linux or a Windows HVM guest; some features are still missing
> compared to the current qemu-xen, among which vga dirty bits, pci
> passthrough and stubdomain support.
>
> For any of you that want to try it, this is the step by step guide:
>
> - clone a fresh copy of xen-unstable.hg, make and install;
> note that the xen-unstable make system will clone a linux tree and a
> qemu-xen tree by default: you can avoid the former just executing 'make
> xen' and 'make tools' instead of 'make world';
>
> - configure qemu using xen-dm-softmmu as target and extra-ldflags and
> extra-cflags pointing at the xen-unstable build directory, something
> like this should work:
>
> ./configure --target-list=xen-dm-softmmu --extra-cflags="-I$HOME/xen-unstable/dist/install/usr/include" --extra-ldflags="-L$HOME/xen-unstable/dist/install/usr/lib" --enable-xen
>
> - build qemu and install the newly compiled binary
> (xen-dm-softmmu/qemu-system-xen);
>
> - edit your VM config file and modify device_model to point at it.
>
>
> Currently only xl (not xend) knows how to spawn the new qemu device model
> with the right command line options.
> As you can see the build and test procedures are not straightforward
> yet, but in the near future we plan to provide a way to select an
> upstream qemu tree for use as xen device model directly from the
> xen-unstable build system.
>
> The patch series adds a new target with the whole xen device model
> machinery; each patch contains a detailed description.
> This is the full list of patches and the diffstat:
>
> Anthony Perard (15):
>      xen: Update libxc calls
>      xen: Add xen_machine_fv
>      xen: Add a new target to qemu: target-xen
>      xen: xen_machine_fv, initialize xenstore
>      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
>      piix3: introduce register_set_irq and register_map_irq
>      piix_pci: introduce a write_config notifier
>      vl.c: Introduce getter for shutdown_requested and reset_requested.
>      xen: destroy the VM when shutdown is requested
>
>   Makefile.target                    |   31 ++
>   arch_init.c                        |    2 +
>   arch_init.h                        |    1 +
>   configure                          |   12 +-
>   default-configs/xen-dm-softmmu.mak |   24 +
>   hw/pc.h                            |    4 +
>   hw/piix_pci.c                      |   45 ++-
>   hw/xen_acpi_piix4.c                |  424 ++++++++++++++++++
>   hw/xen_backend.c                   |   10 +-
>   hw/xen_backend.h                   |    2 +-
>   hw/xen_common.h                    |    6 +
>   hw/xen_disk.c                      |   12 +-
>   hw/xen_domainbuild.c               |    4 +-
>   hw/xen_machine_fv.c                |  234 ++++++++++
>   hw/xen_nic.c                       |   16 +-
>   hw/xen_platform.c                  |  452 ++++++++++++++++++++
>   hw/xen_platform.h                  |    9 +
>   sysemu.h                           |    2 +
>   target-xen/cpu.h                   |  121 ++++++
>   target-xen/exec-dm.c               |  826 ++++++++++++++++++++++++++++++++++++
>   target-xen/helper.c                |  455 ++++++++++++++++++++
>   target-xen/i8259-xen-stub.c        |   63 +++
>   target-xen/qemu-xen.h              |   50 +++
>   target-xen/stub-functions.c        |   42 ++
>   target-xen/xen_mapcache.c          |  247 +++++++++++
>   target-xen/xenstore.c              |  168 ++++++++
>   target-xen/xenstore.h              |   12 +
>   vl.c                               |   10 +
>   28 files changed, 3259 insertions(+), 25 deletions(-)
>
>
> A git tree is available here:
>
> git://xenbits.xen.org/people/sstabellini/qemu-dm.git
>
> branch name qemu-dm-v1.
>
>
> We are committed in providing the best solution for both qemu and xen
> developers and users communities; we greatly appreciate any help you can
> give us to improve the quality of this series, including comments,
> critics, suggestions and of course patches :)
>
> Happy Hacking,
>
> Stefano
>    

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

* Re: [PATCH 00/15] RFC xen device model support
@ 2010-08-13 19:09   ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 19:09 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

Hi Stefano/Anthony,

On 08/12/2010 09:08 AM, Stefano Stabellini wrote:
> Hi all,
> this is the long awaited patch series to add xen device model support in
> qemu; the main author is Anthony Perard.
>    

Thanks for sending this out.  Overall, the series looks pretty good.  I 
think there's just a couple issues we need to address to get it into a 
mergable state.

We definitely need to resolve the various CODING_STYLE issues.

We should limit XenStore interactions to strictly be device model 
setup.  Any management operations should be done through QMP.  The main 
reason to take this approach is to ensure that we don't end up with a 
more powerful interface via xenstore verses QMP or vice versa.

The target changes are probably the most contentious.  Fortunately, we 
have a very similar set of goals with KVM so I think we'll be able to 
come up with a common solution to the problem.

Regards,

Anthony Liguori

> Developing this series we tried to come up with the cleanest possible
> solution from the qemu point of view, limiting the amount of changes to
> common code as much as possible. The end result still requires a couple
> of hooks in piix_pci but overall the impact should be very limited.
> The current series gives you an upstream qemu device model able to boot
> a Linux or a Windows HVM guest; some features are still missing
> compared to the current qemu-xen, among which vga dirty bits, pci
> passthrough and stubdomain support.
>
> For any of you that want to try it, this is the step by step guide:
>
> - clone a fresh copy of xen-unstable.hg, make and install;
> note that the xen-unstable make system will clone a linux tree and a
> qemu-xen tree by default: you can avoid the former just executing 'make
> xen' and 'make tools' instead of 'make world';
>
> - configure qemu using xen-dm-softmmu as target and extra-ldflags and
> extra-cflags pointing at the xen-unstable build directory, something
> like this should work:
>
> ./configure --target-list=xen-dm-softmmu --extra-cflags="-I$HOME/xen-unstable/dist/install/usr/include" --extra-ldflags="-L$HOME/xen-unstable/dist/install/usr/lib" --enable-xen
>
> - build qemu and install the newly compiled binary
> (xen-dm-softmmu/qemu-system-xen);
>
> - edit your VM config file and modify device_model to point at it.
>
>
> Currently only xl (not xend) knows how to spawn the new qemu device model
> with the right command line options.
> As you can see the build and test procedures are not straightforward
> yet, but in the near future we plan to provide a way to select an
> upstream qemu tree for use as xen device model directly from the
> xen-unstable build system.
>
> The patch series adds a new target with the whole xen device model
> machinery; each patch contains a detailed description.
> This is the full list of patches and the diffstat:
>
> Anthony Perard (15):
>      xen: Update libxc calls
>      xen: Add xen_machine_fv
>      xen: Add a new target to qemu: target-xen
>      xen: xen_machine_fv, initialize xenstore
>      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
>      piix3: introduce register_set_irq and register_map_irq
>      piix_pci: introduce a write_config notifier
>      vl.c: Introduce getter for shutdown_requested and reset_requested.
>      xen: destroy the VM when shutdown is requested
>
>   Makefile.target                    |   31 ++
>   arch_init.c                        |    2 +
>   arch_init.h                        |    1 +
>   configure                          |   12 +-
>   default-configs/xen-dm-softmmu.mak |   24 +
>   hw/pc.h                            |    4 +
>   hw/piix_pci.c                      |   45 ++-
>   hw/xen_acpi_piix4.c                |  424 ++++++++++++++++++
>   hw/xen_backend.c                   |   10 +-
>   hw/xen_backend.h                   |    2 +-
>   hw/xen_common.h                    |    6 +
>   hw/xen_disk.c                      |   12 +-
>   hw/xen_domainbuild.c               |    4 +-
>   hw/xen_machine_fv.c                |  234 ++++++++++
>   hw/xen_nic.c                       |   16 +-
>   hw/xen_platform.c                  |  452 ++++++++++++++++++++
>   hw/xen_platform.h                  |    9 +
>   sysemu.h                           |    2 +
>   target-xen/cpu.h                   |  121 ++++++
>   target-xen/exec-dm.c               |  826 ++++++++++++++++++++++++++++++++++++
>   target-xen/helper.c                |  455 ++++++++++++++++++++
>   target-xen/i8259-xen-stub.c        |   63 +++
>   target-xen/qemu-xen.h              |   50 +++
>   target-xen/stub-functions.c        |   42 ++
>   target-xen/xen_mapcache.c          |  247 +++++++++++
>   target-xen/xenstore.c              |  168 ++++++++
>   target-xen/xenstore.h              |   12 +
>   vl.c                               |   10 +
>   28 files changed, 3259 insertions(+), 25 deletions(-)
>
>
> A git tree is available here:
>
> git://xenbits.xen.org/people/sstabellini/qemu-dm.git
>
> branch name qemu-dm-v1.
>
>
> We are committed in providing the best solution for both qemu and xen
> developers and users communities; we greatly appreciate any help you can
> give us to improve the quality of this series, including comments,
> critics, suggestions and of course patches :)
>
> Happy Hacking,
>
> Stefano
>    

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

* [Qemu-devel] Re: [PATCH 00/15] RFC xen device model support
  2010-08-13 19:09   ` Anthony Liguori
@ 2010-08-13 19:35     ` Stefano Stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 19:35 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: Anthony, Perard, xen-devel, qemu-devel, Stefano Stabellini

On Fri, 13 Aug 2010, Anthony Liguori wrote:
> Hi Stefano/Anthony,
> 
> On 08/12/2010 09:08 AM, Stefano Stabellini wrote:
> > Hi all,
> > this is the long awaited patch series to add xen device model support in
> > qemu; the main author is Anthony Perard.
> >    
> 
> Thanks for sending this out.  Overall, the series looks pretty good.  I 
> think there's just a couple issues we need to address to get it into a 
> mergable state.
> 

Thank you very much for taking the time to review our series!

> We definitely need to resolve the various CODING_STYLE issues.
> 

Of course, we'll do in the next version.

> We should limit XenStore interactions to strictly be device model 
> setup.  Any management operations should be done through QMP.  The main 
> reason to take this approach is to ensure that we don't end up with a 
> more powerful interface via xenstore verses QMP or vice versa.
> 

I want to be clear on this: I like QMP and I dislike xenstore,
especially when it is used as an RPC mechanism.
I have NO intention of transforming xenstore in a QMP alternative, in
fact we removed quite a lot of xenstore interactions developing this
series, in particular the whole disk setup (and it felt good :).
Currently in qemu-xen we are using xenstore even for pci passthrough,
but I certainly do not intend to make the same mistake again when we'll
add pci passthrough support to qemu this time.
Implementing QMP support in libxl is definitely on our todo list.


> The target changes are probably the most contentious.  Fortunately, we 
> have a very similar set of goals with KVM so I think we'll be able to 
> come up with a common solution to the problem.
> 

Yes, this is the part that worries me the most.
Do you think is reasonable to keep the new target for the time being or
do you want us to try the other approach ASAP?
If you really want us to drop the xen specific target we'll need
close guidance in how to proceed.

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

* Re: [PATCH 00/15] RFC xen device model support
@ 2010-08-13 19:35     ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-13 19:35 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: Anthony, Perard, xen-devel, qemu-devel, Stefano Stabellini

On Fri, 13 Aug 2010, Anthony Liguori wrote:
> Hi Stefano/Anthony,
> 
> On 08/12/2010 09:08 AM, Stefano Stabellini wrote:
> > Hi all,
> > this is the long awaited patch series to add xen device model support in
> > qemu; the main author is Anthony Perard.
> >    
> 
> Thanks for sending this out.  Overall, the series looks pretty good.  I 
> think there's just a couple issues we need to address to get it into a 
> mergable state.
> 

Thank you very much for taking the time to review our series!

> We definitely need to resolve the various CODING_STYLE issues.
> 

Of course, we'll do in the next version.

> We should limit XenStore interactions to strictly be device model 
> setup.  Any management operations should be done through QMP.  The main 
> reason to take this approach is to ensure that we don't end up with a 
> more powerful interface via xenstore verses QMP or vice versa.
> 

I want to be clear on this: I like QMP and I dislike xenstore,
especially when it is used as an RPC mechanism.
I have NO intention of transforming xenstore in a QMP alternative, in
fact we removed quite a lot of xenstore interactions developing this
series, in particular the whole disk setup (and it felt good :).
Currently in qemu-xen we are using xenstore even for pci passthrough,
but I certainly do not intend to make the same mistake again when we'll
add pci passthrough support to qemu this time.
Implementing QMP support in libxl is definitely on our todo list.


> The target changes are probably the most contentious.  Fortunately, we 
> have a very similar set of goals with KVM so I think we'll be able to 
> come up with a common solution to the problem.
> 

Yes, this is the part that worries me the most.
Do you think is reasonable to keep the new target for the time being or
do you want us to try the other approach ASAP?
If you really want us to drop the xen specific target we'll need
close guidance in how to proceed.

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

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

On Fri, 13 Aug 2010, Anthony Liguori wrote:
> On 08/12/2010 09:10 AM, 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.
> >
> 
> What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt
> your BIOS to cope with our ACPI implementation?
> 

I think it shouldn't be too difficult to adapt our current BIOS, but
we'll need few xen specific hooks in acpi_piix4.
The price that we'll have to pay doing so is loosing live-migration
compatibility with older xen installations.

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

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

On Fri, 13 Aug 2010, Anthony Liguori wrote:
> On 08/12/2010 09:10 AM, 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.
> >
> 
> What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt
> your BIOS to cope with our ACPI implementation?
> 

I think it shouldn't be too difficult to adapt our current BIOS, but
we'll need few xen specific hooks in acpi_piix4.
The price that we'll have to pay doing so is loosing live-migration
compatibility with older xen installations.

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

* [Qemu-devel] Re: [PATCH 00/15] RFC xen device model support
  2010-08-13 19:35     ` Stefano Stabellini
@ 2010-08-13 20:48       ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 20:48 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel

On 08/13/2010 02:35 PM, Stefano Stabellini wrote:
>> We should limit XenStore interactions to strictly be device model
>> setup.  Any management operations should be done through QMP.  The main
>> reason to take this approach is to ensure that we don't end up with a
>> more powerful interface via xenstore verses QMP or vice versa.
>>
>>      
> I want to be clear on this: I like QMP and I dislike xenstore,
> especially when it is used as an RPC mechanism.
> I have NO intention of transforming xenstore in a QMP alternative, in
> fact we removed quite a lot of xenstore interactions developing this
> series, in particular the whole disk setup (and it felt good :).
>    

Ah, fantastic :-)

>> The target changes are probably the most contentious.  Fortunately, we
>> have a very similar set of goals with KVM so I think we'll be able to
>> come up with a common solution to the problem.
>>
>>      
> Yes, this is the part that worries me the most.
> Do you think is reasonable to keep the new target for the time being or
> do you want us to try the other approach ASAP?
>    

Let's figure out the right solution and then we'll figure out the 
incremental approach.  I don't mind if you keep it in the next few 
rounds of the series but I don't think we can merge it.

A good way to start would be for ya'll to take a look at the places 
where we hook for KVM.  For instance, cpu_register_phys_memory_client.  
With an additional hook in the map()/unmap()/rw() path, you should be 
able to implement the map cache support and deal with memory in a sane way.

I think that would allow us to separate the discussion of having xen 
hooks with removing TCG support in the Xen builds which as I said 
earlier, is something we also would like to do in KVM.

Regards,

Anthony Liguori

> If you really want us to drop the xen specific target we'll need
> close guidance in how to proceed.
>    

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

* Re: [PATCH 00/15] RFC xen device model support
@ 2010-08-13 20:48       ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-13 20:48 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel

On 08/13/2010 02:35 PM, Stefano Stabellini wrote:
>> We should limit XenStore interactions to strictly be device model
>> setup.  Any management operations should be done through QMP.  The main
>> reason to take this approach is to ensure that we don't end up with a
>> more powerful interface via xenstore verses QMP or vice versa.
>>
>>      
> I want to be clear on this: I like QMP and I dislike xenstore,
> especially when it is used as an RPC mechanism.
> I have NO intention of transforming xenstore in a QMP alternative, in
> fact we removed quite a lot of xenstore interactions developing this
> series, in particular the whole disk setup (and it felt good :).
>    

Ah, fantastic :-)

>> The target changes are probably the most contentious.  Fortunately, we
>> have a very similar set of goals with KVM so I think we'll be able to
>> come up with a common solution to the problem.
>>
>>      
> Yes, this is the part that worries me the most.
> Do you think is reasonable to keep the new target for the time being or
> do you want us to try the other approach ASAP?
>    

Let's figure out the right solution and then we'll figure out the 
incremental approach.  I don't mind if you keep it in the next few 
rounds of the series but I don't think we can merge it.

A good way to start would be for ya'll to take a look at the places 
where we hook for KVM.  For instance, cpu_register_phys_memory_client.  
With an additional hook in the map()/unmap()/rw() path, you should be 
able to implement the map cache support and deal with memory in a sane way.

I think that would allow us to separate the discussion of having xen 
hooks with removing TCG support in the Xen builds which as I said 
earlier, is something we also would like to do in KVM.

Regards,

Anthony Liguori

> If you really want us to drop the xen specific target we'll need
> close guidance in how to proceed.
>    

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

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

On 08/13/2010 02:37 PM, Stefano Stabellini wrote:
> On Fri, 13 Aug 2010, Anthony Liguori wrote:
>    
>> On 08/12/2010 09:10 AM, 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.
>>>
>>>        
>> What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt
>> your BIOS to cope with our ACPI implementation?
>>
>>      
> I think it shouldn't be too difficult to adapt our current BIOS, but
> we'll need few xen specific hooks in acpi_piix4.
> The price that we'll have to pay doing so is loosing live-migration
> compatibility with older xen installations.
>    

Does Xen migrate roms (like the BIOS) in such a way that the persist 
after a reboot?

I noticed there was only one machine type defined.  In our experience, 
to preserve compatibility with migration, it's useful to have versioned 
machine names.  We also have some special machine parameters to support 
compatibility with qdev.

How does Xen handle hvm migration machine model compatibility?

Regards,

Anthony Liguori

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

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

On 08/13/2010 02:37 PM, Stefano Stabellini wrote:
> On Fri, 13 Aug 2010, Anthony Liguori wrote:
>    
>> On 08/12/2010 09:10 AM, 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.
>>>
>>>        
>> What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt
>> your BIOS to cope with our ACPI implementation?
>>
>>      
> I think it shouldn't be too difficult to adapt our current BIOS, but
> we'll need few xen specific hooks in acpi_piix4.
> The price that we'll have to pay doing so is loosing live-migration
> compatibility with older xen installations.
>    

Does Xen migrate roms (like the BIOS) in such a way that the persist 
after a reboot?

I noticed there was only one machine type defined.  In our experience, 
to preserve compatibility with migration, it's useful to have versioned 
machine names.  We also have some special machine parameters to support 
compatibility with qdev.

How does Xen handle hvm migration machine model compatibility?

Regards,

Anthony Liguori

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

* [Qemu-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-13 18:53     ` Anthony Liguori
@ 2010-08-15 14:12       ` Paolo Bonzini
  -1 siblings, 0 replies; 106+ messages in thread
From: Paolo Bonzini @ 2010-08-15 14:12 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony.Perard, xen-devel, qemu-devel, stefano.stabellini

On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
>> From: Anthony PERARD<anthony.perard@citrix.com>
>>
>> Introduce functions to read and write the state of the VM in xenstore.
>
> This basically creates a new management interface for QEMU via the
> xenstore.
>
> Our management interface is QMP. If you want to maintain compatibility,
> you'll need to write a QMP -> xenstore daemon that maps events
> appropriately.

This would belong in xl/libxl.

Paolo

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

* Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-15 14:12       ` Paolo Bonzini
  0 siblings, 0 replies; 106+ messages in thread
From: Paolo Bonzini @ 2010-08-15 14:12 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony.Perard, xen-devel, qemu-devel, stefano.stabellini

On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
>> From: Anthony PERARD<anthony.perard@citrix.com>
>>
>> Introduce functions to read and write the state of the VM in xenstore.
>
> This basically creates a new management interface for QEMU via the
> xenstore.
>
> Our management interface is QMP. If you want to maintain compatibility,
> you'll need to write a QMP -> xenstore daemon that maps events
> appropriately.

This would belong in xl/libxl.

Paolo

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

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

On Fri, 13 Aug 2010, Anthony Liguori wrote:
> On 08/13/2010 02:37 PM, Stefano Stabellini wrote:
> > On Fri, 13 Aug 2010, Anthony Liguori wrote:
> >    
> >> On 08/12/2010 09:10 AM, 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.
> >>>
> >>>        
> >> What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt
> >> your BIOS to cope with our ACPI implementation?
> >>
> >>      
> > I think it shouldn't be too difficult to adapt our current BIOS, but
> > we'll need few xen specific hooks in acpi_piix4.
> > The price that we'll have to pay doing so is loosing live-migration
> > compatibility with older xen installations.
> >    
> 
> Does Xen migrate roms (like the BIOS) in such a way that the persist 
> after a reboot?
> 

No, I don't think so.
However it is common practice not to require any VM reboot on host
upgrade.


> I noticed there was only one machine type defined.  In our experience, 
> to preserve compatibility with migration, it's useful to have versioned 
> machine names.  We also have some special machine parameters to support 
> compatibility with qdev.
> 

Thanks for the tip, we'll look into it.
Knowing that we would have the BIOS problem mentioned above, we didn't
try yet any save/restore or migration compatibility between old qemu-xen
and new qemu.


> How does Xen handle hvm migration machine model compatibility?
> 
 
We use per-device save state versions and we tend to use always the same
set of devices.

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

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

On Fri, 13 Aug 2010, Anthony Liguori wrote:
> On 08/13/2010 02:37 PM, Stefano Stabellini wrote:
> > On Fri, 13 Aug 2010, Anthony Liguori wrote:
> >    
> >> On 08/12/2010 09:10 AM, 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.
> >>>
> >>>        
> >> What's the long term plan?  Will Xen adopt SeaBIOS or will you adapt
> >> your BIOS to cope with our ACPI implementation?
> >>
> >>      
> > I think it shouldn't be too difficult to adapt our current BIOS, but
> > we'll need few xen specific hooks in acpi_piix4.
> > The price that we'll have to pay doing so is loosing live-migration
> > compatibility with older xen installations.
> >    
> 
> Does Xen migrate roms (like the BIOS) in such a way that the persist 
> after a reboot?
> 

No, I don't think so.
However it is common practice not to require any VM reboot on host
upgrade.


> I noticed there was only one machine type defined.  In our experience, 
> to preserve compatibility with migration, it's useful to have versioned 
> machine names.  We also have some special machine parameters to support 
> compatibility with qdev.
> 

Thanks for the tip, we'll look into it.
Knowing that we would have the BIOS problem mentioned above, we didn't
try yet any save/restore or migration compatibility between old qemu-xen
and new qemu.


> How does Xen handle hvm migration machine model compatibility?
> 
 
We use per-device save state versions and we tend to use always the same
set of devices.

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

* [Qemu-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-15 14:12       ` Paolo Bonzini
@ 2010-08-16 11:15         ` Stefano Stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 11:15 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Sun, 15 Aug 2010, Paolo Bonzini wrote:
> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> > On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> >> From: Anthony PERARD<anthony.perard@citrix.com>
> >>
> >> Introduce functions to read and write the state of the VM in xenstore.
> >
> > This basically creates a new management interface for QEMU via the
> > xenstore.
> >
> > Our management interface is QMP. If you want to maintain compatibility,
> > you'll need to write a QMP -> xenstore daemon that maps events
> > appropriately.
> 
> This would belong in xl/libxl.
 
Yes, but considering that we don't want a xenstore-based management
interface I would gladly do without the compatibility daemon.
We'll try to reduce all the xenstore interaction to the bare minimum,
and use QMP everywhere else.

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

* Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-16 11:15         ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 11:15 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Anthony Perard, xen-devel, qemu-devel, Anthony Liguori,
	Stefano Stabellini

On Sun, 15 Aug 2010, Paolo Bonzini wrote:
> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> > On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> >> From: Anthony PERARD<anthony.perard@citrix.com>
> >>
> >> Introduce functions to read and write the state of the VM in xenstore.
> >
> > This basically creates a new management interface for QEMU via the
> > xenstore.
> >
> > Our management interface is QMP. If you want to maintain compatibility,
> > you'll need to write a QMP -> xenstore daemon that maps events
> > appropriately.
> 
> This would belong in xl/libxl.
 
Yes, but considering that we don't want a xenstore-based management
interface I would gladly do without the compatibility daemon.
We'll try to reduce all the xenstore interaction to the bare minimum,
and use QMP everywhere else.

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

* [Qemu-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-16 11:15         ` Stefano Stabellini
@ 2010-08-16 12:13           ` Paolo Bonzini
  -1 siblings, 0 replies; 106+ messages in thread
From: Paolo Bonzini @ 2010-08-16 12:13 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel

On 08/16/2010 01:15 PM, Stefano Stabellini wrote:
> On Sun, 15 Aug 2010, Paolo Bonzini wrote:
>> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
>>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
>>>> From: Anthony PERARD<anthony.perard@citrix.com>
>>>>
>>>> Introduce functions to read and write the state of the VM in xenstore.
>>>
>>> This basically creates a new management interface for QEMU via the
>>> xenstore.
>>>
>>> Our management interface is QMP. If you want to maintain compatibility,
>>> you'll need to write a QMP ->  xenstore daemon that maps events
>>> appropriately.
>>
>> This would belong in xl/libxl.
>
> Yes, but considering that we don't want a xenstore-based management
> interface I would gladly do without the compatibility daemon.
> We'll try to reduce all the xenstore interaction to the bare minimum,
> and use QMP everywhere else.

Yes, I was just pointing out that you don't need a new compatibility 
daemon.  Since xl is already daemonizing itself to handle on_crash and 
friends, it could also set up all the watches it cares about, and 
convert them to QMP commands.  It's all more code that needs to be 
written of course, and boring stuff even. :)

Paolo

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

* Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-16 12:13           ` Paolo Bonzini
  0 siblings, 0 replies; 106+ messages in thread
From: Paolo Bonzini @ 2010-08-16 12:13 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel, Anthony Liguori

On 08/16/2010 01:15 PM, Stefano Stabellini wrote:
> On Sun, 15 Aug 2010, Paolo Bonzini wrote:
>> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
>>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
>>>> From: Anthony PERARD<anthony.perard@citrix.com>
>>>>
>>>> Introduce functions to read and write the state of the VM in xenstore.
>>>
>>> This basically creates a new management interface for QEMU via the
>>> xenstore.
>>>
>>> Our management interface is QMP. If you want to maintain compatibility,
>>> you'll need to write a QMP ->  xenstore daemon that maps events
>>> appropriately.
>>
>> This would belong in xl/libxl.
>
> Yes, but considering that we don't want a xenstore-based management
> interface I would gladly do without the compatibility daemon.
> We'll try to reduce all the xenstore interaction to the bare minimum,
> and use QMP everywhere else.

Yes, I was just pointing out that you don't need a new compatibility 
daemon.  Since xl is already daemonizing itself to handle on_crash and 
friends, it could also set up all the watches it cares about, and 
convert them to QMP commands.  It's all more code that needs to be 
written of course, and boring stuff even. :)

Paolo

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

* [Qemu-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
  2010-08-16 12:13           ` Paolo Bonzini
@ 2010-08-16 12:59             ` Stefano Stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 12:59 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 16 Aug 2010, Paolo Bonzini wrote:
> On 08/16/2010 01:15 PM, Stefano Stabellini wrote:
> > On Sun, 15 Aug 2010, Paolo Bonzini wrote:
> >> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> >>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> >>>> From: Anthony PERARD<anthony.perard@citrix.com>
> >>>>
> >>>> Introduce functions to read and write the state of the VM in xenstore.
> >>>
> >>> This basically creates a new management interface for QEMU via the
> >>> xenstore.
> >>>
> >>> Our management interface is QMP. If you want to maintain compatibility,
> >>> you'll need to write a QMP ->  xenstore daemon that maps events
> >>> appropriately.
> >>
> >> This would belong in xl/libxl.
> >
> > Yes, but considering that we don't want a xenstore-based management
> > interface I would gladly do without the compatibility daemon.
> > We'll try to reduce all the xenstore interaction to the bare minimum,
> > and use QMP everywhere else.
> 
> Yes, I was just pointing out that you don't need a new compatibility 
> daemon.  Since xl is already daemonizing itself to handle on_crash and 
> friends, it could also set up all the watches it cares about, and 
> convert them to QMP commands.  It's all more code that needs to be 
> written of course, and boring stuff even. :)

Well yes, but after all you cannot write interesting code all the time
:)

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

* Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
@ 2010-08-16 12:59             ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 12:59 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Anthony Perard, xen-devel, qemu-devel, Anthony Liguori,
	Stefano Stabellini

On Mon, 16 Aug 2010, Paolo Bonzini wrote:
> On 08/16/2010 01:15 PM, Stefano Stabellini wrote:
> > On Sun, 15 Aug 2010, Paolo Bonzini wrote:
> >> On 08/13/2010 02:53 PM, Anthony Liguori wrote:
> >>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:
> >>>> From: Anthony PERARD<anthony.perard@citrix.com>
> >>>>
> >>>> Introduce functions to read and write the state of the VM in xenstore.
> >>>
> >>> This basically creates a new management interface for QEMU via the
> >>> xenstore.
> >>>
> >>> Our management interface is QMP. If you want to maintain compatibility,
> >>> you'll need to write a QMP ->  xenstore daemon that maps events
> >>> appropriately.
> >>
> >> This would belong in xl/libxl.
> >
> > Yes, but considering that we don't want a xenstore-based management
> > interface I would gladly do without the compatibility daemon.
> > We'll try to reduce all the xenstore interaction to the bare minimum,
> > and use QMP everywhere else.
> 
> Yes, I was just pointing out that you don't need a new compatibility 
> daemon.  Since xl is already daemonizing itself to handle on_crash and 
> friends, it could also set up all the watches it cares about, and 
> convert them to QMP commands.  It's all more code that needs to be 
> written of course, and boring stuff even. :)

Well yes, but after all you cannot write interesting code all the time
:)

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-12 14:09   ` stefano.stabellini
@ 2010-08-16 13:42     ` Kevin Wolf
  -1 siblings, 0 replies; 106+ messages in thread
From: Kevin Wolf @ 2010-08-16 13:42 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
> 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>

Why does this need its own machine type? Shouldn't an HVM machine really
look like a PC? And indeed most of this code looks like a (slightly
outdated) copy of pc_piix.c with !pci_enabled code paths removed.

Kevin

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

* Re: [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-16 13:42     ` Kevin Wolf
  0 siblings, 0 replies; 106+ messages in thread
From: Kevin Wolf @ 2010-08-16 13:42 UTC (permalink / raw)
  To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel

Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
> 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>

Why does this need its own machine type? Shouldn't an HVM machine really
look like a PC? And indeed most of this code looks like a (slightly
outdated) copy of pc_piix.c with !pci_enabled code paths removed.

Kevin

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-16 13:42     ` Kevin Wolf
  (?)
@ 2010-08-16 14:04     ` Stefano Stabellini
  2010-08-16 14:13         ` Kevin Wolf
  -1 siblings, 1 reply; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 14:04 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 16 Aug 2010, Kevin Wolf wrote:
> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
> > 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>
> 
> Why does this need its own machine type? Shouldn't an HVM machine really
> look like a PC? And indeed most of this code looks like a (slightly
> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
 
The main reason is that we need some xen specific initializations, as you can
see from xen_init_fv.
But considering that we have been asked to remove target-xen and that
will cause a major refactoring of this series, xen_machine_fv could
change significantly in the next iterations anyway...

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-16 14:04     ` [Qemu-devel] " Stefano Stabellini
@ 2010-08-16 14:13         ` Kevin Wolf
  0 siblings, 0 replies; 106+ messages in thread
From: Kevin Wolf @ 2010-08-16 14:13 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel

Am 16.08.2010 16:04, schrieb Stefano Stabellini:
> On Mon, 16 Aug 2010, Kevin Wolf wrote:
>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
>>> 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>
>>
>> Why does this need its own machine type? Shouldn't an HVM machine really
>> look like a PC? And indeed most of this code looks like a (slightly
>> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
>  
> The main reason is that we need some xen specific initializations, as you can
> see from xen_init_fv.

Right, there are some more Xen specific things added later. However, the
main part of it is duplicated from pc_piix.c. I'm sure that with some
refactoring we could call these functions instead of copying and
modifying them. The problem with the latter is that they will inevitably
diverge even for changes that make sense for both.

I'm not even sure that the machine is the right place to do these Xen
specific initializations (expect for the Xen platform PCI device). As
far as I understand, the QEMUMachine is considered guest state whereas
most of these initializations concern host state.

> But considering that we have been asked to remove target-xen and that
> will cause a major refactoring of this series, xen_machine_fv could
> change significantly in the next iterations anyway...

Basically, the request to remove target-xen and my comment both aim in
the same direction, namely making Xen less special and integrate it
better in existing structures.

Kevin

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

* Re: [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-16 14:13         ` Kevin Wolf
  0 siblings, 0 replies; 106+ messages in thread
From: Kevin Wolf @ 2010-08-16 14:13 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Anthony Perard, xen-devel, qemu-devel

Am 16.08.2010 16:04, schrieb Stefano Stabellini:
> On Mon, 16 Aug 2010, Kevin Wolf wrote:
>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
>>> 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>
>>
>> Why does this need its own machine type? Shouldn't an HVM machine really
>> look like a PC? And indeed most of this code looks like a (slightly
>> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
>  
> The main reason is that we need some xen specific initializations, as you can
> see from xen_init_fv.

Right, there are some more Xen specific things added later. However, the
main part of it is duplicated from pc_piix.c. I'm sure that with some
refactoring we could call these functions instead of copying and
modifying them. The problem with the latter is that they will inevitably
diverge even for changes that make sense for both.

I'm not even sure that the machine is the right place to do these Xen
specific initializations (expect for the Xen platform PCI device). As
far as I understand, the QEMUMachine is considered guest state whereas
most of these initializations concern host state.

> But considering that we have been asked to remove target-xen and that
> will cause a major refactoring of this series, xen_machine_fv could
> change significantly in the next iterations anyway...

Basically, the request to remove target-xen and my comment both aim in
the same direction, namely making Xen less special and integrate it
better in existing structures.

Kevin

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-16 14:13         ` Kevin Wolf
@ 2010-08-16 14:38           ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-16 14:38 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On 08/16/2010 09:13 AM, Kevin Wolf wrote:
> Am 16.08.2010 16:04, schrieb Stefano Stabellini:
>    
>> On Mon, 16 Aug 2010, Kevin Wolf wrote:
>>      
>>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
>>>        
>>>> 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>
>>>>          
>>> Why does this need its own machine type? Shouldn't an HVM machine really
>>> look like a PC? And indeed most of this code looks like a (slightly
>>> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
>>>        
>>
>> The main reason is that we need some xen specific initializations, as you can
>> see from xen_init_fv.
>>      
> Right, there are some more Xen specific things added later. However, the
> main part of it is duplicated from pc_piix.c. I'm sure that with some
> refactoring we could call these functions instead of copying and
> modifying them. The problem with the latter is that they will inevitably
> diverge even for changes that make sense for both.
>
> I'm not even sure that the machine is the right place to do these Xen
> specific initializations (expect for the Xen platform PCI device). As
> far as I understand, the QEMUMachine is considered guest state whereas
> most of these initializations concern host state.
>    

To be honest, I think we'll need KVM, Xen, and QEMU specific machines.

The right default set of hardware for all three is different.

Going back to an old series of mine, they might share a MachineCore, but 
they'll ultimately need to be different machines.

Regards,

Anthony Liguori

>    
>> But considering that we have been asked to remove target-xen and that
>> will cause a major refactoring of this series, xen_machine_fv could
>> change significantly in the next iterations anyway...
>>      
> Basically, the request to remove target-xen and my comment both aim in
> the same direction, namely making Xen less special and integrate it
> better in existing structures.
>
> Kevin
>
>    

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

* Re: [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-16 14:38           ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-16 14:38 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On 08/16/2010 09:13 AM, Kevin Wolf wrote:
> Am 16.08.2010 16:04, schrieb Stefano Stabellini:
>    
>> On Mon, 16 Aug 2010, Kevin Wolf wrote:
>>      
>>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
>>>        
>>>> 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>
>>>>          
>>> Why does this need its own machine type? Shouldn't an HVM machine really
>>> look like a PC? And indeed most of this code looks like a (slightly
>>> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
>>>        
>>
>> The main reason is that we need some xen specific initializations, as you can
>> see from xen_init_fv.
>>      
> Right, there are some more Xen specific things added later. However, the
> main part of it is duplicated from pc_piix.c. I'm sure that with some
> refactoring we could call these functions instead of copying and
> modifying them. The problem with the latter is that they will inevitably
> diverge even for changes that make sense for both.
>
> I'm not even sure that the machine is the right place to do these Xen
> specific initializations (expect for the Xen platform PCI device). As
> far as I understand, the QEMUMachine is considered guest state whereas
> most of these initializations concern host state.
>    

To be honest, I think we'll need KVM, Xen, and QEMU specific machines.

The right default set of hardware for all three is different.

Going back to an old series of mine, they might share a MachineCore, but 
they'll ultimately need to be different machines.

Regards,

Anthony Liguori

>    
>> But considering that we have been asked to remove target-xen and that
>> will cause a major refactoring of this series, xen_machine_fv could
>> change significantly in the next iterations anyway...
>>      
> Basically, the request to remove target-xen and my comment both aim in
> the same direction, namely making Xen less special and integrate it
> better in existing structures.
>
> Kevin
>
>    

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-16 14:38           ` Anthony Liguori
@ 2010-08-16 14:51             ` Kevin Wolf
  -1 siblings, 0 replies; 106+ messages in thread
From: Kevin Wolf @ 2010-08-16 14:51 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

Am 16.08.2010 16:38, schrieb Anthony Liguori:
> On 08/16/2010 09:13 AM, Kevin Wolf wrote:
>> Am 16.08.2010 16:04, schrieb Stefano Stabellini:
>>    
>>> On Mon, 16 Aug 2010, Kevin Wolf wrote:
>>>      
>>>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
>>>>        
>>>>> 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>
>>>>>          
>>>> Why does this need its own machine type? Shouldn't an HVM machine really
>>>> look like a PC? And indeed most of this code looks like a (slightly
>>>> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
>>>>        
>>>
>>> The main reason is that we need some xen specific initializations, as you can
>>> see from xen_init_fv.
>>>      
>> Right, there are some more Xen specific things added later. However, the
>> main part of it is duplicated from pc_piix.c. I'm sure that with some
>> refactoring we could call these functions instead of copying and
>> modifying them. The problem with the latter is that they will inevitably
>> diverge even for changes that make sense for both.
>>
>> I'm not even sure that the machine is the right place to do these Xen
>> specific initializations (expect for the Xen platform PCI device). As
>> far as I understand, the QEMUMachine is considered guest state whereas
>> most of these initializations concern host state.
>>    
> 
> To be honest, I think we'll need KVM, Xen, and QEMU specific machines.
> 
> The right default set of hardware for all three is different.

Right, I agree. This is why I put the exception for the platform device.
There are probably some more devices for which the same applies.

But these exceptions all about guest state. If qdev was finished, this
would be a matter of having a different configuration file, right?

This series, as I understand it, is adding much more to the Xen FV
machine. Things that are not about which devices a VM contains, but
about some implementation details of the host.

Kevin

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

* Re: [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-16 14:51             ` Kevin Wolf
  0 siblings, 0 replies; 106+ messages in thread
From: Kevin Wolf @ 2010-08-16 14:51 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

Am 16.08.2010 16:38, schrieb Anthony Liguori:
> On 08/16/2010 09:13 AM, Kevin Wolf wrote:
>> Am 16.08.2010 16:04, schrieb Stefano Stabellini:
>>    
>>> On Mon, 16 Aug 2010, Kevin Wolf wrote:
>>>      
>>>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:
>>>>        
>>>>> 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>
>>>>>          
>>>> Why does this need its own machine type? Shouldn't an HVM machine really
>>>> look like a PC? And indeed most of this code looks like a (slightly
>>>> outdated) copy of pc_piix.c with !pci_enabled code paths removed.
>>>>        
>>>
>>> The main reason is that we need some xen specific initializations, as you can
>>> see from xen_init_fv.
>>>      
>> Right, there are some more Xen specific things added later. However, the
>> main part of it is duplicated from pc_piix.c. I'm sure that with some
>> refactoring we could call these functions instead of copying and
>> modifying them. The problem with the latter is that they will inevitably
>> diverge even for changes that make sense for both.
>>
>> I'm not even sure that the machine is the right place to do these Xen
>> specific initializations (expect for the Xen platform PCI device). As
>> far as I understand, the QEMUMachine is considered guest state whereas
>> most of these initializations concern host state.
>>    
> 
> To be honest, I think we'll need KVM, Xen, and QEMU specific machines.
> 
> The right default set of hardware for all three is different.

Right, I agree. This is why I put the exception for the platform device.
There are probably some more devices for which the same applies.

But these exceptions all about guest state. If qdev was finished, this
would be a matter of having a different configuration file, right?

This series, as I understand it, is adding much more to the Xen FV
machine. Things that are not about which devices a VM contains, but
about some implementation details of the host.

Kevin

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-16 14:51             ` Kevin Wolf
@ 2010-08-16 15:00               ` Stefano Stabellini
  -1 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 15:00 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 16 Aug 2010, Kevin Wolf wrote:
> Right, I agree. This is why I put the exception for the platform device.
> There are probably some more devices for which the same applies.
> 
> But these exceptions all about guest state. If qdev was finished, this
> would be a matter of having a different configuration file, right?
> 
> This series, as I understand it, is adding much more to the Xen FV
> machine. Things that are not about which devices a VM contains, but
> about some implementation details of the host.
 
We could probably move the mapcache initialization and the ioreq and
buffered ioreq page setup to another place, but apart from that the rest
is about emulated devices.

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

* Re: [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-16 15:00               ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-16 15:00 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On Mon, 16 Aug 2010, Kevin Wolf wrote:
> Right, I agree. This is why I put the exception for the platform device.
> There are probably some more devices for which the same applies.
> 
> But these exceptions all about guest state. If qdev was finished, this
> would be a matter of having a different configuration file, right?
> 
> This series, as I understand it, is adding much more to the Xen FV
> machine. Things that are not about which devices a VM contains, but
> about some implementation details of the host.
 
We could probably move the mapcache initialization and the ioreq and
buffered ioreq page setup to another place, but apart from that the rest
is about emulated devices.

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

* Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
  2010-08-16 14:51             ` Kevin Wolf
@ 2010-08-16 15:07               ` Anthony Liguori
  -1 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-16 15:07 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On 08/16/2010 09:51 AM, Kevin Wolf wrote:
> Am 16.08.2010 16:38, schrieb Anthony Liguori:
>    
>>
>> To be honest, I think we'll need KVM, Xen, and QEMU specific machines.
>>
>> The right default set of hardware for all three is different.
>>      
> Right, I agree. This is why I put the exception for the platform device.
> There are probably some more devices for which the same applies.
>
> But these exceptions all about guest state. If qdev was finished, this
> would be a matter of having a different configuration file, right?
>
> This series, as I understand it, is adding much more to the Xen FV
> machine. Things that are not about which devices a VM contains, but
> about some implementation details of the host.
>    

Yeah, but dropping the target-xen will probably fix most of that stuff.

Regards,

Anthony Liguori

> Kevin
>    

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

* Re: [PATCH 02/15] xen: Add xen_machine_fv
@ 2010-08-16 15:07               ` Anthony Liguori
  0 siblings, 0 replies; 106+ messages in thread
From: Anthony Liguori @ 2010-08-16 15:07 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Anthony Perard, xen-devel, qemu-devel, Stefano Stabellini

On 08/16/2010 09:51 AM, Kevin Wolf wrote:
> Am 16.08.2010 16:38, schrieb Anthony Liguori:
>    
>>
>> To be honest, I think we'll need KVM, Xen, and QEMU specific machines.
>>
>> The right default set of hardware for all three is different.
>>      
> Right, I agree. This is why I put the exception for the platform device.
> There are probably some more devices for which the same applies.
>
> But these exceptions all about guest state. If qdev was finished, this
> would be a matter of having a different configuration file, right?
>
> This series, as I understand it, is adding much more to the Xen FV
> machine. Things that are not about which devices a VM contains, but
> about some implementation details of the host.
>    

Yeah, but dropping the target-xen will probably fix most of that stuff.

Regards,

Anthony Liguori

> Kevin
>    

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

* Re: [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
  2010-08-12 14:29         ` Stefano Stabellini
  (?)
@ 2010-08-18  9:50         ` Gerd Hoffmann
  2010-08-18 11:47             ` Stefano Stabellini
  -1 siblings, 1 reply; 106+ messages in thread
From: Gerd Hoffmann @ 2010-08-18  9:50 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Anthony Perard, Paolo Bonzini, Anthony, xen-devel, qemu-devel

   Hi,

> I mean we can add them to libxc so that there is no need for this patch
> anymore.

That would be great.  When adding the xen bits initially I've tried to 
avoid hard dependencies on specific xen versions.  There are some ifdefs 
in the qemu code to support compiling with various xen versions (IIRC 
3.1 -> 3.4 worked last time I've tried).  I think the minimum supported 
range of xen versions should be the ones still actively maintained by 
xensource (I think this is 3.4, 4.0 and unstable right now).  Supporting 
even older versions would be nice to have.

cheers,
   Gerd

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

* Re: [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
  2010-08-18  9:50         ` [Qemu-devel] " Gerd Hoffmann
@ 2010-08-18 11:47             ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-18 11:47 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Paolo, xen-devel, Stefano Stabellini, qemu-devel, Anthony,
	Anthony Perard, Bonzini

On Wed, 18 Aug 2010, Gerd Hoffmann wrote:
>    Hi,
> 
> > I mean we can add them to libxc so that there is no need for this patch
> > anymore.
> 
> That would be great.  When adding the xen bits initially I've tried to 
> avoid hard dependencies on specific xen versions.  There are some ifdefs 
> in the qemu code to support compiling with various xen versions (IIRC 
> 3.1 -> 3.4 worked last time I've tried).  I think the minimum supported 
> range of xen versions should be the ones still actively maintained by 
> xensource (I think this is 3.4, 4.0 and unstable right now).  Supporting 
> even older versions would be nice to have.
> 
 
I agree on the range of xen versions, but supporting even a wider range
shouldn't be too hard, it just requires few more ifdef's. 

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

* Re: [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
@ 2010-08-18 11:47             ` Stefano Stabellini
  0 siblings, 0 replies; 106+ messages in thread
From: Stefano Stabellini @ 2010-08-18 11:47 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Paolo, xen-devel, Stefano Stabellini, qemu-devel, Anthony,
	Anthony Perard, Bonzini

On Wed, 18 Aug 2010, Gerd Hoffmann wrote:
>    Hi,
> 
> > I mean we can add them to libxc so that there is no need for this patch
> > anymore.
> 
> That would be great.  When adding the xen bits initially I've tried to 
> avoid hard dependencies on specific xen versions.  There are some ifdefs 
> in the qemu code to support compiling with various xen versions (IIRC 
> 3.1 -> 3.4 worked last time I've tried).  I think the minimum supported 
> range of xen versions should be the ones still actively maintained by 
> xensource (I think this is 3.4, 4.0 and unstable right now).  Supporting 
> even older versions would be nice to have.
> 
 
I agree on the range of xen versions, but supporting even a wider range
shouldn't be too hard, it just requires few more ifdef's. 

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

* [Qemu-devel] Re: [PATCH 12/15] piix_pci: introduce a write_config notifier
  2010-08-13 13:10     ` Stefano Stabellini
@ 2010-09-05  7:34         ` Michael S. Tsirkin
  0 siblings, 0 replies; 106+ messages in thread
From: Michael S. Tsirkin @ 2010-09-05  7:34 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Blue Swirl, Anthony Perard, xen-devel, qemu-devel

On Fri, Aug 13, 2010 at 02:10:01PM +0100, Stefano Stabellini wrote:
> On Thu, 12 Aug 2010, Blue Swirl wrote:
> > On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> > > From: Anthony PERARD <anthony.perard@citrix.com>
> > >
> > > Introduce a write config notifier in piix_pci, so that clients can be
> > > notified every time a pci config write happens.
> > > The patch also makes use of the notification mechanism in
> > > xen_machine_fv.
> > 
> > Will the mechanism be used elsewhere? If not, I'd just add a call to
> > xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded
> > by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and
> > friends.
> > 
> 
> we were trying to avoid ifdef's in piix_pci, but if you are OK with just a
> couple of them we'll gladly remove the hook.
> 

I second this. Callbacks complicate code significantly.
If there's a single user we are better off without.

-- 
MST

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

* Re: [PATCH 12/15] piix_pci: introduce a write_config notifier
@ 2010-09-05  7:34         ` Michael S. Tsirkin
  0 siblings, 0 replies; 106+ messages in thread
From: Michael S. Tsirkin @ 2010-09-05  7:34 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Blue Swirl, Anthony Perard, xen-devel, qemu-devel

On Fri, Aug 13, 2010 at 02:10:01PM +0100, Stefano Stabellini wrote:
> On Thu, 12 Aug 2010, Blue Swirl wrote:
> > On Thu, Aug 12, 2010 at 2:09 PM,  <stefano.stabellini@eu.citrix.com> wrote:
> > > From: Anthony PERARD <anthony.perard@citrix.com>
> > >
> > > Introduce a write config notifier in piix_pci, so that clients can be
> > > notified every time a pci config write happens.
> > > The patch also makes use of the notification mechanism in
> > > xen_machine_fv.
> > 
> > Will the mechanism be used elsewhere? If not, I'd just add a call to
> > xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded
> > by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and
> > friends.
> > 
> 
> we were trying to avoid ifdef's in piix_pci, but if you are OK with just a
> couple of them we'll gladly remove the hook.
> 

I second this. Callbacks complicate code significantly.
If there's a single user we are better off without.

-- 
MST

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

end of thread, other threads:[~2010-09-05 11:11 UTC | newest]

Thread overview: 106+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-12 14:08 [Qemu-devel] [PATCH 00/15] RFC xen device model support Stefano Stabellini
2010-08-12 14:08 ` Stefano Stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 01/15] xen: Update libxc calls stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 14:19   ` [Qemu-devel] " Paolo Bonzini
2010-08-12 14:19     ` Paolo Bonzini
2010-08-12 14:28     ` [Qemu-devel] " Stefano Stabellini
2010-08-12 14:28       ` Stefano Stabellini
2010-08-12 14:29       ` [Qemu-devel] " Stefano Stabellini
2010-08-12 14:29         ` Stefano Stabellini
2010-08-18  9:50         ` [Qemu-devel] " Gerd Hoffmann
2010-08-18 11:47           ` Stefano Stabellini
2010-08-18 11:47             ` Stefano Stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-16 13:42   ` [Qemu-devel] " Kevin Wolf
2010-08-16 13:42     ` Kevin Wolf
2010-08-16 14:04     ` [Qemu-devel] " Stefano Stabellini
2010-08-16 14:13       ` Kevin Wolf
2010-08-16 14:13         ` Kevin Wolf
2010-08-16 14:38         ` [Qemu-devel] " Anthony Liguori
2010-08-16 14:38           ` Anthony Liguori
2010-08-16 14:51           ` [Qemu-devel] " Kevin Wolf
2010-08-16 14:51             ` Kevin Wolf
2010-08-16 15:00             ` [Qemu-devel] " Stefano Stabellini
2010-08-16 15:00               ` Stefano Stabellini
2010-08-16 15:07             ` [Qemu-devel] " Anthony Liguori
2010-08-16 15:07               ` Anthony Liguori
2010-08-12 14:09 ` [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 18:56   ` [Qemu-devel] " Blue Swirl
2010-08-13 12:47     ` [Xen-devel] " Ian Jackson
2010-08-13 12:47       ` Ian Jackson
2010-08-13 17:35       ` [Xen-devel] " Blue Swirl
2010-08-13 17:35         ` Blue Swirl
2010-08-13 13:10     ` Stefano Stabellini
2010-08-13 17:46       ` Blue Swirl
2010-08-13 18:50   ` [Qemu-devel] " Anthony Liguori
2010-08-13 18:50     ` Anthony Liguori
2010-08-12 14:09 ` [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenstore stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 18:26   ` [Qemu-devel] " Blue Swirl
2010-08-13 13:09     ` Stefano Stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 07/15] xen: handle xenstore events stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-13 18:53   ` [Qemu-devel] " Anthony Liguori
2010-08-13 18:53     ` Anthony Liguori
2010-08-15 14:12     ` [Qemu-devel] " Paolo Bonzini
2010-08-15 14:12       ` Paolo Bonzini
2010-08-16 11:15       ` [Qemu-devel] " Stefano Stabellini
2010-08-16 11:15         ` Stefano Stabellini
2010-08-16 12:13         ` [Qemu-devel] " Paolo Bonzini
2010-08-16 12:13           ` Paolo Bonzini
2010-08-16 12:59           ` [Qemu-devel] " Stefano Stabellini
2010-08-16 12:59             ` Stefano Stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 18:42   ` [Qemu-devel] " Blue Swirl
2010-08-13 13:10     ` Stefano Stabellini
2010-08-13 18:54   ` [Qemu-devel] " Anthony Liguori
2010-08-13 18:54     ` Anthony Liguori
2010-08-12 14:09 ` [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-13 18:55   ` [Qemu-devel] " Anthony Liguori
2010-08-13 18:55     ` Anthony Liguori
2010-08-12 14:09 ` [Qemu-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 18:44   ` [Qemu-devel] " Blue Swirl
2010-08-13 13:10     ` Stefano Stabellini
2010-08-12 14:09 ` [Qemu-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier stefano.stabellini
2010-08-12 14:09   ` stefano.stabellini
2010-08-12 18:35   ` [Qemu-devel] " Blue Swirl
2010-08-13 13:10     ` Stefano Stabellini
2010-09-05  7:34       ` [Qemu-devel] " Michael S. Tsirkin
2010-09-05  7:34         ` Michael S. Tsirkin
2010-08-12 14:10 ` [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested stefano.stabellini
2010-08-12 14:10   ` stefano.stabellini
2010-08-12 14:10 ` [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested stefano.stabellini
2010-08-12 14:10   ` stefano.stabellini
2010-08-13 18:56   ` [Qemu-devel] " Anthony Liguori
2010-08-13 18:56     ` Anthony Liguori
2010-08-12 14:10 ` [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen stefano.stabellini
2010-08-12 14:10   ` stefano.stabellini
2010-08-12 18:46   ` [Qemu-devel] " Blue Swirl
2010-08-13 13:10     ` Stefano Stabellini
2010-08-13 13:10       ` Stefano Stabellini
2010-08-13 18:57   ` [Qemu-devel] " Anthony Liguori
2010-08-13 18:57     ` Anthony Liguori
2010-08-13 19:37     ` [Qemu-devel] " Stefano Stabellini
2010-08-13 19:37       ` Stefano Stabellini
2010-08-13 20:51       ` [Qemu-devel] " Anthony Liguori
2010-08-13 20:51         ` Anthony Liguori
2010-08-16 11:10         ` [Qemu-devel] " Stefano Stabellini
2010-08-16 11:10           ` Stefano Stabellini
2010-08-13 19:09 ` [Qemu-devel] Re: [PATCH 00/15] RFC xen device model support Anthony Liguori
2010-08-13 19:09   ` Anthony Liguori
2010-08-13 19:35   ` [Qemu-devel] " Stefano Stabellini
2010-08-13 19:35     ` Stefano Stabellini
2010-08-13 20:48     ` [Qemu-devel] " Anthony Liguori
2010-08-13 20:48       ` Anthony Liguori

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.