* [Qemu-devel] [PATCH 01/15] xen: Support new libxc calls from xen unstable.
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv stefano.stabellini
` (13 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Update the libxenctrl calls in Qemu to use the new interface, otherwise
Qemu wouldn't be able to build against new versions of the library.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
configure | 5 +++++
hw/xen_backend.c | 10 +++++-----
hw/xen_backend.h | 2 +-
hw/xen_common.h | 23 ++++++++++++++++++++++-
hw/xen_disk.c | 12 ++++++------
hw/xen_domainbuild.c | 2 +-
hw/xen_nic.c | 16 ++++++++--------
7 files changed, 48 insertions(+), 22 deletions(-)
diff --git a/configure b/configure
index a20371c..4c7c729 100755
--- a/configure
+++ b/configure
@@ -1102,7 +1102,12 @@ if test "$xen" != "no" ; then
cat > $TMPC <<EOF
#include <xenctrl.h>
#include <xs.h>
+#include <xen/xen-compat.h>
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
int main(void) { xs_daemon_open(); xc_interface_open(); return 0; }
+#else
+int main(void) { xs_daemon_open(); xc_interface_open(0, 0, 0); return 0; }
+#endif
EOF
if compile_prog "" "$xen_libs" ; then
xen=yes
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index a2e408f..b23620f 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -43,7 +43,7 @@
/* ------------------------------------------------------------- */
/* public */
-int xen_xc;
+qemu_xc_interface xen_xc = XC_HANDLER_INITIAL_VALUE;
struct xs_handle *xenstore = NULL;
const char *xen_protocol;
@@ -216,7 +216,7 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
- xendev->gnttabdev = xc_gnttab_open();
+ xendev->gnttabdev = xc_gnttab_open(xen_xc);
if (xendev->gnttabdev < 0) {
xen_be_printf(NULL, 0, "can't open gnttab device\n");
xc_evtchn_close(xendev->evtchndev);
@@ -269,7 +269,7 @@ static struct XenDevice *xen_be_del_xendev(int dom, int dev)
if (xendev->evtchndev >= 0)
xc_evtchn_close(xendev->evtchndev);
if (xendev->gnttabdev >= 0)
- xc_gnttab_close(xendev->gnttabdev);
+ xc_gnttab_close(xen_xc, xendev->gnttabdev);
QTAILQ_REMOVE(&xendevs, xendev, next);
qemu_free(xendev);
@@ -627,8 +627,8 @@ int xen_be_init(void)
if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
goto err;
- xen_xc = xc_interface_open();
- if (xen_xc == -1) {
+ xen_xc = xc_interface_open(NULL, NULL, 0);
+ if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
xen_be_printf(NULL, 0, "can't open xen interface\n");
goto err;
}
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index cc25f9d..4350df9 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -57,7 +57,7 @@ struct XenDevice {
/* ------------------------------------------------------------- */
/* variables */
-extern int xen_xc;
+extern qemu_xc_interface xen_xc;
extern struct xs_handle *xenstore;
extern const char *xen_protocol;
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 8a55b44..2cbc376 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -16,7 +16,8 @@
* tweaks needed to build with different xen versions
* 0x00030205 -> 3.1.0
* 0x00030207 -> 3.2.0
- * 0x00030208 -> unstable
+ * 0x00030209 -> 3.3.0
+ * 0x0003020a -> unstable
*/
#include <xen/xen-compat.h>
#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030205
@@ -31,4 +32,24 @@
# define xen_wmb() wmb()
#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x0003020a
+typedef int qemu_xc_interface;
+# define XC_HANDLER_INITIAL_VALUE -1
+# define xc_fd(xen_xc) xen_xc
+# define xc_interface_open(l, dl, f) xc_interface_open()
+# define xc_gnttab_open(xc) xc_gnttab_open()
+# define xc_gnttab_map_grant_ref(xc, gnt, domid, ref, flags) \
+ xc_gnttab_map_grant_ref(gnt, domid, ref, flags)
+# define xc_gnttab_map_grant_refs(xc, gnt, count, domids, refs, flags) \
+ xc_gnttab_map_grant_refs(gnt, count, domids, refs, flags)
+# define xc_gnttab_munmap(xc, gnt, pages, niov) xc_gnttab_munmap(gnt, pages, niov)
+# define xc_gnttab_close(xc, dev) xc_gnttab_close(dev)
+#else
+typedef xc_interface *qemu_xc_interface;
+# define XC_HANDLER_INITIAL_VALUE NULL
+/* FIXME The fd of xen_xc is now xen_xc->fd */
+/* fd is the first field, so this works */
+# define xc_fd(xen_xc) (*(int*)xen_xc)
+#endif
+
#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9a466f3..3c1d3ef 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -242,7 +242,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
if (batch_maps) {
if (!ioreq->pages)
return;
- if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0)
+ if (xc_gnttab_munmap(xen_xc, gnt, ioreq->pages, ioreq->v.niov) != 0)
xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
strerror(errno));
ioreq->blkdev->cnt_map -= ioreq->v.niov;
@@ -251,7 +251,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
for (i = 0; i < ioreq->v.niov; i++) {
if (!ioreq->page[i])
continue;
- if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0)
+ if (xc_gnttab_munmap(xen_xc, gnt, ioreq->page[i], 1) != 0)
xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
strerror(errno));
ioreq->blkdev->cnt_map--;
@@ -269,7 +269,7 @@ static int ioreq_map(struct ioreq *ioreq)
return 0;
if (batch_maps) {
ioreq->pages = xc_gnttab_map_grant_refs
- (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
+ (xen_xc, gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
if (ioreq->pages == NULL) {
xen_be_printf(&ioreq->blkdev->xendev, 0,
"can't map %d grant refs (%s, %d maps)\n",
@@ -283,7 +283,7 @@ static int ioreq_map(struct ioreq *ioreq)
} else {
for (i = 0; i < ioreq->v.niov; i++) {
ioreq->page[i] = xc_gnttab_map_grant_ref
- (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+ (xen_xc, gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
if (ioreq->page[i] == NULL) {
xen_be_printf(&ioreq->blkdev->xendev, 0,
"can't map grant ref %d (%s, %d maps)\n",
@@ -683,7 +683,7 @@ static int blk_connect(struct XenDevice *xendev)
blkdev->protocol = BLKIF_PROTOCOL_X86_64;
}
- blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+ blkdev->sring = xc_gnttab_map_grant_ref(xen_xc, blkdev->xendev.gnttabdev,
blkdev->xendev.dom,
blkdev->ring_ref,
PROT_READ | PROT_WRITE);
@@ -738,7 +738,7 @@ static void blk_disconnect(struct XenDevice *xendev)
xen_be_unbind_evtchn(&blkdev->xendev);
if (blkdev->sring) {
- xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+ xc_gnttab_munmap(xen_xc, blkdev->xendev.gnttabdev, blkdev->sring, 1);
blkdev->cnt_map--;
blkdev->sring = NULL;
}
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
index 7f1fd66..232a456 100644
--- a/hw/xen_domainbuild.c
+++ b/hw/xen_domainbuild.c
@@ -176,7 +176,7 @@ static int xen_domain_watcher(void)
for (i = 3; i < n; i++) {
if (i == fd[0])
continue;
- if (i == xen_xc)
+ if (i == xc_fd(xen_xc))
continue;
close(i);
}
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index 08055b8..4f68850 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -166,7 +166,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
(txreq.flags & NETTXF_more_data) ? " more_data" : "",
(txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
- page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
netdev->xendev.dom,
txreq.gref, PROT_READ);
if (page == NULL) {
@@ -185,7 +185,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
} else {
qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size);
}
- xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+ xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1);
net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
}
if (!netdev->tx_work)
@@ -272,7 +272,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
netdev->rx_ring.req_cons = ++rc;
- page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
netdev->xendev.dom,
rxreq.gref, PROT_WRITE);
if (page == NULL) {
@@ -282,7 +282,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz
return -1;
}
memcpy(page + NET_IP_ALIGN, buf, size);
- xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+ xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1);
net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
return size;
@@ -350,11 +350,11 @@ static int net_connect(struct XenDevice *xendev)
return -1;
}
- netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->txs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
netdev->xendev.dom,
netdev->tx_ring_ref,
PROT_READ | PROT_WRITE);
- netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->rxs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev,
netdev->xendev.dom,
netdev->rx_ring_ref,
PROT_READ | PROT_WRITE);
@@ -381,11 +381,11 @@ static void net_disconnect(struct XenDevice *xendev)
xen_be_unbind_evtchn(&netdev->xendev);
if (netdev->txs) {
- xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+ xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->txs, 1);
netdev->txs = NULL;
}
if (netdev->rxs) {
- xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+ xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->rxs, 1);
netdev->rxs = NULL;
}
if (netdev->nic) {
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 01/15] xen: Support new libxc calls from xen unstable stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen stefano.stabellini
` (12 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Add the Xen FV (Fully Virtualized) machine to Qemu;
this is groundwork to add Xen device model support in Qemu.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Makefile.target | 3 +
hw/xen_machine_fv.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 159 insertions(+), 0 deletions(-)
create mode 100644 hw/xen_machine_fv.c
diff --git a/Makefile.target b/Makefile.target
index 8a9c427..8fdc884 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,6 +183,9 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
# xen backend driver support
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
+# xen full virtualized machine
+obj-$(CONFIG_XEN) += xen_machine_fv.o
+
# USB layer
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
new file mode 100644
index 0000000..8114460
--- /dev/null
+++ b/hw/xen_machine_fv.c
@@ -0,0 +1,156 @@
+/*
+ * QEMU Xen FV Machine
+ *
+ * Copyright (c) 2003-2007 Fabrice Bellard
+ * Copyright (c) 2007 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "usb-uhci.h"
+#include "net.h"
+#include "boards.h"
+#include "ide.h"
+#include "sysemu.h"
+
+#include "xen/hvm/hvm_info_table.h"
+
+#define MAX_IDE_BUS 2
+
+static void xen_init_fv(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ int i;
+ ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
+ PCIBus *pci_bus;
+ PCII440FXState *i440fx_state;
+ int piix3_devfn = -1;
+ qemu_irq *cpu_irq;
+ qemu_irq *isa_irq;
+ qemu_irq *i8259;
+ qemu_irq *cmos_s3;
+ qemu_irq *smi_irq;
+ IsaIrqState *isa_irq_state;
+ DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ FDCtrl *floppy_controller;
+ BusState *idebus[MAX_IDE_BUS];
+ ISADevice *rtc_state;
+
+ CPUState *env;
+
+ /* Initialize a dummy CPU */
+ if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+ cpu_model = "qemu64";
+#else
+ cpu_model = "qemu32";
+#endif
+ }
+ env = cpu_init(cpu_model);
+ env->halted = 1;
+
+ cpu_irq = pc_allocate_cpu_irq();
+ i8259 = i8259_init(cpu_irq[0]);
+ isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+ isa_irq_state->i8259 = i8259;
+
+ isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+
+ pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+ isa_bus_irqs(isa_irq);
+
+ pc_register_ferr_irq(isa_reserve_irq(13));
+
+ pc_vga_init(pci_bus);
+
+ /* init basic PC hardware */
+ pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
+
+ for(i = 0; i < nb_nics; i++) {
+ NICInfo *nd = &nd_table[i];
+
+ if (nd->model && strcmp(nd->model, "ne2k_isa") == 0)
+ pc_init_ne2k_isa(nd);
+ else
+ pci_nic_init_nofail(nd, "e1000", NULL);
+ }
+
+ if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+ fprintf(stderr, "qemu: too many IDE bus\n");
+ exit(1);
+ }
+
+ for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+ hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+ }
+
+ PCIDevice *dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+ idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
+ idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
+
+ pc_audio_init(pci_bus, isa_irq);
+
+ if (ram_size >= 0xe0000000 ) {
+ above_4g_mem_size = ram_size - 0xe0000000;
+ below_4g_mem_size = 0xe0000000;
+ } else {
+ below_4g_mem_size = ram_size;
+ }
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+ idebus[0], idebus[1], floppy_controller, rtc_state);
+
+ if (usb_enabled) {
+ usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+ }
+
+ if (acpi_enabled) {
+ cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+ smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+ piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+ isa_reserve_irq(9), *cmos_s3, *smi_irq,
+ 0);
+ }
+
+ if (i440fx_state) {
+ i440fx_init_memory_mappings(i440fx_state);
+ }
+
+ pc_pci_device_init(pci_bus);
+}
+
+static QEMUMachine xenfv_machine = {
+ .name = "xenfv",
+ .desc = "Xen Fully-virtualized PC",
+ .init = xen_init_fv,
+ .max_cpus = HVM_MAX_VCPUS,
+};
+
+static void xenfv_machine_init(void)
+{
+ qemu_register_machine(&xenfv_machine);
+}
+
+machine_init(xenfv_machine_init);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 01/15] xen: Support new libxc calls from xen unstable stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 11:09 ` [Qemu-devel] " Juan Quintela
2010-08-23 9:50 ` [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenctrl stefano.stabellini
` (11 subsequent siblings)
14 siblings, 1 reply; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
This patch adds a new Xen device model target to Qemu, called
target-xen.
The new target makes use of the previously introduced xen_machine_fv.
In order to have a fully working Xen device model we still need
functionalities introduced by the following patches.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Makefile.target | 31 ++-
arch_init.c | 2 +
arch_init.h | 1 +
configure | 11 +-
default-configs/xen-dm-softmmu.mak | 24 ++
target-xen/cpu.h | 116 ++++++
target-xen/exec-dm.c | 791 ++++++++++++++++++++++++++++++++++++
target-xen/helper.c | 63 +++
target-xen/qemu-xen.h | 30 ++
target-xen/stub-functions.c | 42 ++
target-xen/xen_mapcache.c | 14 +
11 files changed, 1120 insertions(+), 5 deletions(-)
create mode 100644 default-configs/xen-dm-softmmu.mak
create mode 100644 target-xen/cpu.h
create mode 100644 target-xen/exec-dm.c
create mode 100644 target-xen/helper.c
create mode 100644 target-xen/machine.c
create mode 100644 target-xen/qemu-xen.h
create mode 100644 target-xen/stub-functions.c
create mode 100644 target-xen/xen_mapcache.c
diff --git a/Makefile.target b/Makefile.target
index 8fdc884..359a984 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
# xen backend driver support
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
-# xen full virtualized machine
-obj-$(CONFIG_XEN) += xen_machine_fv.o
-
# USB layer
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
@@ -310,6 +307,34 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
endif # CONFIG_SOFTMMU
+# Xen Device Model
+# xen full virtualized machine
+
+# Remove some lib, because we don't want it for a xen target.
+ifeq ($(TARGET_BASE_ARCH), xen)
+bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
+bad-libobj-y += tcg%.o fpu/%.o
+bad-libobj-y += disas.o op_helper.o
+libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
+endif
+
+obj-xen-y += xen_machine_fv.o
+obj-xen-y += i8259.o
+obj-xen-y += pc.o
+obj-xen-y += piix_pci.o
+obj-xen-y += mc146818rtc.o
+
+obj-xen-y += xen_mapcache.o
+obj-xen-y += stub-functions.o
+
+obj-xen-y += vga.o
+obj-xen-y += hpet.o
+obj-xen-y += cirrus_vga.o
+obj-xen-y += smbios.o
+obj-xen-y += multiboot.o
+obj-xen-y += exec-dm.o
+obj-xen-y += lsi53c895a.o usb-ohci.o
+
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
diff --git a/arch_init.c b/arch_init.c
index 47bb4b2..ebc5cb6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -75,6 +75,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
#define QEMU_ARCH QEMU_ARCH_SH4
#elif defined(TARGET_SPARC)
#define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XEN)
+#define QEMU_ARCH QEMU_ARCH_XEN
#endif
const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 682890c..b5f8eb1 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -16,6 +16,7 @@ enum {
QEMU_ARCH_S390X = 256,
QEMU_ARCH_SH4 = 512,
QEMU_ARCH_SPARC = 1024,
+ QEMU_ARCH_XEN = 2048,
};
extern const uint32_t arch_type;
diff --git a/configure b/configure
index 4c7c729..1ff6e80 100755
--- a/configure
+++ b/configure
@@ -2522,6 +2522,9 @@ case "$target" in
${target_arch2}-softmmu)
target_softmmu="yes"
;;
+ ${target_arch2}-dm-softmmu)
+ target_softmmu="yes"
+ ;;
${target_arch2}-linux-user)
if test "$linux" != "yes" ; then
echo "ERROR: Target '$target' is only available on a Linux host"
@@ -2587,6 +2590,10 @@ case "$target_arch2" in
TARGET_BASE_ARCH=i386
target_phys_bits=64
;;
+ xen)
+ # This is use for xen mapcache
+ target_phys_bits=64
+ ;;
alpha)
target_phys_bits=64
target_nptl="yes"
@@ -2698,7 +2705,7 @@ if [ "$TARGET_ABI_DIR" = "" ]; then
fi
echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak
case "$target_arch2" in
- i386|x86_64)
+ i386|x86_64|xen)
if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then
echo "CONFIG_XEN=y" >> $config_target_mak
fi
@@ -2864,7 +2871,7 @@ if test "$target_softmmu" = "yes" ; then
arm)
cflags="-DHAS_AUDIO $cflags"
;;
- i386|mips|ppc)
+ i386|mips|ppc|xen)
cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags"
;;
esac
diff --git a/default-configs/xen-dm-softmmu.mak b/default-configs/xen-dm-softmmu.mak
new file mode 100644
index 0000000..72fe141
--- /dev/null
+++ b/default-configs/xen-dm-softmmu.mak
@@ -0,0 +1,24 @@
+# Default configuration for xen-dm-softmmu
+
+CONFIG_VGA_PCI=y
+CONFIG_VGA_ISA=y
+CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+CONFIG_PARALLEL=y
+CONFIG_I8254=y
+CONFIG_PCSPK=y
+CONFIG_PCKBD=y
+CONFIG_USB_UHCI=y
+CONFIG_FDC=y
+CONFIG_ACPI=y
+CONFIG_APM=y
+CONFIG_DMA=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_IDE_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_PIIX=y
+CONFIG_NE2000_ISA=y
+CONFIG_PIIX_PCI=y
+CONFIG_SOUND=y
+CONFIG_XEN=y
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
new file mode 100644
index 0000000..0e08ab3
--- /dev/null
+++ b/target-xen/cpu.h
@@ -0,0 +1,116 @@
+/*
+ * xen virtual CPU header
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef CPU_XEN_H
+#define CPU_XEN_H
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#ifdef TARGET_X86_64
+#define ELF_MACHINE EM_X86_64
+#else
+#define ELF_MACHINE EM_386
+#endif
+
+#define CPUState struct CPUXenState
+#define CPUX86State CPUXenState
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+/* hidden flags - used internally by qemu to represent additional cpu
+ states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not
+ redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit
+ position to ease oring with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT 0
+#define HF_SMM_SHIFT 19 /* CPU in SMM mode */
+
+#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
+#define HF_SMM_MASK (1 << HF_SMM_SHIFT)
+
+/* cpuid_features bits */
+#define CPUID_APIC (1 << 9)
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUXenState {
+ uint32_t hflags; /* TB flags, see HF_xxx constants. These flags
+ are known at translation time. */
+ CPU_COMMON
+
+ /* processor features (e.g. for CPUID insn) */
+ uint32_t cpuid_features;
+ uint32_t cpuid_apic_id;
+
+ /* in order to simplify APIC support, we leave this pointer to the
+ user */
+ struct DeviceState *apic_state;
+} CPUXenState;
+
+CPUXenState *cpu_xen_init(const char *cpu_model);
+int cpu_xen_exec(CPUXenState *s);
+
+int cpu_get_pic_interrupt(CPUXenState *s);
+void cpu_set_ferr(CPUX86State *s);
+
+/* helper.c */
+void cpu_x86_set_a20(CPUXenState *env, int a20_state);
+
+/* hw/pc.c */
+void cpu_smm_update(CPUXenState *env);
+uint64_t cpu_get_tsc(CPUX86State *env);
+
+#define TARGET_PAGE_BITS 12
+
+#ifdef TARGET_X86_64
+#define TARGET_PHYS_ADDR_SPACE_BITS 52
+/* ??? This is really 48 bits, sign-extended, but the only thing
+ accessible to userland with bit 48 set is the VSYSCALL, and that
+ is handled via other mechanisms. */
+#define TARGET_VIRT_ADDR_SPACE_BITS 47
+#else
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#endif
+
+#define cpu_init cpu_xen_init
+#define cpu_exec cpu_xen_exec
+
+/* MMU modes definitions */
+static inline int cpu_mmu_index (CPUState *env)
+{
+ return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+ target_ulong *cs_base, int *flags)
+{
+}
+
+#endif /* CPU_XEN_H */
diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c
new file mode 100644
index 0000000..5af6330
--- /dev/null
+++ b/target-xen/exec-dm.c
@@ -0,0 +1,791 @@
+/*
+ * virtual page mapping and translated block handling
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "config.h"
+
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "disas.h"
+#include "hw/xen_common.h"
+#include "qemu-xen.h"
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+int use_icount = 0;
+int64_t qemu_icount;
+
+RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
+
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+ cpu_exec() */
+CPUState *cpu_single_env;
+
+/* io memory support */
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+static int io_mem_nb = 1;
+
+/* log support */
+FILE *logfile;
+int loglevel;
+
+void cpu_exec_init_all(unsigned long tb_size)
+{
+}
+
+void cpu_exec_init(CPUState *env)
+{
+ CPUState **penv;
+ int cpu_index;
+
+ env->next_cpu = NULL;
+ penv = &first_cpu;
+ cpu_index = 0;
+ while (*penv != NULL) {
+ penv = (CPUState **)&(*penv)->next_cpu;
+ cpu_index++;
+ }
+ env->cpu_index = cpu_index;
+ *penv = env;
+}
+
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+ loglevel = log_flags;
+ if (!logfile) {
+ logfile = stderr;
+ }
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+ logfile = fopen(filename, "w");
+ if (!logfile) {
+ perror(filename);
+ _exit(1);
+ }
+#if !defined(CONFIG_SOFTMMU)
+ /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+ {
+ static uint8_t logfile_buf[4096];
+ setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+ }
+#else
+ setvbuf(logfile, NULL, _IOLBF, 0);
+#endif
+ dup2(fileno(logfile), 1);
+ dup2(fileno(logfile), 2);
+}
+
+/* mask must never be zero, except for A20 change call */
+void cpu_interrupt(CPUState *env, int mask)
+{
+ env->interrupt_request |= mask;
+}
+
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+ env->interrupt_request &= ~mask;
+}
+
+const CPULogItem cpu_log_items[] = {
+#ifdef DEBUG_IOPORT
+ { CPU_LOG_IOPORT, "ioport",
+ "show all i/o ports accesses" },
+#endif
+ { 0, NULL, NULL },
+};
+
+static int cmp1(const char *s1, int n, const char *s2)
+{
+ if (strlen(s2) != n)
+ return 0;
+ return memcmp(s1, s2, n) == 0;
+}
+
+/* takes a comma separated list of log masks. Return 0 if error. */
+int cpu_str_to_log_mask(const char *str)
+{
+ const CPULogItem *item;
+ int mask;
+ const char *p, *p1;
+
+ p = str;
+ mask = 0;
+ for(;;) {
+ p1 = strchr(p, ',');
+ if (!p1) {
+ p1 = p + strlen(p);
+ }
+ if(cmp1(p,p1-p,"all")) {
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ mask |= item->mask;
+ }
+ } else {
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ if (cmp1(p, p1 - p, item->name))
+ goto found;
+ }
+ return 0;
+ }
+found:
+ mask |= item->mask;
+ if (*p1 != ',')
+ break;
+ p = p1 + 1;
+ }
+ return mask;
+}
+
+/* XXX: Simple implementation. Fix later */
+#define MAX_MMIO 1024
+static struct MMIOSpace {
+ target_phys_addr_t start;
+ unsigned long size;
+ unsigned long io_index;
+} mmio[MAX_MMIO];
+static unsigned long mmio_cnt;
+
+/* register physical memory. 'size' must be a multiple of the target
+ page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+ io memory page */
+void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+ ram_addr_t size,
+ ram_addr_t phys_offset,
+ ram_addr_t region_offset)
+{
+ region_offset &= TARGET_PAGE_MASK;
+ start_addr += region_offset;
+
+ int i;
+
+ for (i = 0; i < mmio_cnt; i++) {
+ if(mmio[i].start == start_addr) {
+ mmio[i].io_index = phys_offset;
+ mmio[i].size = size;
+ return;
+ }
+ }
+
+ if (mmio_cnt == MAX_MMIO) {
+ fprintf(stderr, "too many mmio regions\n");
+ exit(-1);
+ }
+
+ mmio[mmio_cnt].io_index = phys_offset;
+ mmio[mmio_cnt].start = start_addr;
+ mmio[mmio_cnt++].size = size;
+}
+
+/* mem_read and mem_write are arrays of functions containing the
+ function to access byte (index 0), word (index 1) and dword (index
+ 2). All functions must be supplied. If io_index is non zero, the
+ corresponding io zone is modified. If it is zero, a new io zone is
+ allocated. The return value can be used with
+ cpu_register_physical_memory(). (-1) is returned if error. */
+int cpu_register_io_memory_fixed(int io_index,
+ CPUReadMemoryFunc * const *mem_read,
+ CPUWriteMemoryFunc * const *mem_write,
+ void *opaque)
+{
+ int i;
+
+ if (io_index <= 0) {
+ if (io_index >= IO_MEM_NB_ENTRIES)
+ return -1;
+ io_index = io_mem_nb++;
+ } else {
+ if (io_index >= IO_MEM_NB_ENTRIES)
+ return -1;
+ }
+
+ for(i = 0;i < 3; i++) {
+ io_mem_read[io_index][i] = mem_read[i];
+ io_mem_write[io_index][i] = mem_write[i];
+ }
+ io_mem_opaque[io_index] = opaque;
+ return io_index << IO_MEM_SHIFT;
+}
+
+int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
+ CPUWriteMemoryFunc * const *mem_write,
+ void *opaque)
+{
+ return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
+}
+
+void cpu_unregister_io_memory(int io_table_address)
+{
+ int i;
+ int io_index = io_table_address >> IO_MEM_SHIFT;
+
+ for (i = 0; i < mmio_cnt; i++) {
+ if (mmio[i].size && mmio[i].io_index == io_index) {
+ mmio[i].start = mmio[i].size = 0;
+ break;
+ }
+ }
+
+ for (i=0;i < 3; i++) {
+ io_mem_read[io_index][i] = NULL;
+ io_mem_write[io_index][i] = NULL;
+ }
+ io_mem_opaque[io_index] = NULL;
+}
+
+int cpu_physical_memory_set_dirty_tracking(int enable)
+{
+ return 0;
+}
+
+#ifdef __ia64__
+
+#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory")
+#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory")
+
+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
+ * So to emulate right behavior that guest OS is assumed, we need to flush
+ * I/D cache here.
+ */
+static void sync_icache(uint8_t *address, int len)
+{
+ unsigned long addr = (unsigned long)address;
+ unsigned long end = addr + len;
+
+ for (addr &= ~(32UL-1); addr < end; addr += 32UL) {
+ __ia64_fc(addr);
+ }
+
+ ia64_sync_i();
+ ia64_srlz_i();
+}
+#endif
+
+static int iomem_index(target_phys_addr_t addr)
+{
+ int i;
+
+ for (i = 0; i < mmio_cnt; i++) {
+ unsigned long start, end;
+
+ start = mmio[i].start;
+ end = mmio[i].start + mmio[i].size;
+
+ if ((addr >= start) && (addr < end)) {
+ return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+ }
+ }
+ return 0;
+}
+
+unsigned int xen_logdirty_enable = 0;
+
+/*
+ * Replace the standard byte memcpy with a word memcpy for appropriately sized
+ * memory copy operations. Some users (USB-UHCI) can not tolerate the possible
+ * word tearing that can result from a guest concurrently writing a memory
+ * structure while the qemu device model is modifying the same location.
+ * Forcing a word-sized read/write prevents the guest from seeing a partially
+ * written word-sized atom.
+ */
+#if defined(__x86_64__) || defined(__i386__)
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+ asm volatile (
+ " movl %%edx,%%ecx \n"
+#ifdef __x86_64__
+ " shrl $3,%%ecx \n"
+ " rep movsq \n"
+ " test $4,%%edx \n"
+ " jz 1f \n"
+ " movsl \n"
+#else /* __i386__ */
+ " shrl $2,%%ecx \n"
+ " rep movsl \n"
+#endif
+ "1: test $2,%%edx \n"
+ " jz 1f \n"
+ " movsw \n"
+ "1: test $1,%%edx \n"
+ " jz 1f \n"
+ " movsb \n"
+ "1: \n"
+ : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" );
+}
+#else
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+ /* Some architectures do not like unaligned accesses. */
+ if (((unsigned long)dst | (unsigned long)src) & 3) {
+ memcpy(dst, src, n);
+ return;
+ }
+
+ while (n >= sizeof(uint32_t)) {
+ *((uint32_t *)dst) = *((uint32_t *)src);
+ dst = ((uint32_t *)dst) + 1;
+ src = ((uint32_t *)src) + 1;
+ n -= sizeof(uint32_t);
+ }
+
+ if (n & 2) {
+ *((uint16_t *)dst) = *((uint16_t *)src);
+ dst = ((uint16_t *)dst) + 1;
+ src = ((uint16_t *)src) + 1;
+ }
+
+ if (n & 1) {
+ *((uint8_t *)dst) = *((uint8_t *)src);
+ dst = ((uint8_t *)dst) + 1;
+ src = ((uint8_t *)src) + 1;
+ }
+}
+#endif
+
+void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf,
+ int _len, int is_write)
+{
+ target_phys_addr_t addr = _addr;
+ int len = _len;
+ int l, io_index;
+ uint8_t *ptr;
+ uint32_t val;
+
+ mapcache_lock();
+
+ while (len > 0) {
+ /* How much can we copy before the next page boundary? */
+ l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
+ if (l > len) {
+ l = len;
+ }
+
+ io_index = iomem_index(addr);
+ if (is_write) {
+ if (io_index) {
+ if (l >= 4 && ((addr & 3) == 0)) {
+ /* 32 bit read access */
+ val = ldl_raw(buf);
+ io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+ l = 4;
+ } else if (l >= 2 && ((addr & 1) == 0)) {
+ /* 16 bit read access */
+ val = lduw_raw(buf);
+ io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+ l = 2;
+ } else {
+ /* 8 bit access */
+ val = ldub_raw(buf);
+ io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
+ l = 1;
+ }
+ } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+ /* Writing to RAM */
+ memcpy_words(ptr, buf, l);
+
+ if (xen_logdirty_enable) {
+ xc_hvm_modified_memory(xen_xc,
+ xen_domid,
+ addr >> TARGET_PAGE_BITS,
+ ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+ - (addr >> TARGET_PAGE_BITS));
+ }
+#ifdef __ia64__
+ sync_icache(ptr, l);
+#endif
+ }
+ } else {
+ if (io_index) {
+ if (l >= 4 && ((addr & 3) == 0)) {
+ /* 32 bit read access */
+ val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+ stl_raw(buf, val);
+ l = 4;
+ } else if (l >= 2 && ((addr & 1) == 0)) {
+ /* 16 bit read access */
+ val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+ stw_raw(buf, val);
+ l = 2;
+ } else {
+ /* 8 bit access */
+ val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
+ stb_raw(buf, val);
+ l = 1;
+ }
+ } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+ /* Reading from RAM */
+ memcpy_words(buf, ptr, l);
+ } else {
+ /* Neither RAM nor known MMIO space */
+ memset(buf, 0xff, len);
+ }
+ }
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+
+ mapcache_unlock();
+}
+
+/* virtual memory access for debug */
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+ uint8_t *buf, int len, int is_write)
+{
+ int l;
+ target_ulong page, phys_addr;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ phys_addr = cpu_get_phys_page_debug(env, page);
+ /* if no physical page mapped, return an error */
+ if (phys_addr == -1)
+ return -1;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
+ buf, l, is_write);
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+ return 0;
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+ int dirty_flags)
+{
+ unsigned long length;
+ int i, mask, len;
+ uint8_t *p;
+
+ start &= TARGET_PAGE_MASK;
+ end = TARGET_PAGE_ALIGN(end);
+
+ length = end - start;
+ if (length == 0)
+ return;
+ mask = ~dirty_flags;
+ p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+ len = length >> TARGET_PAGE_BITS;
+ for(i = 0; i < len; i++) {
+ p[i] &= mask;
+ }
+
+ return;
+}
+
+
+/* Unoptimised in Xen DM, nicked from git
+ * aab33094073678d459ccaac5c60ea7533e8d1d8e */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+ uint8_t val;
+ cpu_physical_memory_read(addr, &val, 1);
+ return val;
+}
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+ uint16_t val;
+ cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
+ return tswap16(val);
+}
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+ uint64_t val;
+ cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
+ return tswap64(val);
+}
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+ uint8_t v = val;
+ cpu_physical_memory_write(addr, &v, 1);
+}
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+ uint16_t v = tswap16(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
+}
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+ val = tswap64(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+}
+
+/* stubs which we hope (think!) are OK for Xen DM */
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+ val = tswap32(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&val, 4);
+}
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+ stl_phys(addr, val);
+}
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+ uint32_t val;
+ cpu_physical_memory_read(addr, (uint8_t *)&val, 4);
+ return tswap32(val);
+}
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+ const uint8_t *buf, int len)
+{
+ return cpu_physical_memory_write(addr,buf,len);
+}
+
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+}
+
+/* stub out various functions for Xen DM */
+void dump_exec_info(FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+}
+
+void monitor_disas(Monitor *mon, CPUState *env,
+ target_ulong pc, int nb_insn, int is_physical, int flags)
+{
+}
+
+/*
+ * This next section was clone-and-hacked from the version in exec.c
+ * :-(. But the exec.c version is full of tcg-specific stuff and
+ * assumptions about phys_ram_base.
+ */
+
+typedef struct MapClient {
+ void *opaque;
+ void (*callback)(void *opaque);
+ QLIST_ENTRY(MapClient) link;
+} MapClient;
+
+static QLIST_HEAD(map_client_list, MapClient) map_client_list
+ = QLIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+ MapClient *client = qemu_malloc(sizeof(*client));
+
+ client->opaque = opaque;
+ client->callback = callback;
+ QLIST_INSERT_HEAD(&map_client_list, client, link);
+ return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+ MapClient *client = (MapClient *)_client;
+
+ QLIST_REMOVE(client, link);
+ qemu_free(client);
+}
+
+static void cpu_notify_map_clients(void)
+{
+ MapClient *client;
+
+ while (!QLIST_EMPTY(&map_client_list)) {
+ client = QLIST_FIRST(&map_client_list);
+ client->callback(client->opaque);
+ cpu_unregister_map_client(client);
+ }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+ target_phys_addr_t *plen,
+ int is_write)
+{
+ unsigned long l = 0;
+#ifdef MAPCACHE
+ l = MCACHE_BUCKET_SIZE - (addr & (MCACHE_BUCKET_SIZE-1));
+ if ((*plen) > l) {
+ *plen = l;
+ }
+#endif
+ if (xen_logdirty_enable) {
+ xc_hvm_modified_memory(xen_xc, xen_domid, addr >> TARGET_PAGE_BITS,
+ ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+ - (addr >> TARGET_PAGE_BITS));
+ }
+
+ return qemu_map_cache(addr, 1);
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1. access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+ int is_write, target_phys_addr_t access_len)
+{
+ qemu_invalidate_entry(buffer);
+ cpu_notify_map_clients();
+}
+
+
+void cpu_exit(CPUState *env)
+{
+ env->exit_request = 1;
+}
+
+void qemu_flush_coalesced_mmio_buffer(void)
+{
+}
+
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+ RAMBlock *block;
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ if (addr - block->offset < block->length) {
+ QLIST_REMOVE(block, next);
+ QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
+ return block->host + (addr - block->offset);
+ }
+ }
+ return block->host + (addr - block->offset);
+
+ fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+ abort();
+
+ return NULL;
+}
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr)
+{
+ return 0;
+}
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
+{
+ return 0;
+}
+
+static ram_addr_t find_ram_offset(ram_addr_t size)
+{
+ RAMBlock *block;
+ ram_addr_t last = 0;
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ last = MAX(last, block->offset + block->length);
+ }
+
+ return last;
+}
+
+ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
+{
+ RAMBlock *new_block;
+
+ size = TARGET_PAGE_ALIGN(size);
+ new_block = qemu_malloc(sizeof(*new_block));
+
+ if (mem_path) {
+#if defined (__linux__) && !defined(TARGET_S390X)
+ new_block->host = 0; // file_ram_alloc(size, mem_path);
+ if (!new_block->host) {
+ new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+ madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+ }
+#else
+ fprintf(stderr, "-mem-path option unsupported\n");
+ exit(1);
+#endif
+ } else {
+ new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+ madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+ }
+ new_block->offset = find_ram_offset(size);
+ new_block->length = size;
+
+ QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);
+
+ ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
+ (new_block->offset + size) >> TARGET_PAGE_BITS);
+ memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+ 0xff, size >> TARGET_PAGE_BITS);
+
+ return new_block->offset;
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+}
+
+void tb_flush(CPUState *env1)
+{
+}
+
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+ int flags, CPUWatchpoint **watchpoint)
+{
+ return -ENOSYS;
+}
+
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+ int flags)
+{
+ return -ENOENT;
+}
+
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+ CPUBreakpoint **breakpoint)
+{
+ return -ENOSYS;
+}
+
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
+{
+ return -ENOSYS;
+}
+
+void cpu_breakpoint_remove_all(CPUState *env, int mask)
+{
+}
+
+void cpu_single_step(CPUState *env, int enabled)
+{
+}
diff --git a/target-xen/helper.c b/target-xen/helper.c
new file mode 100644
index 0000000..f8512c8
--- /dev/null
+++ b/target-xen/helper.c
@@ -0,0 +1,63 @@
+/*
+ * i386 helpers (without register variable usage)
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cpu.h"
+
+CPUXenState *cpu_xen_init(const char *cpu_model)
+{
+ CPUXenState *env = NULL;
+ static int inited;
+
+ env = qemu_mallocz(sizeof(CPUXenState));
+ cpu_exec_init(env);
+
+ /* init various static tables */
+ if (!inited) {
+ inited = 1;
+
+ cpu_single_env = env;
+ }
+
+ return env;
+}
+
+int cpu_xen_exec(CPUState *env1)
+{
+ return 0;
+}
+
+void cpu_reset(CPUXenState *env)
+{
+}
+
+void cpu_dump_state(CPUState *env, FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+}
+
+void cpu_x86_set_a20(CPUXenState *env, int a20_state)
+{
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+ return addr;
+}
diff --git a/target-xen/machine.c b/target-xen/machine.c
new file mode 100644
index 0000000..e69de29
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
new file mode 100644
index 0000000..d1910d6
--- /dev/null
+++ b/target-xen/qemu-xen.h
@@ -0,0 +1,30 @@
+#ifndef QEMU_XEN_H
+#define QEMU_XEN_H
+
+#include "hw/xen_common.h"
+
+/* vl.c */
+
+#if defined(__i386__) || defined(__x86_64__)
+#define phys_ram_addr(x) (qemu_map_cache(x, 0))
+#elif defined(__ia64__)
+#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL)
+#endif
+
+/* xen_mapcache.c */
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
+void qemu_invalidate_entry(uint8_t *buffer);
+void qemu_invalidate_map_cache(void);
+
+#define mapcache_lock() ((void)0)
+#define mapcache_unlock() ((void)0)
+
+/* target-xen/exec-dm.c */
+
+int cpu_register_io_memory_fixed(int io_index,
+ CPUReadMemoryFunc * const *mem_read,
+ CPUWriteMemoryFunc * const *mem_write,
+ void *opaque);
+
+#endif /*QEMU_XEN_H*/
diff --git a/target-xen/stub-functions.c b/target-xen/stub-functions.c
new file mode 100644
index 0000000..0db6898
--- /dev/null
+++ b/target-xen/stub-functions.c
@@ -0,0 +1,42 @@
+#include "config.h"
+#include "disas.h"
+#include "hw/apic.h"
+#include "hw/pc.h"
+#include "cpu.h"
+
+/* disas */
+struct syminfo *syminfos = NULL;
+
+/* apic */
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+ return -1;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+ return 0;
+}
+
+/* vmmouse */
+void *vmmouse_init(void *m)
+{
+ return NULL;
+}
+
+/* cpu-exec */
+volatile sig_atomic_t exit_request;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+ return NULL;
+}
+
+int qemu_cpu_has_work(CPUState *env)
+{
+ return 0;
+}
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
new file mode 100644
index 0000000..39daae2
--- /dev/null
+++ b/target-xen/xen_mapcache.c
@@ -0,0 +1,14 @@
+#include "qemu-xen.h"
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+ return phys_ram_addr(phys_addr);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
2010-08-23 9:50 ` [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen stefano.stabellini
@ 2010-08-23 11:09 ` Juan Quintela
2010-08-23 11:16 ` Stefano Stabellini
0 siblings, 1 reply; 25+ messages in thread
From: Juan Quintela @ 2010-08-23 11:09 UTC (permalink / raw)
To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel
stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> This patch adds a new Xen device model target to Qemu, called
> target-xen.
> The new target makes use of the previously introduced xen_machine_fv.
> In order to have a fully working Xen device model we still need
> functionalities introduced by the following patches.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
....
> diff --git a/Makefile.target b/Makefile.target
> index 8fdc884..359a984 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
> # xen backend driver support
....
> +# Xen Device Model
> +# xen full virtualized machine
> +
> +# Remove some lib, because we don't want it for a xen target.
> +ifeq ($(TARGET_BASE_ARCH), xen)
> +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
> +bad-libobj-y += tcg%.o fpu/%.o
> +bad-libobj-y += disas.o op_helper.o
> +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
> +endif
This is a hack (to call it something). Can we have a proper fix for
this? Just putting that files under tcg-libobj-y (or something like
that), and add it only to some targets. There is (another similar bad
hack) on qemu-kvm.git to disable them for ia64. Can we get something
saner here?
Later, Juan.
PD. No, this is not xen specific, disabling compilation of tcg on qemu
is basically imposible.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [Qemu-devel] Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
2010-08-23 11:09 ` [Qemu-devel] " Juan Quintela
@ 2010-08-23 11:16 ` Stefano Stabellini
0 siblings, 0 replies; 25+ messages in thread
From: Stefano Stabellini @ 2010-08-23 11:16 UTC (permalink / raw)
To: Juan Quintela
Cc: Anthony Perard, xen-devel@lists.xensource.com,
qemu-devel@nongnu.org, Stefano Stabellini
On Mon, 23 Aug 2010, Juan Quintela wrote:
> > +# Xen Device Model
> > +# xen full virtualized machine
> > +
> > +# Remove some lib, because we don't want it for a xen target.
> > +ifeq ($(TARGET_BASE_ARCH), xen)
> > +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o
> > +bad-libobj-y += tcg%.o fpu/%.o
> > +bad-libobj-y += disas.o op_helper.o
> > +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
> > +endif
>
> This is a hack (to call it something). Can we have a proper fix for
> this? Just putting that files under tcg-libobj-y (or something like
> that), and add it only to some targets. There is (another similar bad
> hack) on qemu-kvm.git to disable them for ia64. Can we get something
> saner here?
>
As I mentioned in the introduction email to the series, we haven't tried
to remove target-xen yet, but it is the next item on our todo list.
Removing the new target will remove this hack too.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenctrl
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (2 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller stefano.stabellini
` (10 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Introduce a xen_dm_init function that opens the xenctrl interface; call
xen_dm_init from xen_machine_fv.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Makefile.target | 1 +
hw/xen_machine_fv.c | 8 ++++++++
target-xen/xenstore.c | 13 +++++++++++++
target-xen/xenstore.h | 6 ++++++
4 files changed, 28 insertions(+), 0 deletions(-)
create mode 100644 target-xen/xenstore.c
create mode 100644 target-xen/xenstore.h
diff --git a/Makefile.target b/Makefile.target
index 359a984..63dc7d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -323,6 +323,7 @@ obj-xen-y += i8259.o
obj-xen-y += pc.o
obj-xen-y += piix_pci.o
obj-xen-y += mc146818rtc.o
+obj-xen-y += xenstore.o
obj-xen-y += xen_mapcache.o
obj-xen-y += stub-functions.o
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 8114460..5fef7de 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -32,6 +32,8 @@
#include "ide.h"
#include "sysemu.h"
+#include "xen_backend.h"
+#include "xenstore.h"
#include "xen/hvm/hvm_info_table.h"
#define MAX_IDE_BUS 2
@@ -61,6 +63,12 @@ static void xen_init_fv(ram_addr_t ram_size,
CPUState *env;
+ /* Initialize backend core & drivers */
+ if (xen_dm_init() != 0) {
+ fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+ exit(1);
+ }
+
/* Initialize a dummy CPU */
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
new file mode 100644
index 0000000..bd74787
--- /dev/null
+++ b/target-xen/xenstore.c
@@ -0,0 +1,13 @@
+#include "hw/xen_backend.h"
+#include "xenstore.h"
+
+int xen_dm_init(void)
+{
+ xen_xc = xc_interface_open(NULL, NULL, 0);
+ if (xen_xc == NULL) {
+ xen_be_printf(NULL, 0, "can't open xen interface\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
new file mode 100644
index 0000000..90baf79
--- /dev/null
+++ b/target-xen/xenstore.h
@@ -0,0 +1,6 @@
+#ifndef XENSTORE_H_
+#define XENSTORE_H_
+
+int xen_dm_init(void);
+
+#endif /* !XENSTORE_H_ */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (3 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenctrl stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device stefano.stabellini
` (9 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Introduce a 8259 Interrupt Controller for target-xen; every set_irq
call makes a Xen hypercall.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Makefile.target | 2 +-
hw/xen_common.h | 3 ++
hw/xen_machine_fv.c | 5 +--
target-xen/i8259-xen-stub.c | 63 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 69 insertions(+), 4 deletions(-)
create mode 100644 target-xen/i8259-xen-stub.c
diff --git a/Makefile.target b/Makefile.target
index 63dc7d1..d1b63f2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -319,7 +319,7 @@ libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y))
endif
obj-xen-y += xen_machine_fv.o
-obj-xen-y += i8259.o
+obj-xen-y += i8259-xen-stub.o
obj-xen-y += pc.o
obj-xen-y += piix_pci.o
obj-xen-y += mc146818rtc.o
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 2cbc376..c49358c 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -52,4 +52,7 @@ typedef xc_interface *qemu_xc_interface;
# define xc_fd(xen_xc) (*(int*)xen_xc)
#endif
+/* hw/i8259-xen-stub.c */
+qemu_irq *i8259_xen_init(void);
+
#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 5fef7de..114addf 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -32,6 +32,7 @@
#include "ide.h"
#include "sysemu.h"
+#include "xen_common.h"
#include "xen_backend.h"
#include "xenstore.h"
#include "xen/hvm/hvm_info_table.h"
@@ -50,7 +51,6 @@ static void xen_init_fv(ram_addr_t ram_size,
PCIBus *pci_bus;
PCII440FXState *i440fx_state;
int piix3_devfn = -1;
- qemu_irq *cpu_irq;
qemu_irq *isa_irq;
qemu_irq *i8259;
qemu_irq *cmos_s3;
@@ -80,8 +80,7 @@ static void xen_init_fv(ram_addr_t ram_size,
env = cpu_init(cpu_model);
env->halted = 1;
- cpu_irq = pc_allocate_cpu_irq();
- i8259 = i8259_init(cpu_irq[0]);
+ i8259 = i8259_xen_init();
isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
isa_irq_state->i8259 = i8259;
diff --git a/target-xen/i8259-xen-stub.c b/target-xen/i8259-xen-stub.c
new file mode 100644
index 0000000..aa2aae1
--- /dev/null
+++ b/target-xen/i8259-xen-stub.c
@@ -0,0 +1,63 @@
+/* Xen 8259 stub for interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2005 Intel corperation
+ * Copyright (c) 2008 Citrix / Xensource
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "monitor.h"
+#include "hw/xen_common.h"
+#include "hw/xen_backend.h"
+
+#include <xen/hvm/ioreq.h>
+
+PicState2 *isa_pic = NULL;
+
+void pic_update_irq(PicState2 *s)
+{
+}
+
+static void i8259_set_irq(void *opaque, int irq, int level)
+{
+ xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level);
+}
+
+int pic_read_irq(PicState2 *s)
+{
+ return -1;
+}
+
+void irq_info(Monitor *mon)
+{
+ monitor_printf(mon, "irq statistics not supported with Xen.\n");
+}
+
+void pic_info(Monitor *mon)
+{
+ monitor_printf(mon, "pic_info not supported with Xen .\n");
+}
+
+qemu_irq *i8259_xen_init(void)
+{
+ return qemu_allocate_irqs(i8259_set_irq, NULL, 16);
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (4 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 07/15] xen: handle xenstore events stefano.stabellini
` (8 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Introduce a new emulated PCI device, specific to fully virtualized Xen
guests. The device is necessary for PV on HVM drivers to work.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Makefile.target | 1 +
hw/hw.h | 3 +
hw/pci_ids.h | 2 +
hw/xen_machine_fv.c | 3 +
hw/xen_platform.c | 449 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/xen_platform.h | 8 +
6 files changed, 466 insertions(+), 0 deletions(-)
create mode 100644 hw/xen_platform.c
create mode 100644 hw/xen_platform.h
diff --git a/Makefile.target b/Makefile.target
index d1b63f2..1984cdd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -324,6 +324,7 @@ obj-xen-y += pc.o
obj-xen-y += piix_pci.o
obj-xen-y += mc146818rtc.o
obj-xen-y += xenstore.o
+obj-xen-y += xen_platform.o
obj-xen-y += xen_mapcache.o
obj-xen-y += stub-functions.o
diff --git a/hw/hw.h b/hw/hw.h
index e3c3db2..aa17aaf 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -651,6 +651,9 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_INT32_LE(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+#define VMSTATE_UINT8_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
#define VMSTATE_UINT16_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 39e9f1d..1f2e0dd 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -105,3 +105,5 @@
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+
+#define PCI_VENDOR_ID_XENSOURCE 0x5853
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 114addf..12a7723 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -35,6 +35,7 @@
#include "xen_common.h"
#include "xen_backend.h"
#include "xenstore.h"
+#include "xen_platform.h"
#include "xen/hvm/hvm_info_table.h"
#define MAX_IDE_BUS 2
@@ -93,6 +94,8 @@ static void xen_init_fv(ram_addr_t ram_size,
pc_vga_init(pci_bus);
+ pci_xen_platform_init(pci_bus);
+
/* init basic PC hardware */
pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
new file mode 100644
index 0000000..d843b3d
--- /dev/null
+++ b/hw/xen_platform.c
@@ -0,0 +1,449 @@
+/*
+ * XEN platform pci device, formerly known as the event channel device
+ *
+ * Copyright (c) 2003-2004 Intel Corp.
+ * Copyright (c) 2006 XenSource
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "irq.h"
+#include "xen_common.h"
+#include "net.h"
+#include "xen_platform.h"
+#include "xen_backend.h"
+#include "qemu-log.h"
+
+#include <assert.h>
+#include <xenguest.h>
+
+#define DPRINTF(fmt, ...) do { \
+ fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState {
+ PCIDevice pci_dev;
+ uint8_t flags; /* used only for version_id == 2 */
+ int drivers_blacklisted;
+ uint16_t driver_product_version;
+
+ /* Log from guest drivers */
+ int throttling_disabled;
+ char log_buffer[4096];
+ int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* We throttle access to dom0 syslog, to avoid DOS attacks. This is
+ modelled as a token bucket, with one token for every byte of log.
+ The bucket size is 128KB (->1024 lines of 128 bytes each) and
+ refills at 256B/s. It starts full. The guest is blocked if no
+ tokens are available when it tries to generate a log message. */
+#define BUCKET_MAX_SIZE (128*1024)
+#define BUCKET_FILL_RATE 256
+
+static void throttle(PCIXenPlatformState *s, unsigned count)
+{
+ static unsigned available;
+ static struct timespec last_refil;
+ static int started;
+ static int warned;
+
+ struct timespec waiting_for, now;
+ double delay;
+ struct timespec ts;
+
+ if (s->throttling_disabled)
+ return;
+
+ if (!started) {
+ clock_gettime(CLOCK_MONOTONIC, &last_refil);
+ available = BUCKET_MAX_SIZE;
+ started = 1;
+ }
+
+ if (count > BUCKET_MAX_SIZE) {
+ DPRINTF("tried to get %d tokens, but bucket size is %d\n",
+ BUCKET_MAX_SIZE, count);
+ exit(1);
+ }
+
+ if (available < count) {
+ /* The bucket is empty. Refil it */
+
+ /* When will it be full enough to handle this request? */
+ delay = (double)(count - available) / BUCKET_FILL_RATE;
+ waiting_for = last_refil;
+ waiting_for.tv_sec += delay;
+ waiting_for.tv_nsec += (delay - (int)delay) * 1e9;
+ if (waiting_for.tv_nsec >= 1000000000) {
+ waiting_for.tv_nsec -= 1000000000;
+ waiting_for.tv_sec++;
+ }
+
+ /* How long do we have to wait? (might be negative) */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ts.tv_sec = waiting_for.tv_sec - now.tv_sec;
+ ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec;
+ if (ts.tv_nsec < 0) {
+ ts.tv_sec--;
+ ts.tv_nsec += 1000000000;
+ }
+
+ /* Wait for it. */
+ if (ts.tv_sec > 0 ||
+ (ts.tv_sec == 0 && ts.tv_nsec > 0)) {
+ if (!warned) {
+ DPRINTF("throttling guest access to syslog");
+ warned = 1;
+ }
+ while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
+ ;
+ }
+
+ /* Refil */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ delay = (now.tv_sec - last_refil.tv_sec) +
+ (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9;
+ available += BUCKET_FILL_RATE * delay;
+ if (available > BUCKET_MAX_SIZE)
+ available = BUCKET_MAX_SIZE;
+ last_refil = now;
+ }
+
+ assert(available >= count);
+
+ available -= count;
+}
+
+/* Xen Platform, Fixed IOPort */
+
+static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIXenPlatformState *s = opaque;
+
+ switch (addr - XEN_PLATFORM_IOPORT) {
+ case 0:
+ /* TODO: */
+ /* Unplug devices. Value is a bitmask of which devices to
+ unplug, with bit 0 the IDE devices, bit 1 the network
+ devices, and bit 2 the non-primary-master IDE devices. */
+ break;
+ case 2:
+ switch (val) {
+ case 1:
+ DPRINTF("Citrix Windows PV drivers loaded in guest\n");
+ break;
+ case 0:
+ DPRINTF("Guest claimed to be running PV product 0?\n");
+ break;
+ default:
+ DPRINTF("Unknown PV product %d loaded in guest\n", val);
+ break;
+ }
+ s->driver_product_version = val;
+ break;
+ }
+}
+
+static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
+ uint32_t val)
+{
+ switch (addr - XEN_PLATFORM_IOPORT) {
+ case 0:
+ /* PV driver version */
+ break;
+ }
+}
+
+static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIXenPlatformState *s = opaque;
+
+ switch (addr - XEN_PLATFORM_IOPORT) {
+ case 0: /* Platform flags */ {
+ hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
+ HVMMEM_ram_ro : HVMMEM_ram_rw;
+ if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40))
+ DPRINTF("unable to change ro/rw state of ROM memory area!\n");
+ else {
+ s->flags = val & PFFLAG_ROM_LOCK;
+ DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
+ (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
+ }
+ break;
+ }
+ case 2:
+ /* Send bytes to syslog */
+ if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+ /* Flush buffer */
+ s->log_buffer[s->log_buffer_off] = 0;
+ throttle(s, s->log_buffer_off);
+ DPRINTF("%s\n", s->log_buffer);
+ s->log_buffer_off = 0;
+ break;
+ }
+ s->log_buffer[s->log_buffer_off++] = val;
+ break;
+ }
+}
+
+static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
+{
+ PCIXenPlatformState *s = opaque;
+
+ switch (addr - XEN_PLATFORM_IOPORT) {
+ case 0:
+ if (s->drivers_blacklisted) {
+ /* The drivers will recognise this magic number and refuse
+ * to do anything. */
+ return 0xd249;
+ } else {
+ /* Magic value so that you can identify the interface. */
+ return 0x49d2;
+ }
+ default:
+ return 0xffff;
+ }
+}
+
+static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
+{
+ PCIXenPlatformState *s = opaque;
+
+ switch (addr - XEN_PLATFORM_IOPORT) {
+ case 0:
+ /* Platform flags */
+ return s->flags;
+ case 2:
+ /* Version number */
+ return 1;
+ default:
+ return 0xff;
+ }
+}
+
+static void platform_fixed_ioport_reset(void *opaque)
+{
+ PCIXenPlatformState *s = opaque;
+
+ platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, 0);
+}
+
+static void platform_fixed_ioport_init(PCIXenPlatformState* s)
+{
+ register_ioport_write(XEN_PLATFORM_IOPORT, 16, 4, platform_fixed_ioport_writel, s);
+ register_ioport_write(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_writew, s);
+ register_ioport_write(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_writeb, s);
+ register_ioport_read(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_readw, s);
+ register_ioport_read(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_readb, s);
+}
+
+/* Xen Platform PCI Device */
+
+static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
+{
+ addr &= 0xff;
+
+ if (addr == 0)
+ return platform_fixed_ioport_readb(opaque, XEN_PLATFORM_IOPORT);
+ else
+ return ~0u;
+}
+
+static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIXenPlatformState *s = opaque;
+
+ addr &= 0xff;
+ val &= 0xff;
+
+ switch (addr) {
+ case 0: /* Platform flags */
+ platform_fixed_ioport_writeb(opaque, XEN_PLATFORM_IOPORT, val);
+ break;
+ case 8:
+ {
+ if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+ /* Flush buffer */
+ s->log_buffer[s->log_buffer_off] = 0;
+ throttle(s, s->log_buffer_off);
+ DPRINTF("%s\n", s->log_buffer);
+ s->log_buffer_off = 0;
+ break;
+ }
+ s->log_buffer[s->log_buffer_off++] = val;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type)
+{
+ PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, pci_dev);
+
+ register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
+ register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
+}
+
+static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr)
+{
+ static int warnings = 0;
+
+ if (warnings < 5) {
+ DPRINTF("Warning: attempted read from physical address "
+ "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+ warnings++;
+ }
+ return 0;
+}
+
+static void platform_mmio_write(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ static int warnings = 0;
+
+ if (warnings < 5) {
+ DPRINTF("Warning: attempted write of 0x%x to physical "
+ "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+ val, addr);
+ warnings++;
+ }
+}
+
+static CPUReadMemoryFunc * const platform_mmio_read_funcs[3] = {
+ platform_mmio_read,
+ platform_mmio_read,
+ platform_mmio_read,
+};
+
+static CPUWriteMemoryFunc * const platform_mmio_write_funcs[3] = {
+ platform_mmio_write,
+ platform_mmio_write,
+ platform_mmio_write,
+};
+
+static void platform_mmio_map(PCIDevice *d, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ int mmio_io_addr;
+
+ mmio_io_addr = cpu_register_io_memory(platform_mmio_read_funcs,
+ platform_mmio_write_funcs, NULL);
+
+ cpu_register_physical_memory(addr, size, mmio_io_addr);
+}
+
+static int xen_platform_post_load(void *opaque, int version_id)
+{
+ PCIXenPlatformState *s = opaque;
+
+ platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, s->flags);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_xen_platform = {
+ .name = "platform",
+ .version_id = 4,
+ .minimum_version_id = 4,
+ .minimum_version_id_old = 4,
+ .post_load = xen_platform_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
+ VMSTATE_UINT8(flags, PCIXenPlatformState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int xen_platform_initfn(PCIDevice *dev)
+{
+ PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
+ uint8_t *pci_conf;
+
+ pci_conf = d->pci_dev.config;
+
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_XENSOURCE);
+ pci_config_set_device_id(pci_conf, 0x0001);
+ pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+ pci_config_set_revision(pci_conf, 1);
+ pci_config_set_prog_interface(pci_conf, 0);
+
+ pci_config_set_class(pci_conf, PCI_CLASS_OTHERS << 8 | 0x80);
+
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+ pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+ /* Microsoft WHQL requires non-zero subsystem IDs. */
+ /* http://www.pcisig.com/reflector/msg02205.html. */
+ pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, pci_conf[PCI_VENDOR_ID]);
+ pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0001);
+
+ pci_register_bar(&d->pci_dev, 0, 0x100,
+ PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
+
+ /* reserve 16MB mmio address for share memory*/
+ pci_register_bar(&d->pci_dev, 1, 0x1000000,
+ PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
+
+ platform_fixed_ioport_init(d);
+
+ return 0;
+}
+
+static void platform_reset(DeviceState *dev)
+{
+ PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
+
+ platform_fixed_ioport_reset(s);
+}
+
+void pci_xen_platform_init(PCIBus *bus)
+{
+ PCIDevice *dev;
+
+ dev = pci_create(bus, -1, "xen-platform");
+
+ qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo xen_platform_info = {
+ .init = xen_platform_initfn,
+ .qdev.name = "xen-platform",
+ .qdev.desc = "XEN platform pci device",
+ .qdev.size = sizeof(PCIXenPlatformState),
+ .qdev.vmsd = &vmstate_xen_platform,
+ .qdev.reset = platform_reset,
+};
+
+static void xen_platform_register(void)
+{
+ pci_qdev_register(&xen_platform_info);
+}
+
+device_init(xen_platform_register);
diff --git a/hw/xen_platform.h b/hw/xen_platform.h
new file mode 100644
index 0000000..574eecd
--- /dev/null
+++ b/hw/xen_platform.h
@@ -0,0 +1,8 @@
+#ifndef XEN_PLATFORM_H
+#define XEN_PLATFORM_H
+
+#include "hw/pci.h"
+
+void pci_xen_platform_init(PCIBus *bus);
+
+#endif
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 07/15] xen: handle xenstore events
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (5 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore stefano.stabellini
` (7 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Add an handler to process xenstore events.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
target-xen/xenstore.c | 30 +++++++++++++++++++++++++++++-
1 files changed, 29 insertions(+), 1 deletions(-)
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index bd74787..331b25f 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -1,13 +1,41 @@
#include "hw/xen_backend.h"
#include "xenstore.h"
+static void xenstore_process_event(void *opaque)
+{
+ char **vec;
+ unsigned int num;
+
+ vec = xs_read_watch(xenstore, &num);
+ if (!vec)
+ return;
+
+ free(vec);
+}
+
int xen_dm_init(void)
{
+ xenstore = xs_daemon_open();
+ if (!xenstore) {
+ xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+ return -1;
+ }
+
+ if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_process_event, NULL, NULL) < 0)
+ goto err;
+
xen_xc = xc_interface_open(NULL, NULL, 0);
if (xen_xc == NULL) {
xen_be_printf(NULL, 0, "can't open xen interface\n");
- return -1;
+ goto err;
}
return 0;
+
+err:
+ qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+ xs_daemon_close(xenstore);
+ xenstore = NULL;
+
+ return -1;
}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (6 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 07/15] xen: handle xenstore events stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings stefano.stabellini
` (6 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Introduce functions to read and write the state of the VM in xenstore.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
hw/xen_machine_fv.c | 9 ++++
target-xen/helper.c | 7 +++
target-xen/qemu-xen.h | 3 +
target-xen/xenstore.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++
target-xen/xenstore.h | 6 ++
5 files changed, 152 insertions(+), 0 deletions(-)
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index 12a7723..f0c3c03 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -36,10 +36,17 @@
#include "xen_backend.h"
#include "xenstore.h"
#include "xen_platform.h"
+#include "qemu-xen.h"
#include "xen/hvm/hvm_info_table.h"
#define MAX_IDE_BUS 2
+static void xen_vm_change_state_handler(void *opaque, int running, int reason)
+{
+ if (running)
+ xen_main_loop_prepare();
+}
+
static void xen_init_fv(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename,
@@ -149,6 +156,8 @@ static void xen_init_fv(ram_addr_t ram_size,
}
pc_pci_device_init(pci_bus);
+
+ qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL);
}
static QEMUMachine xenfv_machine = {
diff --git a/target-xen/helper.c b/target-xen/helper.c
index f8512c8..b6b722b 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -19,6 +19,8 @@
*/
#include "cpu.h"
+#include "qemu-xen.h"
+#include "xenstore.h"
CPUXenState *cpu_xen_init(const char *cpu_model)
{
@@ -61,3 +63,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
+
+void xen_main_loop_prepare(void)
+{
+ xenstore_record_dm_state("running");
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index d1910d6..091ae07 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -27,4 +27,7 @@ int cpu_register_io_memory_fixed(int io_index,
CPUWriteMemoryFunc * const *mem_write,
void *opaque);
+/* target-xen/helper.c */
+void xen_main_loop_prepare(void);
+
#endif /*QEMU_XEN_H*/
diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c
index 331b25f..6eb6a30 100644
--- a/target-xen/xenstore.c
+++ b/target-xen/xenstore.c
@@ -13,6 +13,60 @@ static void xenstore_process_event(void *opaque)
free(vec);
}
+static const char *xenstore_get_guest_uuid(void)
+{
+ static char *already_computed = NULL;
+
+ char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL;
+ unsigned int len;
+
+ if (already_computed)
+ return already_computed;
+
+ if (xen_xc == NULL)
+ return NULL;
+
+ domain_path = xs_get_domain_path(xenstore, xen_domid);
+ if (domain_path == NULL) {
+ fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid);
+ goto out;
+ }
+
+ if (asprintf(&vm_path, "%s/vm", domain_path) == -1) {
+ fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+ goto out;
+ }
+ vm_value = xs_read(xenstore, XBT_NULL, vm_path, &len);
+ if (vm_value == NULL) {
+ fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path);
+ goto out;
+ }
+
+ if (strtok(vm_value, "/") == NULL) {
+ fprintf(stderr, "failed to parse guest uuid\n");
+ goto out;
+ }
+ p = strtok(NULL, "/");
+ if (p == NULL) {
+ fprintf(stderr, "failed to parse guest uuid\n");
+ goto out;
+ }
+
+ if (asprintf(&already_computed, "%s", p) == -1) {
+ fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n");
+ goto out;
+ }
+
+ fprintf(stderr, "Guest uuid = %s\n", already_computed);
+
+out:
+ free(domain_path);
+ free(vm_path);
+ free(vm_value);
+
+ return already_computed;
+}
+
int xen_dm_init(void)
{
xenstore = xs_daemon_open();
@@ -39,3 +93,76 @@ err:
return -1;
}
+
+static char *xenstore_vm_key_path(int domid, const char *key) {
+ const char *uuid;
+ char *buf = NULL;
+
+ if (xenstore == NULL)
+ return NULL;
+
+ uuid = xenstore_get_guest_uuid();
+ if (!uuid)
+ return NULL;
+
+ if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
+ return NULL;
+
+ return buf;
+}
+
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len)
+{
+ char *path = NULL, *value = NULL;
+
+ path = xenstore_vm_key_path(domid, key);
+ if (!path)
+ return NULL;
+
+ value = xs_read(xenstore, XBT_NULL, path, len);
+ if (value == NULL) {
+ fprintf(stderr, "xs_read(%s): read error\n", path);
+ }
+
+ free(path);
+ return value;
+}
+
+int xenstore_vm_write(int domid, const char *key, const char *value)
+{
+ char *path = NULL;
+ int rc = -1;
+
+ path = xenstore_vm_key_path(domid, key);
+ if (!path)
+ return 0;
+
+ rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value));
+ if (rc == 0) {
+ fprintf(stderr, "xs_write(%s, %s): write error\n", path, key);
+ }
+
+ free(path);
+ return rc;
+}
+
+void xenstore_record_dm(const char *subpath, const char *state)
+{
+ char *path = NULL;
+
+ if (asprintf(&path,
+ "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) {
+ fprintf(stderr, "out of memory recording dm\n");
+ goto out;
+ }
+ if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state)))
+ fprintf(stderr, "error recording dm\n");
+
+out:
+ free(path);
+}
+
+void xenstore_record_dm_state(const char *state)
+{
+ xenstore_record_dm("state", state);
+}
diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h
index 90baf79..c8144ea 100644
--- a/target-xen/xenstore.h
+++ b/target-xen/xenstore.h
@@ -3,4 +3,10 @@
int xen_dm_init(void);
+char *xenstore_vm_read(int domid, const char *key, unsigned int *len);
+int xenstore_vm_write(int domid, const char *key, const char *value);
+
+void xenstore_record_dm(const char *subpath, const char *state);
+void xenstore_record_dm_state(const char *state);
+
#endif /* !XENSTORE_H_ */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (7 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache stefano.stabellini
` (5 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Open and bind event channels; map ioreq and buffered ioreq rings.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
hw/xen_machine_fv.c | 21 +++
target-xen/cpu.h | 6 +
target-xen/helper.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++++
target-xen/qemu-xen.h | 2 +
4 files changed, 368 insertions(+), 0 deletions(-)
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index f0c3c03..bcf1101 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -22,6 +22,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "config.h"
+
+#include <sys/mman.h>
#include "hw.h"
#include "pc.h"
@@ -71,12 +74,30 @@ static void xen_init_fv(ram_addr_t ram_size,
CPUState *env;
+ unsigned long ioreq_pfn;
+
/* Initialize backend core & drivers */
if (xen_dm_init() != 0) {
fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
exit(1);
}
+ xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
+ fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn);
+ shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+ PROT_READ|PROT_WRITE, ioreq_pfn);
+ if (shared_page == NULL) {
+ hw_error("map shared IO page returned error %d handle=%p", errno, xen_xc);
+ }
+
+ xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn);
+ fprintf(stderr, "buffered io page at pfn %lx\n", ioreq_pfn);
+ buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
+ PROT_READ|PROT_WRITE, ioreq_pfn);
+ if (buffered_io_page == NULL) {
+ hw_error("map buffered IO page returned error %d", errno);
+ }
+
/* Initialize a dummy CPU */
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
diff --git a/target-xen/cpu.h b/target-xen/cpu.h
index 0e08ab3..26896e1 100644
--- a/target-xen/cpu.h
+++ b/target-xen/cpu.h
@@ -68,6 +68,7 @@ typedef struct CPUXenState {
CPUXenState *cpu_xen_init(const char *cpu_model);
int cpu_xen_exec(CPUXenState *s);
+void cpu_xen_close(CPUXenState *s);
int cpu_get_pic_interrupt(CPUXenState *s);
void cpu_set_ferr(CPUX86State *s);
@@ -113,4 +114,9 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
{
}
+#include <xen/hvm/ioreq.h>
+
+extern shared_iopage_t *shared_page;
+extern buffered_iopage_t *buffered_io_page;
+
#endif /* CPU_XEN_H */
diff --git a/target-xen/helper.c b/target-xen/helper.c
index b6b722b..c4339ce 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -18,23 +18,73 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "config.h"
+
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xen/hvm/ioreq.h>
+
#include "cpu.h"
#include "qemu-xen.h"
#include "xenstore.h"
+#include "hw/xen_backend.h"
+
+long time_offset = 0;
+
+shared_iopage_t *shared_page = NULL;
+
+#define BUFFER_IO_MAX_DELAY 100
+buffered_iopage_t *buffered_io_page = NULL;
+QEMUTimer *buffered_io_timer;
+
+/* the evtchn fd for polling */
+int xce_handle = -1;
+
+/* which vcpu we are serving */
+int send_vcpu = 0;
+
+/* the evtchn port for polling the notification, */
+evtchn_port_t *ioreq_local_port;
CPUXenState *cpu_xen_init(const char *cpu_model)
{
CPUXenState *env = NULL;
static int inited;
+ int i, rc;
env = qemu_mallocz(sizeof(CPUXenState));
cpu_exec_init(env);
+ /* There is no shared_page for PV, we're done now */
+ if (shared_page == NULL)
+ return env;
+
+ ioreq_local_port =
+ (evtchn_port_t *)qemu_mallocz(smp_cpus * sizeof(evtchn_port_t));
+
/* init various static tables */
if (!inited) {
inited = 1;
cpu_single_env = env;
+
+ xce_handle = xc_evtchn_open();
+ if (xce_handle == -1) {
+ perror("open");
+ return NULL;
+ }
+
+ /* FIXME: how about if we overflow the page here? */
+ for (i = 0; i < smp_cpus; i++) {
+ rc = xc_evtchn_bind_interdomain(
+ xce_handle, xen_domid, shared_page->vcpu_ioreq[i].vp_eport);
+ if (rc == -1) {
+ fprintf(stderr, "bind interdomain ioctl error %d\n", errno);
+ return NULL;
+ }
+ ioreq_local_port[i] = rc;
+ }
}
return env;
@@ -64,7 +114,296 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
return addr;
}
+/* get the ioreq packets from share mem */
+static ioreq_t *cpu_get_ioreq_from_shared_memory(int vcpu)
+{
+ ioreq_t *req = &shared_page->vcpu_ioreq[vcpu];
+
+ if (req->state != STATE_IOREQ_READY) {
+ fprintf(stderr, "I/O request not ready: "
+ "%x, ptr: %x, port: %"PRIx64", "
+ "data: %"PRIx64", count: %u, size: %u\n",
+ req->state, req->data_is_ptr, req->addr,
+ req->data, req->count, req->size);
+ return NULL;
+ }
+
+ xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
+
+ req->state = STATE_IOREQ_INPROCESS;
+ return req;
+}
+
+/* use poll to get the port notification */
+/* ioreq_vec--out,the */
+/* retval--the number of ioreq packet */
+static ioreq_t *cpu_get_ioreq(void)
+{
+ int i;
+ evtchn_port_t port;
+
+ port = xc_evtchn_pending(xce_handle);
+ if (port != -1) {
+ for ( i = 0; i < smp_cpus; i++ )
+ if ( ioreq_local_port[i] == port )
+ break;
+
+ if ( i == smp_cpus ) {
+ fprintf(stderr, "Fatal error while trying to get io event!\n");
+ exit(1);
+ }
+
+ /* unmask the wanted port again */
+ xc_evtchn_unmask(xce_handle, port);
+
+ /* get the io packet from shared memory */
+ send_vcpu = i;
+ return cpu_get_ioreq_from_shared_memory(i);
+ }
+
+ /* read error or read nothing */
+ return NULL;
+}
+
+static uint32_t do_inp(CPUState *env, pio_addr_t addr, unsigned long size)
+{
+ switch(size) {
+ case 1:
+ return cpu_inb(addr);
+ case 2:
+ return cpu_inw(addr);
+ case 4:
+ return cpu_inl(addr);
+ default:
+ hw_error("inp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+ }
+}
+
+static void do_outp(CPUState *env, pio_addr_t addr,
+ unsigned long size, uint32_t val)
+{
+ switch(size) {
+ case 1:
+ return cpu_outb(addr, val);
+ case 2:
+ return cpu_outw(addr, val);
+ case 4:
+ return cpu_outl(addr, val);
+ default:
+ hw_error("outp: bad size: %04"FMT_pioaddr" %lx", addr, size);
+ }
+}
+
+static void cpu_ioreq_pio(CPUState *env, ioreq_t *req)
+{
+ int i, sign;
+
+ sign = req->df ? -1 : 1;
+
+ if (req->dir == IOREQ_READ) {
+ if (!req->data_is_ptr) {
+ req->data = do_inp(env, req->addr, req->size);
+ } else {
+ uint32_t tmp;
+
+ for (i = 0; i < req->count; i++) {
+ tmp = do_inp(env, req->addr, req->size);
+ cpu_physical_memory_write(req->data + (sign * i * req->size),
+ (uint8_t*) &tmp, req->size);
+ }
+ }
+ } else if (req->dir == IOREQ_WRITE) {
+ if (!req->data_is_ptr) {
+ do_outp(env, req->addr, req->size, req->data);
+ } else {
+ for (i = 0; i < req->count; i++) {
+ uint32_t tmp = 0;
+
+ cpu_physical_memory_read(req->data + (sign * i * req->size),
+ (uint8_t*) &tmp, req->size);
+ do_outp(env, req->addr, req->size, tmp);
+ }
+ }
+ }
+}
+
+static void cpu_ioreq_move(CPUState *env, ioreq_t *req)
+{
+ int i, sign;
+
+ sign = req->df ? -1 : 1;
+
+ if (!req->data_is_ptr) {
+ if (req->dir == IOREQ_READ) {
+ for (i = 0; i < req->count; i++) {
+ cpu_physical_memory_read(req->addr + (sign * i * req->size),
+ (uint8_t*) &req->data, req->size);
+ }
+ } else if (req->dir == IOREQ_WRITE) {
+ for (i = 0; i < req->count; i++) {
+ cpu_physical_memory_write(req->addr + (sign * i * req->size),
+ (uint8_t*) &req->data, req->size);
+ }
+ }
+ } else {
+ target_ulong tmp;
+
+ if (req->dir == IOREQ_READ) {
+ for (i = 0; i < req->count; i++) {
+ cpu_physical_memory_read(req->addr + (sign * i * req->size),
+ (uint8_t*) &tmp, req->size);
+ cpu_physical_memory_write(req->data + (sign * i * req->size),
+ (uint8_t*) &tmp, req->size);
+ }
+ } else if (req->dir == IOREQ_WRITE) {
+ for (i = 0; i < req->count; i++) {
+ cpu_physical_memory_read(req->data + (sign * i * req->size),
+ (uint8_t*) &tmp, req->size);
+ cpu_physical_memory_write(req->addr + (sign * i * req->size),
+ (uint8_t*) &tmp, req->size);
+ }
+ }
+ }
+}
+
+static void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req)
+{
+ char b[64];
+
+ time_offset += (unsigned long)req->data;
+
+ fprintf(stderr, "Time offset set %ld, added offset %"PRId64"\n",
+ time_offset, req->data);
+ snprintf(b, 64, "%ld", time_offset);
+ xenstore_vm_write(xen_domid, "rtc/timeoffset", b);
+}
+
+static void handle_ioreq(CPUState *env, ioreq_t *req)
+{
+ if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) &&
+ (req->size < sizeof(target_ulong)))
+ req->data &= ((target_ulong)1 << (8 * req->size)) - 1;
+
+ switch (req->type) {
+ case IOREQ_TYPE_PIO:
+ cpu_ioreq_pio(env, req);
+ break;
+ case IOREQ_TYPE_COPY:
+ cpu_ioreq_move(env, req);
+ break;
+ case IOREQ_TYPE_TIMEOFFSET:
+ cpu_ioreq_timeoffset(env, req);
+ break;
+ case IOREQ_TYPE_INVALIDATE:
+ qemu_invalidate_map_cache();
+ break;
+ default:
+ hw_error("Invalid ioreq type 0x%x\n", req->type);
+ }
+}
+
+static void handle_buffered_iopage(CPUState *env)
+{
+ buf_ioreq_t *buf_req = NULL;
+ ioreq_t req;
+ int qw;
+
+ if (!buffered_io_page)
+ return;
+
+ while (buffered_io_page->read_pointer !=
+ buffered_io_page->write_pointer) {
+ buf_req = &buffered_io_page->buf_ioreq[
+ buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM];
+ req.size = 1UL << buf_req->size;
+ req.count = 1;
+ req.addr = buf_req->addr;
+ req.data = buf_req->data;
+ req.state = STATE_IOREQ_READY;
+ req.dir = buf_req->dir;
+ req.df = 1;
+ req.type = buf_req->type;
+ req.data_is_ptr = 0;
+ qw = (req.size == 8);
+ if (qw) {
+ buf_req = &buffered_io_page->buf_ioreq[
+ (buffered_io_page->read_pointer+1) % IOREQ_BUFFER_SLOT_NUM];
+ req.data |= ((uint64_t)buf_req->data) << 32;
+ }
+
+ handle_ioreq(env, &req);
+
+ xen_mb();
+ buffered_io_page->read_pointer += qw ? 2 : 1;
+ }
+}
+
+static void handle_buffered_io(void *opaque)
+{
+ CPUState *env = opaque;
+
+ handle_buffered_iopage(env);
+ qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY +
+ qemu_get_clock(rt_clock));
+}
+
+static void cpu_handle_ioreq(void *opaque)
+{
+ CPUState *env = opaque;
+ ioreq_t *req = cpu_get_ioreq();
+
+ handle_buffered_iopage(env);
+ if (req) {
+ handle_ioreq(env, req);
+
+ if (req->state != STATE_IOREQ_INPROCESS) {
+ fprintf(stderr, "Badness in I/O request ... not in service?!: "
+ "%x, ptr: %x, port: %"PRIx64", "
+ "data: %"PRIx64", count: %u, size: %u\n",
+ req->state, req->data_is_ptr, req->addr,
+ req->data, req->count, req->size);
+ destroy_hvm_domain();
+ return;
+ }
+
+ xen_wmb(); /* Update ioreq contents /then/ update state. */
+
+ req->state = STATE_IORESP_READY;
+ xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
+ }
+}
+
void xen_main_loop_prepare(void)
{
+ CPUState *env = cpu_single_env;
+
+ int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle);
+
+ buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io,
+ cpu_single_env);
+ qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock));
+
+ if (evtchn_fd != -1)
+ qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env);
+
xenstore_record_dm_state("running");
}
+
+void destroy_hvm_domain(void)
+{
+ xc_interface *xc_handle;
+ int sts;
+
+ xc_handle = xc_interface_open(NULL, NULL, 0);
+ if (!xc_handle)
+ fprintf(stderr, "Cannot acquire xenctrl handle\n");
+ else {
+ sts = xc_domain_shutdown(xc_handle, xen_domid, SHUTDOWN_poweroff);
+ if (sts != 0)
+ fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, "
+ "sts %d, errno %d\n", sts, errno);
+ else
+ fprintf(stderr, "Issued domain %d poweroff\n", xen_domid);
+ xc_interface_close(xc_handle);
+ }
+}
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index 091ae07..79a4638 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -22,12 +22,14 @@ void qemu_invalidate_map_cache(void);
/* target-xen/exec-dm.c */
+void destroy_hvm_domain(void);
int cpu_register_io_memory_fixed(int io_index,
CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write,
void *opaque);
/* target-xen/helper.c */
+extern int xce_handle;
void xen_main_loop_prepare(void);
#endif /*QEMU_XEN_H*/
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (8 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 11/15] xen: Introduce --enable-xen command options stefano.stabellini
` (4 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Introduce a mapcache to handle the 64bit address space of the guest
from a 32bit userland process (Qemu).
The mapcache maps chucks of guest memory on demand, unmaps them when
they are not needed anymore.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
hw/xen_machine_fv.c | 7 ++
target-xen/qemu-xen.h | 15 +++
target-xen/xen_mapcache.c | 247 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 269 insertions(+), 0 deletions(-)
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index bcf1101..cb40d22 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -82,6 +82,13 @@ static void xen_init_fv(ram_addr_t ram_size,
exit(1);
}
+#if defined(__i386__) || defined(__x86_64__)
+ if (qemu_map_cache_init()) {
+ fprintf(stderr, "qemu_map_cache_init returned: error %d\n", errno);
+ exit(-1);
+ }
+#endif
+
xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn);
fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn);
shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE,
diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h
index 79a4638..e4a7030 100644
--- a/target-xen/qemu-xen.h
+++ b/target-xen/qemu-xen.h
@@ -13,6 +13,21 @@
/* xen_mapcache.c */
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(QEMU_TOOL)
+#define MAPCACHE
+
+#if defined(__i386__)
+#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */
+#define MCACHE_BUCKET_SHIFT 16
+#elif defined(__x86_64__)
+#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */
+#define MCACHE_BUCKET_SHIFT 20
+#endif
+
+#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
+#endif
+
+int qemu_map_cache_init(void);
uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock);
void qemu_invalidate_entry(uint8_t *buffer);
void qemu_invalidate_map_cache(void);
diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c
index 39daae2..5baaeb9 100644
--- a/target-xen/xen_mapcache.c
+++ b/target-xen/xen_mapcache.c
@@ -1,5 +1,251 @@
+#include "config.h"
+
+#include "hw/xen_backend.h"
#include "qemu-xen.h"
+#include <xen/hvm/params.h>
+#include <sys/mman.h>
+
+#define DPRINTF(fmt, ...) do { \
+ fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
+} while (0)
+
+#if defined(MAPCACHE)
+
+#define BITS_PER_LONG (sizeof(long)*8)
+#define BITS_TO_LONGS(bits) \
+ (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+ unsigned long name[BITS_TO_LONGS(bits)]
+#define test_bit(bit,map) \
+ (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG))))
+
+typedef struct MapCacheEntry {
+ unsigned long paddr_index;
+ uint8_t *vaddr_base;
+ DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT);
+ uint8_t lock;
+ struct MapCacheEntry *next;
+} MapCacheEntry;
+
+typedef struct MapCacheRev {
+ uint8_t *vaddr_req;
+ unsigned long paddr_index;
+ QTAILQ_ENTRY(MapCacheRev) next;
+} MapCacheRev;
+
+typedef struct MapCache {
+ MapCacheEntry *entry;
+ unsigned long nr_buckets;
+ QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
+
+ /* For most cases (>99.9%), the page address is the same. */
+ unsigned long last_address_index;
+ uint8_t *last_address_vaddr;
+} MapCache;
+
+static MapCache *mapcache;
+
+
+int qemu_map_cache_init(void)
+{
+ unsigned long size;
+
+ mapcache = qemu_mallocz(sizeof (MapCache));
+
+ QTAILQ_INIT(&mapcache->locked_entries);
+ mapcache->last_address_index = ~0UL;
+
+ mapcache->nr_buckets = (((MAX_MCACHE_SIZE >> XC_PAGE_SHIFT) +
+ (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >>
+ (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT));
+
+ /*
+ * Use mmap() directly: lets us allocate a big hash table with no up-front
+ * cost in storage space. The OS will allocate memory only for the buckets
+ * that we actually use. All others will contain all zeroes.
+ */
+ size = mapcache->nr_buckets * sizeof(MapCacheEntry);
+ size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
+ DPRINTF("qemu_map_cache_init, nr_buckets = %lx size %lu\n", mapcache->nr_buckets, size);
+ mapcache->entry = mmap(NULL, size, PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_ANON, -1, 0);
+ if (mapcache->entry == MAP_FAILED) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void qemu_remap_bucket(MapCacheEntry *entry,
+ unsigned long address_index)
+{
+ uint8_t *vaddr_base;
+ xen_pfn_t pfns[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT];
+ int err[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT];
+ unsigned int i, j;
+
+ if (entry->vaddr_base != NULL) {
+ errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+ if (errno) {
+ fprintf(stderr, "unmap fails %d\n", errno);
+ exit(-1);
+ }
+ }
+
+ for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i++) {
+ pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i;
+ }
+
+ vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE,
+ pfns, err,
+ MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT);
+ if (vaddr_base == NULL) {
+ fprintf(stderr, "xc_map_foreign_bulk error %d\n", errno);
+ exit(-1);
+ }
+
+ entry->vaddr_base = vaddr_base;
+ entry->paddr_index = address_index;
+
+ for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i += BITS_PER_LONG) {
+ unsigned long word = 0;
+ j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT)) ?
+ (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG;
+ while (j > 0) {
+ word = (word << 1) | !err[i + --j];
+ }
+ entry->valid_mapping[i / BITS_PER_LONG] = word;
+ }
+}
+
+uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
+{
+ MapCacheEntry *entry, *pentry = NULL;
+ unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT;
+ unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1);
+
+ if (address_index == mapcache->last_address_index && !lock)
+ return mapcache->last_address_vaddr + address_offset;
+
+ entry = &mapcache->entry[address_index % mapcache->nr_buckets];
+
+ while (entry && entry->lock && entry->paddr_index != address_index && entry->vaddr_base) {
+ pentry = entry;
+ entry = entry->next;
+ }
+ if (!entry) {
+ entry = qemu_mallocz(sizeof(MapCacheEntry));
+ pentry->next = entry;
+ qemu_remap_bucket(entry, address_index);
+ } else if (!entry->lock) {
+ if (!entry->vaddr_base || entry->paddr_index != address_index || !test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping))
+ qemu_remap_bucket(entry, address_index);
+ }
+
+ if (!test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) {
+ mapcache->last_address_index = ~0UL;
+ return NULL;
+ }
+
+ mapcache->last_address_index = address_index;
+ mapcache->last_address_vaddr = entry->vaddr_base;
+ if (lock) {
+ MapCacheRev *reventry = qemu_mallocz(sizeof(MapCacheRev));
+ entry->lock++;
+ reventry->vaddr_req = mapcache->last_address_vaddr + address_offset;
+ reventry->paddr_index = mapcache->last_address_index;
+ QTAILQ_INSERT_TAIL(&mapcache->locked_entries, reventry, next);
+ }
+
+ return mapcache->last_address_vaddr + address_offset;
+}
+
+void qemu_invalidate_entry(uint8_t *buffer)
+{
+ MapCacheEntry *entry = NULL, *pentry = NULL;
+ MapCacheRev *reventry;
+ unsigned long paddr_index;
+ int found = 0;
+
+ if (mapcache->last_address_vaddr == buffer)
+ mapcache->last_address_index = ~0UL;
+
+ QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+ if (reventry->vaddr_req == buffer) {
+ paddr_index = reventry->paddr_index;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ DPRINTF("qemu_invalidate_entry, could not find %p\n", buffer);
+ QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+ DPRINTF(" %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+ }
+ return;
+ }
+ QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
+ qemu_free(reventry);
+
+ entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
+ while (entry && entry->paddr_index != paddr_index) {
+ pentry = entry;
+ entry = entry->next;
+ }
+ if (!entry) {
+ DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer);
+ return;
+ }
+ entry->lock--;
+ if (entry->lock > 0 || pentry == NULL)
+ return;
+
+ pentry->next = entry->next;
+ errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+ if (errno) {
+ fprintf(stderr, "unmap fails %d\n", errno);
+ exit(-1);
+ }
+ qemu_free(entry);
+}
+
+void qemu_invalidate_map_cache(void)
+{
+ unsigned long i;
+ MapCacheRev *reventry;
+
+ qemu_aio_flush();
+
+ QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
+ DPRINTF("There should be no locked mappings at this time, but %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req);
+ }
+
+ mapcache_lock();
+
+ for (i = 0; i < mapcache->nr_buckets; i++) {
+ MapCacheEntry *entry = &mapcache->entry[i];
+
+ if (entry->vaddr_base == NULL)
+ continue;
+
+ errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE);
+ if (errno) {
+ fprintf(stderr, "unmap fails %d\n", errno);
+ exit(-1);
+ }
+
+ entry->paddr_index = 0;
+ entry->vaddr_base = NULL;
+ }
+
+ mapcache->last_address_index = ~0UL;
+ mapcache->last_address_vaddr = NULL;
+
+ mapcache_unlock();
+}
+#else
uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock)
{
return phys_ram_addr(phys_addr);
@@ -12,3 +258,4 @@ void qemu_invalidate_map_cache(void)
void qemu_invalidate_entry(uint8_t *buffer)
{
}
+#endif /* !MAPCACHE */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 11/15] xen: Introduce --enable-xen command options.
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (9 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 10/15] xen: Introduce the Xen mapcache stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq stefano.stabellini
` (3 subsequent siblings)
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
This options will check if the target is build with Xen support.
---
Makefile.target | 3 +++
hw/xen.h | 8 ++++++++
qemu-options.hx | 9 +++++++++
vl.c | 11 +++++++++++
4 files changed, 31 insertions(+), 0 deletions(-)
create mode 100644 xen-all.c
create mode 100644 xen-stub.c
diff --git a/Makefile.target b/Makefile.target
index 1984cdd..840b87b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -2,6 +2,7 @@
GENERATED_HEADERS = config-target.h
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
+CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
include ../config-host.mak
include config-devices.mak
@@ -182,6 +183,8 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
# xen backend driver support
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
+obj-$(CONFIG_XEN) += xen-all.o
+obj-$(CONFIG_NO_XEN) += xen-stub.o
# USB layer
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
diff --git a/hw/xen.h b/hw/xen.h
index 780dcf7..f1d01d3 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -18,4 +18,12 @@ enum xen_mode {
extern uint32_t xen_domid;
extern enum xen_mode xen_mode;
+extern int xen_allowed;
+
+#if defined CONFIG_XEN
+#define xen_enabled() (xen_allowed)
+#else
+#define xen_enabled() (0)
+#endif
+
#endif /* QEMU_HW_XEN_H */
diff --git a/qemu-options.hx b/qemu-options.hx
index db86feb..0abdfc4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1908,6 +1908,15 @@ Enable KVM full virtualization support. This option is only available
if KVM support is enabled when compiling.
ETEXI
+DEF("enable-xen", 0, QEMU_OPTION_enable_xen, \
+ "-enable-xen enable Xen full virtualization support\n", QEMU_ARCH_ALL)
+STEXI
+@item -enable-xen
+@findex -enable-xen
+Enable Xen full virtualization support. This option is only available
+if Xen support is enabled when compiling.
+ETEXI
+
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
"-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL)
DEF("xen-create", 0, QEMU_OPTION_xen_create,
diff --git a/vl.c b/vl.c
index b3e3676..dd88806 100644
--- a/vl.c
+++ b/vl.c
@@ -239,6 +239,7 @@ static NotifierList exit_notifiers =
NOTIFIER_LIST_INITIALIZER(exit_notifiers);
int kvm_allowed = 0;
+int xen_allowed = 0;
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_EMULATE;
@@ -2436,6 +2437,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_enable_kvm:
kvm_allowed = 1;
break;
+ case QEMU_OPTION_enable_xen:
+ xen_allowed = 1;
+ break;
case QEMU_OPTION_usb:
usb_enabled = 1;
break;
@@ -2730,6 +2734,13 @@ int main(int argc, char **argv, char **envp)
}
}
+ if (xen_allowed) {
+ if (!xen_available()) {
+ printf("Xen not supported for this target\n");
+ exit(1);
+ }
+ }
+
if (qemu_init_main_loop()) {
fprintf(stderr, "qemu_init_main_loop failed\n");
exit(1);
diff --git a/xen-all.c b/xen-all.c
new file mode 100644
index 0000000..e69de29
diff --git a/xen-stub.c b/xen-stub.c
new file mode 100644
index 0000000..e69de29
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq.
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (10 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 11/15] xen: Introduce --enable-xen command options stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-24 11:20 ` Isaku Yamahata
2010-08-23 9:50 ` [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested stefano.stabellini
` (2 subsequent siblings)
14 siblings, 1 reply; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
This patch introduces Xen specific call in piix_pci.
The specific part for Xen is in write_config, set_irq and get_pirq.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
hw/piix_pci.c | 19 ++++++++++++++++---
hw/xen.h | 3 +++
xen-all.c | 25 +++++++++++++++++++++++++
xen-stub.c | 9 +++++++++
4 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0f..994057f 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -28,6 +28,7 @@
#include "pci_host.h"
#include "isa.h"
#include "sysbus.h"
+#include "xen.h"
/*
* I440FX chipset data sheet.
@@ -61,9 +62,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level);
mapping. */
static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
{
- int slot_addend;
- slot_addend = (pci_dev->devfn >> 3) - 1;
- return (irq_num + slot_addend) & 3;
+ if (!xen_enabled()) {
+ int slot_addend;
+ slot_addend = (pci_dev->devfn >> 3) - 1;
+ return (irq_num + slot_addend) & 3;
+ } else {
+ return irq_num + ((pci_dev->devfn >> 3) << 2);
+ }
}
static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
@@ -142,6 +147,9 @@ static void i440fx_write_config(PCIDevice *dev,
{
PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
+ if (xen_enabled())
+ xen_piix_pci_write_config_client(address, val, len);
+
/* XXX: implement SMRAM.D_LOCK */
pci_default_write_config(dev, address, val, len);
if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
@@ -255,6 +263,11 @@ static void piix3_set_irq(void *opaque, int irq_num, int level)
int i, pic_irq, pic_level;
PIIX3State *piix3 = opaque;
+ if (xen_enabled()) {
+ xen_piix3_set_irq(irq_num, level);
+ return;
+ }
+
piix3->pci_irq_levels[irq_num] = level;
/* now we change the pic irq level according to the piix irq mappings */
diff --git a/hw/xen.h b/hw/xen.h
index f1d01d3..77012c2 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -26,4 +26,7 @@ extern int xen_allowed;
#define xen_enabled() (0)
#endif
+void xen_piix3_set_irq(int irq_num, int level);
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+
#endif /* QEMU_HW_XEN_H */
diff --git a/xen-all.c b/xen-all.c
index e69de29..2d789ad 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -0,0 +1,25 @@
+#include "config.h"
+
+#include "hw/xen.h"
+#include "hw/xen_backend.h"
+
+void xen_piix3_set_irq(int irq_num, int level)
+{
+ xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
+ irq_num & 3, level);
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+ int i;
+
+ /* Scan for updates to PCI link routes (0x60-0x63). */
+ for (i = 0; i < len; i++) {
+ uint8_t v = (val >> (8*i)) & 0xff;
+ if (v & 0x80)
+ v = 0;
+ v &= 0xf;
+ if (((address+i) >= 0x60) && ((address+i) <= 0x63))
+ xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
+ }
+}
diff --git a/xen-stub.c b/xen-stub.c
index e69de29..38c64cf 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -0,0 +1,9 @@
+#include "hw/xen.h"
+
+void xen_piix3_set_irq(int irq_num, int level)
+{
+}
+
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
+{
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq.
2010-08-23 9:50 ` [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq stefano.stabellini
@ 2010-08-24 11:20 ` Isaku Yamahata
0 siblings, 0 replies; 25+ messages in thread
From: Isaku Yamahata @ 2010-08-24 11:20 UTC (permalink / raw)
To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel
On Mon, Aug 23, 2010 at 10:50:49AM +0100, stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> This patch introduces Xen specific call in piix_pci.
>
> The specific part for Xen is in write_config, set_irq and get_pirq.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
> hw/piix_pci.c | 19 ++++++++++++++++---
> hw/xen.h | 3 +++
> xen-all.c | 25 +++++++++++++++++++++++++
> xen-stub.c | 9 +++++++++
> 4 files changed, 53 insertions(+), 3 deletions(-)
>
> diff --git a/hw/piix_pci.c b/hw/piix_pci.c
> index f152a0f..994057f 100644
> --- a/hw/piix_pci.c
> +++ b/hw/piix_pci.c
> @@ -28,6 +28,7 @@
> #include "pci_host.h"
> #include "isa.h"
> #include "sysbus.h"
> +#include "xen.h"
>
> /*
> * I440FX chipset data sheet.
> @@ -61,9 +62,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level);
> mapping. */
> static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
> {
> - int slot_addend;
> - slot_addend = (pci_dev->devfn >> 3) - 1;
> - return (irq_num + slot_addend) & 3;
> + if (!xen_enabled()) {
> + int slot_addend;
> + slot_addend = (pci_dev->devfn >> 3) - 1;
> + return (irq_num + slot_addend) & 3;
> + } else {
> + return irq_num + ((pci_dev->devfn >> 3) << 2);
> + }
> }
>
> static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
pci_slot_get_pirq() is passed to pci_bus_irqs() in i440fx_init().
It would be better to pass xen specific function to pci_bus_irqs() instead of
dynamic check.
> @@ -142,6 +147,9 @@ static void i440fx_write_config(PCIDevice *dev,
> {
> PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
>
> + if (xen_enabled())
> + xen_piix_pci_write_config_client(address, val, len);
> +
> /* XXX: implement SMRAM.D_LOCK */
> pci_default_write_config(dev, address, val, len);
> if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
Maybe do we want another PCIDeviceInfo whose difference is .write_config?
I'm not sure which is better, though.
> @@ -255,6 +263,11 @@ static void piix3_set_irq(void *opaque, int irq_num, int level)
> int i, pic_irq, pic_level;
> PIIX3State *piix3 = opaque;
>
> + if (xen_enabled()) {
> + xen_piix3_set_irq(irq_num, level);
> + return;
> + }
> +
> piix3->pci_irq_levels[irq_num] = level;
Ditto. Pass xen_piix3_set_irq() to pci_bus_irqs()?
thanks,
>
> /* now we change the pic irq level according to the piix irq mappings */
> diff --git a/hw/xen.h b/hw/xen.h
> index f1d01d3..77012c2 100644
> --- a/hw/xen.h
> +++ b/hw/xen.h
> @@ -26,4 +26,7 @@ extern int xen_allowed;
> #define xen_enabled() (0)
> #endif
>
> +void xen_piix3_set_irq(int irq_num, int level);
> +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
> +
> #endif /* QEMU_HW_XEN_H */
> diff --git a/xen-all.c b/xen-all.c
> index e69de29..2d789ad 100644
> --- a/xen-all.c
> +++ b/xen-all.c
> @@ -0,0 +1,25 @@
> +#include "config.h"
> +
> +#include "hw/xen.h"
> +#include "hw/xen_backend.h"
> +
> +void xen_piix3_set_irq(int irq_num, int level)
> +{
> + xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2,
> + irq_num & 3, level);
> +}
> +
> +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
> +{
> + int i;
> +
> + /* Scan for updates to PCI link routes (0x60-0x63). */
> + for (i = 0; i < len; i++) {
> + uint8_t v = (val >> (8*i)) & 0xff;
> + if (v & 0x80)
> + v = 0;
> + v &= 0xf;
> + if (((address+i) >= 0x60) && ((address+i) <= 0x63))
> + xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v);
> + }
> +}
> diff --git a/xen-stub.c b/xen-stub.c
> index e69de29..38c64cf 100644
> --- a/xen-stub.c
> +++ b/xen-stub.c
> @@ -0,0 +1,9 @@
> +#include "hw/xen.h"
> +
> +void xen_piix3_set_irq(int irq_num, int level)
> +{
> +}
> +
> +void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
> +{
> +}
> --
> 1.7.0.4
>
>
--
yamahata
^ permalink raw reply [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested.
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (11 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 12/15] piix_pci: Introduces Xen specific call for irq stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen stefano.stabellini
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Introduce two functions qemu_shutdown_requested_get and
qemu_reset_requested_get to get the value of shutdown/reset_requested
without reset it.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
sysemu.h | 2 ++
vl.c | 10 ++++++++++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/sysemu.h b/sysemu.h
index a1f6466..7facfae 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -51,6 +51,8 @@ void cpu_disable_ticks(void);
void qemu_system_reset_request(void);
void qemu_system_shutdown_request(void);
void qemu_system_powerdown_request(void);
+int qemu_shutdown_requested_get(void);
+int qemu_reset_requested_get(void);
int qemu_shutdown_requested(void);
int qemu_reset_requested(void);
int qemu_powerdown_requested(void);
diff --git a/vl.c b/vl.c
index dd88806..3316063 100644
--- a/vl.c
+++ b/vl.c
@@ -1130,6 +1130,16 @@ static int powerdown_requested;
int debug_requested;
int vmstop_requested;
+int qemu_shutdown_requested_get(void)
+{
+ return shutdown_requested;
+}
+
+int qemu_reset_requested_get(void)
+{
+ return reset_requested;
+}
+
int qemu_shutdown_requested(void)
{
int r = shutdown_requested;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (12 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 9:50 ` [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen stefano.stabellini
14 siblings, 0 replies; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Handle shutdown and reset requests in helper.c.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
target-xen/helper.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/target-xen/helper.c b/target-xen/helper.c
index c4339ce..d77d63e 100644
--- a/target-xen/helper.c
+++ b/target-xen/helper.c
@@ -368,6 +368,21 @@ static void cpu_handle_ioreq(void *opaque)
xen_wmb(); /* Update ioreq contents /then/ update state. */
+ /*
+ * We do this before we send the response so that the tools
+ * have the opportunity to pick up on the reset before the
+ * guest resumes and does a hlt with interrupts disabled which
+ * causes Xen to powerdown the domain.
+ */
+ if (vm_running) {
+ if (qemu_shutdown_requested_get()) {
+ destroy_hvm_domain();
+ }
+ if (qemu_reset_requested_get()) {
+ qemu_system_reset();
+ }
+ }
+
req->state = STATE_IORESP_READY;
xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
2010-08-23 9:49 [Qemu-devel] [PATCH 00/15] v2: RFC xen device model support Stefano Stabellini
` (13 preceding siblings ...)
2010-08-23 9:50 ` [Qemu-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested stefano.stabellini
@ 2010-08-23 9:50 ` stefano.stabellini
2010-08-23 11:15 ` [Qemu-devel] " Juan Quintela
14 siblings, 1 reply; 25+ messages in thread
From: stefano.stabellini @ 2010-08-23 9:50 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony.Perard, Anthony PERARD, xen-devel, stefano.stabellini
From: Anthony PERARD <anthony.perard@citrix.com>
Xen currently uses a different BIOS (hvmloader + rombios) therefore the
Qemu acpi_piix4 implementation wouldn't work correctly with Xen.
We plan on fixing this properly but at the moment we are just adding a
new Xen specific acpi_piix4 implementation.
This patch is optional; without it the VM boots but it cannot shutdown
properly or go to S3.
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Makefile.target | 1 +
hw/xen_acpi_piix4.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/xen_common.h | 3 +
hw/xen_machine_fv.c | 6 +-
4 files changed, 429 insertions(+), 5 deletions(-)
create mode 100644 hw/xen_acpi_piix4.c
diff --git a/Makefile.target b/Makefile.target
index 840b87b..e815937 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -328,6 +328,7 @@ obj-xen-y += piix_pci.o
obj-xen-y += mc146818rtc.o
obj-xen-y += xenstore.o
obj-xen-y += xen_platform.o
+obj-xen-y += xen_acpi_piix4.o
obj-xen-y += xen_mapcache.o
obj-xen-y += stub-functions.o
diff --git a/hw/xen_acpi_piix4.c b/hw/xen_acpi_piix4.c
new file mode 100644
index 0000000..3c65963
--- /dev/null
+++ b/hw/xen_acpi_piix4.c
@@ -0,0 +1,424 @@
+ /*
+ * PIIX4 ACPI controller emulation
+ *
+ * Winston liwen Wang, winston.l.wang@intel.com
+ * Copyright (c) 2006 , Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "sysemu.h"
+#include "acpi.h"
+
+#include "xen_backend.h"
+#include "xen_common.h"
+#include "qemu-log.h"
+
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+
+#define PIIX4ACPI_LOG_ERROR 0
+#define PIIX4ACPI_LOG_INFO 1
+#define PIIX4ACPI_LOG_DEBUG 2
+#define PIIX4ACPI_LOGLEVEL PIIX4ACPI_LOG_INFO
+#define PIIX4ACPI_LOG(level, fmt, ...) do { if (level <= PIIX4ACPI_LOGLEVEL) qemu_log(fmt, ## __VA_ARGS__); } while (0)
+
+/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */
+/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */
+#define SLP_TYP_S4 (6 << 10)
+#define SLP_TYP_S3 (5 << 10)
+#define SLP_TYP_S5 (7 << 10)
+
+#define ACPI_DBG_IO_ADDR 0xb044
+#define ACPI_PHP_IO_ADDR 0x10c0
+
+#define PHP_EVT_ADD 0x0
+#define PHP_EVT_REMOVE 0x3
+
+/* The bit in GPE0_STS/EN to notify the pci hotplug event */
+#define ACPI_PHP_GPE_BIT 3
+
+#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn >> 1)
+#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg << 1) | hilo)
+
+/* ioport to monitor cpu add/remove status */
+#define PROC_BASE 0xaf00
+
+typedef struct PCIAcpiState {
+ PCIDevice dev;
+ uint16_t pm1_control; /* pm1a_ECNT_BLK */
+ qemu_irq irq;
+ qemu_irq cmos_s3;
+} PCIAcpiState;
+
+typedef struct GPEState {
+ /* GPE0 block */
+ uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2];
+ uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2];
+
+ /* CPU bitmap */
+ uint8_t cpus_sts[32];
+
+ /* SCI IRQ level */
+ uint8_t sci_asserted;
+
+} GPEState;
+
+static GPEState gpe_state;
+
+static qemu_irq sci_irq;
+
+typedef struct AcpiDeviceState AcpiDeviceState;
+AcpiDeviceState *acpi_device_table;
+
+static const VMStateDescription vmstate_acpi = {
+ .name = "PIIX4 ACPI",
+ .version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(dev, PCIAcpiState),
+ VMSTATE_UINT16(pm1_control, PCIAcpiState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIAcpiState *s = opaque;
+ s->pm1_control = (s->pm1_control & 0xff00) | (val & 0xff);
+}
+
+static uint32_t acpiPm1Control_readb(void *opaque, uint32_t addr)
+{
+ PCIAcpiState *s = opaque;
+ /* Mask out the write-only bits */
+ return (uint8_t)(s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE));
+}
+
+static void acpi_shutdown(PCIAcpiState *s, uint32_t val)
+{
+ if (!(val & ACPI_BITMASK_SLEEP_ENABLE))
+ return;
+
+ switch (val & ACPI_BITMASK_SLEEP_TYPE) {
+ case SLP_TYP_S3:
+ qemu_system_reset();
+ qemu_irq_raise(s->cmos_s3);
+ xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);
+ break;
+ case SLP_TYP_S4:
+ case SLP_TYP_S5:
+ qemu_system_shutdown_request();
+ break;
+ default:
+ break;
+ }
+}
+
+static void acpiPm1ControlP1_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIAcpiState *s = opaque;
+
+ val <<= 8;
+ s->pm1_control = ((s->pm1_control & 0xff) | val) & ~ACPI_BITMASK_SLEEP_ENABLE;
+
+ acpi_shutdown(s, val);
+}
+
+static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr)
+{
+ PCIAcpiState *s = opaque;
+ /* Mask out the write-only bits */
+ return (uint8_t)((s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)) >> 8);
+}
+
+static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCIAcpiState *s = opaque;
+
+ s->pm1_control = val & ~ACPI_BITMASK_SLEEP_ENABLE;
+
+ acpi_shutdown(s, val);
+}
+
+static uint32_t acpiPm1Control_readw(void *opaque, uint32_t addr)
+{
+ PCIAcpiState *s = opaque;
+ /* Mask out the write-only bits */
+ return (s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE));
+}
+
+static void acpi_map(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ PCIAcpiState *d = (PCIAcpiState *)pci_dev;
+
+ /* Byte access */
+ register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d);
+ register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d);
+ register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d);
+ register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d);
+
+ /* Word access */
+ register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d);
+ register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
+}
+
+static inline int test_bit(uint8_t *map, int bit)
+{
+ return ( map[bit / 8] & (1 << (bit % 8)) );
+}
+
+static inline void set_bit(uint8_t *map, int bit)
+{
+ map[bit / 8] |= (1 << (bit % 8));
+}
+
+static inline void clear_bit(uint8_t *map, int bit)
+{
+ map[bit / 8] &= ~(1 << (bit % 8));
+}
+
+static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "ACPI: DBG: 0x%08x\n", val);
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val);
+}
+
+/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */
+static uint32_t gpe_sts_read(void *opaque, uint32_t addr)
+{
+ GPEState *s = opaque;
+
+ return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS];
+}
+
+/* write 1 to clear specific GPE bits */
+static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ GPEState *s = opaque;
+ int hotplugged = 0;
+
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val);
+
+ hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT);
+ s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val;
+ if ( s->sci_asserted &&
+ hotplugged &&
+ !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) {
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n");
+ qemu_irq_lower(sci_irq);
+ }
+
+}
+
+static uint32_t gpe_en_read(void *opaque, uint32_t addr)
+{
+ GPEState *s = opaque;
+
+ return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)];
+}
+
+/* write 0 to clear en bit */
+static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ GPEState *s = opaque;
+ int reg_count;
+
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val);
+ reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2);
+ s->gpe0_en[reg_count] = val;
+ /* If disable GPE bit right after generating SCI on it,
+ * need deassert the intr to avoid redundant intrs
+ */
+ if ( s->sci_asserted &&
+ reg_count == (ACPI_PHP_GPE_BIT / 8) &&
+ !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) {
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "deassert due to disable GPE bit.\n");
+ s->sci_asserted = 0;
+ qemu_irq_lower(sci_irq);
+ }
+
+}
+
+static void gpe_save(QEMUFile* f, void* opaque)
+{
+ GPEState *s = (GPEState*)opaque;
+ int i;
+
+ for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+ qemu_put_8s(f, &s->gpe0_sts[i]);
+ qemu_put_8s(f, &s->gpe0_en[i]);
+ }
+
+ qemu_put_8s(f, &s->sci_asserted);
+ if ( s->sci_asserted ) {
+ PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
+ }
+}
+
+static int gpe_load(QEMUFile* f, void* opaque, int version_id)
+{
+ GPEState *s = (GPEState*)opaque;
+ int i;
+ if (version_id != 1)
+ return -EINVAL;
+
+ for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
+ qemu_get_8s(f, &s->gpe0_sts[i]);
+ qemu_get_8s(f, &s->gpe0_en[i]);
+ }
+
+ qemu_get_8s(f, &s->sci_asserted);
+ return 0;
+}
+
+static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr)
+{
+ uint32_t val = 0;
+ GPEState *g = opaque;
+
+ switch (addr) {
+ case PROC_BASE ... PROC_BASE+31:
+ val = g->cpus_sts[addr - PROC_BASE];
+ default:
+ break;
+ }
+
+ return val;
+}
+
+static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ /* GPEState *g = opaque; */
+
+ switch (addr) {
+ case PROC_BASE ... PROC_BASE + 31:
+ /* don't allow to change cpus_sts from inside a guest */
+ break;
+ default:
+ break;
+ }
+}
+
+static void gpe_acpi_init(void)
+{
+ GPEState *s = &gpe_state;
+ memset(s, 0, sizeof(GPEState));
+
+ s->cpus_sts[0] = 1;
+
+ register_ioport_read(PROC_BASE, 32, 1, gpe_cpus_readb, s);
+ register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s);
+
+ register_ioport_read(ACPI_GPE0_BLK_ADDRESS,
+ ACPI_GPE0_BLK_LEN / 2,
+ 1,
+ gpe_sts_read,
+ s);
+ register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
+ ACPI_GPE0_BLK_LEN / 2,
+ 1,
+ gpe_en_read,
+ s);
+
+ register_ioport_write(ACPI_GPE0_BLK_ADDRESS,
+ ACPI_GPE0_BLK_LEN / 2,
+ 1,
+ gpe_sts_write,
+ s);
+ register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
+ ACPI_GPE0_BLK_LEN / 2,
+ 1,
+ gpe_en_write,
+ s);
+
+ register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
+}
+
+static int piix4_pm_xen_initfn(PCIDevice *dev)
+{
+ PCIAcpiState *s = DO_UPCAST(PCIAcpiState, dev, dev);
+ uint8_t *pci_conf;
+
+ pci_conf = s->dev.config;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3);
+ pci_conf[0x08] = 0x01; /* B0 stepping */
+ pci_conf[0x09] = 0x00; /* base class */
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
+ pci_conf[0x3d] = 0x01; /* Hardwired to PIRQA is used */
+
+ /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40
+ * to make shutdown work for IPF, due to IPF Guest Firmware
+ * will enumerate pci devices.
+ *
+ * TODO: if Guest Firmware or Guest OS will change this PMBA,
+ * More logic will be added.
+ */
+ pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */
+ pci_conf[0x41] = 0x1f;
+ pci_conf[0x42] = 0x00;
+ pci_conf[0x43] = 0x00;
+
+ s->pm1_control = ACPI_BITMASK_SCI_ENABLE;
+
+ acpi_map((PCIDevice *)s, 0, 0x1f40, 0x10, PCI_BASE_ADDRESS_SPACE_IO);
+
+ gpe_acpi_init();
+
+ register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
+
+ return 0;
+}
+
+void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3)
+{
+ PCIDevice *dev;
+ PCIAcpiState *s;
+
+ sci_irq = sci_irq_spec;
+
+ dev = pci_create(bus, devfn, "PIIX4 ACPI");
+
+ s = DO_UPCAST(PCIAcpiState, dev, dev);
+
+ s->irq = sci_irq_spec;
+ s->cmos_s3 = cmos_s3;
+
+ qdev_init_nofail(&dev->qdev);
+}
+
+static PCIDeviceInfo piix4_pm_xen_info = {
+ .qdev.name = "PIIX4 ACPI",
+ .qdev.desc = "dm",
+ .qdev.size = sizeof(PCIAcpiState),
+ .qdev.vmsd = &vmstate_acpi,
+ .init = piix4_pm_xen_initfn,
+};
+
+static void piix4_pm_xen_register(void)
+{
+ pci_qdev_register(&piix4_pm_xen_info);
+}
+
+device_init(piix4_pm_xen_register);
diff --git a/hw/xen_common.h b/hw/xen_common.h
index c49358c..cd62097 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -55,4 +55,7 @@ typedef xc_interface *qemu_xc_interface;
/* hw/i8259-xen-stub.c */
qemu_irq *i8259_xen_init(void);
+/* hw/xen_acpi_piix4.c */
+void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3);
+
#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c
index cb40d22..5132c97 100644
--- a/hw/xen_machine_fv.c
+++ b/hw/xen_machine_fv.c
@@ -65,7 +65,6 @@ static void xen_init_fv(ram_addr_t ram_size,
qemu_irq *isa_irq;
qemu_irq *i8259;
qemu_irq *cmos_s3;
- qemu_irq *smi_irq;
IsaIrqState *isa_irq_state;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
FDCtrl *floppy_controller;
@@ -173,10 +172,7 @@ static void xen_init_fv(ram_addr_t ram_size,
if (acpi_enabled) {
cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
- smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
- piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- isa_reserve_irq(9), *cmos_s3, *smi_irq,
- 0);
+ piix4_pm_xen_init(pci_bus, piix3_devfn + 3, isa_reserve_irq(9), *cmos_s3);
}
if (i440fx_state) {
--
1.7.0.4
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [Qemu-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
2010-08-23 9:50 ` [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen stefano.stabellini
@ 2010-08-23 11:15 ` Juan Quintela
2010-08-23 13:15 ` Stefano Stabellini
0 siblings, 1 reply; 25+ messages in thread
From: Juan Quintela @ 2010-08-23 11:15 UTC (permalink / raw)
To: stefano.stabellini; +Cc: Anthony.Perard, xen-devel, qemu-devel
stefano.stabellini@eu.citrix.com wrote:
> From: Anthony PERARD <anthony.perard@citrix.com>
>
> Xen currently uses a different BIOS (hvmloader + rombios) therefore the
> Qemu acpi_piix4 implementation wouldn't work correctly with Xen.
> We plan on fixing this properly but at the moment we are just adding a
> new Xen specific acpi_piix4 implementation.
> This patch is optional; without it the VM boots but it cannot shutdown
> properly or go to S3.
>
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> +static void gpe_save(QEMUFile* f, void* opaque)
> +{
> + GPEState *s = (GPEState*)opaque;
> + int i;
> +
> + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> + qemu_put_8s(f, &s->gpe0_sts[i]);
> + qemu_put_8s(f, &s->gpe0_en[i]);
> + }
> +
> + qemu_put_8s(f, &s->sci_asserted);
> + if ( s->sci_asserted ) {
> + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n");
> + }
> +}
> +
> +static int gpe_load(QEMUFile* f, void* opaque, int version_id)
> +{
> + GPEState *s = (GPEState*)opaque;
> + int i;
> + if (version_id != 1)
> + return -EINVAL;
> +
> + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> + qemu_get_8s(f, &s->gpe0_sts[i]);
> + qemu_get_8s(f, &s->gpe0_en[i]);
> + }
> +
> + qemu_get_8s(f, &s->sci_asserted);
> + return 0;
> +}
....
> + register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
Please port this to VMSTATE.
If possible (i.e. not problems with backwards compatibility), something like:
> + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> + qemu_get_8s(f, &s->gpe0_sts[i]);
> + }
> + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> + qemu_get_8s(f, &s->gpe0_en[i]);
> + }
Would be easier to put in vmstate.
Later, Juan.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [Qemu-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
2010-08-23 11:15 ` [Qemu-devel] " Juan Quintela
@ 2010-08-23 13:15 ` Stefano Stabellini
0 siblings, 0 replies; 25+ messages in thread
From: Stefano Stabellini @ 2010-08-23 13:15 UTC (permalink / raw)
To: Juan Quintela
Cc: Anthony Perard, xen-devel@lists.xensource.com,
qemu-devel@nongnu.org, Stefano Stabellini
On Mon, 23 Aug 2010, Juan Quintela wrote:
> > + register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s);
>
> Please port this to VMSTATE.
>
> If possible (i.e. not problems with backwards compatibility), something like:
>
> > + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> > + qemu_get_8s(f, &s->gpe0_sts[i]);
> > + }
> > + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
> > + qemu_get_8s(f, &s->gpe0_en[i]);
> > + }
>
> Would be easier to put in vmstate.
>
Ok, will do.
^ permalink raw reply [flat|nested] 25+ messages in thread