Stefano Stabellini
2010-Aug-12 14:08 UTC
[Xen-devel] [PATCH 00/15] RFC xen device model support
Hi all, this is the long awaited patch series to add xen device model support in qemu; the main author is Anthony Perard. Developing this series we tried to come up with the cleanest possible solution from the qemu point of view, limiting the amount of changes to common code as much as possible. The end result still requires a couple of hooks in piix_pci but overall the impact should be very limited. The current series gives you an upstream qemu device model able to boot a Linux or a Windows HVM guest; some features are still missing compared to the current qemu-xen, among which vga dirty bits, pci passthrough and stubdomain support. For any of you that want to try it, this is the step by step guide: - clone a fresh copy of xen-unstable.hg, make and install; note that the xen-unstable make system will clone a linux tree and a qemu-xen tree by default: you can avoid the former just executing ''make xen'' and ''make tools'' instead of ''make world''; - configure qemu using xen-dm-softmmu as target and extra-ldflags and extra-cflags pointing at the xen-unstable build directory, something like this should work: ./configure --target-list=xen-dm-softmmu --extra-cflags="-I$HOME/xen-unstable/dist/install/usr/include" --extra-ldflags="-L$HOME/xen-unstable/dist/install/usr/lib" --enable-xen - build qemu and install the newly compiled binary (xen-dm-softmmu/qemu-system-xen); - edit your VM config file and modify device_model to point at it. Currently only xl (not xend) knows how to spawn the new qemu device model with the right command line options. As you can see the build and test procedures are not straightforward yet, but in the near future we plan to provide a way to select an upstream qemu tree for use as xen device model directly from the xen-unstable build system. The patch series adds a new target with the whole xen device model machinery; each patch contains a detailed description. This is the full list of patches and the diffstat: Anthony Perard (15): xen: Update libxc calls xen: Add xen_machine_fv xen: Add a new target to qemu: target-xen xen: xen_machine_fv, initialize xenstore xen: add a 8259 Interrupt Controller xen: Add the Xen platform pci device xen: handle xenstore events xen: Read and write the state of the VM in xenstore xen: Initialize event channels and io rings xen: Introduce the Xen mapcache piix3: introduce register_set_irq and register_map_irq piix_pci: introduce a write_config notifier vl.c: Introduce getter for shutdown_requested and reset_requested. xen: destroy the VM when shutdown is requested Makefile.target | 31 ++ arch_init.c | 2 + arch_init.h | 1 + configure | 12 +- default-configs/xen-dm-softmmu.mak | 24 + hw/pc.h | 4 + hw/piix_pci.c | 45 ++- hw/xen_acpi_piix4.c | 424 ++++++++++++++++++ hw/xen_backend.c | 10 +- hw/xen_backend.h | 2 +- hw/xen_common.h | 6 + hw/xen_disk.c | 12 +- hw/xen_domainbuild.c | 4 +- hw/xen_machine_fv.c | 234 ++++++++++ hw/xen_nic.c | 16 +- hw/xen_platform.c | 452 ++++++++++++++++++++ hw/xen_platform.h | 9 + sysemu.h | 2 + target-xen/cpu.h | 121 ++++++ target-xen/exec-dm.c | 826 ++++++++++++++++++++++++++++++++++++ target-xen/helper.c | 455 ++++++++++++++++++++ target-xen/i8259-xen-stub.c | 63 +++ target-xen/qemu-xen.h | 50 +++ target-xen/stub-functions.c | 42 ++ target-xen/xen_mapcache.c | 247 +++++++++++ target-xen/xenstore.c | 168 ++++++++ target-xen/xenstore.h | 12 + vl.c | 10 + 28 files changed, 3259 insertions(+), 25 deletions(-) A git tree is available here: git://xenbits.xen.org/people/sstabellini/qemu-dm.git branch name qemu-dm-v1. We are committed in providing the best solution for both qemu and xen developers and users communities; we greatly appreciate any help you can give us to improve the quality of this series, including comments, critics, suggestions and of course patches :) Happy Hacking, Stefano _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 01/15] xen: Update libxc calls
From: Anthony PERARD <anthony.perard@citrix.com> Update the libxenctrl calls in Qemu to use the new interface, otherwise Qemu wouldn''t be able to build against new versions of the library. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- configure | 2 +- hw/xen_backend.c | 10 +++++----- hw/xen_backend.h | 2 +- hw/xen_disk.c | 12 ++++++------ hw/xen_domainbuild.c | 4 +++- hw/xen_nic.c | 16 ++++++++-------- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/configure b/configure index a20371c..89d9b44 100755 --- a/configure +++ b/configure @@ -1102,7 +1102,7 @@ if test "$xen" != "no" ; then cat > $TMPC <<EOF #include <xenctrl.h> #include <xs.h> -int main(void) { xs_daemon_open(); xc_interface_open(); return 0; } +int main(void) { xs_daemon_open(); xc_interface_open(0, 0, 0); return 0; } EOF if compile_prog "" "$xen_libs" ; then xen=yes diff --git a/hw/xen_backend.c b/hw/xen_backend.c index a2e408f..b2d302b 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -43,7 +43,7 @@ /* ------------------------------------------------------------- */ /* public */ -int xen_xc; +xc_interface *xen_xc = NULL; struct xs_handle *xenstore = NULL; const char *xen_protocol; @@ -216,7 +216,7 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev, fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC); if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) { - xendev->gnttabdev = xc_gnttab_open(); + xendev->gnttabdev = xc_gnttab_open(xen_xc); if (xendev->gnttabdev < 0) { xen_be_printf(NULL, 0, "can''t open gnttab device\n"); xc_evtchn_close(xendev->evtchndev); @@ -269,7 +269,7 @@ static struct XenDevice *xen_be_del_xendev(int dom, int dev) if (xendev->evtchndev >= 0) xc_evtchn_close(xendev->evtchndev); if (xendev->gnttabdev >= 0) - xc_gnttab_close(xendev->gnttabdev); + xc_gnttab_close(xen_xc, xendev->gnttabdev); QTAILQ_REMOVE(&xendevs, xendev, next); qemu_free(xendev); @@ -627,8 +627,8 @@ int xen_be_init(void) if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) goto err; - xen_xc = xc_interface_open(); - if (xen_xc == -1) { + xen_xc = xc_interface_open(NULL, NULL, 0); + if (xen_xc == NULL) { xen_be_printf(NULL, 0, "can''t open xen interface\n"); goto err; } diff --git a/hw/xen_backend.h b/hw/xen_backend.h index cc25f9d..385e851 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -57,7 +57,7 @@ struct XenDevice { /* ------------------------------------------------------------- */ /* variables */ -extern int xen_xc; +extern xc_interface *xen_xc; extern struct xs_handle *xenstore; extern const char *xen_protocol; diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 9a466f3..3c1d3ef 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -242,7 +242,7 @@ static void ioreq_unmap(struct ioreq *ioreq) if (batch_maps) { if (!ioreq->pages) return; - if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) + if (xc_gnttab_munmap(xen_xc, gnt, ioreq->pages, ioreq->v.niov) != 0) xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", strerror(errno)); ioreq->blkdev->cnt_map -= ioreq->v.niov; @@ -251,7 +251,7 @@ static void ioreq_unmap(struct ioreq *ioreq) for (i = 0; i < ioreq->v.niov; i++) { if (!ioreq->page[i]) continue; - if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) + if (xc_gnttab_munmap(xen_xc, gnt, ioreq->page[i], 1) != 0) xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", strerror(errno)); ioreq->blkdev->cnt_map--; @@ -269,7 +269,7 @@ static int ioreq_map(struct ioreq *ioreq) return 0; if (batch_maps) { ioreq->pages = xc_gnttab_map_grant_refs - (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot); + (xen_xc, gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot); if (ioreq->pages == NULL) { xen_be_printf(&ioreq->blkdev->xendev, 0, "can''t map %d grant refs (%s, %d maps)\n", @@ -283,7 +283,7 @@ static int ioreq_map(struct ioreq *ioreq) } else { for (i = 0; i < ioreq->v.niov; i++) { ioreq->page[i] = xc_gnttab_map_grant_ref - (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot); + (xen_xc, gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot); if (ioreq->page[i] == NULL) { xen_be_printf(&ioreq->blkdev->xendev, 0, "can''t map grant ref %d (%s, %d maps)\n", @@ -683,7 +683,7 @@ static int blk_connect(struct XenDevice *xendev) blkdev->protocol = BLKIF_PROTOCOL_X86_64; } - blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev, + blkdev->sring = xc_gnttab_map_grant_ref(xen_xc, blkdev->xendev.gnttabdev, blkdev->xendev.dom, blkdev->ring_ref, PROT_READ | PROT_WRITE); @@ -738,7 +738,7 @@ static void blk_disconnect(struct XenDevice *xendev) xen_be_unbind_evtchn(&blkdev->xendev); if (blkdev->sring) { - xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1); + xc_gnttab_munmap(xen_xc, blkdev->xendev.gnttabdev, blkdev->sring, 1); blkdev->cnt_map--; blkdev->sring = NULL; } diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index 7f1fd66..1620312 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -176,7 +176,9 @@ static int xen_domain_watcher(void) for (i = 3; i < n; i++) { if (i == fd[0]) continue; - if (i == xen_xc) + // FIXME The fd of xen_xc is now xen_xc->fd + // fd is the first field, so this works + if (i == *(int*)xen_xc) continue; close(i); } diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 08055b8..4f68850 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -166,7 +166,7 @@ static void net_tx_packets(struct XenNetDev *netdev) (txreq.flags & NETTXF_more_data) ? " more_data" : "", (txreq.flags & NETTXF_extra_info) ? " extra_info" : ""); - page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, + page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev, netdev->xendev.dom, txreq.gref, PROT_READ); if (page == NULL) { @@ -185,7 +185,7 @@ static void net_tx_packets(struct XenNetDev *netdev) } else { qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size); } - xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); + xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1); net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); } if (!netdev->tx_work) @@ -272,7 +272,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq)); netdev->rx_ring.req_cons = ++rc; - page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, + page = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev, netdev->xendev.dom, rxreq.gref, PROT_WRITE); if (page == NULL) { @@ -282,7 +282,7 @@ static ssize_t net_rx_packet(VLANClientState *nc, const uint8_t *buf, size_t siz return -1; } memcpy(page + NET_IP_ALIGN, buf, size); - xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); + xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, page, 1); net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0); return size; @@ -350,11 +350,11 @@ static int net_connect(struct XenDevice *xendev) return -1; } - netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, + netdev->txs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev, netdev->xendev.dom, netdev->tx_ring_ref, PROT_READ | PROT_WRITE); - netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev, + netdev->rxs = xc_gnttab_map_grant_ref(xen_xc, netdev->xendev.gnttabdev, netdev->xendev.dom, netdev->rx_ring_ref, PROT_READ | PROT_WRITE); @@ -381,11 +381,11 @@ static void net_disconnect(struct XenDevice *xendev) xen_be_unbind_evtchn(&netdev->xendev); if (netdev->txs) { - xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1); + xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->txs, 1); netdev->txs = NULL; } if (netdev->rxs) { - xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1); + xc_gnttab_munmap(xen_xc, netdev->xendev.gnttabdev, netdev->rxs, 1); netdev->rxs = NULL; } if (netdev->nic) { -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 02/15] xen: Add xen_machine_fv
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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
From: Anthony PERARD <anthony.perard@citrix.com> This patch adds a new Xen device model target to Qemu, called target-xen. The new target makes use of the previously introduced xen_machine_fv. In order to have a fully working Xen device model we still need functionalities introduced by the following patches. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- Makefile.target | 31 ++- arch_init.c | 2 + arch_init.h | 1 + configure | 11 +- default-configs/xen-dm-softmmu.mak | 24 ++ target-xen/cpu.h | 120 ++++++ target-xen/exec-dm.c | 791 ++++++++++++++++++++++++++++++++++++ target-xen/helper.c | 69 ++++ target-xen/qemu-xen.h | 30 ++ target-xen/stub-functions.c | 42 ++ target-xen/xen_mapcache.c | 14 + 11 files changed, 1130 insertions(+), 5 deletions(-) create mode 100644 default-configs/xen-dm-softmmu.mak create mode 100644 target-xen/cpu.h create mode 100644 target-xen/exec-dm.c create mode 100644 target-xen/helper.c create mode 100644 target-xen/machine.c create mode 100644 target-xen/qemu-xen.h create mode 100644 target-xen/stub-functions.c create mode 100644 target-xen/xen_mapcache.c diff --git a/Makefile.target b/Makefile.target index 8fdc884..359a984 100644 --- a/Makefile.target +++ b/Makefile.target @@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS) # xen backend driver support obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o -# xen full virtualized machine -obj-$(CONFIG_XEN) += xen_machine_fv.o - # USB layer obj-$(CONFIG_USB_OHCI) += usb-ohci.o @@ -310,6 +307,34 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) endif # CONFIG_SOFTMMU +# Xen Device Model +# xen full virtualized machine + +# Remove some lib, because we don''t want it for a xen target. +ifeq ($(TARGET_BASE_ARCH), xen) +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o +bad-libobj-y += tcg%.o fpu/%.o +bad-libobj-y += disas.o op_helper.o +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y)) +endif + +obj-xen-y += xen_machine_fv.o +obj-xen-y += i8259.o +obj-xen-y += pc.o +obj-xen-y += piix_pci.o +obj-xen-y += mc146818rtc.o + +obj-xen-y += xen_mapcache.o +obj-xen-y += stub-functions.o + +obj-xen-y += vga.o +obj-xen-y += hpet.o +obj-xen-y += cirrus_vga.o +obj-xen-y += smbios.o +obj-xen-y += multiboot.o +obj-xen-y += exec-dm.o +obj-xen-y += lsi53c895a.o usb-ohci.o + obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) diff --git a/arch_init.c b/arch_init.c index 47bb4b2..ebc5cb6 100644 --- a/arch_init.c +++ b/arch_init.c @@ -75,6 +75,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con #define QEMU_ARCH QEMU_ARCH_SH4 #elif defined(TARGET_SPARC) #define QEMU_ARCH QEMU_ARCH_SPARC +#elif defined(TARGET_XEN) +#define QEMU_ARCH QEMU_ARCH_XEN #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/arch_init.h b/arch_init.h index 682890c..b5f8eb1 100644 --- a/arch_init.h +++ b/arch_init.h @@ -16,6 +16,7 @@ enum { QEMU_ARCH_S390X = 256, QEMU_ARCH_SH4 = 512, QEMU_ARCH_SPARC = 1024, + QEMU_ARCH_XEN = 2048, }; extern const uint32_t arch_type; diff --git a/configure b/configure index 89d9b44..c3f52ce 100755 --- a/configure +++ b/configure @@ -2517,6 +2517,9 @@ case "$target" in ${target_arch2}-softmmu) target_softmmu="yes" ;; + ${target_arch2}-dm-softmmu) + target_softmmu="yes" + ;; ${target_arch2}-linux-user) if test "$linux" != "yes" ; then echo "ERROR: Target ''$target'' is only available on a Linux host" @@ -2582,6 +2585,10 @@ case "$target_arch2" in TARGET_BASE_ARCH=i386 target_phys_bits=64 ;; + xen) + # This is use for xen mapcache + target_phys_bits=64 + ;; alpha) target_phys_bits=64 target_nptl="yes" @@ -2693,7 +2700,7 @@ if [ "$TARGET_ABI_DIR" = "" ]; then fi echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak case "$target_arch2" in - i386|x86_64) + i386|x86_64|xen) if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then echo "CONFIG_XEN=y" >> $config_target_mak fi @@ -2859,7 +2866,7 @@ if test "$target_softmmu" = "yes" ; then arm) cflags="-DHAS_AUDIO $cflags" ;; - i386|mips|ppc) + i386|mips|ppc|xen) cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags" ;; esac diff --git a/default-configs/xen-dm-softmmu.mak b/default-configs/xen-dm-softmmu.mak new file mode 100644 index 0000000..72fe141 --- /dev/null +++ b/default-configs/xen-dm-softmmu.mak @@ -0,0 +1,24 @@ +# Default configuration for xen-dm-softmmu + +CONFIG_VGA_PCI=y +CONFIG_VGA_ISA=y +CONFIG_VMWARE_VGA=y +CONFIG_SERIAL=y +CONFIG_PARALLEL=y +CONFIG_I8254=y +CONFIG_PCSPK=y +CONFIG_PCKBD=y +CONFIG_USB_UHCI=y +CONFIG_FDC=y +CONFIG_ACPI=y +CONFIG_APM=y +CONFIG_DMA=y +CONFIG_IDE_CORE=y +CONFIG_IDE_QDEV=y +CONFIG_IDE_PCI=y +CONFIG_IDE_ISA=y +CONFIG_IDE_PIIX=y +CONFIG_NE2000_ISA=y +CONFIG_PIIX_PCI=y +CONFIG_SOUND=y +CONFIG_XEN=y diff --git a/target-xen/cpu.h b/target-xen/cpu.h new file mode 100644 index 0000000..5a45d1c --- /dev/null +++ b/target-xen/cpu.h @@ -0,0 +1,120 @@ +/* + * xen virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#ifndef CPU_XEN_H +#define CPU_XEN_H + +#include "config.h" + +#ifdef TARGET_X86_64 +#define TARGET_LONG_BITS 64 +#else +#define TARGET_LONG_BITS 32 +#endif + +#ifdef TARGET_X86_64 +#define ELF_MACHINE EM_X86_64 +#else +#define ELF_MACHINE EM_386 +#endif + +#define CPUState struct CPUXenState +#define CPUX86State CPUXenState + +#include "cpu-defs.h" + +#include "softfloat.h" + +/* hidden flags - used internally by qemu to represent additional cpu + states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not + redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit + position to ease oring with eflags. */ +/* current cpl */ +#define HF_CPL_SHIFT 0 +#define HF_SMM_SHIFT 19 /* CPU in SMM mode */ + +#define HF_CPL_MASK (3 << HF_CPL_SHIFT) +#define HF_SMM_MASK (1 << HF_SMM_SHIFT) + +/* cpuid_features bits */ +#define CPUID_APIC (1 << 9) + +#define NB_MMU_MODES 2 + +typedef struct CPUXenState { + uint32_t hflags; /* TB flags, see HF_xxx constants. These flags + are known at translation time. */ + CPU_COMMON + + /* processor features (e.g. for CPUID insn) */ + uint32_t cpuid_features; + uint32_t cpuid_apic_id; + + /* in order to simplify APIC support, we leave this pointer to the + user */ + struct DeviceState *apic_state; +} CPUXenState; + +CPUXenState *cpu_xen_init(const char *cpu_model); +int cpu_xen_exec(CPUXenState *s); + +int cpu_get_pic_interrupt(CPUXenState *s); +void cpu_set_ferr(CPUX86State *s); + +/* helper.c */ +void cpu_x86_set_a20(CPUXenState *env, int a20_state); + +/* hw/pc.c */ +void cpu_smm_update(CPUXenState *env); +uint64_t cpu_get_tsc(CPUX86State *env); + +#define TARGET_PAGE_BITS 12 + +#ifdef TARGET_X86_64 +#define TARGET_PHYS_ADDR_SPACE_BITS 52 +/* ??? This is really 48 bits, sign-extended, but the only thing + accessible to userland with bit 48 set is the VSYSCALL, and that + is handled via other mechanisms. */ +#define TARGET_VIRT_ADDR_SPACE_BITS 47 +#else +#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#endif + +#define cpu_init cpu_xen_init +#define cpu_exec cpu_xen_exec + +/* MMU modes definitions */ +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; +} + +#include "cpu-all.h" +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ +} + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ +} + +#endif /* CPU_XEN_H */ diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c new file mode 100644 index 0000000..3d64695 --- /dev/null +++ b/target-xen/exec-dm.c @@ -0,0 +1,791 @@ +/* + * virtual page mapping and translated block handling + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#include "cpu.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "disas.h" +#include "hw/xen_common.h" +#include "qemu-xen.h" +#include "hw/xen.h" +#include "hw/xen_backend.h" + +int use_icount = 0; +int64_t qemu_icount; + +RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) }; + +CPUState *first_cpu; +/* current CPU in the current thread. It is only valid inside + cpu_exec() */ +CPUState *cpu_single_env; + +/* io memory support */ +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +void *io_mem_opaque[IO_MEM_NB_ENTRIES]; +static int io_mem_nb = 1; + +/* log support */ +FILE *logfile; +int loglevel; + +void cpu_exec_init_all(unsigned long tb_size) +{ +} + +void cpu_exec_init(CPUState *env) +{ + CPUState **penv; + int cpu_index; + + env->next_cpu = NULL; + penv = &first_cpu; + cpu_index = 0; + while (*penv != NULL) { + penv = (CPUState **)&(*penv)->next_cpu; + cpu_index++; + } + env->cpu_index = cpu_index; + *penv = env; +} + +/* enable or disable low levels log */ +void cpu_set_log(int log_flags) +{ + loglevel = log_flags; + if (!logfile) { + logfile = stderr; + } +} + +void cpu_set_log_filename(const char *filename) +{ + logfile = fopen(filename, "w"); + if (!logfile) { + perror(filename); + _exit(1); + } +#if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ + { + static uint8_t logfile_buf[4096]; + setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); + } +#else + setvbuf(logfile, NULL, _IOLBF, 0); +#endif + dup2(fileno(logfile), 1); + dup2(fileno(logfile), 2); +} + +/* mask must never be zero, except for A20 change call */ +void cpu_interrupt(CPUState *env, int mask) +{ + env->interrupt_request |= mask; +} + +void cpu_reset_interrupt(CPUState *env, int mask) +{ + env->interrupt_request &= ~mask; +} + +const CPULogItem cpu_log_items[] = { +#ifdef DEBUG_IOPORT + { CPU_LOG_IOPORT, "ioport", + "show all i/o ports accesses" }, +#endif + { 0, NULL, NULL }, +}; + +static int cmp1(const char *s1, int n, const char *s2) +{ + if (strlen(s2) != n) + return 0; + return memcmp(s1, s2, n) == 0; +} + +/* takes a comma separated list of log masks. Return 0 if error. */ +int cpu_str_to_log_mask(const char *str) +{ + const CPULogItem *item; + int mask; + const char *p, *p1; + + p = str; + mask = 0; + for(;;) { + p1 = strchr(p, '',''); + if (!p1) { + p1 = p + strlen(p); + } + if(cmp1(p,p1-p,"all")) { + for(item = cpu_log_items; item->mask != 0; item++) { + mask |= item->mask; + } + } else { + for(item = cpu_log_items; item->mask != 0; item++) { + if (cmp1(p, p1 - p, item->name)) + goto found; + } + return 0; + } +found: + mask |= item->mask; + if (*p1 != '','') + break; + p = p1 + 1; + } + return mask; +} + +/* XXX: Simple implementation. Fix later */ +#define MAX_MMIO 1024 +static struct mmio_space { + target_phys_addr_t start; + unsigned long size; + unsigned long io_index; +} mmio[MAX_MMIO]; +static unsigned long mmio_cnt; + +/* register physical memory. ''size'' must be a multiple of the target + page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an + io memory page */ +void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, + ram_addr_t size, + ram_addr_t phys_offset, + ram_addr_t region_offset) +{ + region_offset &= TARGET_PAGE_MASK; + start_addr += region_offset; + + int i; + + for (i = 0; i < mmio_cnt; i++) { + if(mmio[i].start == start_addr) { + mmio[i].io_index = phys_offset; + mmio[i].size = size; + return; + } + } + + if (mmio_cnt == MAX_MMIO) { + fprintf(stderr, "too many mmio regions\n"); + exit(-1); + } + + mmio[mmio_cnt].io_index = phys_offset; + mmio[mmio_cnt].start = start_addr; + mmio[mmio_cnt++].size = size; +} + +/* mem_read and mem_write are arrays of functions containing the + function to access byte (index 0), word (index 1) and dword (index + 2). All functions must be supplied. If io_index is non zero, the + corresponding io zone is modified. If it is zero, a new io zone is + allocated. The return value can be used with + cpu_register_physical_memory(). (-1) is returned if error. */ +int cpu_register_io_memory_fixed(int io_index, + CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque) +{ + int i; + + if (io_index <= 0) { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + io_index = io_mem_nb++; + } else { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + } + + for(i = 0;i < 3; i++) { + io_mem_read[io_index][i] = mem_read[i]; + io_mem_write[io_index][i] = mem_write[i]; + } + io_mem_opaque[io_index] = opaque; + return io_index << IO_MEM_SHIFT; +} + +int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque) +{ + return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque); +} + +void cpu_unregister_io_memory(int io_table_address) +{ + int i; + int io_index = io_table_address >> IO_MEM_SHIFT; + + for (i = 0; i < mmio_cnt; i++) { + if (mmio[i].size && mmio[i].io_index == io_index) { + mmio[i].start = mmio[i].size = 0; + break; + } + } + + for (i=0;i < 3; i++) { + io_mem_read[io_index][i] = NULL; + io_mem_write[io_index][i] = NULL; + } + io_mem_opaque[io_index] = NULL; +} + +int cpu_physical_memory_set_dirty_tracking(int enable) +{ + return 0; +} + +#ifdef __ia64__ + +#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory") +#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory") +#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory") + +/* IA64 has seperate I/D cache, with coherence maintained by DMA controller. + * So to emulate right behavior that guest OS is assumed, we need to flush + * I/D cache here. + */ +static void sync_icache(uint8_t *address, int len) +{ + unsigned long addr = (unsigned long)address; + unsigned long end = addr + len; + + for (addr &= ~(32UL-1); addr < end; addr += 32UL) { + __ia64_fc(addr); + } + + ia64_sync_i(); + ia64_srlz_i(); +} +#endif + +static int iomem_index(target_phys_addr_t addr) +{ + int i; + + for (i = 0; i < mmio_cnt; i++) { + unsigned long start, end; + + start = mmio[i].start; + end = mmio[i].start + mmio[i].size; + + if ((addr >= start) && (addr < end)) { + return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + } + } + return 0; +} + +unsigned int xen_logdirty_enable = 0; + +/* + * Replace the standard byte memcpy with a word memcpy for appropriately sized + * memory copy operations. Some users (USB-UHCI) can not tolerate the possible + * word tearing that can result from a guest concurrently writing a memory + * structure while the qemu device model is modifying the same location. + * Forcing a word-sized read/write prevents the guest from seeing a partially + * written word-sized atom. + */ +#if defined(__x86_64__) || defined(__i386__) +static void memcpy_words(void *dst, void *src, size_t n) +{ + asm volatile ( + " movl %%edx,%%ecx \n" +#ifdef __x86_64__ + " shrl $3,%%ecx \n" + " rep movsq \n" + " test $4,%%edx \n" + " jz 1f \n" + " movsl \n" +#else /* __i386__ */ + " shrl $2,%%ecx \n" + " rep movsl \n" +#endif + "1: test $2,%%edx \n" + " jz 1f \n" + " movsw \n" + "1: test $1,%%edx \n" + " jz 1f \n" + " movsb \n" + "1: \n" + : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" ); +} +#else +static void memcpy_words(void *dst, void *src, size_t n) +{ + /* Some architectures do not like unaligned accesses. */ + if (((unsigned long)dst | (unsigned long)src) & 3) { + memcpy(dst, src, n); + return; + } + + while (n >= sizeof(uint32_t)) { + *((uint32_t *)dst) = *((uint32_t *)src); + dst = ((uint32_t *)dst) + 1; + src = ((uint32_t *)src) + 1; + n -= sizeof(uint32_t); + } + + if (n & 2) { + *((uint16_t *)dst) = *((uint16_t *)src); + dst = ((uint16_t *)dst) + 1; + src = ((uint16_t *)src) + 1; + } + + if (n & 1) { + *((uint8_t *)dst) = *((uint8_t *)src); + dst = ((uint8_t *)dst) + 1; + src = ((uint8_t *)src) + 1; + } +} +#endif + +void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf, + int _len, int is_write) +{ + target_phys_addr_t addr = _addr; + int len = _len; + int l, io_index; + uint8_t *ptr; + uint32_t val; + + mapcache_lock(); + + while (len > 0) { + /* How much can we copy before the next page boundary? */ + l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); + if (l > len) { + l = len; + } + + io_index = iomem_index(addr); + if (is_write) { + if (io_index) { + if (l >= 4 && ((addr & 3) == 0)) { + /* 32 bit read access */ + val = ldl_raw(buf); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + l = 4; + } else if (l >= 2 && ((addr & 1) == 0)) { + /* 16 bit read access */ + val = lduw_raw(buf); + io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); + l = 2; + } else { + /* 8 bit access */ + val = ldub_raw(buf); + io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); + l = 1; + } + } else if ((ptr = phys_ram_addr(addr)) != NULL) { + /* Writing to RAM */ + memcpy_words(ptr, buf, l); + + if (xen_logdirty_enable) { + xc_hvm_modified_memory(xen_xc, + xen_domid, + addr >> TARGET_PAGE_BITS, + ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS) + - (addr >> TARGET_PAGE_BITS)); + } +#ifdef __ia64__ + sync_icache(ptr, l); +#endif + } + } else { + if (io_index) { + if (l >= 4 && ((addr & 3) == 0)) { + /* 32 bit read access */ + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + stl_raw(buf, val); + l = 4; + } else if (l >= 2 && ((addr & 1) == 0)) { + /* 16 bit read access */ + val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); + stw_raw(buf, val); + l = 2; + } else { + /* 8 bit access */ + val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); + stb_raw(buf, val); + l = 1; + } + } else if ((ptr = phys_ram_addr(addr)) != NULL) { + /* Reading from RAM */ + memcpy_words(buf, ptr, l); + } else { + /* Neither RAM nor known MMIO space */ + memset(buf, 0xff, len); + } + } + len -= l; + buf += l; + addr += l; + } + + mapcache_unlock(); +} + +/* virtual memory access for debug */ +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) +{ + int l; + target_ulong page, phys_addr; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + phys_addr = cpu_get_phys_page_debug(env, page); + /* if no physical page mapped, return an error */ + if (phys_addr == -1) + return -1; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), + buf, l, is_write); + len -= l; + buf += l; + addr += l; + } + return 0; +} + +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, + int dirty_flags) +{ + unsigned long length; + int i, mask, len; + uint8_t *p; + + start &= TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + + length = end - start; + if (length == 0) + return; + mask = ~dirty_flags; + p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS); + len = length >> TARGET_PAGE_BITS; + for(i = 0; i < len; i++) { + p[i] &= mask; + } + + return; +} + + +/* Unoptimised in Xen DM, nicked from git + * aab33094073678d459ccaac5c60ea7533e8d1d8e */ +uint32_t ldub_phys(target_phys_addr_t addr) +{ + uint8_t val; + cpu_physical_memory_read(addr, &val, 1); + return val; +} +uint32_t lduw_phys(target_phys_addr_t addr) +{ + uint16_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 2); + return tswap16(val); +} +uint64_t ldq_phys(target_phys_addr_t addr) +{ + uint64_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 8); + return tswap64(val); +} +void stb_phys(target_phys_addr_t addr, uint32_t val) +{ + uint8_t v = val; + cpu_physical_memory_write(addr, &v, 1); +} +void stw_phys(target_phys_addr_t addr, uint32_t val) +{ + uint16_t v = tswap16(val); + cpu_physical_memory_write(addr, (const uint8_t *)&v, 2); +} +void stq_phys(target_phys_addr_t addr, uint64_t val) +{ + val = tswap64(val); + cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); +} + +/* stubs which we hope (think!) are OK for Xen DM */ +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ + val = tswap32(val); + cpu_physical_memory_write(addr, (const uint8_t *)&val, 4); +} +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ + stl_phys(addr, val); +} +uint32_t ldl_phys(target_phys_addr_t addr) +{ + uint32_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 4); + return tswap32(val); +} + +void cpu_physical_memory_write_rom(target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + return cpu_physical_memory_write(addr,buf,len); +} + +void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) +{ +} +void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) +{ +} + +/* stub out various functions for Xen DM */ +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ +} + +void monitor_disas(Monitor *mon, CPUState *env, + target_ulong pc, int nb_insn, int is_physical, int flags) +{ +} + +/* + * This next section was clone-and-hacked from the version in exec.c + * :-(. But the exec.c version is full of tcg-specific stuff and + * assumptions about phys_ram_base. + */ + +typedef struct MapClient { + void *opaque; + void (*callback)(void *opaque); + QLIST_ENTRY(MapClient) link; +} MapClient; + +static QLIST_HEAD(map_client_list, MapClient) map_client_list + = QLIST_HEAD_INITIALIZER(map_client_list); + +void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)) +{ + MapClient *client = qemu_malloc(sizeof(*client)); + + client->opaque = opaque; + client->callback = callback; + QLIST_INSERT_HEAD(&map_client_list, client, link); + return client; +} + +void cpu_unregister_map_client(void *_client) +{ + MapClient *client = (MapClient *)_client; + + QLIST_REMOVE(client, link); + qemu_free(client); +} + +static void cpu_notify_map_clients(void) +{ + MapClient *client; + + while (!QLIST_EMPTY(&map_client_list)) { + client = QLIST_FIRST(&map_client_list); + client->callback(client->opaque); + cpu_unregister_map_client(client); + } +} + +/* Map a physical memory region into a host virtual address. + * May map a subset of the requested range, given by and returned in *plen. + * May return NULL if resources needed to perform the mapping are exhausted. + * Use only for reads OR writes - not for read-modify-write operations. + * Use cpu_register_map_client() to know when retrying the map operation is + * likely to succeed. + */ +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write) +{ + unsigned long l = 0; +#ifdef MAPCACHE + l = MCACHE_BUCKET_SIZE - (addr & (MCACHE_BUCKET_SIZE-1)); + if ((*plen) > l) { + *plen = l; + } +#endif + if (xen_logdirty_enable) { + xc_hvm_modified_memory(xen_xc, xen_domid, addr >> TARGET_PAGE_BITS, + ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS) + - (addr >> TARGET_PAGE_BITS)); + } + + return qemu_map_cache(addr, 1); +} + +/* Unmaps a memory region previously mapped by cpu_physical_memory_map(). + * Will also mark the memory as dirty if is_write == 1. access_len gives + * the amount of memory that was actually read or written by the caller. + */ +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) +{ + qemu_invalidate_entry(buffer); + cpu_notify_map_clients(); +} + + +void cpu_exit(CPUState *env) +{ + env->exit_request = 1; +} + +void qemu_flush_coalesced_mmio_buffer(void) +{ +} + +void *qemu_get_ram_ptr(ram_addr_t addr) +{ + RAMBlock *block; + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (addr - block->offset < block->length) { + QLIST_REMOVE(block, next); + QLIST_INSERT_HEAD(&ram_list.blocks, block, next); + return block->host + (addr - block->offset); + } + } + return block->host + (addr - block->offset); + + fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); + abort(); + + return NULL; +} + +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr) +{ + return 0; +} +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr) +{ + return 0; +} + +static ram_addr_t find_ram_offset(ram_addr_t size) +{ + RAMBlock *block; + ram_addr_t last = 0; + + QLIST_FOREACH(block, &ram_list.blocks, next) { + last = MAX(last, block->offset + block->length); + } + + return last; +} + +ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size) +{ + RAMBlock *new_block; + + size = TARGET_PAGE_ALIGN(size); + new_block = qemu_malloc(sizeof(*new_block)); + + if (mem_path) { +#if defined (__linux__) && !defined(TARGET_S390X) + new_block->host = 0; // file_ram_alloc(size, mem_path); + if (!new_block->host) { + new_block->host = qemu_vmalloc(size); +#ifdef MADV_MERGEABLE + madvise(new_block->host, size, MADV_MERGEABLE); +#endif + } +#else + fprintf(stderr, "-mem-path option unsupported\n"); + exit(1); +#endif + } else { + new_block->host = qemu_vmalloc(size); +#ifdef MADV_MERGEABLE + madvise(new_block->host, size, MADV_MERGEABLE); +#endif + } + new_block->offset = find_ram_offset(size); + new_block->length = size; + + QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next); + + ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty, + (new_block->offset + size) >> TARGET_PAGE_BITS); + memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS), + 0xff, size >> TARGET_PAGE_BITS); + + return new_block->offset; +} + +void qemu_ram_free(ram_addr_t addr) +{ +} + +void tb_flush(CPUState *env1) +{ +} + +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint) +{ + return -ENOSYS; +} + +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len, + int flags) +{ + return -ENOENT; +} + +void cpu_watchpoint_remove_all(CPUState *env, int mask) +{ +} + +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint) +{ + return -ENOSYS; +} + +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags) +{ + return -ENOSYS; +} + +void cpu_breakpoint_remove_all(CPUState *env, int mask) +{ +} + +void cpu_single_step(CPUState *env, int enabled) +{ +} diff --git a/target-xen/helper.c b/target-xen/helper.c new file mode 100644 index 0000000..d588e64 --- /dev/null +++ b/target-xen/helper.c @@ -0,0 +1,69 @@ +/* + * i386 helpers (without register variable usage) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "cpu.h" + +CPUXenState *cpu_xen_init(const char *cpu_model) +{ + CPUXenState *env = NULL; + static int inited; + + env = qemu_mallocz(sizeof(CPUXenState)); + if (!env) + return NULL; + cpu_exec_init(env); + + /* init various static tables */ + if (!inited) { + inited = 1; + + cpu_single_env = env; + } + + return env; +} + +int cpu_xen_exec(CPUState *env1) +{ + return 0; +} + +void cpu_reset(CPUXenState *env) +{ +} + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ +} + +/***********************************************************/ +/* x86 mmu */ +/* XXX: add PGE support */ + +void cpu_x86_set_a20(CPUXenState *env, int a20_state) +{ +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} diff --git a/target-xen/machine.c b/target-xen/machine.c new file mode 100644 index 0000000..e69de29 diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h new file mode 100644 index 0000000..d1910d6 --- /dev/null +++ b/target-xen/qemu-xen.h @@ -0,0 +1,30 @@ +#ifndef QEMU_XEN_H +#define QEMU_XEN_H + +#include "hw/xen_common.h" + +/* vl.c */ + +#if defined(__i386__) || defined(__x86_64__) +#define phys_ram_addr(x) (qemu_map_cache(x, 0)) +#elif defined(__ia64__) +#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL) +#endif + +/* xen_mapcache.c */ + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock); +void qemu_invalidate_entry(uint8_t *buffer); +void qemu_invalidate_map_cache(void); + +#define mapcache_lock() ((void)0) +#define mapcache_unlock() ((void)0) + +/* target-xen/exec-dm.c */ + +int cpu_register_io_memory_fixed(int io_index, + CPUReadMemoryFunc * const *mem_read, + CPUWriteMemoryFunc * const *mem_write, + void *opaque); + +#endif /*QEMU_XEN_H*/ diff --git a/target-xen/stub-functions.c b/target-xen/stub-functions.c new file mode 100644 index 0000000..0db6898 --- /dev/null +++ b/target-xen/stub-functions.c @@ -0,0 +1,42 @@ +#include "config.h" +#include "disas.h" +#include "hw/apic.h" +#include "hw/pc.h" +#include "cpu.h" + +/* disas */ +struct syminfo *syminfos = NULL; + +/* apic */ +void apic_deliver_pic_intr(DeviceState *d, int level) +{ +} + +int apic_get_interrupt(DeviceState *d) +{ + return -1; +} + +int apic_accept_pic_intr(DeviceState *d) +{ + return 0; +} + +/* vmmouse */ +void *vmmouse_init(void *m) +{ + return NULL; +} + +/* cpu-exec */ +volatile sig_atomic_t exit_request; + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) +{ + return NULL; +} + +int qemu_cpu_has_work(CPUState *env) +{ + return 0; +} diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c new file mode 100644 index 0000000..39daae2 --- /dev/null +++ b/target-xen/xen_mapcache.c @@ -0,0 +1,14 @@ +#include "qemu-xen.h" + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock) +{ + return phys_ram_addr(phys_addr); +} + +void qemu_invalidate_map_cache(void) +{ +} + +void qemu_invalidate_entry(uint8_t *buffer) +{ +} -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 04/15] xen: xen_machine_fv, initialize xenstore
From: Anthony PERARD <anthony.perard@citrix.com> Introduce a xen_dm_init function that opens a new xenstore connection and the xenctrl interface; call xen_dm_init from xen_machine_fv. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- Makefile.target | 1 + hw/xen_machine_fv.c | 8 ++++++++ target-xen/xenstore.c | 24 ++++++++++++++++++++++++ target-xen/xenstore.h | 6 ++++++ 4 files changed, 39 insertions(+), 0 deletions(-) create mode 100644 target-xen/xenstore.c create mode 100644 target-xen/xenstore.h diff --git a/Makefile.target b/Makefile.target index 359a984..63dc7d1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -323,6 +323,7 @@ obj-xen-y += i8259.o obj-xen-y += pc.o obj-xen-y += piix_pci.o obj-xen-y += mc146818rtc.o +obj-xen-y += xenstore.o obj-xen-y += xen_mapcache.o obj-xen-y += stub-functions.o diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index 8114460..5fef7de 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -32,6 +32,8 @@ #include "ide.h" #include "sysemu.h" +#include "xen_backend.h" +#include "xenstore.h" #include "xen/hvm/hvm_info_table.h" #define MAX_IDE_BUS 2 @@ -61,6 +63,12 @@ static void xen_init_fv(ram_addr_t ram_size, CPUState *env; + /* Initialize backend core & drivers */ + if (xen_dm_init() != 0) { + fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); + exit(1); + } + /* Initialize a dummy CPU */ if (cpu_model == NULL) { #ifdef TARGET_X86_64 diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c new file mode 100644 index 0000000..c202f66 --- /dev/null +++ b/target-xen/xenstore.c @@ -0,0 +1,24 @@ +#include "hw/xen_backend.h" +#include "xenstore.h" + +int xen_dm_init(void) +{ + xenstore = xs_daemon_open(); + if (!xenstore) { + xen_be_printf(NULL, 0, "can''t connect to xenstored\n"); + return -1; + } + + xen_xc = xc_interface_open(NULL, NULL, 0); + if (xen_xc == NULL) { + xen_be_printf(NULL, 0, "can''t open xen interface\n"); + goto err; + } + return 0; + +err: + xs_daemon_close(xenstore); + xenstore = NULL; + + return -1; +} diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h new file mode 100644 index 0000000..90baf79 --- /dev/null +++ b/target-xen/xenstore.h @@ -0,0 +1,6 @@ +#ifndef XENSTORE_H_ +#define XENSTORE_H_ + +int xen_dm_init(void); + +#endif /* !XENSTORE_H_ */ -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 05/15] xen: add a 8259 Interrupt Controller
From: Anthony PERARD <anthony.perard@citrix.com> Introduce a 8259 Interrupt Controller for target-xen; every set_irq call makes a Xen hypercall. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- Makefile.target | 2 +- hw/xen_common.h | 3 ++ hw/xen_machine_fv.c | 5 +-- target-xen/i8259-xen-stub.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 target-xen/i8259-xen-stub.c diff --git a/Makefile.target b/Makefile.target index 63dc7d1..d1b63f2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -319,7 +319,7 @@ libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y)) endif obj-xen-y += xen_machine_fv.o -obj-xen-y += i8259.o +obj-xen-y += i8259-xen-stub.o obj-xen-y += pc.o obj-xen-y += piix_pci.o obj-xen-y += mc146818rtc.o diff --git a/hw/xen_common.h b/hw/xen_common.h index 8a55b44..020fdd7 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -31,4 +31,7 @@ # define xen_wmb() wmb() #endif +/* hw/i8259-xen-stub.c */ +qemu_irq *i8259_xen_init(void); + #endif /* QEMU_HW_XEN_COMMON_H */ diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index 5fef7de..114addf 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -32,6 +32,7 @@ #include "ide.h" #include "sysemu.h" +#include "xen_common.h" #include "xen_backend.h" #include "xenstore.h" #include "xen/hvm/hvm_info_table.h" @@ -50,7 +51,6 @@ static void xen_init_fv(ram_addr_t ram_size, PCIBus *pci_bus; PCII440FXState *i440fx_state; int piix3_devfn = -1; - qemu_irq *cpu_irq; qemu_irq *isa_irq; qemu_irq *i8259; qemu_irq *cmos_s3; @@ -80,8 +80,7 @@ static void xen_init_fv(ram_addr_t ram_size, env = cpu_init(cpu_model); env->halted = 1; - cpu_irq = pc_allocate_cpu_irq(); - i8259 = i8259_init(cpu_irq[0]); + i8259 = i8259_xen_init(); isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state)); isa_irq_state->i8259 = i8259; diff --git a/target-xen/i8259-xen-stub.c b/target-xen/i8259-xen-stub.c new file mode 100644 index 0000000..aa2aae1 --- /dev/null +++ b/target-xen/i8259-xen-stub.c @@ -0,0 +1,63 @@ +/* Xen 8259 stub for interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2005 Intel corperation + * Copyright (c) 2008 Citrix / Xensource + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/hw.h" +#include "hw/pc.h" +#include "monitor.h" +#include "hw/xen_common.h" +#include "hw/xen_backend.h" + +#include <xen/hvm/ioreq.h> + +PicState2 *isa_pic = NULL; + +void pic_update_irq(PicState2 *s) +{ +} + +static void i8259_set_irq(void *opaque, int irq, int level) +{ + xc_hvm_set_isa_irq_level(xen_xc, xen_domid, irq, level); +} + +int pic_read_irq(PicState2 *s) +{ + return -1; +} + +void irq_info(Monitor *mon) +{ + monitor_printf(mon, "irq statistics not supported with Xen.\n"); +} + +void pic_info(Monitor *mon) +{ + monitor_printf(mon, "pic_info not supported with Xen .\n"); +} + +qemu_irq *i8259_xen_init(void) +{ + return qemu_allocate_irqs(i8259_set_irq, NULL, 16); +} -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 06/15] xen: Add the Xen platform pci device
From: Anthony PERARD <anthony.perard@citrix.com> Introduce a new emulated PCI device, specific to fully virtualized Xen guests. The device is necessary for PV on HVM drivers to work. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- Makefile.target | 1 + hw/xen_machine_fv.c | 4 + hw/xen_platform.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/xen_platform.h | 9 + 4 files changed, 466 insertions(+), 0 deletions(-) create mode 100644 hw/xen_platform.c create mode 100644 hw/xen_platform.h diff --git a/Makefile.target b/Makefile.target index d1b63f2..1984cdd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -324,6 +324,7 @@ obj-xen-y += pc.o obj-xen-y += piix_pci.o obj-xen-y += mc146818rtc.o obj-xen-y += xenstore.o +obj-xen-y += xen_platform.o obj-xen-y += xen_mapcache.o obj-xen-y += stub-functions.o diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index 114addf..ec826e7 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -35,6 +35,7 @@ #include "xen_common.h" #include "xen_backend.h" #include "xenstore.h" +#include "xen_platform.h" #include "xen/hvm/hvm_info_table.h" #define MAX_IDE_BUS 2 @@ -93,6 +94,9 @@ static void xen_init_fv(ram_addr_t ram_size, pc_vga_init(pci_bus); + pci_xen_platform_init(pci_bus); + platform_fixed_ioport_init(); + /* init basic PC hardware */ pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state); diff --git a/hw/xen_platform.c b/hw/xen_platform.c new file mode 100644 index 0000000..85d3f8b --- /dev/null +++ b/hw/xen_platform.c @@ -0,0 +1,452 @@ +/* + * XEN platform pci device, formerly known as the event channel device + * + * Copyright (c) 2003-2004 Intel Corp. + * Copyright (c) 2006 XenSource + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "pc.h" +#include "pci.h" +#include "irq.h" +#include "xen_common.h" +#include "net.h" +#include "xen_platform.h" +#include "xen_backend.h" +#include "qemu-log.h" + +#include <assert.h> +#include <xenguest.h> + +static int drivers_blacklisted; +static uint16_t driver_product_version; +static int throttling_disabled; +static char log_buffer[4096]; +static int log_buffer_off; + +static uint8_t platform_flags; + +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */ + +typedef struct PCIXenPlatformState +{ + PCIDevice pci_dev; +} PCIXenPlatformState; + + +/* We throttle access to dom0 syslog, to avoid DOS attacks. This is + modelled as a token bucket, with one token for every byte of log. + The bucket size is 128KB (->1024 lines of 128 bytes each) and + refills at 256B/s. It starts full. The guest is blocked if no + tokens are available when it tries to generate a log message. */ +#define BUCKET_MAX_SIZE (128*1024) +#define BUCKET_FILL_RATE 256 + +static void throttle(unsigned count) +{ + static unsigned available; + static struct timespec last_refil; + static int started; + static int warned; + + struct timespec waiting_for, now; + double delay; + struct timespec ts; + + if (throttling_disabled) + return; + + if (!started) { + clock_gettime(CLOCK_MONOTONIC, &last_refil); + available = BUCKET_MAX_SIZE; + started = 1; + } + + if (count > BUCKET_MAX_SIZE) { + fprintf(stderr, "tried to get %d tokens, but bucket size is %d\n", + BUCKET_MAX_SIZE, count); + exit(1); + } + + if (available < count) { + /* The bucket is empty. Refil it */ + + /* When will it be full enough to handle this request? */ + delay = (double)(count - available) / BUCKET_FILL_RATE; + waiting_for = last_refil; + waiting_for.tv_sec += delay; + waiting_for.tv_nsec += (delay - (int)delay) * 1e9; + if (waiting_for.tv_nsec >= 1000000000) { + waiting_for.tv_nsec -= 1000000000; + waiting_for.tv_sec++; + } + + /* How long do we have to wait? (might be negative) */ + clock_gettime(CLOCK_MONOTONIC, &now); + ts.tv_sec = waiting_for.tv_sec - now.tv_sec; + ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000; + } + + /* Wait for it. */ + if (ts.tv_sec > 0 || + (ts.tv_sec == 0 && ts.tv_nsec > 0)) { + if (!warned) { + fprintf(stderr, "throttling guest access to syslog"); + warned = 1; + } + while (nanosleep(&ts, &ts) < 0 && errno == EINTR) + ; + } + + /* Refil */ + clock_gettime(CLOCK_MONOTONIC, &now); + delay = (now.tv_sec - last_refil.tv_sec) + + (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9; + available += BUCKET_FILL_RATE * delay; + if (available > BUCKET_MAX_SIZE) + available = BUCKET_MAX_SIZE; + last_refil = now; + } + + assert(available >= count); + + available -= count; +} + +#define UNPLUG_ALL_IDE_DISKS 1 +#define UNPLUG_ALL_NICS 2 +#define UNPLUG_AUX_IDE_DISKS 4 + +static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val) +{ + switch (addr - 0x10) { + case 0: + /* Unplug devices. Value is a bitmask of which devices to + unplug, with bit 0 the IDE devices, bit 1 the network + devices, and bit 2 the non-primary-master IDE devices. */ + break; + case 2: + switch (val) { + case 1: + fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n"); + break; + case 0: + fprintf(stderr, "Guest claimed to be running PV product 0?\n"); + break; + default: + fprintf(stderr, "Unknown PV product %d loaded in guest\n", val); + break; + } + driver_product_version = val; + break; + } +} + +static void platform_fixed_ioport_write4(void *opaque, uint32_t addr, + uint32_t val) +{ + switch (addr - 0x10) { + case 0: + /* PV driver version */ + break; + } +} + +static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val) +{ + switch (addr - 0x10) { + case 0: /* Platform flags */ { + hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ? + HVMMEM_ram_ro : HVMMEM_ram_rw; + if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) + fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw " + "state of ROM memory area!\n"); + else { + platform_flags = val & PFFLAG_ROM_LOCK; + fprintf(stderr,"platform_fixed_ioport: changed ro/rw " + "state of ROM memory area. now is %s state.\n", + (mem_type == HVMMEM_ram_ro ? "ro":"rw")); + } + break; + } + case 2: + /* Send bytes to syslog */ + if (val == ''\n'' || log_buffer_off == sizeof(log_buffer) - 1) { + /* Flush buffer */ + log_buffer[log_buffer_off] = 0; + throttle(log_buffer_off); + fprintf(stderr, "%s\n", log_buffer); + log_buffer_off = 0; + break; + } + log_buffer[log_buffer_off++] = val; + break; + } +} + +static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr) +{ + switch (addr - 0x10) { + case 0: + if (drivers_blacklisted) { + /* The drivers will recognise this magic number and refuse + * to do anything. */ + return 0xd249; + } else { + /* Magic value so that you can identify the interface. */ + return 0x49d2; + } + default: + return 0xffff; + } +} + +static uint32_t platform_fixed_ioport_read1(void *opaque, uint32_t addr) +{ + switch (addr - 0x10) { + case 0: + /* Platform flags */ + return platform_flags; + case 2: + /* Version number */ + return 1; + default: + return 0xff; + } +} + +static void platform_fixed_ioport_save(QEMUFile *f, void *opaque) +{ + qemu_put_8s(f, &platform_flags); +} + +static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id) +{ + uint8_t flags; + + if (version_id > 1) + return -EINVAL; + + qemu_get_8s(f, &flags); + platform_fixed_ioport_write1(NULL, 0x10, flags); + + return 0; +} + +void platform_fixed_ioport_init(void) +{ + register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save, + platform_fixed_ioport_load, NULL); + + register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL); + register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL); + register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL); + register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL); + register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL); + + platform_fixed_ioport_write1(NULL, 0x10, 0); +} + +static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr) +{ + addr &= 0xff; + + return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u; +} + +static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + addr &= 0xff; + val &= 0xff; + + switch (addr) { + case 0: /* Platform flags */ + platform_fixed_ioport_write1(NULL, 0x10, val); + break; + case 8: + { + if (val == ''\n'' || log_buffer_off == sizeof(log_buffer) - 1) { + /* Flush buffer */ + log_buffer[log_buffer_off] = 0; + throttle(log_buffer_off); + fprintf(stderr, "%s\n", log_buffer); + log_buffer_off = 0; + break; + } + log_buffer[log_buffer_off++] = val; + } + break; + default: + break; + } +} + +static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type) +{ + PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev; + register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d); + register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d); +} + +static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr) +{ + static int warnings = 0; + if (warnings < 5) { + fprintf(stderr, "Warning: attempted read from physical address " + "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)addr); + warnings++; + } + return 0; +} + +static void platform_mmio_write(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + static int warnings = 0; + if (warnings < 5) { + fprintf(stderr, "Warning: attempted write of 0x%x to physical " + "address 0x%"PRIx64" in xen platform mmio space\n", + val, (uint64_t)addr); + warnings++; + } + return; +} + +static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = { + platform_mmio_read, + platform_mmio_read, + platform_mmio_read, +}; + +static CPUWriteMemoryFunc *platform_mmio_write_funcs[3] = { + platform_mmio_write, + platform_mmio_write, + platform_mmio_write, +}; + +static void platform_mmio_map(PCIDevice *d, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + int mmio_io_addr; + + mmio_io_addr = cpu_register_io_memory(platform_mmio_read_funcs, + platform_mmio_write_funcs, NULL); + + cpu_register_physical_memory(addr, 0x1000000, mmio_io_addr); +} + +struct pci_config_header { + uint16_t vendor_id; + uint16_t device_id; + uint16_t command; + uint16_t status; + uint8_t revision; + uint8_t api; + uint8_t subclass; + uint8_t class; + uint8_t cache_line_size; /* Units of 32 bit words */ + uint8_t latency_timer; /* In units of bus cycles */ + uint8_t header_type; /* Should be 0 */ + uint8_t bist; /* Built in self test */ + uint32_t base_address_regs[6]; + uint32_t reserved1; + uint16_t subsystem_vendor_id; + uint16_t subsystem_id; + uint32_t rom_addr; + uint32_t reserved3; + uint32_t reserved4; + uint8_t interrupt_line; + uint8_t interrupt_pin; + uint8_t min_gnt; + uint8_t max_lat; +}; + +static void xen_pci_save(QEMUFile *f, void *opaque) +{ + PCIXenPlatformState *d = opaque; + uint64_t t = 0; + + pci_device_save(&d->pci_dev, f); + qemu_put_be64s(f, &t); +} + +static int xen_pci_load(QEMUFile *f, void *opaque, int version_id) +{ + PCIXenPlatformState *d = opaque; + int ret; + + if (version_id > 3) + return -EINVAL; + + ret = pci_device_load(&d->pci_dev, f); + if (ret < 0) + return ret; + + if (version_id >= 2) { + if (version_id == 2) { + uint8_t flags; + qemu_get_8s(f, &flags); + xen_platform_ioport_writeb(d, 0, flags); + } + qemu_get_be64(f); + } + + return 0; +} + +void pci_xen_platform_init(PCIBus *bus) +{ + PCIXenPlatformState *d; + struct pci_config_header *pch; + + printf("Register xen platform.\n"); + d = (PCIXenPlatformState *)pci_register_device( + bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL); + pch = (struct pci_config_header *)d->pci_dev.config; + pch->vendor_id = 0x5853; + pch->device_id = 0x0001; + pch->command = 3; /* IO and memory access */ + pch->revision = 1; + pch->api = 0; + pch->subclass = 0x80; /* Other */ + pch->class = 0xff; /* Unclassified device class */ + pch->header_type = 0; + pch->interrupt_pin = 1; + + /* Microsoft WHQL requires non-zero subsystem IDs. */ + /* http://www.pcisig.com/reflector/msg02205.html. */ + pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id. */ + pch->subsystem_id = 0x0001; /* Hardcode sub-id as 1. */ + + pci_register_bar(&d->pci_dev, 0, 0x100, + PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map); + + /* reserve 16MB mmio address for share memory*/ + pci_register_bar(&d->pci_dev, 1, 0x1000000, + PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map); + + register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d); + printf("Done register platform.\n"); +} + diff --git a/hw/xen_platform.h b/hw/xen_platform.h new file mode 100644 index 0000000..6eeff22 --- /dev/null +++ b/hw/xen_platform.h @@ -0,0 +1,9 @@ +#ifndef XEN_PLATFORM_H +#define XEN_PLATFORM_H + +#include "hw/pci.h" + +void pci_xen_platform_init(PCIBus *bus); +void platform_fixed_ioport_init(void); + +#endif -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 07/15] xen: handle xenstore events
From: Anthony PERARD <anthony.perard@citrix.com> Add an handler to process xenstore events. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- target-xen/xenstore.c | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c index c202f66..9f2e1ea 100644 --- a/target-xen/xenstore.c +++ b/target-xen/xenstore.c @@ -1,6 +1,18 @@ #include "hw/xen_backend.h" #include "xenstore.h" +static void xenstore_process_event(void *opaque) +{ + char **vec; + unsigned int num; + + vec = xs_read_watch(xenstore, &num); + if (!vec) + return; + + free(vec); +} + int xen_dm_init(void) { xenstore = xs_daemon_open(); @@ -9,6 +21,9 @@ int xen_dm_init(void) return -1; } + if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_process_event, NULL, NULL) < 0) + goto err; + xen_xc = xc_interface_open(NULL, NULL, 0); if (xen_xc == NULL) { xen_be_printf(NULL, 0, "can''t open xen interface\n"); @@ -17,6 +32,7 @@ int xen_dm_init(void) return 0; err: + qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL); xs_daemon_close(xenstore); xenstore = NULL; -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 08/15] xen: Read and write the state of the VM in xenstore
From: Anthony PERARD <anthony.perard@citrix.com> Introduce functions to read and write the state of the VM in xenstore. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- hw/xen_machine_fv.c | 9 ++++ target-xen/helper.c | 7 +++ target-xen/qemu-xen.h | 3 + target-xen/xenstore.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ target-xen/xenstore.h | 6 ++ 5 files changed, 153 insertions(+), 0 deletions(-) diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index ec826e7..a6e778a 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -36,10 +36,17 @@ #include "xen_backend.h" #include "xenstore.h" #include "xen_platform.h" +#include "qemu-xen.h" #include "xen/hvm/hvm_info_table.h" #define MAX_IDE_BUS 2 +static void xen_vm_change_state_handler(void *opaque, int running, int reason) +{ + if (running) + xen_main_loop_prepare(); +} + static void xen_init_fv(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -150,6 +157,8 @@ static void xen_init_fv(ram_addr_t ram_size, } pc_pci_device_init(pci_bus); + + qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL); } static QEMUMachine xenfv_machine = { diff --git a/target-xen/helper.c b/target-xen/helper.c index d588e64..8cb7771 100644 --- a/target-xen/helper.c +++ b/target-xen/helper.c @@ -19,6 +19,8 @@ */ #include "cpu.h" +#include "qemu-xen.h" +#include "xenstore.h" CPUXenState *cpu_xen_init(const char *cpu_model) { @@ -67,3 +69,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } + +void xen_main_loop_prepare(void) +{ + xenstore_record_dm_state("running"); +} diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h index d1910d6..091ae07 100644 --- a/target-xen/qemu-xen.h +++ b/target-xen/qemu-xen.h @@ -27,4 +27,7 @@ int cpu_register_io_memory_fixed(int io_index, CPUWriteMemoryFunc * const *mem_write, void *opaque); +/* target-xen/helper.c */ +void xen_main_loop_prepare(void); + #endif /*QEMU_XEN_H*/ diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c index 9f2e1ea..6eb6a30 100644 --- a/target-xen/xenstore.c +++ b/target-xen/xenstore.c @@ -13,6 +13,60 @@ static void xenstore_process_event(void *opaque) free(vec); } +static const char *xenstore_get_guest_uuid(void) +{ + static char *already_computed = NULL; + + char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL; + unsigned int len; + + if (already_computed) + return already_computed; + + if (xen_xc == NULL) + return NULL; + + domain_path = xs_get_domain_path(xenstore, xen_domid); + if (domain_path == NULL) { + fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid); + goto out; + } + + if (asprintf(&vm_path, "%s/vm", domain_path) == -1) { + fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n"); + goto out; + } + vm_value = xs_read(xenstore, XBT_NULL, vm_path, &len); + if (vm_value == NULL) { + fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path); + goto out; + } + + if (strtok(vm_value, "/") == NULL) { + fprintf(stderr, "failed to parse guest uuid\n"); + goto out; + } + p = strtok(NULL, "/"); + if (p == NULL) { + fprintf(stderr, "failed to parse guest uuid\n"); + goto out; + } + + if (asprintf(&already_computed, "%s", p) == -1) { + fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n"); + goto out; + } + + fprintf(stderr, "Guest uuid = %s\n", already_computed); + +out: + free(domain_path); + free(vm_path); + free(vm_value); + + return already_computed; +} + int xen_dm_init(void) { xenstore = xs_daemon_open(); @@ -29,6 +83,7 @@ int xen_dm_init(void) xen_be_printf(NULL, 0, "can''t open xen interface\n"); goto err; } + return 0; err: @@ -38,3 +93,76 @@ err: return -1; } + +static char *xenstore_vm_key_path(int domid, const char *key) { + const char *uuid; + char *buf = NULL; + + if (xenstore == NULL) + return NULL; + + uuid = xenstore_get_guest_uuid(); + if (!uuid) + return NULL; + + if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1) + return NULL; + + return buf; +} + +char *xenstore_vm_read(int domid, const char *key, unsigned int *len) +{ + char *path = NULL, *value = NULL; + + path = xenstore_vm_key_path(domid, key); + if (!path) + return NULL; + + value = xs_read(xenstore, XBT_NULL, path, len); + if (value == NULL) { + fprintf(stderr, "xs_read(%s): read error\n", path); + } + + free(path); + return value; +} + +int xenstore_vm_write(int domid, const char *key, const char *value) +{ + char *path = NULL; + int rc = -1; + + path = xenstore_vm_key_path(domid, key); + if (!path) + return 0; + + rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value)); + if (rc == 0) { + fprintf(stderr, "xs_write(%s, %s): write error\n", path, key); + } + + free(path); + return rc; +} + +void xenstore_record_dm(const char *subpath, const char *state) +{ + char *path = NULL; + + if (asprintf(&path, + "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) { + fprintf(stderr, "out of memory recording dm\n"); + goto out; + } + if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state))) + fprintf(stderr, "error recording dm\n"); + +out: + free(path); +} + +void xenstore_record_dm_state(const char *state) +{ + xenstore_record_dm("state", state); +} diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h index 90baf79..c8144ea 100644 --- a/target-xen/xenstore.h +++ b/target-xen/xenstore.h @@ -3,4 +3,10 @@ int xen_dm_init(void); +char *xenstore_vm_read(int domid, const char *key, unsigned int *len); +int xenstore_vm_write(int domid, const char *key, const char *value); + +void xenstore_record_dm(const char *subpath, const char *state); +void xenstore_record_dm_state(const char *state); + #endif /* !XENSTORE_H_ */ -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 09/15] xen: Initialize event channels and io rings
From: Anthony PERARD <anthony.perard@citrix.com> Open and bind event channels; map ioreq and buffered ioreq rings. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- hw/xen_machine_fv.c | 25 ++++ target-xen/cpu.h | 1 + target-xen/helper.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++++ target-xen/qemu-xen.h | 2 + 4 files changed, 390 insertions(+), 0 deletions(-) diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index a6e778a..b1bc88d 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -22,6 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "config.h" + +#include <sys/mman.h> #include "hw.h" #include "pc.h" @@ -71,12 +74,34 @@ static void xen_init_fv(ram_addr_t ram_size, CPUState *env; + unsigned long ioreq_pfn; + extern void *shared_page; + extern void *buffered_io_page; + /* Initialize backend core & drivers */ if (xen_dm_init() != 0) { fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); exit(1); } + xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); + fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn); + shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, + PROT_READ|PROT_WRITE, ioreq_pfn); + if (shared_page == NULL) { + fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc); + exit(-1); + } + + xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); + fprintf(stderr, "buffered io page at pfn %lx\n", ioreq_pfn); + buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, + PROT_READ|PROT_WRITE, ioreq_pfn); + if (buffered_io_page == NULL) { + fprintf(logfile, "map buffered IO page returned error %d\n", errno); + exit(-1); + } + /* Initialize a dummy CPU */ if (cpu_model == NULL) { #ifdef TARGET_X86_64 diff --git a/target-xen/cpu.h b/target-xen/cpu.h index 5a45d1c..573241f 100644 --- a/target-xen/cpu.h +++ b/target-xen/cpu.h @@ -72,6 +72,7 @@ typedef struct CPUXenState { CPUXenState *cpu_xen_init(const char *cpu_model); int cpu_xen_exec(CPUXenState *s); +void cpu_xen_close(CPUXenState *s); int cpu_get_pic_interrupt(CPUXenState *s); void cpu_set_ferr(CPUX86State *s); diff --git a/target-xen/helper.c b/target-xen/helper.c index 8cb7771..4571ac0 100644 --- a/target-xen/helper.c +++ b/target-xen/helper.c @@ -18,25 +18,77 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + +#include <inttypes.h> + +#include <xenctrl.h> +#include <xen/hvm/ioreq.h> + #include "cpu.h" #include "qemu-xen.h" #include "xenstore.h" +#include "hw/xen_backend.h" + +long time_offset = 0; + +shared_iopage_t *shared_page = NULL; + +#define BUFFER_IO_MAX_DELAY 100 +buffered_iopage_t *buffered_io_page = NULL; +QEMUTimer *buffered_io_timer; + +/* the evtchn fd for polling */ +int xce_handle = -1; + +/* which vcpu we are serving */ +int send_vcpu = 0; + +/* the evtchn port for polling the notification, */ +evtchn_port_t *ioreq_local_port; CPUXenState *cpu_xen_init(const char *cpu_model) { CPUXenState *env = NULL; static int inited; + int i, rc; env = qemu_mallocz(sizeof(CPUXenState)); if (!env) return NULL; cpu_exec_init(env); + /* There is no shared_page for PV, we''re done now */ + if (shared_page == NULL) + return env; + + ioreq_local_port + (evtchn_port_t *)qemu_mallocz(smp_cpus * sizeof(evtchn_port_t)); + if (!ioreq_local_port) + return NULL; + /* init various static tables */ if (!inited) { inited = 1; cpu_single_env = env; + + xce_handle = xc_evtchn_open(); + if (xce_handle == -1) { + perror("open"); + return NULL; + } + + /* FIXME: how about if we overflow the page here? */ + for (i = 0; i < smp_cpus; i++) { + rc = xc_evtchn_bind_interdomain( + xce_handle, xen_domid, shared_page->vcpu_ioreq[i].vp_eport); + if (rc == -1) { + fprintf(stderr, "bind interdomain ioctl error %d\n", errno); + return NULL; + } + ioreq_local_port[i] = rc; + } } return env; @@ -70,7 +122,317 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return addr; } +// get the ioreq packets from share mem +static ioreq_t *__cpu_get_ioreq(int vcpu) +{ + ioreq_t *req = &shared_page->vcpu_ioreq[vcpu]; + + if (req->state != STATE_IOREQ_READY) { + fprintf(stderr, "I/O request not ready: " + "%x, ptr: %x, port: %"PRIx64", " + "data: %"PRIx64", count: %u, size: %u\n", + req->state, req->data_is_ptr, req->addr, + req->data, req->count, req->size); + return NULL; + } + + xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */ + + req->state = STATE_IOREQ_INPROCESS; + return req; +} + +// use poll to get the port notification +// ioreq_vec--out,the +// retval--the number of ioreq packet +static ioreq_t *cpu_get_ioreq(void) +{ + int i; + evtchn_port_t port; + + port = xc_evtchn_pending(xce_handle); + if (port != -1) { + for ( i = 0; i < smp_cpus; i++ ) + if ( ioreq_local_port[i] == port ) + break; + + if ( i == smp_cpus ) { + fprintf(stderr, "Fatal error while trying to get io event!\n"); + exit(1); + } + + // unmask the wanted port again + xc_evtchn_unmask(xce_handle, port); + + // get the io packet from shared memory + send_vcpu = i; + return __cpu_get_ioreq(i); + } + + // read error or read nothing + return NULL; +} + +static unsigned long do_inp(CPUState *env, unsigned long addr, + unsigned long size) +{ + switch(size) { + case 1: + return cpu_inb(addr); + case 2: + return cpu_inw(addr); + case 4: + return cpu_inl(addr); + default: + fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size); + exit(-1); + } +} + +static void do_outp(CPUState *env, unsigned long addr, + unsigned long size, unsigned long val) +{ + switch(size) { + case 1: + return cpu_outb(addr, val); + case 2: + return cpu_outw(addr, val); + case 4: + return cpu_outl(addr, val); + default: + fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size); + exit(-1); + } +} + +static inline void read_physical(uint64_t addr, unsigned long size, void *val) +{ + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0); +} + +static inline void write_physical(uint64_t addr, unsigned long size, void *val) +{ + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1); +} + +static void cpu_ioreq_pio(CPUState *env, ioreq_t *req) +{ + int i, sign; + + sign = req->df ? -1 : 1; + + if (req->dir == IOREQ_READ) { + if (!req->data_is_ptr) { + req->data = do_inp(env, req->addr, req->size); + } else { + unsigned long tmp; + + for (i = 0; i < req->count; i++) { + tmp = do_inp(env, req->addr, req->size); + write_physical((target_phys_addr_t) req->data + + (sign * i * req->size), + req->size, &tmp); + } + } + } else if (req->dir == IOREQ_WRITE) { + if (!req->data_is_ptr) { + do_outp(env, req->addr, req->size, req->data); + } else { + for (i = 0; i < req->count; i++) { + unsigned long tmp = 0; + + read_physical((target_phys_addr_t) req->data + + (sign * i * req->size), + req->size, &tmp); + do_outp(env, req->addr, req->size, tmp); + } + } + } +} + +static void cpu_ioreq_move(CPUState *env, ioreq_t *req) +{ + int i, sign; + + sign = req->df ? -1 : 1; + + if (!req->data_is_ptr) { + if (req->dir == IOREQ_READ) { + for (i = 0; i < req->count; i++) { + read_physical(req->addr + + (sign * i * req->size), + req->size, &req->data); + } + } else if (req->dir == IOREQ_WRITE) { + for (i = 0; i < req->count; i++) { + write_physical(req->addr + + (sign * i * req->size), + req->size, &req->data); + } + } + } else { + target_ulong tmp; + + if (req->dir == IOREQ_READ) { + for (i = 0; i < req->count; i++) { + read_physical(req->addr + + (sign * i * req->size), + req->size, &tmp); + write_physical((target_phys_addr_t )req->data + + (sign * i * req->size), + req->size, &tmp); + } + } else if (req->dir == IOREQ_WRITE) { + for (i = 0; i < req->count; i++) { + read_physical((target_phys_addr_t) req->data + + (sign * i * req->size), + req->size, &tmp); + write_physical(req->addr + + (sign * i * req->size), + req->size, &tmp); + } + } + } +} + +static void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req) +{ + char b[64]; + + time_offset += (unsigned long)req->data; + + fprintf(stderr, "Time offset set %ld, added offset %"PRId64"\n", + time_offset, req->data); + sprintf(b, "%ld", time_offset); + xenstore_vm_write(xen_domid, "rtc/timeoffset", b); +} + +static void __handle_ioreq(CPUState *env, ioreq_t *req) +{ + if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) && + (req->size < sizeof(target_ulong))) + req->data &= ((target_ulong)1 << (8 * req->size)) - 1; + + switch (req->type) { + case IOREQ_TYPE_PIO: + cpu_ioreq_pio(env, req); + break; + case IOREQ_TYPE_COPY: + cpu_ioreq_move(env, req); + break; + case IOREQ_TYPE_TIMEOFFSET: + cpu_ioreq_timeoffset(env, req); + break; + case IOREQ_TYPE_INVALIDATE: + qemu_invalidate_map_cache(); + break; + default: + hw_error("Invalid ioreq type 0x%x\n", req->type); + } +} + +static void __handle_buffered_iopage(CPUState *env) +{ + buf_ioreq_t *buf_req = NULL; + ioreq_t req; + int qw; + + if (!buffered_io_page) + return; + + while (buffered_io_page->read_pointer !+ buffered_io_page->write_pointer) { + buf_req = &buffered_io_page->buf_ioreq[ + buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM]; + req.size = 1UL << buf_req->size; + req.count = 1; + req.addr = buf_req->addr; + req.data = buf_req->data; + req.state = STATE_IOREQ_READY; + req.dir = buf_req->dir; + req.df = 1; + req.type = buf_req->type; + req.data_is_ptr = 0; + qw = (req.size == 8); + if (qw) { + buf_req = &buffered_io_page->buf_ioreq[ + (buffered_io_page->read_pointer+1) % IOREQ_BUFFER_SLOT_NUM]; + req.data |= ((uint64_t)buf_req->data) << 32; + } + + __handle_ioreq(env, &req); + + xen_mb(); + buffered_io_page->read_pointer += qw ? 2 : 1; + } +} + +static void handle_buffered_io(void *opaque) +{ + CPUState *env = opaque; + + __handle_buffered_iopage(env); + qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY + + qemu_get_clock(rt_clock)); +} + +static void cpu_handle_ioreq(void *opaque) +{ + CPUState *env = opaque; + ioreq_t *req = cpu_get_ioreq(); + + __handle_buffered_iopage(env); + if (req) { + __handle_ioreq(env, req); + + if (req->state != STATE_IOREQ_INPROCESS) { + fprintf(stderr, "Badness in I/O request ... not in service?!: " + "%x, ptr: %x, port: %"PRIx64", " + "data: %"PRIx64", count: %u, size: %u\n", + req->state, req->data_is_ptr, req->addr, + req->data, req->count, req->size); + destroy_hvm_domain(); + return; + } + + xen_wmb(); /* Update ioreq contents /then/ update state. */ + + req->state = STATE_IORESP_READY; + xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); + } +} + void xen_main_loop_prepare(void) { + CPUState *env = cpu_single_env; + + int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle); + + buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io, + cpu_single_env); + qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock)); + + if (evtchn_fd != -1) + qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); + xenstore_record_dm_state("running"); } + +void destroy_hvm_domain(void) +{ + xc_interface *xcHandle; + int sts; + + xcHandle = xc_interface_open(NULL, NULL, 0); + if (xcHandle < 0) + fprintf(stderr, "Cannot acquire xenctrl handle\n"); + else { + sts = xc_domain_shutdown(xcHandle, xen_domid, SHUTDOWN_poweroff); + if (sts != 0) + fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, " + "sts %d, errno %d\n", sts, errno); + else + fprintf(stderr, "Issued domain %d poweroff\n", xen_domid); + xc_interface_close(xcHandle); + } +} diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h index 091ae07..79a4638 100644 --- a/target-xen/qemu-xen.h +++ b/target-xen/qemu-xen.h @@ -22,12 +22,14 @@ void qemu_invalidate_map_cache(void); /* target-xen/exec-dm.c */ +void destroy_hvm_domain(void); int cpu_register_io_memory_fixed(int io_index, CPUReadMemoryFunc * const *mem_read, CPUWriteMemoryFunc * const *mem_write, void *opaque); /* target-xen/helper.c */ +extern int xce_handle; void xen_main_loop_prepare(void); #endif /*QEMU_XEN_H*/ -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 10/15] xen: Introduce the Xen mapcache
From: Anthony PERARD <anthony.perard@citrix.com> Introduce a mapcache to handle the 64bit address space of the guest from a 32bit userland process (Qemu). The mapcache maps chucks of guest memory on demand, unmaps them when they are not needed anymore. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- hw/xen_machine_fv.c | 7 ++ target-xen/qemu-xen.h | 15 +++ target-xen/xen_mapcache.c | 233 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 255 insertions(+), 0 deletions(-) diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index b1bc88d..58237d6 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -84,6 +84,13 @@ static void xen_init_fv(ram_addr_t ram_size, exit(1); } +#if defined(__i386__) || defined(__x86_64__) + if (qemu_map_cache_init()) { + fprintf(stderr, "qemu_map_cache_init returned: error %d\n", errno); + exit(-1); + } +#endif + xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn); shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h index 79a4638..e4a7030 100644 --- a/target-xen/qemu-xen.h +++ b/target-xen/qemu-xen.h @@ -13,6 +13,21 @@ /* xen_mapcache.c */ +#if (defined(__i386__) || defined(__x86_64__)) && !defined(QEMU_TOOL) +#define MAPCACHE + +#if defined(__i386__) +#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ +#define MCACHE_BUCKET_SHIFT 16 +#elif defined(__x86_64__) +#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ +#define MCACHE_BUCKET_SHIFT 20 +#endif + +#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) +#endif + +int qemu_map_cache_init(void); uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock); void qemu_invalidate_entry(uint8_t *buffer); void qemu_invalidate_map_cache(void); diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c index 39daae2..efe036c 100644 --- a/target-xen/xen_mapcache.c +++ b/target-xen/xen_mapcache.c @@ -1,5 +1,237 @@ +#include "config.h" + +#include "hw/xen_backend.h" #include "qemu-xen.h" +#include <xen/hvm/params.h> +#include <sys/mman.h> + +#if defined(MAPCACHE) + +#define BITS_PER_LONG (sizeof(long)*8) +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] +#define test_bit(bit,map) \ + (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG)))) + +struct map_cache { + unsigned long paddr_index; + uint8_t *vaddr_base; + DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT); + uint8_t lock; + struct map_cache *next; +}; + +struct map_cache_rev { + uint8_t *vaddr_req; + unsigned long paddr_index; + QTAILQ_ENTRY(map_cache_rev) next; +}; + +static struct map_cache *mapcache_entry; +static unsigned long nr_buckets; +QTAILQ_HEAD(map_cache_head, map_cache_rev) locked_entries = QTAILQ_HEAD_INITIALIZER(locked_entries); + +/* For most cases (>99.9%), the page address is the same. */ +static unsigned long last_address_index = ~0UL; +static uint8_t *last_address_vaddr; + +int qemu_map_cache_init(void) +{ + unsigned long size; + + nr_buckets = (((MAX_MCACHE_SIZE >> XC_PAGE_SHIFT) + + (1UL << (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1) >> + (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)); + + /* + * Use mmap() directly: lets us allocate a big hash table with no up-front + * cost in storage space. The OS will allocate memory only for the buckets + * that we actually use. All others will contain all zeroes. + */ + size = nr_buckets * sizeof(struct map_cache); + size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1); + fprintf(stderr, "qemu_map_cache_init nr_buckets = %lx size %lu\n", nr_buckets, size); + mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANON, -1, 0); + if (mapcache_entry == MAP_FAILED) { + errno = ENOMEM; + return -1; + } + + return 0; +} + +static void qemu_remap_bucket(struct map_cache *entry, + unsigned long address_index) +{ + uint8_t *vaddr_base; + xen_pfn_t pfns[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT]; + int err[MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT]; + unsigned int i, j; + + if (entry->vaddr_base != NULL) { + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(stderr, "unmap fails %d\n", errno); + exit(-1); + } + } + + for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i++) { + pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i; + } + + vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE, + pfns, err, + MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT); + if (vaddr_base == NULL) { + fprintf(stderr, "xc_map_foreign_bulk error %d\n", errno); + exit(-1); + } + + entry->vaddr_base = vaddr_base; + entry->paddr_index = address_index; + + for (i = 0; i < MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT; i += BITS_PER_LONG) { + unsigned long word = 0; + j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT)) ? + (MCACHE_BUCKET_SIZE >> XC_PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; + while (j > 0) { + word = (word << 1) | !err[i + --j]; + } + entry->valid_mapping[i / BITS_PER_LONG] = word; + } +} + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock) +{ + struct map_cache *entry, *pentry = NULL; + unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; + unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); + + if (address_index == last_address_index && !lock) + return last_address_vaddr + address_offset; + + entry = &mapcache_entry[address_index % nr_buckets]; + + while (entry && entry->lock && entry->paddr_index != address_index && entry->vaddr_base) { + pentry = entry; + entry = entry->next; + } + if (!entry) { + entry = qemu_mallocz(sizeof(struct map_cache)); + pentry->next = entry; + qemu_remap_bucket(entry, address_index); + } else if (!entry->lock) { + if (!entry->vaddr_base || entry->paddr_index != address_index || !test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) + qemu_remap_bucket(entry, address_index); + } + + if (!test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) { + last_address_index = ~0UL; + return NULL; + } + + last_address_index = address_index; + last_address_vaddr = entry->vaddr_base; + if (lock) { + struct map_cache_rev *reventry = qemu_mallocz(sizeof(struct map_cache_rev)); + entry->lock++; + reventry->vaddr_req = last_address_vaddr + address_offset; + reventry->paddr_index = last_address_index; + QTAILQ_INSERT_TAIL(&locked_entries, reventry, next); + } + + return last_address_vaddr + address_offset; +} + +void qemu_invalidate_entry(uint8_t *buffer) +{ + struct map_cache *entry = NULL, *pentry = NULL; + struct map_cache_rev *reventry; + unsigned long paddr_index; + int found = 0; + + if (last_address_vaddr == buffer) + last_address_index = ~0UL; + + QTAILQ_FOREACH(reventry, &locked_entries, next) { + if (reventry->vaddr_req == buffer) { + paddr_index = reventry->paddr_index; + found = 1; + break; + } + } + if (!found) { + fprintf(stderr, "qemu_invalidate_entry: could not find %p\n", buffer); + QTAILQ_FOREACH(reventry, &locked_entries, next) { + fprintf(stderr, " %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); + } + return; + } + QTAILQ_REMOVE(&locked_entries, reventry, next); + qemu_free(reventry); + + entry = &mapcache_entry[paddr_index % nr_buckets]; + while (entry && entry->paddr_index != paddr_index) { + pentry = entry; + entry = entry->next; + } + if (!entry) { + fprintf(stderr, "Trying to unmap address %p that is not in the mapcache!\n", buffer); + return; + } + entry->lock--; + if (entry->lock > 0 || pentry == NULL) + return; + + pentry->next = entry->next; + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(stderr, "unmap fails %d\n", errno); + exit(-1); + } + qemu_free(entry); +} + +void qemu_invalidate_map_cache(void) +{ + unsigned long i; + struct map_cache_rev *reventry; + + qemu_aio_flush(); + + QTAILQ_FOREACH(reventry, &locked_entries, next) { + fprintf(stderr, "There should be no locked mappings at this time, but %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); + } + + mapcache_lock(); + + for (i = 0; i < nr_buckets; i++) { + struct map_cache *entry = &mapcache_entry[i]; + + if (entry->vaddr_base == NULL) + continue; + + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(stderr, "unmap fails %d\n", errno); + exit(-1); + } + + entry->paddr_index = 0; + entry->vaddr_base = NULL; + } + + last_address_index = ~0UL; + last_address_vaddr = NULL; + + mapcache_unlock(); +} +#else uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock) { return phys_ram_addr(phys_addr); @@ -12,3 +244,4 @@ void qemu_invalidate_map_cache(void) void qemu_invalidate_entry(uint8_t *buffer) { } +#endif /* !MAPCACHE */ -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
From: Anthony PERARD <anthony.perard@citrix.com> This patch introduces a generic function registration mechanism for set_irq and map_irq in piix3, so that the two calls can be overridden with platform specific functions whenever needed. The patch also implements and registers the Xen specific version of the functions. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- hw/pc.h | 3 +++ hw/piix_pci.c | 17 ++++++++++++++++- hw/xen_machine_fv.c | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 1 deletions(-) diff --git a/hw/pc.h b/hw/pc.h index 63b0249..ee562cd 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -5,6 +5,7 @@ #include "ioport.h" #include "isa.h" #include "fdc.h" +#include "pci.h" /* PC-style peripherals (also used by other machines). */ @@ -138,6 +139,8 @@ int pcspk_audio_init(qemu_irq *pic); struct PCII440FXState; typedef struct PCII440FXState PCII440FXState; +void piix3_register_set_irq(pci_set_irq_fn set_irq); +void piix3_register_map_irq(pci_map_irq_fn map_irq); PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size); void i440fx_init_memory_mappings(PCII440FXState *d); diff --git a/hw/piix_pci.c b/hw/piix_pci.c index f152a0f..56e3f61 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -55,6 +55,21 @@ struct PCII440FXState { #define I440FX_SMRAM 0x72 static void piix3_set_irq(void *opaque, int irq_num, int level); +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); + +static pci_set_irq_fn piix3_set_irq_handler = piix3_set_irq; +static pci_map_irq_fn piix3_map_irq_handler = pci_slot_get_pirq; + +/* Must be called before call i440fx_init() */ +void piix3_register_set_irq(pci_set_irq_fn set_irq) +{ + piix3_set_irq_handler = set_irq; +} + +void piix3_register_map_irq(pci_map_irq_fn map_irq) +{ + piix3_map_irq_handler = map_irq; +} /* return the global irq number corresponding to a given device irq pin. We could also use the bus number to have a more precise @@ -235,7 +250,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq * piix3 = DO_UPCAST(PIIX3State, dev, pci_create_simple_multifunction(b, -1, true, "PIIX3")); piix3->pic = pic; - pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4); + pci_bus_irqs(b, piix3_set_irq_handler, piix3_map_irq_handler, piix3, 4); (*pi440fx_state)->piix3 = piix3; *piix3_devfn = piix3->dev.devfn; diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index 58237d6..5d553b6 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -50,6 +50,18 @@ static void xen_vm_change_state_handler(void *opaque, int running, int reason) xen_main_loop_prepare(); } +static int xen_piix3_map_irq(PCIDevice *pci_dev, int irq_num) +{ + return irq_num + ((pci_dev->devfn >> 3) << 2); +} + +static void xen_piix3_set_irq(void *opaque, int irq_num, int level) +{ + xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2, + irq_num & 3, level); +} + + static void xen_init_fv(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -126,6 +138,8 @@ static void xen_init_fv(ram_addr_t ram_size, isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); + piix3_register_set_irq(xen_piix3_set_irq); + piix3_register_map_irq(xen_piix3_map_irq); pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size); isa_bus_irqs(isa_irq); -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:09 UTC
[Xen-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier
From: Anthony PERARD <anthony.perard@citrix.com> Introduce a write config notifier in piix_pci, so that clients can be notified every time a pci config write happens. The patch also makes use of the notification mechanism in xen_machine_fv. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- hw/pc.h | 1 + hw/piix_pci.c | 28 ++++++++++++++++++++++++++++ hw/xen_machine_fv.c | 16 ++++++++++++++++ 3 files changed, 45 insertions(+), 0 deletions(-) diff --git a/hw/pc.h b/hw/pc.h index ee562cd..3a745ae 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -141,6 +141,7 @@ typedef struct PCII440FXState PCII440FXState; void piix3_register_set_irq(pci_set_irq_fn set_irq); void piix3_register_map_irq(pci_map_irq_fn map_irq); +void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config); PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size); void i440fx_init_memory_mappings(PCII440FXState *d); diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 56e3f61..afa9e9d 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -49,6 +49,13 @@ struct PCII440FXState { PIIX3State *piix3; }; +typedef struct PCII440FXWriteConfigNotifier { + PCIConfigWriteFunc *write_config; + QLIST_ENTRY(PCII440FXWriteConfigNotifier) next; +} PCII440FXWriteConfigNotifier; + +static QLIST_HEAD(write_config_list, PCII440FXWriteConfigNotifier) write_config_list + = QLIST_HEAD_INITIALIZER(write_config_list); #define I440FX_PAM 0x59 #define I440FX_PAM_SIZE 7 @@ -71,6 +78,25 @@ void piix3_register_map_irq(pci_map_irq_fn map_irq) piix3_map_irq_handler = map_irq; } +void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config) +{ + PCII440FXWriteConfigNotifier *new_notifier; + + assert(write_config); + new_notifier = qemu_mallocz(sizeof(PCII440FXWriteConfigNotifier)); + new_notifier->write_config = write_config; + QLIST_INSERT_HEAD(&write_config_list, new_notifier, next); +} + +static void piix_pci_notify_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len) +{ + PCII440FXWriteConfigNotifier *notifier; + + QLIST_FOREACH(notifier, &write_config_list, next) { + notifier->write_config(dev, address, val, len); + } +} + /* return the global irq number corresponding to a given device irq pin. We could also use the bus number to have a more precise mapping. */ @@ -157,6 +183,8 @@ static void i440fx_write_config(PCIDevice *dev, { PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); + piix_pci_notify_write_config(dev, address, val, len); + /* XXX: implement SMRAM.D_LOCK */ pci_default_write_config(dev, address, val, len); if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) || diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index 5d553b6..77563db 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -61,6 +61,21 @@ static void xen_piix3_set_irq(void *opaque, int irq_num, int level) irq_num & 3, level); } +static void xen_piix_pci_write_config_client(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + int i; + + /* Scan for updates to PCI link routes (0x60-0x63). */ + for (i = 0; i < len; i++) { + uint8_t v = (val >> (8*i)) & 0xff; + if (v & 0x80) + v = 0; + v &= 0xf; + if (((address+i) >= 0x60) && ((address+i) <= 0x63)) + xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v); + } +} static void xen_init_fv(ram_addr_t ram_size, const char *boot_device, @@ -141,6 +156,7 @@ static void xen_init_fv(ram_addr_t ram_size, piix3_register_set_irq(xen_piix3_set_irq); piix3_register_map_irq(xen_piix3_map_irq); pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size); + piix_pci_register_write_config_notifier(i440fx_state, xen_piix_pci_write_config_client); isa_bus_irqs(isa_irq); pc_register_ferr_irq(isa_reserve_irq(13)); -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:10 UTC
[Xen-devel] [PATCH 13/15] vl.c: Introduce getter for shutdown_requested and reset_requested.
From: Anthony PERARD <anthony.perard@citrix.com> Introduce two functions qemu_shutdown_requested_get and qemu_reset_requested_get to get the value of shutdown/reset_requested without reset it. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- sysemu.h | 2 ++ vl.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/sysemu.h b/sysemu.h index a1f6466..7facfae 100644 --- a/sysemu.h +++ b/sysemu.h @@ -51,6 +51,8 @@ void cpu_disable_ticks(void); void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); +int qemu_shutdown_requested_get(void); +int qemu_reset_requested_get(void); int qemu_shutdown_requested(void); int qemu_reset_requested(void); int qemu_powerdown_requested(void); diff --git a/vl.c b/vl.c index b3e3676..1ff727f 100644 --- a/vl.c +++ b/vl.c @@ -1129,6 +1129,16 @@ static int powerdown_requested; int debug_requested; int vmstop_requested; +int qemu_shutdown_requested_get(void) +{ + return shutdown_requested; +} + +int qemu_reset_requested_get(void) +{ + return reset_requested; +} + int qemu_shutdown_requested(void) { int r = shutdown_requested; -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:10 UTC
[Xen-devel] [PATCH 14/15] xen: destroy the VM when shutdown is requested
From: Anthony PERARD <anthony.perard@citrix.com> Handle shutdown and reset requests in helper.c. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- target-xen/helper.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/target-xen/helper.c b/target-xen/helper.c index 4571ac0..16e628c 100644 --- a/target-xen/helper.c +++ b/target-xen/helper.c @@ -397,6 +397,23 @@ static void cpu_handle_ioreq(void *opaque) xen_wmb(); /* Update ioreq contents /then/ update state. */ + /* + * We do this before we send the response so that the tools + * have the opportunity to pick up on the reset before the + * guest resumes and does a hlt with interrupts disabled which + * causes Xen to powerdown the domain. + */ + if (vm_running) { + if (qemu_shutdown_requested_get()) { + fprintf(stderr, "shutdown requested in cpu_handle_ioreq\n"); + destroy_hvm_domain(); + } + if (qemu_reset_requested_get()) { + fprintf(stderr, "reset requested in cpu_handle_ioreq.\n"); + qemu_system_reset(); + } + } + req->state = STATE_IORESP_READY; xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); } -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
stefano.stabellini@eu.citrix.com
2010-Aug-12 14:10 UTC
[Xen-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
From: Anthony PERARD <anthony.perard@citrix.com> Xen currently uses a different BIOS (hvmloader + rombios) therefore the Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. We plan on fixing this properly but at the moment we are just adding a new Xen specific acpi_piix4 implementation. This patch is optional; without it the VM boots but it cannot shutdown properly or go to S3. Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- Makefile.target | 1 + hw/xen_acpi_piix4.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/xen_common.h | 3 + hw/xen_machine_fv.c | 6 +- 4 files changed, 429 insertions(+), 5 deletions(-) create mode 100644 hw/xen_acpi_piix4.c diff --git a/Makefile.target b/Makefile.target index 1984cdd..a2d9217 100644 --- a/Makefile.target +++ b/Makefile.target @@ -325,6 +325,7 @@ obj-xen-y += piix_pci.o obj-xen-y += mc146818rtc.o obj-xen-y += xenstore.o obj-xen-y += xen_platform.o +obj-xen-y += xen_acpi_piix4.o obj-xen-y += xen_mapcache.o obj-xen-y += stub-functions.o diff --git a/hw/xen_acpi_piix4.c b/hw/xen_acpi_piix4.c new file mode 100644 index 0000000..3c65963 --- /dev/null +++ b/hw/xen_acpi_piix4.c @@ -0,0 +1,424 @@ + /* + * PIIX4 ACPI controller emulation + * + * Winston liwen Wang, winston.l.wang@intel.com + * Copyright (c) 2006 , Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "pc.h" +#include "pci.h" +#include "sysemu.h" +#include "acpi.h" + +#include "xen_backend.h" +#include "xen_common.h" +#include "qemu-log.h" + +#include <xen/hvm/ioreq.h> +#include <xen/hvm/params.h> + +#define PIIX4ACPI_LOG_ERROR 0 +#define PIIX4ACPI_LOG_INFO 1 +#define PIIX4ACPI_LOG_DEBUG 2 +#define PIIX4ACPI_LOGLEVEL PIIX4ACPI_LOG_INFO +#define PIIX4ACPI_LOG(level, fmt, ...) do { if (level <= PIIX4ACPI_LOGLEVEL) qemu_log(fmt, ## __VA_ARGS__); } while (0) + +/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */ +/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */ +#define SLP_TYP_S4 (6 << 10) +#define SLP_TYP_S3 (5 << 10) +#define SLP_TYP_S5 (7 << 10) + +#define ACPI_DBG_IO_ADDR 0xb044 +#define ACPI_PHP_IO_ADDR 0x10c0 + +#define PHP_EVT_ADD 0x0 +#define PHP_EVT_REMOVE 0x3 + +/* The bit in GPE0_STS/EN to notify the pci hotplug event */ +#define ACPI_PHP_GPE_BIT 3 + +#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn >> 1) +#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg << 1) | hilo) + +/* ioport to monitor cpu add/remove status */ +#define PROC_BASE 0xaf00 + +typedef struct PCIAcpiState { + PCIDevice dev; + uint16_t pm1_control; /* pm1a_ECNT_BLK */ + qemu_irq irq; + qemu_irq cmos_s3; +} PCIAcpiState; + +typedef struct GPEState { + /* GPE0 block */ + uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2]; + uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2]; + + /* CPU bitmap */ + uint8_t cpus_sts[32]; + + /* SCI IRQ level */ + uint8_t sci_asserted; + +} GPEState; + +static GPEState gpe_state; + +static qemu_irq sci_irq; + +typedef struct AcpiDeviceState AcpiDeviceState; +AcpiDeviceState *acpi_device_table; + +static const VMStateDescription vmstate_acpi = { + .name = "PIIX4 ACPI", + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(dev, PCIAcpiState), + VMSTATE_UINT16(pm1_control, PCIAcpiState), + VMSTATE_END_OF_LIST() + } +}; + +static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PCIAcpiState *s = opaque; + s->pm1_control = (s->pm1_control & 0xff00) | (val & 0xff); +} + +static uint32_t acpiPm1Control_readb(void *opaque, uint32_t addr) +{ + PCIAcpiState *s = opaque; + /* Mask out the write-only bits */ + return (uint8_t)(s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)); +} + +static void acpi_shutdown(PCIAcpiState *s, uint32_t val) +{ + if (!(val & ACPI_BITMASK_SLEEP_ENABLE)) + return; + + switch (val & ACPI_BITMASK_SLEEP_TYPE) { + case SLP_TYP_S3: + qemu_system_reset(); + qemu_irq_raise(s->cmos_s3); + xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3); + break; + case SLP_TYP_S4: + case SLP_TYP_S5: + qemu_system_shutdown_request(); + break; + default: + break; + } +} + +static void acpiPm1ControlP1_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PCIAcpiState *s = opaque; + + val <<= 8; + s->pm1_control = ((s->pm1_control & 0xff) | val) & ~ACPI_BITMASK_SLEEP_ENABLE; + + acpi_shutdown(s, val); +} + +static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr) +{ + PCIAcpiState *s = opaque; + /* Mask out the write-only bits */ + return (uint8_t)((s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)) >> 8); +} + +static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val) +{ + PCIAcpiState *s = opaque; + + s->pm1_control = val & ~ACPI_BITMASK_SLEEP_ENABLE; + + acpi_shutdown(s, val); +} + +static uint32_t acpiPm1Control_readw(void *opaque, uint32_t addr) +{ + PCIAcpiState *s = opaque; + /* Mask out the write-only bits */ + return (s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)); +} + +static void acpi_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIAcpiState *d = (PCIAcpiState *)pci_dev; + + /* Byte access */ + register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d); + register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d); + register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d); + register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); + + /* Word access */ + register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d); + register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d); +} + +static inline int test_bit(uint8_t *map, int bit) +{ + return ( map[bit / 8] & (1 << (bit % 8)) ); +} + +static inline void set_bit(uint8_t *map, int bit) +{ + map[bit / 8] |= (1 << (bit % 8)); +} + +static inline void clear_bit(uint8_t *map, int bit) +{ + map[bit / 8] &= ~(1 << (bit % 8)); +} + +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "ACPI: DBG: 0x%08x\n", val); + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val); +} + +/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */ +static uint32_t gpe_sts_read(void *opaque, uint32_t addr) +{ + GPEState *s = opaque; + + return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS]; +} + +/* write 1 to clear specific GPE bits */ +static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val) +{ + GPEState *s = opaque; + int hotplugged = 0; + + PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val); + + hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT); + s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val; + if ( s->sci_asserted && + hotplugged && + !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) { + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n"); + qemu_irq_lower(sci_irq); + } + +} + +static uint32_t gpe_en_read(void *opaque, uint32_t addr) +{ + GPEState *s = opaque; + + return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)]; +} + +/* write 0 to clear en bit */ +static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val) +{ + GPEState *s = opaque; + int reg_count; + + PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val); + reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2); + s->gpe0_en[reg_count] = val; + /* If disable GPE bit right after generating SCI on it, + * need deassert the intr to avoid redundant intrs + */ + if ( s->sci_asserted && + reg_count == (ACPI_PHP_GPE_BIT / 8) && + !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) { + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "deassert due to disable GPE bit.\n"); + s->sci_asserted = 0; + qemu_irq_lower(sci_irq); + } + +} + +static void gpe_save(QEMUFile* f, void* opaque) +{ + GPEState *s = (GPEState*)opaque; + int i; + + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) { + qemu_put_8s(f, &s->gpe0_sts[i]); + qemu_put_8s(f, &s->gpe0_en[i]); + } + + qemu_put_8s(f, &s->sci_asserted); + if ( s->sci_asserted ) { + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n"); + } +} + +static int gpe_load(QEMUFile* f, void* opaque, int version_id) +{ + GPEState *s = (GPEState*)opaque; + int i; + if (version_id != 1) + return -EINVAL; + + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) { + qemu_get_8s(f, &s->gpe0_sts[i]); + qemu_get_8s(f, &s->gpe0_en[i]); + } + + qemu_get_8s(f, &s->sci_asserted); + return 0; +} + +static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr) +{ + uint32_t val = 0; + GPEState *g = opaque; + + switch (addr) { + case PROC_BASE ... PROC_BASE+31: + val = g->cpus_sts[addr - PROC_BASE]; + default: + break; + } + + return val; +} + +static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + /* GPEState *g = opaque; */ + + switch (addr) { + case PROC_BASE ... PROC_BASE + 31: + /* don''t allow to change cpus_sts from inside a guest */ + break; + default: + break; + } +} + +static void gpe_acpi_init(void) +{ + GPEState *s = &gpe_state; + memset(s, 0, sizeof(GPEState)); + + s->cpus_sts[0] = 1; + + register_ioport_read(PROC_BASE, 32, 1, gpe_cpus_readb, s); + register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s); + + register_ioport_read(ACPI_GPE0_BLK_ADDRESS, + ACPI_GPE0_BLK_LEN / 2, + 1, + gpe_sts_read, + s); + register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, + ACPI_GPE0_BLK_LEN / 2, + 1, + gpe_en_read, + s); + + register_ioport_write(ACPI_GPE0_BLK_ADDRESS, + ACPI_GPE0_BLK_LEN / 2, + 1, + gpe_sts_write, + s); + register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, + ACPI_GPE0_BLK_LEN / 2, + 1, + gpe_en_write, + s); + + register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s); +} + +static int piix4_pm_xen_initfn(PCIDevice *dev) +{ + PCIAcpiState *s = DO_UPCAST(PCIAcpiState, dev, dev); + uint8_t *pci_conf; + + pci_conf = s->dev.config; + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3); + pci_conf[0x08] = 0x01; /* B0 stepping */ + pci_conf[0x09] = 0x00; /* base class */ + pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); + pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */ + pci_conf[0x3d] = 0x01; /* Hardwired to PIRQA is used */ + + /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40 + * to make shutdown work for IPF, due to IPF Guest Firmware + * will enumerate pci devices. + * + * TODO: if Guest Firmware or Guest OS will change this PMBA, + * More logic will be added. + */ + pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */ + pci_conf[0x41] = 0x1f; + pci_conf[0x42] = 0x00; + pci_conf[0x43] = 0x00; + + s->pm1_control = ACPI_BITMASK_SCI_ENABLE; + + acpi_map((PCIDevice *)s, 0, 0x1f40, 0x10, PCI_BASE_ADDRESS_SPACE_IO); + + gpe_acpi_init(); + + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + + return 0; +} + +void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3) +{ + PCIDevice *dev; + PCIAcpiState *s; + + sci_irq = sci_irq_spec; + + dev = pci_create(bus, devfn, "PIIX4 ACPI"); + + s = DO_UPCAST(PCIAcpiState, dev, dev); + + s->irq = sci_irq_spec; + s->cmos_s3 = cmos_s3; + + qdev_init_nofail(&dev->qdev); +} + +static PCIDeviceInfo piix4_pm_xen_info = { + .qdev.name = "PIIX4 ACPI", + .qdev.desc = "dm", + .qdev.size = sizeof(PCIAcpiState), + .qdev.vmsd = &vmstate_acpi, + .init = piix4_pm_xen_initfn, +}; + +static void piix4_pm_xen_register(void) +{ + pci_qdev_register(&piix4_pm_xen_info); +} + +device_init(piix4_pm_xen_register); diff --git a/hw/xen_common.h b/hw/xen_common.h index 020fdd7..e1f07ba 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -34,4 +34,7 @@ /* hw/i8259-xen-stub.c */ qemu_irq *i8259_xen_init(void); +/* hw/xen_acpi_piix4.c */ +void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3); + #endif /* QEMU_HW_XEN_COMMON_H */ diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c index 77563db..bfda944 100644 --- a/hw/xen_machine_fv.c +++ b/hw/xen_machine_fv.c @@ -92,7 +92,6 @@ static void xen_init_fv(ram_addr_t ram_size, qemu_irq *isa_irq; qemu_irq *i8259; qemu_irq *cmos_s3; - qemu_irq *smi_irq; IsaIrqState *isa_irq_state; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; FDCtrl *floppy_controller; @@ -208,10 +207,7 @@ static void xen_init_fv(ram_addr_t ram_size, if (acpi_enabled) { cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); - smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); - piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, - isa_reserve_irq(9), *cmos_s3, *smi_irq, - 0); + piix4_pm_xen_init(pci_bus, piix3_devfn + 3, isa_reserve_irq(9), *cmos_s3); } if (i440fx_state) { -- 1.7.0.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > Update the libxenctrl calls in Qemu to use the new interface, otherwise > Qemu wouldn''t be able to build against new versions of the library.What''s the earliest version of libxc that will be supported after this patch? Thanks! Paolo _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-12 14:28 UTC
[Xen-devel] Re: [PATCH 01/15] xen: Update libxc calls
On Thu, 12 Aug 2010, Paolo Bonzini wrote:> On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote: > > From: Anthony PERARD<anthony.perard@citrix.com> > > > > Update the libxenctrl calls in Qemu to use the new interface, otherwise > > Qemu wouldn''t be able to build against new versions of the library. > > What''s the earliest version of libxc that will be supported after this > patch?xen-unstable only at the moment. We can probably add some #define so that qemu can work with both (old and new versions of libxc). _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-12 14:29 UTC
[Xen-devel] Re: [PATCH 01/15] xen: Update libxc calls
On Thu, 12 Aug 2010, Stefano Stabellini wrote:> On Thu, 12 Aug 2010, Paolo Bonzini wrote: > > On 08/12/2010 10:09 AM, stefano.stabellini@eu.citrix.com wrote: > > > From: Anthony PERARD<anthony.perard@citrix.com> > > > > > > Update the libxenctrl calls in Qemu to use the new interface, otherwise > > > Qemu wouldn''t be able to build against new versions of the library. > > > > What''s the earliest version of libxc that will be supported after this > > patch? > > xen-unstable only at the moment. > > We can probably add some #define so that qemu can work with both (old > and new versions of libxc). >I mean we can add them to libxc so that there is no need for this patch anymore. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-12 18:26 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > Introduce a new emulated PCI device, specific to fully virtualized Xen > guests.  The device is necessary for PV on HVM drivers to work.The code should be converted to qdev and VMState.> > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- >  Makefile.target   |   1 + >  hw/xen_machine_fv.c |   4 + >  hw/xen_platform.c  |  452 +++++++++++++++++++++++++++++++++++++++++++++++++++ >  hw/xen_platform.h  |   9 + >  4 files changed, 466 insertions(+), 0 deletions(-) >  create mode 100644 hw/xen_platform.c >  create mode 100644 hw/xen_platform.h > > diff --git a/Makefile.target b/Makefile.target > index d1b63f2..1984cdd 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -324,6 +324,7 @@ obj-xen-y += pc.o >  obj-xen-y += piix_pci.o >  obj-xen-y += mc146818rtc.o >  obj-xen-y += xenstore.o > +obj-xen-y += xen_platform.o > >  obj-xen-y += xen_mapcache.o >  obj-xen-y += stub-functions.o > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index 114addf..ec826e7 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -35,6 +35,7 @@ >  #include "xen_common.h" >  #include "xen_backend.h" >  #include "xenstore.h" > +#include "xen_platform.h" >  #include "xen/hvm/hvm_info_table.h" > >  #define MAX_IDE_BUS 2 > @@ -93,6 +94,9 @@ static void xen_init_fv(ram_addr_t ram_size, > >   pc_vga_init(pci_bus); > > +   pci_xen_platform_init(pci_bus); > +   platform_fixed_ioport_init(); > + >   /* init basic PC hardware */ >   pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state); > > diff --git a/hw/xen_platform.c b/hw/xen_platform.c > new file mode 100644 > index 0000000..85d3f8b > --- /dev/null > +++ b/hw/xen_platform.c > @@ -0,0 +1,452 @@ > +/* > + * XEN platform pci device, formerly known as the event channel device > + * > + * Copyright (c) 2003-2004 Intel Corp. > + * Copyright (c) 2006 XenSource > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "hw.h" > +#include "pc.h" > +#include "pci.h" > +#include "irq.h" > +#include "xen_common.h" > +#include "net.h" > +#include "xen_platform.h" > +#include "xen_backend.h" > +#include "qemu-log.h" > + > +#include <assert.h> > +#include <xenguest.h> > + > +static int drivers_blacklisted; > +static uint16_t driver_product_version; > +static int throttling_disabled; > +static char log_buffer[4096]; > +static int log_buffer_off; > + > +static uint8_t platform_flags;A lot of static variables. Could you put these to PCIXenPlatformState?> + > +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */ > + > +typedef struct PCIXenPlatformState > +{ > +   PCIDevice  pci_dev; > +} PCIXenPlatformState; > + > + > +/* We throttle access to dom0 syslog, to avoid DOS attacks.  This is > +  modelled as a token bucket, with one token for every byte of log. > +  The bucket size is 128KB (->1024 lines of 128 bytes each) and > +  refills at 256B/s.  It starts full.  The guest is blocked if no > +  tokens are available when it tries to generate a log message. */ > +#define BUCKET_MAX_SIZE (128*1024) > +#define BUCKET_FILL_RATE 256 > + > +static void throttle(unsigned count) > +{ > +   static unsigned available; > +   static struct timespec last_refil; > +   static int started; > +   static int warned; > + > +   struct timespec waiting_for, now; > +   double delay; > +   struct timespec ts; > + > +   if (throttling_disabled) > +     return; > + > +   if (!started) { > +     clock_gettime(CLOCK_MONOTONIC, &last_refil); > +     available = BUCKET_MAX_SIZE; > +     started = 1; > +   } > + > +   if (count > BUCKET_MAX_SIZE) { > +     fprintf(stderr, "tried to get %d tokens, but bucket size is %d\n", > +         BUCKET_MAX_SIZE, count); > +     exit(1); > +   } > + > +   if (available < count) { > +     /* The bucket is empty.  Refil it */ > + > +     /* When will it be full enough to handle this request? */ > +     delay = (double)(count - available) / BUCKET_FILL_RATE; > +     waiting_for = last_refil; > +     waiting_for.tv_sec += delay; > +     waiting_for.tv_nsec += (delay - (int)delay) * 1e9; > +     if (waiting_for.tv_nsec >= 1000000000) { > +       waiting_for.tv_nsec -= 1000000000; > +       waiting_for.tv_sec++; > +     } > + > +     /* How long do we have to wait? (might be negative) */ > +     clock_gettime(CLOCK_MONOTONIC, &now); > +     ts.tv_sec = waiting_for.tv_sec - now.tv_sec; > +     ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec; > +     if (ts.tv_nsec < 0) { > +       ts.tv_sec--; > +       ts.tv_nsec += 1000000000; > +     } > + > +     /* Wait for it. */ > +     if (ts.tv_sec > 0 || > +       (ts.tv_sec == 0 && ts.tv_nsec > 0)) { > +       if (!warned) { > +         fprintf(stderr, "throttling guest access to syslog"); > +         warned = 1; > +       } > +       while (nanosleep(&ts, &ts) < 0 && errno == EINTR) > +         ; > +     } > + > +     /* Refil */ > +     clock_gettime(CLOCK_MONOTONIC, &now); > +     delay = (now.tv_sec - last_refil.tv_sec) + > +       (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9; > +     available += BUCKET_FILL_RATE * delay; > +     if (available > BUCKET_MAX_SIZE) > +       available = BUCKET_MAX_SIZE; > +     last_refil = now; > +   } > + > +   assert(available >= count); > + > +   available -= count; > +} > + > +#define UNPLUG_ALL_IDE_DISKS 1 > +#define UNPLUG_ALL_NICS 2 > +#define UNPLUG_AUX_IDE_DISKS 4These should go to the top of the file. Are they even used, the function below doesn''t?> + > +static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val) > +{ > +   switch (addr - 0x10) {0x10 should be a #define, which should be used...> +   case 0: > +     /* Unplug devices.  Value is a bitmask of which devices to > +      unplug, with bit 0 the IDE devices, bit 1 the network > +      devices, and bit 2 the non-primary-master IDE devices. */ > +     break; > +   case 2: > +     switch (val) { > +     case 1: > +       fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n"); > +       break; > +     case 0: > +       fprintf(stderr, "Guest claimed to be running PV product 0?\n"); > +       break; > +     default: > +       fprintf(stderr, "Unknown PV product %d loaded in guest\n", val); > +       break; > +     } > +     driver_product_version = val; > +     break; > +   } > +} > + > +static void platform_fixed_ioport_write4(void *opaque, uint32_t addr, > +                     uint32_t val) > +{ > +   switch (addr - 0x10) {... here ...> +   case 0: > +     /* PV driver version */ > +     break; > +   } > +} > + > +static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val) > +{ > +   switch (addr - 0x10) {... here ...> +   case 0: /* Platform flags */ { > +     hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ? > +       HVMMEM_ram_ro : HVMMEM_ram_rw; > +     if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) > +       fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw " > +           "state of ROM memory area!\n");Please introduce a macro (DPRINTF) and use that.> +     else { > +       platform_flags = val & PFFLAG_ROM_LOCK; > +       fprintf(stderr,"platform_fixed_ioport: changed ro/rw " > +           "state of ROM memory area. now is %s state.\n", > +           (mem_type == HVMMEM_ram_ro ? "ro":"rw")); > +     } > +     break; > +   } > +   case 2: > +     /* Send bytes to syslog */ > +     if (val == ''\n'' || log_buffer_off == sizeof(log_buffer) - 1) { > +       /* Flush buffer */ > +       log_buffer[log_buffer_off] = 0; > +       throttle(log_buffer_off); > +       fprintf(stderr, "%s\n", log_buffer); > +       log_buffer_off = 0; > +       break; > +     } > +     log_buffer[log_buffer_off++] = val; > +     break; > +   } > +} > + > +static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr) > +{ > +   switch (addr - 0x10) {... here ...> +   case 0: > +     if (drivers_blacklisted) { > +       /* The drivers will recognise this magic number and refuse > +       * to do anything. */ > +       return 0xd249; > +     } else { > +       /* Magic value so that you can identify the interface. */ > +       return 0x49d2; > +     } > +   default: > +     return 0xffff; > +   } > +} > + > +static uint32_t platform_fixed_ioport_read1(void *opaque, uint32_t addr) > +{ > +   switch (addr - 0x10) {... here ...> +   case 0: > +     /* Platform flags */ > +     return platform_flags; > +   case 2: > +     /* Version number */ > +     return 1; > +   default: > +     return 0xff; > +   } > +} > + > +static void platform_fixed_ioport_save(QEMUFile *f, void *opaque) > +{ > +   qemu_put_8s(f, &platform_flags); > +} > + > +static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id) > +{ > +   uint8_t flags; > + > +   if (version_id > 1) > +     return -EINVAL; > + > +   qemu_get_8s(f, &flags); > +   platform_fixed_ioport_write1(NULL, 0x10, flags); > + > +   return 0; > +} > + > +void platform_fixed_ioport_init(void) > +{ > +   register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save, > +           platform_fixed_ioport_load, NULL);Please use VMState instead.> + > +   register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL);and here and below. In fact, just s/0x10/XEN_PLATFORM_IOPORT/g.> +   register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL); > +   register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL); > +   register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL); > +   register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL); > + > +   platform_fixed_ioport_write1(NULL, 0x10, 0);Introduce a reset function which performs something similar.> +} > + > +static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr) > +{ > +   addr &= 0xff; > + > +   return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u;Just use if.> +} > + > +static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > +   addr &= 0xff; > +   val  &= 0xff; > + > +   switch (addr) { > +   case 0: /* Platform flags */ > +     platform_fixed_ioport_write1(NULL, 0x10, val); > +     break; > +   case 8: > +     { > +       if (val == ''\n'' || log_buffer_off == sizeof(log_buffer) - 1) { > +         /* Flush buffer */ > +         log_buffer[log_buffer_off] = 0; > +         throttle(log_buffer_off); > +         fprintf(stderr, "%s\n", log_buffer); > +         log_buffer_off = 0; > +         break; > +       } > +       log_buffer[log_buffer_off++] = val; > +     } > +     break; > +   default: > +     break; > +   } > +} > + > +static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type) > +{ > +   PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev;Useless cast in C. Moreover, you should use DO_UPCAST or container_of.> +   register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d); > +   register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d); > +} > + > +static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr) > +{ > +   static int warnings = 0; > +   if (warnings < 5) { > +     fprintf(stderr, "Warning: attempted read from physical address " > +         "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)addr);Instead of the cast, you should use TARGET_FMT_plx.> +     warnings++; > +   } > +   return 0; > +} > + > +static void platform_mmio_write(void *opaque, target_phys_addr_t addr, > +                 uint32_t val) > +{ > +   static int warnings = 0; > +   if (warnings < 5) { > +     fprintf(stderr, "Warning: attempted write of 0x%x to physical " > +         "address 0x%"PRIx64" in xen platform mmio space\n", > +         val, (uint64_t)addr); > +     warnings++; > +   } > +   return; > +} > + > +static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = {These should be ''const''.> +   platform_mmio_read, > +   platform_mmio_read, > +   platform_mmio_read, > +}; > + > +static CPUWriteMemoryFunc *platform_mmio_write_funcs[3] = { > +   platform_mmio_write, > +   platform_mmio_write, > +   platform_mmio_write, > +}; > + > +static void platform_mmio_map(PCIDevice *d, int region_num, > +                pcibus_t addr, pcibus_t size, int type) > +{ > +   int mmio_io_addr; > + > +   mmio_io_addr = cpu_register_io_memory(platform_mmio_read_funcs, > +                      platform_mmio_write_funcs, NULL); > + > +   cpu_register_physical_memory(addr, 0x1000000, mmio_io_addr); > +} > + > +struct pci_config_header { > +   uint16_t vendor_id; > +   uint16_t device_id; > +   uint16_t command; > +   uint16_t status; > +   uint8_t  revision; > +   uint8_t  api; > +   uint8_t  subclass; > +   uint8_t  class; > +   uint8_t  cache_line_size; /* Units of 32 bit words */ > +   uint8_t  latency_timer; /* In units of bus cycles */ > +   uint8_t  header_type; /* Should be 0 */ > +   uint8_t  bist; /* Built in self test */ > +   uint32_t base_address_regs[6]; > +   uint32_t reserved1; > +   uint16_t subsystem_vendor_id; > +   uint16_t subsystem_id; > +   uint32_t rom_addr; > +   uint32_t reserved3; > +   uint32_t reserved4; > +   uint8_t  interrupt_line; > +   uint8_t  interrupt_pin; > +   uint8_t  min_gnt; > +   uint8_t  max_lat; > +};Why can''t you use the facilities from pci.h?> + > +static void xen_pci_save(QEMUFile *f, void *opaque) > +{ > +   PCIXenPlatformState *d = opaque; > +   uint64_t t = 0; > + > +   pci_device_save(&d->pci_dev, f); > +   qemu_put_be64s(f, &t); > +} > + > +static int xen_pci_load(QEMUFile *f, void *opaque, int version_id) > +{ > +   PCIXenPlatformState *d = opaque; > +   int ret; > + > +   if (version_id > 3) > +     return -EINVAL; > + > +   ret = pci_device_load(&d->pci_dev, f); > +   if (ret < 0) > +     return ret; > + > +   if (version_id >= 2) { > +     if (version_id == 2) { > +       uint8_t flags; > +       qemu_get_8s(f, &flags); > +       xen_platform_ioport_writeb(d, 0, flags); > +     } > +     qemu_get_be64(f); > +   } > + > +   return 0; > +} > + > +void pci_xen_platform_init(PCIBus *bus) > +{ > +   PCIXenPlatformState *d; > +   struct pci_config_header *pch; > + > +   printf("Register xen platform.\n"); > +   d = (PCIXenPlatformState *)pci_register_device( > +     bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL); > +   pch = (struct pci_config_header *)d->pci_dev.config; > +   pch->vendor_id = 0x5853;You should use pci_set_word etc. Please add 0x5853 to pci_ids.h.> +   pch->device_id = 0x0001; > +   pch->command = 3; /* IO and memory access */ > +   pch->revision = 1; > +   pch->api = 0; > +   pch->subclass = 0x80; /* Other */ > +   pch->class = 0xff; /* Unclassified device class */ > +   pch->header_type = 0; > +   pch->interrupt_pin = 1; > + > +   /* Microsoft WHQL requires non-zero subsystem IDs. */ > +   /* http://www.pcisig.com/reflector/msg02205.html.  */ > +   pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id.  */ > +   pch->subsystem_id     = 0x0001;     /* Hardcode sub-id as 1. */ > + > +   pci_register_bar(&d->pci_dev, 0, 0x100, > +              PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map); > + > +   /* reserve 16MB mmio address for share memory*/ > +   pci_register_bar(&d->pci_dev, 1, 0x1000000, > +              PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map); > + > +   register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d); > +   printf("Done register platform.\n"); > +} > + > diff --git a/hw/xen_platform.h b/hw/xen_platform.h > new file mode 100644 > index 0000000..6eeff22 > --- /dev/null > +++ b/hw/xen_platform.h > @@ -0,0 +1,9 @@ > +#ifndef XEN_PLATFORM_H > +#define XEN_PLATFORM_H > + > +#include "hw/pci.h" > + > +void pci_xen_platform_init(PCIBus *bus); > +void platform_fixed_ioport_init(void); > + > +#endif > -- > 1.7.0.4 > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-12 18:35 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier
On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > Introduce a write config notifier in piix_pci, so that clients can be > notified every time a pci config write happens. > The patch also makes use of the notification mechanism in > xen_machine_fv.Will the mechanism be used elsewhere? If not, I''d just add a call to xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and friends.> > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- >  hw/pc.h       |   1 + >  hw/piix_pci.c    |  28 ++++++++++++++++++++++++++++ >  hw/xen_machine_fv.c |  16 ++++++++++++++++ >  3 files changed, 45 insertions(+), 0 deletions(-) > > diff --git a/hw/pc.h b/hw/pc.h > index ee562cd..3a745ae 100644 > --- a/hw/pc.h > +++ b/hw/pc.h > @@ -141,6 +141,7 @@ typedef struct PCII440FXState PCII440FXState; > >  void piix3_register_set_irq(pci_set_irq_fn set_irq); >  void piix3_register_map_irq(pci_map_irq_fn map_irq); > +void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config); >  PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size); >  void i440fx_init_memory_mappings(PCII440FXState *d); > > diff --git a/hw/piix_pci.c b/hw/piix_pci.c > index 56e3f61..afa9e9d 100644 > --- a/hw/piix_pci.c > +++ b/hw/piix_pci.c > @@ -49,6 +49,13 @@ struct PCII440FXState { >   PIIX3State *piix3; >  }; > > +typedef struct PCII440FXWriteConfigNotifier { > +   PCIConfigWriteFunc *write_config; > +   QLIST_ENTRY(PCII440FXWriteConfigNotifier) next; > +} PCII440FXWriteConfigNotifier; > + > +static QLIST_HEAD(write_config_list, PCII440FXWriteConfigNotifier) write_config_list > +   = QLIST_HEAD_INITIALIZER(write_config_list); > >  #define I440FX_PAM    0x59 >  #define I440FX_PAM_SIZE 7 > @@ -71,6 +78,25 @@ void piix3_register_map_irq(pci_map_irq_fn map_irq) >   piix3_map_irq_handler = map_irq; >  } > > +void piix_pci_register_write_config_notifier(PCII440FXState *d, PCIConfigWriteFunc *write_config) > +{ > +   PCII440FXWriteConfigNotifier *new_notifier; > + > +   assert(write_config); > +   new_notifier = qemu_mallocz(sizeof(PCII440FXWriteConfigNotifier)); > +   new_notifier->write_config = write_config; > +   QLIST_INSERT_HEAD(&write_config_list, new_notifier, next); > +} > + > +static void piix_pci_notify_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len) > +{ > +   PCII440FXWriteConfigNotifier *notifier; > + > +   QLIST_FOREACH(notifier, &write_config_list, next) { > +     notifier->write_config(dev, address, val, len); > +   } > +} > + >  /* return the global irq number corresponding to a given device irq >   pin. We could also use the bus number to have a more precise >   mapping. */ > @@ -157,6 +183,8 @@ static void i440fx_write_config(PCIDevice *dev, >  { >   PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); > > +   piix_pci_notify_write_config(dev, address, val, len); > + >   /* XXX: implement SMRAM.D_LOCK */ >   pci_default_write_config(dev, address, val, len); >   if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) || > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index 5d553b6..77563db 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -61,6 +61,21 @@ static void xen_piix3_set_irq(void *opaque, int irq_num, int level) >       irq_num & 3, level); >  } > > +static void xen_piix_pci_write_config_client(PCIDevice *dev, > +     uint32_t address, uint32_t val, int len) > +{ > +   int i; > + > +   /* Scan for updates to PCI link routes (0x60-0x63). */ > +   for (i = 0; i < len; i++) { > +     uint8_t v = (val >> (8*i)) & 0xff; > +     if (v & 0x80) > +       v = 0; > +     v &= 0xf; > +     if (((address+i) >= 0x60) && ((address+i) <= 0x63)) > +       xc_hvm_set_pci_link_route(xen_xc, xen_domid, address + i - 0x60, v); > +   } > +} > >  static void xen_init_fv(ram_addr_t ram_size, >             const char *boot_device, > @@ -141,6 +156,7 @@ static void xen_init_fv(ram_addr_t ram_size, >   piix3_register_set_irq(xen_piix3_set_irq); >   piix3_register_map_irq(xen_piix3_map_irq); >   pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size); > +   piix_pci_register_write_config_notifier(i440fx_state, xen_piix_pci_write_config_client); >   isa_bus_irqs(isa_irq); > >   pc_register_ferr_irq(isa_reserve_irq(13)); > -- > 1.7.0.4 > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-12 18:42 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > Open and bind event channels; map ioreq and buffered ioreq rings. > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- >  hw/xen_machine_fv.c  |  25 ++++ >  target-xen/cpu.h    |   1 + >  target-xen/helper.c  |  362 +++++++++++++++++++++++++++++++++++++++++++++++++ >  target-xen/qemu-xen.h |   2 + >  4 files changed, 390 insertions(+), 0 deletions(-) > > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index a6e778a..b1bc88d 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -22,6 +22,9 @@ >  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN >  * THE SOFTWARE. >  */ > +#include "config.h" > + > +#include <sys/mman.h> > >  #include "hw.h" >  #include "pc.h" > @@ -71,12 +74,34 @@ static void xen_init_fv(ram_addr_t ram_size, > >   CPUState *env; > > +   unsigned long ioreq_pfn; > +   extern void *shared_page; > +   extern void *buffered_io_page;These should be defined in a header file.> + >   /* Initialize backend core & drivers */ >   if (xen_dm_init() != 0) { >     fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); >     exit(1); >   } > > +   xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); > +   fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn); > +   shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, > +       PROT_READ|PROT_WRITE, ioreq_pfn); > +   if (shared_page == NULL) { > +     fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc);hw_error()?> +     exit(-1); > +   } > + > +   xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); > +   fprintf(stderr, "buffered io page at pfn %lx\n", ioreq_pfn); > +   buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, > +                       PROT_READ|PROT_WRITE, ioreq_pfn); > +   if (buffered_io_page == NULL) { > +     fprintf(logfile, "map buffered IO page returned error %d\n", errno); > +     exit(-1); > +   } > + >   /* Initialize a dummy CPU */ >   if (cpu_model == NULL) { >  #ifdef TARGET_X86_64 > diff --git a/target-xen/cpu.h b/target-xen/cpu.h > index 5a45d1c..573241f 100644 > --- a/target-xen/cpu.h > +++ b/target-xen/cpu.h > @@ -72,6 +72,7 @@ typedef struct CPUXenState { > >  CPUXenState *cpu_xen_init(const char *cpu_model); >  int cpu_xen_exec(CPUXenState *s); > +void cpu_xen_close(CPUXenState *s); > >  int cpu_get_pic_interrupt(CPUXenState *s); >  void cpu_set_ferr(CPUX86State *s); > diff --git a/target-xen/helper.c b/target-xen/helper.c > index 8cb7771..4571ac0 100644 > --- a/target-xen/helper.c > +++ b/target-xen/helper.c > @@ -18,25 +18,77 @@ >  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA >  */ > > +#include "config.h" > + > +#include <inttypes.h> > + > +#include <xenctrl.h> > +#include <xen/hvm/ioreq.h> > + >  #include "cpu.h" >  #include "qemu-xen.h" >  #include "xenstore.h" > +#include "hw/xen_backend.h" > + > +long time_offset = 0; > + > +shared_iopage_t *shared_page = NULL; > + > +#define BUFFER_IO_MAX_DELAY  100 > +buffered_iopage_t *buffered_io_page = NULL; > +QEMUTimer *buffered_io_timer; > + > +/* the evtchn fd for polling */ > +int xce_handle = -1; > + > +/* which vcpu we are serving */ > +int send_vcpu = 0; > + > +/* the evtchn port for polling the notification, */ > +evtchn_port_t *ioreq_local_port; > >  CPUXenState *cpu_xen_init(const char *cpu_model) >  { >   CPUXenState *env = NULL; >   static int inited; > +   int i, rc; > >   env = qemu_mallocz(sizeof(CPUXenState)); >   if (!env) >     return NULL; >   cpu_exec_init(env); > > +   /* There is no shared_page for PV, we''re done now */ > +   if (shared_page == NULL) > +     return env; > + > +   ioreq_local_port > +     (evtchn_port_t *)qemu_mallocz(smp_cpus * sizeof(evtchn_port_t)); > +   if (!ioreq_local_port) > +     return NULL; > + >   /* init various static tables */ >   if (!inited) { >     inited = 1; > >     cpu_single_env = env; > + > +     xce_handle = xc_evtchn_open(); > +     if (xce_handle == -1) { > +       perror("open"); > +       return NULL; > +     } > + > +     /* FIXME: how about if we overflow the page here? */ > +     for (i = 0; i < smp_cpus; i++) { > +       rc = xc_evtchn_bind_interdomain( > +           xce_handle, xen_domid, shared_page->vcpu_ioreq[i].vp_eport); > +       if (rc == -1) { > +         fprintf(stderr, "bind interdomain ioctl error %d\n", errno); > +         return NULL; > +       } > +       ioreq_local_port[i] = rc; > +     } >   } > >   return env; > @@ -70,7 +122,317 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) >   return addr; >  } > > +// get the ioreq packets from share mem > +static ioreq_t *__cpu_get_ioreq(int vcpu)Don''t use names with leading underscores.> +{ > +   ioreq_t *req = &shared_page->vcpu_ioreq[vcpu]; > + > +   if (req->state != STATE_IOREQ_READY) { > +     fprintf(stderr, "I/O request not ready: " > +         "%x, ptr: %x, port: %"PRIx64", " > +         "data: %"PRIx64", count: %u, size: %u\n", > +         req->state, req->data_is_ptr, req->addr, > +         req->data, req->count, req->size); > +     return NULL; > +   } > + > +   xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */ > + > +   req->state = STATE_IOREQ_INPROCESS; > +   return req; > +} > + > +// use poll to get the port notification > +// ioreq_vec--out,the > +// retval--the number of ioreq packet > +static ioreq_t *cpu_get_ioreq(void) > +{ > +   int i; > +   evtchn_port_t port; > + > +   port = xc_evtchn_pending(xce_handle); > +   if (port != -1) { > +     for ( i = 0; i < smp_cpus; i++ ) > +       if ( ioreq_local_port[i] == port ) > +         break; > + > +     if ( i == smp_cpus ) { > +       fprintf(stderr, "Fatal error while trying to get io event!\n"); > +       exit(1); > +     } > + > +     // unmask the wanted port again > +     xc_evtchn_unmask(xce_handle, port); > + > +     // get the io packet from shared memory > +     send_vcpu = i; > +     return __cpu_get_ioreq(i); > +   } > + > +   // read error or read nothing > +   return NULL; > +} > + > +static unsigned long do_inp(CPUState *env, unsigned long addr, > +     unsigned long size) > +{ > +   switch(size) { > +     case 1: > +       return cpu_inb(addr); > +     case 2: > +       return cpu_inw(addr); > +     case 4: > +       return cpu_inl(addr); > +     default: > +       fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size); > +       exit(-1); > +   } > +} > + > +static void do_outp(CPUState *env, unsigned long addr, > +     unsigned long size, unsigned long val) > +{ > +   switch(size) { > +     case 1: > +       return cpu_outb(addr, val); > +     case 2: > +       return cpu_outw(addr, val); > +     case 4: > +       return cpu_outl(addr, val); > +     default: > +       fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size); > +       exit(-1); > +   } > +} > + > +static inline void read_physical(uint64_t addr, unsigned long size, void *val) > +{ > +   return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0); > +} > + > +static inline void write_physical(uint64_t addr, unsigned long size, void *val) > +{ > +   return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1); > +}Useless redirection?> + > +static void cpu_ioreq_pio(CPUState *env, ioreq_t *req) > +{ > +   int i, sign; > + > +   sign = req->df ? -1 : 1; > + > +   if (req->dir == IOREQ_READ) { > +     if (!req->data_is_ptr) { > +       req->data = do_inp(env, req->addr, req->size); > +     } else { > +       unsigned long tmp; > + > +       for (i = 0; i < req->count; i++) { > +         tmp = do_inp(env, req->addr, req->size); > +         write_physical((target_phys_addr_t) req->data > +             + (sign * i * req->size), > +             req->size, &tmp); > +       } > +     } > +   } else if (req->dir == IOREQ_WRITE) { > +     if (!req->data_is_ptr) { > +       do_outp(env, req->addr, req->size, req->data); > +     } else { > +       for (i = 0; i < req->count; i++) { > +         unsigned long tmp = 0; > + > +         read_physical((target_phys_addr_t) req->data > +             + (sign * i * req->size), > +             req->size, &tmp); > +         do_outp(env, req->addr, req->size, tmp); > +       } > +     } > +   } > +} > + > +static void cpu_ioreq_move(CPUState *env, ioreq_t *req) > +{ > +   int i, sign; > + > +   sign = req->df ? -1 : 1; > + > +   if (!req->data_is_ptr) { > +     if (req->dir == IOREQ_READ) { > +       for (i = 0; i < req->count; i++) { > +         read_physical(req->addr > +             + (sign * i * req->size), > +             req->size, &req->data); > +       } > +     } else if (req->dir == IOREQ_WRITE) { > +       for (i = 0; i < req->count; i++) { > +         write_physical(req->addr > +             + (sign * i * req->size), > +             req->size, &req->data); > +       } > +     } > +   } else { > +     target_ulong tmp; > + > +     if (req->dir == IOREQ_READ) { > +       for (i = 0; i < req->count; i++) { > +         read_physical(req->addr > +             + (sign * i * req->size), > +             req->size, &tmp); > +         write_physical((target_phys_addr_t )req->data > +             + (sign * i * req->size), > +             req->size, &tmp); > +       } > +     } else if (req->dir == IOREQ_WRITE) { > +       for (i = 0; i < req->count; i++) { > +         read_physical((target_phys_addr_t) req->data > +             + (sign * i * req->size), > +             req->size, &tmp); > +         write_physical(req->addr > +             + (sign * i * req->size), > +             req->size, &tmp); > +       } > +     } > +   } > +} > + > +static void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req) > +{ > +   char b[64]; > + > +   time_offset += (unsigned long)req->data; > + > +   fprintf(stderr, "Time offset set %ld, added offset %"PRId64"\n", > +       time_offset, req->data); > +   sprintf(b, "%ld", time_offset);snprintf> +   xenstore_vm_write(xen_domid, "rtc/timeoffset", b); > +} > + > +static void __handle_ioreq(CPUState *env, ioreq_t *req) > +{ > +   if (!req->data_is_ptr && (req->dir == IOREQ_WRITE) && > +       (req->size < sizeof(target_ulong))) > +     req->data &= ((target_ulong)1 << (8 * req->size)) - 1; > + > +   switch (req->type) { > +     case IOREQ_TYPE_PIO: > +       cpu_ioreq_pio(env, req); > +       break; > +     case IOREQ_TYPE_COPY: > +       cpu_ioreq_move(env, req); > +       break; > +     case IOREQ_TYPE_TIMEOFFSET: > +       cpu_ioreq_timeoffset(env, req); > +       break; > +     case IOREQ_TYPE_INVALIDATE: > +       qemu_invalidate_map_cache(); > +       break; > +     default: > +       hw_error("Invalid ioreq type 0x%x\n", req->type); > +   } > +} > + > +static void __handle_buffered_iopage(CPUState *env) > +{ > +   buf_ioreq_t *buf_req = NULL; > +   ioreq_t req; > +   int qw; > + > +   if (!buffered_io_page) > +     return; > + > +   while (buffered_io_page->read_pointer !> +       buffered_io_page->write_pointer) { > +     buf_req = &buffered_io_page->buf_ioreq[ > +       buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM]; > +     req.size = 1UL << buf_req->size; > +     req.count = 1; > +     req.addr = buf_req->addr; > +     req.data = buf_req->data; > +     req.state = STATE_IOREQ_READY; > +     req.dir = buf_req->dir; > +     req.df = 1; > +     req.type = buf_req->type; > +     req.data_is_ptr = 0; > +     qw = (req.size == 8); > +     if (qw) { > +       buf_req = &buffered_io_page->buf_ioreq[ > +         (buffered_io_page->read_pointer+1) % IOREQ_BUFFER_SLOT_NUM]; > +       req.data |= ((uint64_t)buf_req->data) << 32; > +     } > + > +     __handle_ioreq(env, &req); > + > +     xen_mb(); > +     buffered_io_page->read_pointer += qw ? 2 : 1; > +   } > +} > + > +static void handle_buffered_io(void *opaque) > +{ > +   CPUState *env = opaque; > + > +   __handle_buffered_iopage(env); > +   qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY + > +          qemu_get_clock(rt_clock)); > +} > + > +static void cpu_handle_ioreq(void *opaque) > +{ > +   CPUState *env = opaque; > +   ioreq_t *req = cpu_get_ioreq(); > + > +   __handle_buffered_iopage(env); > +   if (req) { > +     __handle_ioreq(env, req); > + > +     if (req->state != STATE_IOREQ_INPROCESS) { > +       fprintf(stderr, "Badness in I/O request ... not in service?!: " > +           "%x, ptr: %x, port: %"PRIx64", " > +           "data: %"PRIx64", count: %u, size: %u\n", > +           req->state, req->data_is_ptr, req->addr, > +           req->data, req->count, req->size); > +       destroy_hvm_domain(); > +       return; > +     } > + > +     xen_wmb(); /* Update ioreq contents /then/ update state. */ > + > +     req->state = STATE_IORESP_READY; > +     xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); > +   } > +} > + >  void xen_main_loop_prepare(void) >  { > +   CPUState *env = cpu_single_env; > + > +   int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle); > + > +   buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io, > +                    cpu_single_env); > +   qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock)); > + > +   if (evtchn_fd != -1) > +     qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); > + >   xenstore_record_dm_state("running"); >  } > + > +void destroy_hvm_domain(void) > +{ > +   xc_interface *xcHandle;xc_handle or something.> +   int sts; > + > +   xcHandle = xc_interface_open(NULL, NULL, 0); > +   if (xcHandle < 0) > +     fprintf(stderr, "Cannot acquire xenctrl handle\n"); > +   else { > +     sts = xc_domain_shutdown(xcHandle, xen_domid, SHUTDOWN_poweroff); > +     if (sts != 0) > +       fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, " > +           "sts %d, errno %d\n", sts, errno); > +     else > +       fprintf(stderr, "Issued domain %d poweroff\n", xen_domid); > +     xc_interface_close(xcHandle); > +   } > +} > diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h > index 091ae07..79a4638 100644 > --- a/target-xen/qemu-xen.h > +++ b/target-xen/qemu-xen.h > @@ -22,12 +22,14 @@ void   qemu_invalidate_map_cache(void); > >  /* target-xen/exec-dm.c */ > > +void destroy_hvm_domain(void); >  int cpu_register_io_memory_fixed(int io_index, >               CPUReadMemoryFunc * const *mem_read, >               CPUWriteMemoryFunc * const *mem_write, >               void *opaque); > >  /* target-xen/helper.c */ > +extern int xce_handle; >  void xen_main_loop_prepare(void); > >  #endif /*QEMU_XEN_H*/ > -- > 1.7.0.4 > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-12 18:44 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > This patch introduces a generic function registration mechanism for > set_irq and map_irq in piix3, so that the two calls can be > overridden with platform specific functions whenever needed. > The patch also implements and registers the Xen specific version of the > functions.I''d avoid the registration, see my comments for the other registration patch.> > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- >  hw/pc.h       |   3 +++ >  hw/piix_pci.c    |  17 ++++++++++++++++- >  hw/xen_machine_fv.c |  14 ++++++++++++++ >  3 files changed, 33 insertions(+), 1 deletions(-) > > diff --git a/hw/pc.h b/hw/pc.h > index 63b0249..ee562cd 100644 > --- a/hw/pc.h > +++ b/hw/pc.h > @@ -5,6 +5,7 @@ >  #include "ioport.h" >  #include "isa.h" >  #include "fdc.h" > +#include "pci.h" > >  /* PC-style peripherals (also used by other machines).  */ > > @@ -138,6 +139,8 @@ int pcspk_audio_init(qemu_irq *pic); >  struct PCII440FXState; >  typedef struct PCII440FXState PCII440FXState; > > +void piix3_register_set_irq(pci_set_irq_fn set_irq); > +void piix3_register_map_irq(pci_map_irq_fn map_irq); >  PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size); >  void i440fx_init_memory_mappings(PCII440FXState *d); > > diff --git a/hw/piix_pci.c b/hw/piix_pci.c > index f152a0f..56e3f61 100644 > --- a/hw/piix_pci.c > +++ b/hw/piix_pci.c > @@ -55,6 +55,21 @@ struct PCII440FXState { >  #define I440FX_SMRAM   0x72 > >  static void piix3_set_irq(void *opaque, int irq_num, int level); > +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); > + > +static pci_set_irq_fn piix3_set_irq_handler = piix3_set_irq; > +static pci_map_irq_fn piix3_map_irq_handler = pci_slot_get_pirq; > + > +/* Must be called before call i440fx_init() */ > +void piix3_register_set_irq(pci_set_irq_fn set_irq) > +{ > +   piix3_set_irq_handler = set_irq; > +} > + > +void piix3_register_map_irq(pci_map_irq_fn map_irq) > +{ > +   piix3_map_irq_handler = map_irq; > +} > >  /* return the global irq number corresponding to a given device irq >   pin. We could also use the bus number to have a more precise > @@ -235,7 +250,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq * >   piix3 = DO_UPCAST(PIIX3State, dev, >            pci_create_simple_multifunction(b, -1, true, "PIIX3")); >   piix3->pic = pic; > -   pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4); > +   pci_bus_irqs(b, piix3_set_irq_handler, piix3_map_irq_handler, piix3, 4); >   (*pi440fx_state)->piix3 = piix3; > >   *piix3_devfn = piix3->dev.devfn; > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index 58237d6..5d553b6 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -50,6 +50,18 @@ static void xen_vm_change_state_handler(void *opaque, int running, int reason) >     xen_main_loop_prepare(); >  } > > +static int xen_piix3_map_irq(PCIDevice *pci_dev, int irq_num) > +{ > +   return irq_num + ((pci_dev->devfn >> 3) << 2); > +} > + > +static void xen_piix3_set_irq(void *opaque, int irq_num, int level) > +{ > +   xc_hvm_set_pci_intx_level(xen_xc, xen_domid, 0, 0, irq_num >> 2, > +       irq_num & 3, level); > +} > + > + >  static void xen_init_fv(ram_addr_t ram_size, >             const char *boot_device, >             const char *kernel_filename, > @@ -126,6 +138,8 @@ static void xen_init_fv(ram_addr_t ram_size, > >   isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); > > +   piix3_register_set_irq(xen_piix3_set_irq); > +   piix3_register_map_irq(xen_piix3_map_irq); >   pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size); >   isa_bus_irqs(isa_irq); > > -- > 1.7.0.4 > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-12 18:46 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
On Thu, Aug 12, 2010 at 2:10 PM, <stefano.stabellini@eu.citrix.com> wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > Xen currently uses a different BIOS (hvmloader + rombios) therefore the > Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. > We plan on fixing this properly but at the moment we are just adding a > new Xen specific acpi_piix4 implementation.I''d suppose the proper fix is to modify acpi_piix4 instead of copy&paste.> This patch is optional; without it the VM boots but it cannot shutdown > properly or go to S3. > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- >  Makefile.target   |   1 + >  hw/xen_acpi_piix4.c |  424 +++++++++++++++++++++++++++++++++++++++++++++++++++ >  hw/xen_common.h   |   3 + >  hw/xen_machine_fv.c |   6 +- >  4 files changed, 429 insertions(+), 5 deletions(-) >  create mode 100644 hw/xen_acpi_piix4.c > > diff --git a/Makefile.target b/Makefile.target > index 1984cdd..a2d9217 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -325,6 +325,7 @@ obj-xen-y += piix_pci.o >  obj-xen-y += mc146818rtc.o >  obj-xen-y += xenstore.o >  obj-xen-y += xen_platform.o > +obj-xen-y += xen_acpi_piix4.o > >  obj-xen-y += xen_mapcache.o >  obj-xen-y += stub-functions.o > diff --git a/hw/xen_acpi_piix4.c b/hw/xen_acpi_piix4.c > new file mode 100644 > index 0000000..3c65963 > --- /dev/null > +++ b/hw/xen_acpi_piix4.c > @@ -0,0 +1,424 @@ > + /* > + * PIIX4 ACPI controller emulation > + * > + * Winston liwen Wang, winston.l.wang@intel.com > + * Copyright (c) 2006 , Intel Corporation. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "hw.h" > +#include "pc.h" > +#include "pci.h" > +#include "sysemu.h" > +#include "acpi.h" > + > +#include "xen_backend.h" > +#include "xen_common.h" > +#include "qemu-log.h" > + > +#include <xen/hvm/ioreq.h> > +#include <xen/hvm/params.h> > + > +#define PIIX4ACPI_LOG_ERROR 0 > +#define PIIX4ACPI_LOG_INFO 1 > +#define PIIX4ACPI_LOG_DEBUG 2 > +#define PIIX4ACPI_LOGLEVEL PIIX4ACPI_LOG_INFO > +#define PIIX4ACPI_LOG(level, fmt, ...) do { if (level <= PIIX4ACPI_LOGLEVEL) qemu_log(fmt, ## __VA_ARGS__); } while (0) > + > +/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */ > +/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */ > +#define SLP_TYP_S4     (6 << 10) > +#define SLP_TYP_S3     (5 << 10) > +#define SLP_TYP_S5     (7 << 10) > + > +#define ACPI_DBG_IO_ADDR  0xb044 > +#define ACPI_PHP_IO_ADDR  0x10c0 > + > +#define PHP_EVT_ADD   0x0 > +#define PHP_EVT_REMOVE  0x3 > + > +/* The bit in GPE0_STS/EN to notify the pci hotplug event */ > +#define ACPI_PHP_GPE_BIT 3 > + > +#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn >> 1) > +#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg << 1) | hilo) > + > +/* ioport to monitor cpu add/remove status */ > +#define PROC_BASE 0xaf00 > + > +typedef struct PCIAcpiState { > +   PCIDevice dev; > +   uint16_t pm1_control; /* pm1a_ECNT_BLK */ > +   qemu_irq irq; > +   qemu_irq cmos_s3; > +} PCIAcpiState; > + > +typedef struct GPEState { > +   /* GPE0 block */ > +   uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2]; > +   uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2]; > + > +   /* CPU bitmap */ > +   uint8_t cpus_sts[32]; > + > +   /* SCI IRQ level */ > +   uint8_t sci_asserted; > + > +} GPEState; > + > +static GPEState gpe_state; > + > +static qemu_irq sci_irq; > + > +typedef struct AcpiDeviceState AcpiDeviceState; > +AcpiDeviceState *acpi_device_table; > + > +static const VMStateDescription vmstate_acpi = { > +   .name = "PIIX4 ACPI", > +   .version_id = 1, > +   .fields    = (VMStateField []) { > +     VMSTATE_PCI_DEVICE(dev, PCIAcpiState), > +     VMSTATE_UINT16(pm1_control, PCIAcpiState), > +     VMSTATE_END_OF_LIST() > +   } > +}; > + > +static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > +   PCIAcpiState *s = opaque; > +   s->pm1_control = (s->pm1_control & 0xff00) | (val & 0xff); > +} > + > +static uint32_t acpiPm1Control_readb(void *opaque, uint32_t addr) > +{ > +   PCIAcpiState *s = opaque; > +   /* Mask out the write-only bits */ > +   return (uint8_t)(s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)); > +} > + > +static void acpi_shutdown(PCIAcpiState *s, uint32_t val) > +{ > +   if (!(val & ACPI_BITMASK_SLEEP_ENABLE)) > +     return; > + > +   switch (val & ACPI_BITMASK_SLEEP_TYPE) { > +   case SLP_TYP_S3: > +     qemu_system_reset(); > +     qemu_irq_raise(s->cmos_s3); > +     xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3); > +     break; > +   case SLP_TYP_S4: > +   case SLP_TYP_S5: > +     qemu_system_shutdown_request(); > +     break; > +   default: > +     break; > +   } > +} > + > +static void acpiPm1ControlP1_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > +   PCIAcpiState *s = opaque; > + > +   val <<= 8; > +   s->pm1_control = ((s->pm1_control & 0xff) | val) & ~ACPI_BITMASK_SLEEP_ENABLE; > + > +   acpi_shutdown(s, val); > +} > + > +static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr) > +{ > +   PCIAcpiState *s = opaque; > +   /* Mask out the write-only bits */ > +   return (uint8_t)((s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)) >> 8); > +} > + > +static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val) > +{ > +   PCIAcpiState *s = opaque; > + > +   s->pm1_control = val & ~ACPI_BITMASK_SLEEP_ENABLE; > + > +   acpi_shutdown(s, val); > +} > + > +static uint32_t acpiPm1Control_readw(void *opaque, uint32_t addr) > +{ > +   PCIAcpiState *s = opaque; > +   /* Mask out the write-only bits */ > +   return (s->pm1_control & ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)); > +} > + > +static void acpi_map(PCIDevice *pci_dev, int region_num, > +           uint32_t addr, uint32_t size, int type) > +{ > +   PCIAcpiState *d = (PCIAcpiState *)pci_dev; > + > +   /* Byte access */ > +   register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d); > +   register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d); > +   register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d); > +   register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); > + > +   /* Word access */ > +   register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d); > +   register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d); > +} > + > +static inline int test_bit(uint8_t *map, int bit) > +{ > +   return ( map[bit / 8] & (1 << (bit % 8)) ); > +} > + > +static inline void set_bit(uint8_t *map, int bit) > +{ > +   map[bit / 8] |= (1 << (bit % 8)); > +} > + > +static inline void clear_bit(uint8_t *map, int bit) > +{ > +   map[bit / 8] &= ~(1 << (bit % 8)); > +} > + > +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) > +{ > +   PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "ACPI: DBG: 0x%08x\n", val); > +   PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val); > +} > + > +/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */ > +static uint32_t gpe_sts_read(void *opaque, uint32_t addr) > +{ > +   GPEState *s = opaque; > + > +   return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS]; > +} > + > +/* write 1 to clear specific GPE bits */ > +static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val) > +{ > +   GPEState *s = opaque; > +   int hotplugged = 0; > + > +   PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val); > + > +   hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT); > +   s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val; > +   if ( s->sci_asserted && > +     hotplugged && > +     !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) { > +     PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n"); > +     qemu_irq_lower(sci_irq); > +   } > + > +} > + > +static uint32_t gpe_en_read(void *opaque, uint32_t addr) > +{ > +   GPEState *s = opaque; > + > +   return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)]; > +} > + > +/* write 0 to clear en bit */ > +static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val) > +{ > +   GPEState *s = opaque; > +   int reg_count; > + > +   PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val); > +   reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2); > +   s->gpe0_en[reg_count] = val; > +   /* If disable GPE bit right after generating SCI on it, > +   * need deassert the intr to avoid redundant intrs > +   */ > +   if ( s->sci_asserted && > +     reg_count == (ACPI_PHP_GPE_BIT / 8) && > +     !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) { > +     PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "deassert due to disable GPE bit.\n"); > +     s->sci_asserted = 0; > +     qemu_irq_lower(sci_irq); > +   } > + > +} > + > +static void gpe_save(QEMUFile* f, void* opaque) > +{ > +   GPEState *s = (GPEState*)opaque; > +   int i; > + > +   for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) { > +     qemu_put_8s(f, &s->gpe0_sts[i]); > +     qemu_put_8s(f, &s->gpe0_en[i]); > +   } > + > +   qemu_put_8s(f, &s->sci_asserted); > +   if ( s->sci_asserted ) { > +     PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n"); > +   } > +} > + > +static int gpe_load(QEMUFile* f, void* opaque, int version_id) > +{ > +   GPEState *s = (GPEState*)opaque; > +   int i; > +   if (version_id != 1) > +     return -EINVAL; > + > +   for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) { > +     qemu_get_8s(f, &s->gpe0_sts[i]); > +     qemu_get_8s(f, &s->gpe0_en[i]); > +   } > + > +   qemu_get_8s(f, &s->sci_asserted); > +   return 0; > +} > + > +static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr) > +{ > +   uint32_t val = 0; > +   GPEState *g = opaque; > + > +   switch (addr) { > +     case PROC_BASE ... PROC_BASE+31: > +       val = g->cpus_sts[addr - PROC_BASE]; > +     default: > +       break; > +   } > + > +   return val; > +} > + > +static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > +   /* GPEState *g = opaque; */ > + > +   switch (addr) { > +     case PROC_BASE ... PROC_BASE + 31: > +       /* don''t allow to change cpus_sts from inside a guest */ > +       break; > +     default: > +       break; > +   } > +} > + > +static void gpe_acpi_init(void) > +{ > +   GPEState *s = &gpe_state; > +   memset(s, 0, sizeof(GPEState)); > + > +   s->cpus_sts[0] = 1; > + > +   register_ioport_read(PROC_BASE, 32, 1,  gpe_cpus_readb, s); > +   register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s); > + > +   register_ioport_read(ACPI_GPE0_BLK_ADDRESS, > +             ACPI_GPE0_BLK_LEN / 2, > +             1, > +             gpe_sts_read, > +             s); > +   register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, > +             ACPI_GPE0_BLK_LEN / 2, > +             1, > +             gpe_en_read, > +             s); > + > +   register_ioport_write(ACPI_GPE0_BLK_ADDRESS, > +              ACPI_GPE0_BLK_LEN / 2, > +              1, > +              gpe_sts_write, > +              s); > +   register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, > +              ACPI_GPE0_BLK_LEN / 2, > +              1, > +              gpe_en_write, > +              s); > + > +   register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s); > +} > + > +static int piix4_pm_xen_initfn(PCIDevice *dev) > +{ > +   PCIAcpiState *s = DO_UPCAST(PCIAcpiState, dev, dev); > +   uint8_t *pci_conf; > + > +   pci_conf = s->dev.config; > +   pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); > +   pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3); > +   pci_conf[0x08] = 0x01;  /* B0 stepping */ > +   pci_conf[0x09] = 0x00;  /* base class */ > +   pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); > +   pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */ > +   pci_conf[0x3d] = 0x01;  /* Hardwired to PIRQA is used */ > + > +   /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40 > +   * to make shutdown work for IPF, due to IPF Guest Firmware > +   * will enumerate pci devices. > +   * > +   * TODO:  if Guest Firmware or Guest OS will change this PMBA, > +   * More logic will be added. > +   */ > +   pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */ > +   pci_conf[0x41] = 0x1f; > +   pci_conf[0x42] = 0x00; > +   pci_conf[0x43] = 0x00; > + > +   s->pm1_control = ACPI_BITMASK_SCI_ENABLE; > + > +   acpi_map((PCIDevice *)s, 0, 0x1f40, 0x10, PCI_BASE_ADDRESS_SPACE_IO); > + > +   gpe_acpi_init(); > + > +   register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); > + > +   return 0; > +} > + > +void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3) > +{ > +   PCIDevice *dev; > +   PCIAcpiState *s; > + > +   sci_irq = sci_irq_spec; > + > +   dev = pci_create(bus, devfn, "PIIX4 ACPI"); > + > +   s = DO_UPCAST(PCIAcpiState, dev, dev); > + > +   s->irq = sci_irq_spec; > +   s->cmos_s3 = cmos_s3; > + > +   qdev_init_nofail(&dev->qdev); > +} > + > +static PCIDeviceInfo piix4_pm_xen_info = { > +   .qdev.name   = "PIIX4 ACPI", > +   .qdev.desc   = "dm", > +   .qdev.size   = sizeof(PCIAcpiState), > +   .qdev.vmsd   = &vmstate_acpi, > +   .init     = piix4_pm_xen_initfn, > +}; > + > +static void piix4_pm_xen_register(void) > +{ > +   pci_qdev_register(&piix4_pm_xen_info); > +} > + > +device_init(piix4_pm_xen_register); > diff --git a/hw/xen_common.h b/hw/xen_common.h > index 020fdd7..e1f07ba 100644 > --- a/hw/xen_common.h > +++ b/hw/xen_common.h > @@ -34,4 +34,7 @@ >  /* hw/i8259-xen-stub.c */ >  qemu_irq *i8259_xen_init(void); > > +/* hw/xen_acpi_piix4.c */ > +void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3); > + >  #endif /* QEMU_HW_XEN_COMMON_H */ > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index 77563db..bfda944 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -92,7 +92,6 @@ static void xen_init_fv(ram_addr_t ram_size, >   qemu_irq *isa_irq; >   qemu_irq *i8259; >   qemu_irq *cmos_s3; > -   qemu_irq *smi_irq; >   IsaIrqState *isa_irq_state; >   DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; >   FDCtrl *floppy_controller; > @@ -208,10 +207,7 @@ static void xen_init_fv(ram_addr_t ram_size, > >   if (acpi_enabled) { >     cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); > -     smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); > -     piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, > -         isa_reserve_irq(9), *cmos_s3, *smi_irq, > -         0); > +     piix4_pm_xen_init(pci_bus, piix3_devfn + 3, isa_reserve_irq(9), *cmos_s3); >   } > >   if (i440fx_state) { > -- > 1.7.0.4 > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-12 18:56 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > This patch adds a new Xen device model target to Qemu, called > target-xen.I don''t understand why it would be a target, QEMU calls CPU architectures targets. Isn''t it possible to have Xen for Sparc, PPC or ARM? It should really be just a machine, not copy&paste from x86 target.> The new target makes use of the previously introduced xen_machine_fv. > In order to have a fully working Xen device model we still need > functionalities introduced by the following patches. > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- >  Makefile.target           |  31 ++- >  arch_init.c             |   2 + >  arch_init.h             |   1 + >  configure              |  11 +- >  default-configs/xen-dm-softmmu.mak |  24 ++ >  target-xen/cpu.h          |  120 ++++++ >  target-xen/exec-dm.c        |  791 ++++++++++++++++++++++++++++++++++++ >  target-xen/helper.c         |  69 ++++ >  target-xen/qemu-xen.h        |  30 ++ >  target-xen/stub-functions.c     |  42 ++ >  target-xen/xen_mapcache.c      |  14 + >  11 files changed, 1130 insertions(+), 5 deletions(-) >  create mode 100644 default-configs/xen-dm-softmmu.mak >  create mode 100644 target-xen/cpu.h >  create mode 100644 target-xen/exec-dm.c >  create mode 100644 target-xen/helper.c >  create mode 100644 target-xen/machine.c >  create mode 100644 target-xen/qemu-xen.h >  create mode 100644 target-xen/stub-functions.c >  create mode 100644 target-xen/xen_mapcache.c > > diff --git a/Makefile.target b/Makefile.target > index 8fdc884..359a984 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -183,9 +183,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS) >  # xen backend driver support >  obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o > > -# xen full virtualized machine > -obj-$(CONFIG_XEN) += xen_machine_fv.o > - >  # USB layer >  obj-$(CONFIG_USB_OHCI) += usb-ohci.o > > @@ -310,6 +307,34 @@ obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) > >  endif # CONFIG_SOFTMMU > > +# Xen Device Model > +# xen full virtualized machine > + > +# Remove some lib, because we don''t want it for a xen target. > +ifeq ($(TARGET_BASE_ARCH), xen) > +bad-libobj-y = exec.o translate-all.o cpu-exec.o translate.o > +bad-libobj-y += tcg%.o fpu/%.o > +bad-libobj-y += disas.o op_helper.o > +libobj-y := $(filter-out $(bad-libobj-y), $(libobj-y)) > +endif > + > +obj-xen-y += xen_machine_fv.o > +obj-xen-y += i8259.o > +obj-xen-y += pc.o > +obj-xen-y += piix_pci.o > +obj-xen-y += mc146818rtc.o > + > +obj-xen-y += xen_mapcache.o > +obj-xen-y += stub-functions.o > + > +obj-xen-y += vga.o > +obj-xen-y += hpet.o > +obj-xen-y += cirrus_vga.o > +obj-xen-y += smbios.o > +obj-xen-y += multiboot.o > +obj-xen-y += exec-dm.o > +obj-xen-y += lsi53c895a.o usb-ohci.o > + >  obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o > >  $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) > diff --git a/arch_init.c b/arch_init.c > index 47bb4b2..ebc5cb6 100644 > --- a/arch_init.c > +++ b/arch_init.c > @@ -75,6 +75,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con >  #define QEMU_ARCH QEMU_ARCH_SH4 >  #elif defined(TARGET_SPARC) >  #define QEMU_ARCH QEMU_ARCH_SPARC > +#elif defined(TARGET_XEN) > +#define QEMU_ARCH QEMU_ARCH_XEN >  #endif > >  const uint32_t arch_type = QEMU_ARCH; > diff --git a/arch_init.h b/arch_init.h > index 682890c..b5f8eb1 100644 > --- a/arch_init.h > +++ b/arch_init.h > @@ -16,6 +16,7 @@ enum { >   QEMU_ARCH_S390X = 256, >   QEMU_ARCH_SH4 = 512, >   QEMU_ARCH_SPARC = 1024, > +   QEMU_ARCH_XEN = 2048, >  }; > >  extern const uint32_t arch_type; > diff --git a/configure b/configure > index 89d9b44..c3f52ce 100755 > --- a/configure > +++ b/configure > @@ -2517,6 +2517,9 @@ case "$target" in >  ${target_arch2}-softmmu) >   target_softmmu="yes" >   ;; > +  ${target_arch2}-dm-softmmu) > +   target_softmmu="yes" > +   ;; >  ${target_arch2}-linux-user) >   if test "$linux" != "yes" ; then >    echo "ERROR: Target ''$target'' is only available on a Linux host" > @@ -2582,6 +2585,10 @@ case "$target_arch2" in >   TARGET_BASE_ARCH=i386 >   target_phys_bits=64 >  ;; > +  xen) > +   # This is use for xen mapcache > +   target_phys_bits=64 > +  ;; >  alpha) >   target_phys_bits=64 >   target_nptl="yes" > @@ -2693,7 +2700,7 @@ if [ "$TARGET_ABI_DIR" = "" ]; then >  fi >  echo "TARGET_ABI_DIR=$TARGET_ABI_DIR" >> $config_target_mak >  case "$target_arch2" in > -  i386|x86_64) > +  i386|x86_64|xen) >   if test "$xen" = "yes" -a "$target_softmmu" = "yes" ; then >    echo "CONFIG_XEN=y" >> $config_target_mak >   fi > @@ -2859,7 +2866,7 @@ if test "$target_softmmu" = "yes" ; then >  arm) >   cflags="-DHAS_AUDIO $cflags" >  ;; > -  i386|mips|ppc) > +  i386|mips|ppc|xen) >   cflags="-DHAS_AUDIO -DHAS_AUDIO_CHOICE $cflags" >  ;; >  esac > diff --git a/default-configs/xen-dm-softmmu.mak b/default-configs/xen-dm-softmmu.mak > new file mode 100644 > index 0000000..72fe141 > --- /dev/null > +++ b/default-configs/xen-dm-softmmu.mak > @@ -0,0 +1,24 @@ > +# Default configuration for xen-dm-softmmu > + > +CONFIG_VGA_PCI=y > +CONFIG_VGA_ISA=y > +CONFIG_VMWARE_VGA=y > +CONFIG_SERIAL=y > +CONFIG_PARALLEL=y > +CONFIG_I8254=y > +CONFIG_PCSPK=y > +CONFIG_PCKBD=y > +CONFIG_USB_UHCI=y > +CONFIG_FDC=y > +CONFIG_ACPI=y > +CONFIG_APM=y > +CONFIG_DMA=y > +CONFIG_IDE_CORE=y > +CONFIG_IDE_QDEV=y > +CONFIG_IDE_PCI=y > +CONFIG_IDE_ISA=y > +CONFIG_IDE_PIIX=y > +CONFIG_NE2000_ISA=y > +CONFIG_PIIX_PCI=y > +CONFIG_SOUND=y > +CONFIG_XEN=y > diff --git a/target-xen/cpu.h b/target-xen/cpu.h > new file mode 100644 > index 0000000..5a45d1c > --- /dev/null > +++ b/target-xen/cpu.h > @@ -0,0 +1,120 @@ > +/* > + * xen virtual CPU header > + * > + *  Copyright (c) 2003 Fabrice Bellard > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see <http://www.gnu.org/licenses/>. > + */ > +#ifndef CPU_XEN_H > +#define CPU_XEN_H > + > +#include "config.h" > + > +#ifdef TARGET_X86_64 > +#define TARGET_LONG_BITS 64 > +#else > +#define TARGET_LONG_BITS 32 > +#endif > + > +#ifdef TARGET_X86_64 > +#define ELF_MACHINE   EM_X86_64 > +#else > +#define ELF_MACHINE   EM_386 > +#endif > + > +#define CPUState struct CPUXenState > +#define CPUX86State CPUXenState > + > +#include "cpu-defs.h" > + > +#include "softfloat.h" > + > +/* hidden flags - used internally by qemu to represent additional cpu > +  states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not > +  redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit > +  position to ease oring with eflags. */ > +/* current cpl */ > +#define HF_CPL_SHIFT     0 > +#define HF_SMM_SHIFT     19 /* CPU in SMM mode */ > + > +#define HF_CPL_MASK      (3 << HF_CPL_SHIFT) > +#define HF_SMM_MASK      (1 << HF_SMM_SHIFT) > + > +/* cpuid_features bits */ > +#define CPUID_APIC (1 << 9) > + > +#define NB_MMU_MODES 2 > + > +typedef struct CPUXenState { > +   uint32_t hflags; /* TB flags, see HF_xxx constants. These flags > +             are known at translation time. */ > +   CPU_COMMON > + > +   /* processor features (e.g. for CPUID insn) */ > +   uint32_t cpuid_features; > +   uint32_t cpuid_apic_id; > + > +   /* in order to simplify APIC support, we leave this pointer to the > +    user */ > +   struct DeviceState *apic_state; > +} CPUXenState; > + > +CPUXenState *cpu_xen_init(const char *cpu_model); > +int cpu_xen_exec(CPUXenState *s); > + > +int cpu_get_pic_interrupt(CPUXenState *s); > +void cpu_set_ferr(CPUX86State *s); > + > +/* helper.c */ > +void cpu_x86_set_a20(CPUXenState *env, int a20_state); > + > +/* hw/pc.c */ > +void cpu_smm_update(CPUXenState *env); > +uint64_t cpu_get_tsc(CPUX86State *env); > + > +#define TARGET_PAGE_BITS 12 > + > +#ifdef TARGET_X86_64 > +#define TARGET_PHYS_ADDR_SPACE_BITS 52 > +/* ??? This is really 48 bits, sign-extended, but the only thing > +  accessible to userland with bit 48 set is the VSYSCALL, and that > +  is handled via other mechanisms.  */ > +#define TARGET_VIRT_ADDR_SPACE_BITS 47 > +#else > +#define TARGET_PHYS_ADDR_SPACE_BITS 36 > +#define TARGET_VIRT_ADDR_SPACE_BITS 32 > +#endif > + > +#define cpu_init cpu_xen_init > +#define cpu_exec cpu_xen_exec > + > +/* MMU modes definitions */ > +static inline int cpu_mmu_index (CPUState *env) > +{ > +   return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; > +} > + > +#include "cpu-all.h" > +#include "exec-all.h" > + > +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) > +{ > +} > + > +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, > +                     target_ulong *cs_base, int *flags) > +{ > +} > + > +#endif /* CPU_XEN_H */ > diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c > new file mode 100644 > index 0000000..3d64695 > --- /dev/null > +++ b/target-xen/exec-dm.c > @@ -0,0 +1,791 @@ > +/* > + *  virtual page mapping and translated block handling > + * > + *  Copyright (c) 2003 Fabrice Bellard > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USAPlease use the URL version. The address is ancient.> + */ > +#include "config.h" > + > +#include "cpu.h" > +#include "hw/hw.h" > +#include "hw/pc.h" > +#include "disas.h" > +#include "hw/xen_common.h" > +#include "qemu-xen.h" > +#include "hw/xen.h" > +#include "hw/xen_backend.h" > + > +int use_icount = 0; > +int64_t qemu_icount; > + > +RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) }; > + > +CPUState *first_cpu; > +/* current CPU in the current thread. It is only valid inside > +  cpu_exec() */ > +CPUState *cpu_single_env; > + > +/* io memory support */ > +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; > +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; > +void *io_mem_opaque[IO_MEM_NB_ENTRIES]; > +static int io_mem_nb = 1; > + > +/* log support */ > +FILE *logfile; > +int loglevel; > + > +void cpu_exec_init_all(unsigned long tb_size) > +{ > +} > + > +void cpu_exec_init(CPUState *env) > +{ > +   CPUState **penv; > +   int cpu_index; > + > +   env->next_cpu = NULL; > +   penv = &first_cpu; > +   cpu_index = 0; > +   while (*penv != NULL) { > +     penv = (CPUState **)&(*penv)->next_cpu; > +     cpu_index++; > +   } > +   env->cpu_index = cpu_index; > +   *penv = env; > +} > + > +/* enable or disable low levels log */ > +void cpu_set_log(int log_flags) > +{ > +   loglevel = log_flags; > +   if (!logfile) { > +     logfile = stderr; > +   } > +} > + > +void cpu_set_log_filename(const char *filename) > +{ > +   logfile = fopen(filename, "w"); > +   if (!logfile) { > +     perror(filename); > +     _exit(1); > +   } > +#if !defined(CONFIG_SOFTMMU) > +   /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ > +   { > +     static uint8_t logfile_buf[4096]; > +     setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); > +   } > +#else > +   setvbuf(logfile, NULL, _IOLBF, 0); > +#endif > +   dup2(fileno(logfile), 1); > +   dup2(fileno(logfile), 2); > +} > + > +/* mask must never be zero, except for A20 change call */ > +void cpu_interrupt(CPUState *env, int mask) > +{ > +   env->interrupt_request |= mask; > +} > + > +void cpu_reset_interrupt(CPUState *env, int mask) > +{ > +   env->interrupt_request &= ~mask; > +} > + > +const CPULogItem cpu_log_items[] = { > +#ifdef DEBUG_IOPORT > +   { CPU_LOG_IOPORT, "ioport", > +    "show all i/o ports accesses" }, > +#endif > +   { 0, NULL, NULL }, > +}; > + > +static int cmp1(const char *s1, int n, const char *s2) > +{ > +   if (strlen(s2) != n) > +     return 0; > +   return memcmp(s1, s2, n) == 0; > +} > + > +/* takes a comma separated list of log masks. Return 0 if error. */ > +int cpu_str_to_log_mask(const char *str) > +{ > +   const CPULogItem *item; > +   int mask; > +   const char *p, *p1; > + > +   p = str; > +   mask = 0; > +   for(;;) { > +     p1 = strchr(p, '',''); > +     if (!p1) { > +       p1 = p + strlen(p); > +     } > +     if(cmp1(p,p1-p,"all")) { > +       for(item = cpu_log_items; item->mask != 0; item++) { > +         mask |= item->mask; > +       } > +     } else { > +       for(item = cpu_log_items; item->mask != 0; item++) { > +         if (cmp1(p, p1 - p, item->name)) > +           goto found; > +       } > +       return 0; > +     } > +found: > +     mask |= item->mask; > +     if (*p1 != '','') > +       break; > +     p = p1 + 1; > +   } > +   return mask; > +} > + > +/* XXX: Simple implementation. Fix later */ > +#define MAX_MMIO 1024 > +static struct mmio_space { > +   target_phys_addr_t start; > +   unsigned long size; > +   unsigned long io_index; > +} mmio[MAX_MMIO]; > +static unsigned long mmio_cnt; > + > +/* register physical memory. ''size'' must be a multiple of the target > +  page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an > +  io memory page */ > +void cpu_register_physical_memory_offset(target_phys_addr_t start_addr, > +                     ram_addr_t size, > +                     ram_addr_t phys_offset, > +                     ram_addr_t region_offset) > +{ > +   region_offset &= TARGET_PAGE_MASK; > +   start_addr += region_offset; > + > +   int i; > + > +   for (i = 0; i < mmio_cnt; i++) { > +     if(mmio[i].start == start_addr) { > +       mmio[i].io_index = phys_offset; > +       mmio[i].size = size; > +       return; > +     } > +   } > + > +   if (mmio_cnt == MAX_MMIO) { > +     fprintf(stderr, "too many mmio regions\n"); > +     exit(-1); > +   } > + > +   mmio[mmio_cnt].io_index = phys_offset; > +   mmio[mmio_cnt].start = start_addr; > +   mmio[mmio_cnt++].size = size; > +} > + > +/* mem_read and mem_write are arrays of functions containing the > +  function to access byte (index 0), word (index 1) and dword (index > +  2). All functions must be supplied. If io_index is non zero, the > +  corresponding io zone is modified. If it is zero, a new io zone is > +  allocated. The return value can be used with > +  cpu_register_physical_memory(). (-1) is returned if error. */ > +int cpu_register_io_memory_fixed(int io_index, > +              CPUReadMemoryFunc * const *mem_read, > +              CPUWriteMemoryFunc * const *mem_write, > +              void *opaque) > +{ > +   int i; > + > +   if (io_index <= 0) { > +     if (io_index >= IO_MEM_NB_ENTRIES) > +       return -1; > +     io_index = io_mem_nb++; > +   } else { > +     if (io_index >= IO_MEM_NB_ENTRIES) > +       return -1; > +   } > + > +   for(i = 0;i < 3; i++) { > +     io_mem_read[io_index][i] = mem_read[i]; > +     io_mem_write[io_index][i] = mem_write[i]; > +   } > +   io_mem_opaque[io_index] = opaque; > +   return io_index << IO_MEM_SHIFT; > +} > + > +int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, > +              CPUWriteMemoryFunc * const *mem_write, > +              void *opaque) > +{ > +   return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque); > +} > + > +void cpu_unregister_io_memory(int io_table_address) > +{ > +   int i; > +   int io_index = io_table_address >> IO_MEM_SHIFT; > + > +   for (i = 0; i < mmio_cnt; i++) { > +     if (mmio[i].size && mmio[i].io_index == io_index) { > +       mmio[i].start = mmio[i].size = 0; > +       break; > +     } > +   } > + > +   for (i=0;i < 3; i++) { > +     io_mem_read[io_index][i] = NULL; > +     io_mem_write[io_index][i] = NULL; > +   } > +   io_mem_opaque[io_index] = NULL; > +} > + > +int cpu_physical_memory_set_dirty_tracking(int enable) > +{ > +   return 0; > +} > + > +#ifdef __ia64__ > + > +#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory") > +#define ia64_sync_i()  asm volatile (";; sync.i" ::: "memory") > +#define ia64_srlz_i()  asm volatile (";; srlz.i ;;" ::: "memory") > + > +/* IA64 has seperate I/D cache, with coherence maintained by DMA controller. > + * So to emulate right behavior that guest OS is assumed, we need to flush > + * I/D cache here. > + */ > +static void sync_icache(uint8_t *address, int len) > +{ > +   unsigned long addr = (unsigned long)address; > +   unsigned long end = addr + len; > + > +   for (addr &= ~(32UL-1); addr < end; addr += 32UL) { > +     __ia64_fc(addr); > +   } > + > +   ia64_sync_i(); > +   ia64_srlz_i(); > +} > +#endif > + > +static int iomem_index(target_phys_addr_t addr) > +{ > +   int i; > + > +   for (i = 0; i < mmio_cnt; i++) { > +     unsigned long start, end; > + > +     start = mmio[i].start; > +     end = mmio[i].start + mmio[i].size; > + > +     if ((addr >= start) && (addr < end)) { > +       return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); > +     } > +   } > +   return 0; > +} > + > +unsigned int xen_logdirty_enable = 0; > + > +/* > + * Replace the standard byte memcpy with a word memcpy for appropriately sized > + * memory copy operations.  Some users (USB-UHCI) can not tolerate the possible > + * word tearing that can result from a guest concurrently writing a memory > + * structure while the qemu device model is modifying the same location. > + * Forcing a word-sized read/write prevents the guest from seeing a partially > + * written word-sized atom. > + */ > +#if defined(__x86_64__) || defined(__i386__) > +static void memcpy_words(void *dst, void *src, size_t n) > +{ > +   asm volatile ( > +     "  movl %%edx,%%ecx \n" > +#ifdef __x86_64__ > +     "  shrl $3,%%ecx   \n" > +     "  rep  movsq    \n" > +     "  test $4,%%edx   \n" > +     "  jz  1f      \n" > +     "  movsl       \n" > +#else /* __i386__ */ > +     "  shrl $2,%%ecx   \n" > +     "  rep  movsl    \n" > +#endif > +     "1: test $2,%%edx   \n" > +     "  jz  1f      \n" > +     "  movsw       \n" > +     "1: test $1,%%edx   \n" > +     "  jz  1f      \n" > +     "  movsb       \n" > +     "1:          \n" > +     : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" ); > +} > +#else > +static void memcpy_words(void *dst, void *src, size_t n) > +{ > +   /* Some architectures do not like unaligned accesses. */ > +   if (((unsigned long)dst | (unsigned long)src) & 3) { > +     memcpy(dst, src, n); > +     return; > +   } > + > +   while (n >= sizeof(uint32_t)) { > +     *((uint32_t *)dst) = *((uint32_t *)src); > +     dst = ((uint32_t *)dst) + 1; > +     src = ((uint32_t *)src) + 1; > +     n -= sizeof(uint32_t); > +   } > + > +   if (n & 2) { > +     *((uint16_t *)dst) = *((uint16_t *)src); > +     dst = ((uint16_t *)dst) + 1; > +     src = ((uint16_t *)src) + 1; > +   } > + > +   if (n & 1) { > +     *((uint8_t *)dst) = *((uint8_t *)src); > +     dst = ((uint8_t *)dst) + 1; > +     src = ((uint8_t *)src) + 1; > +   } > +} > +#endif > + > +void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf, > +               int _len, int is_write) > +{ > +   target_phys_addr_t addr = _addr; > +   int len = _len; > +   int l, io_index; > +   uint8_t *ptr; > +   uint32_t val; > + > +   mapcache_lock(); > + > +   while (len > 0) { > +     /* How much can we copy before the next page boundary? */ > +     l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); > +     if (l > len) { > +       l = len; > +     } > + > +     io_index = iomem_index(addr); > +     if (is_write) { > +       if (io_index) { > +         if (l >= 4 && ((addr & 3) == 0)) { > +           /* 32 bit read access */ > +           val = ldl_raw(buf); > +           io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); > +           l = 4; > +         } else if (l >= 2 && ((addr & 1) == 0)) { > +           /* 16 bit read access */ > +           val = lduw_raw(buf); > +           io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); > +           l = 2; > +         } else { > +           /* 8 bit access */ > +           val = ldub_raw(buf); > +           io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); > +           l = 1; > +         } > +       } else if ((ptr = phys_ram_addr(addr)) != NULL) { > +         /* Writing to RAM */ > +         memcpy_words(ptr, buf, l); > + > +         if (xen_logdirty_enable) { > +           xc_hvm_modified_memory(xen_xc, > +               xen_domid, > +               addr >> TARGET_PAGE_BITS, > +               ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS) > +               - (addr >> TARGET_PAGE_BITS)); > +         } > +#ifdef __ia64__ > +         sync_icache(ptr, l); > +#endif > +       } > +     } else { > +       if (io_index) { > +         if (l >= 4 && ((addr & 3) == 0)) { > +           /* 32 bit read access */ > +           val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); > +           stl_raw(buf, val); > +           l = 4; > +         } else if (l >= 2 && ((addr & 1) == 0)) { > +           /* 16 bit read access */ > +           val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); > +           stw_raw(buf, val); > +           l = 2; > +         } else { > +           /* 8 bit access */ > +           val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); > +           stb_raw(buf, val); > +           l = 1; > +         } > +       } else if ((ptr = phys_ram_addr(addr)) != NULL) { > +         /* Reading from RAM */ > +         memcpy_words(buf, ptr, l); > +       } else { > +         /* Neither RAM nor known MMIO space */ > +         memset(buf, 0xff, len); > +       } > +     } > +     len -= l; > +     buf += l; > +     addr += l; > +   } > + > +   mapcache_unlock(); > +} > + > +/* virtual memory access for debug */ > +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, > +             uint8_t *buf, int len, int is_write) > +{ > +   int l; > +   target_ulong page, phys_addr; > + > +   while (len > 0) { > +     page = addr & TARGET_PAGE_MASK; > +     phys_addr = cpu_get_phys_page_debug(env, page); > +     /* if no physical page mapped, return an error */ > +     if (phys_addr == -1) > +       return -1; > +     l = (page + TARGET_PAGE_SIZE) - addr; > +     if (l > len) > +       l = len; > +     cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), > +                buf, l, is_write); > +     len -= l; > +     buf += l; > +     addr += l; > +   } > +   return 0; > +} > + > +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, > +                   int dirty_flags) > +{ > +   unsigned long length; > +   int i, mask, len; > +   uint8_t *p; > + > +   start &= TARGET_PAGE_MASK; > +   end = TARGET_PAGE_ALIGN(end); > + > +   length = end - start; > +   if (length == 0) > +     return; > +   mask = ~dirty_flags; > +   p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS); > +   len = length >> TARGET_PAGE_BITS; > +   for(i = 0; i < len; i++) { > +     p[i] &= mask; > +   } > + > +   return; > +} > + > + > +/* Unoptimised in Xen DM, nicked from git > + *  aab33094073678d459ccaac5c60ea7533e8d1d8e */ > +uint32_t ldub_phys(target_phys_addr_t addr) > +{ > +   uint8_t val; > +   cpu_physical_memory_read(addr, &val, 1); > +   return val; > +} > +uint32_t lduw_phys(target_phys_addr_t addr) > +{ > +   uint16_t val; > +   cpu_physical_memory_read(addr, (uint8_t *)&val, 2); > +   return tswap16(val); > +} > +uint64_t ldq_phys(target_phys_addr_t addr) > +{ > +   uint64_t val; > +   cpu_physical_memory_read(addr, (uint8_t *)&val, 8); > +   return tswap64(val); > +} > +void stb_phys(target_phys_addr_t addr, uint32_t val) > +{ > +   uint8_t v = val; > +   cpu_physical_memory_write(addr, &v, 1); > +} > +void stw_phys(target_phys_addr_t addr, uint32_t val) > +{ > +   uint16_t v = tswap16(val); > +   cpu_physical_memory_write(addr, (const uint8_t *)&v, 2); > +} > +void stq_phys(target_phys_addr_t addr, uint64_t val) > +{ > +   val = tswap64(val); > +   cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); > +} > + > +/* stubs which we hope (think!) are OK for Xen DM */ > +void stl_phys(target_phys_addr_t addr, uint32_t val) > +{ > +   val = tswap32(val); > +   cpu_physical_memory_write(addr, (const uint8_t *)&val, 4); > +} > +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) > +{ > +   stl_phys(addr, val); > +} > +uint32_t ldl_phys(target_phys_addr_t addr) > +{ > +   uint32_t val; > +   cpu_physical_memory_read(addr, (uint8_t *)&val, 4); > +   return tswap32(val); > +} > + > +void cpu_physical_memory_write_rom(target_phys_addr_t addr, > +                  const uint8_t *buf, int len) > +{ > +   return cpu_physical_memory_write(addr,buf,len); > +} > + > +void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) > +{ > +} > +void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) > +{ > +} > + > +/* stub out various functions for Xen DM */ > +void dump_exec_info(FILE *f, > +           int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) > +{ > +} > + > +void monitor_disas(Monitor *mon, CPUState *env, > +          target_ulong pc, int nb_insn, int is_physical, int flags) > +{ > +} > + > +/* > + * This next section was clone-and-hacked from the version in exec.c > + * :-(.  But the exec.c version is full of tcg-specific stuff and > + * assumptions about phys_ram_base.Then fix those assumptions and introduce xen specific hooks, like KVM.> + */ > + > +typedef struct MapClient { > +   void *opaque; > +   void (*callback)(void *opaque); > +   QLIST_ENTRY(MapClient) link; > +} MapClient; > + > +static QLIST_HEAD(map_client_list, MapClient) map_client_list > +   = QLIST_HEAD_INITIALIZER(map_client_list); > + > +void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque)) > +{ > +   MapClient *client = qemu_malloc(sizeof(*client)); > + > +   client->opaque = opaque; > +   client->callback = callback; > +   QLIST_INSERT_HEAD(&map_client_list, client, link); > +   return client; > +} > + > +void cpu_unregister_map_client(void *_client) > +{ > +   MapClient *client = (MapClient *)_client; > + > +   QLIST_REMOVE(client, link); > +   qemu_free(client); > +} > + > +static void cpu_notify_map_clients(void) > +{ > +   MapClient *client; > + > +   while (!QLIST_EMPTY(&map_client_list)) { > +     client = QLIST_FIRST(&map_client_list); > +     client->callback(client->opaque); > +     cpu_unregister_map_client(client); > +   } > +} > + > +/* Map a physical memory region into a host virtual address. > + * May map a subset of the requested range, given by and returned in *plen. > + * May return NULL if resources needed to perform the mapping are exhausted. > + * Use only for reads OR writes - not for read-modify-write operations. > + * Use cpu_register_map_client() to know when retrying the map operation is > + * likely to succeed. > + */ > +void *cpu_physical_memory_map(target_phys_addr_t addr, > +                target_phys_addr_t *plen, > +                int is_write) > +{ > +   unsigned long l = 0; > +#ifdef MAPCACHE > +   l = MCACHE_BUCKET_SIZE - (addr & (MCACHE_BUCKET_SIZE-1)); > +   if ((*plen) > l) { > +     *plen = l; > +   } > +#endif > +   if (xen_logdirty_enable) { > +     xc_hvm_modified_memory(xen_xc, xen_domid, addr >> TARGET_PAGE_BITS, > +         ((addr + l + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS) > +           - (addr >> TARGET_PAGE_BITS)); > +   } > + > +   return qemu_map_cache(addr, 1); > +} > + > +/* Unmaps a memory region previously mapped by cpu_physical_memory_map(). > + * Will also mark the memory as dirty if is_write == 1.  access_len gives > + * the amount of memory that was actually read or written by the caller. > + */ > +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, > +                int is_write, target_phys_addr_t access_len) > +{ > +   qemu_invalidate_entry(buffer); > +   cpu_notify_map_clients(); > +} > + > + > +void cpu_exit(CPUState *env) > +{ > +   env->exit_request = 1; > +} > + > +void qemu_flush_coalesced_mmio_buffer(void) > +{ > +} > + > +void *qemu_get_ram_ptr(ram_addr_t addr) > +{ > +   RAMBlock *block; > + > +   QLIST_FOREACH(block, &ram_list.blocks, next) { > +     if (addr - block->offset < block->length) { > +       QLIST_REMOVE(block, next); > +       QLIST_INSERT_HEAD(&ram_list.blocks, block, next); > +       return block->host + (addr - block->offset); > +     } > +   } > +   return block->host + (addr - block->offset); > + > +   fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); > +   abort(); > + > +   return NULL; > +} > + > +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, > +                  target_phys_addr_t end_addr) > +{ > +   return 0; > +} > +ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr) > +{ > +   return 0; > +} > + > +static ram_addr_t find_ram_offset(ram_addr_t size) > +{ > +   RAMBlock *block; > +   ram_addr_t last = 0; > + > +   QLIST_FOREACH(block, &ram_list.blocks, next) { > +     last = MAX(last, block->offset + block->length); > +   } > + > +   return last; > +} > + > +ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size) > +{ > +   RAMBlock *new_block; > + > +   size = TARGET_PAGE_ALIGN(size); > +   new_block = qemu_malloc(sizeof(*new_block)); > + > +   if (mem_path) { > +#if defined (__linux__) && !defined(TARGET_S390X) > +     new_block->host = 0; // file_ram_alloc(size, mem_path); > +     if (!new_block->host) { > +       new_block->host = qemu_vmalloc(size); > +#ifdef MADV_MERGEABLE > +       madvise(new_block->host, size, MADV_MERGEABLE); > +#endif > +     } > +#else > +     fprintf(stderr, "-mem-path option unsupported\n"); > +     exit(1); > +#endif > +   } else { > +     new_block->host = qemu_vmalloc(size); > +#ifdef MADV_MERGEABLE > +     madvise(new_block->host, size, MADV_MERGEABLE); > +#endif > +   } > +   new_block->offset = find_ram_offset(size); > +   new_block->length = size; > + > +   QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next); > + > +   ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty, > +     (new_block->offset + size) >> TARGET_PAGE_BITS); > +   memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS), > +      0xff, size >> TARGET_PAGE_BITS); > + > +   return new_block->offset; > +} > + > +void qemu_ram_free(ram_addr_t addr) > +{ > +} > + > +void tb_flush(CPUState *env1) > +{ > +} > + > +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, > +              int flags, CPUWatchpoint **watchpoint) > +{ > +   return -ENOSYS; > +} > + > +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len, > +              int flags) > +{ > +   return -ENOENT; > +} > + > +void cpu_watchpoint_remove_all(CPUState *env, int mask) > +{ > +} > + > +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, > +              CPUBreakpoint **breakpoint) > +{ > +   return -ENOSYS; > +} > + > +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags) > +{ > +   return -ENOSYS; > +} > + > +void cpu_breakpoint_remove_all(CPUState *env, int mask) > +{ > +} > + > +void cpu_single_step(CPUState *env, int enabled) > +{ > +} > diff --git a/target-xen/helper.c b/target-xen/helper.c > new file mode 100644 > index 0000000..d588e64 > --- /dev/null > +++ b/target-xen/helper.c > @@ -0,0 +1,69 @@ > +/* > + *  i386 helpers (without register variable usage) > + * > + *  Copyright (c) 2003 Fabrice Bellard > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA > + */ > + > +#include "cpu.h" > + > +CPUXenState *cpu_xen_init(const char *cpu_model) > +{ > +   CPUXenState *env = NULL; > +   static int inited; > + > +   env = qemu_mallocz(sizeof(CPUXenState)); > +   if (!env)qemu_mallocz won''t return NULL.> +     return NULL; > +   cpu_exec_init(env); > + > +   /* init various static tables */ > +   if (!inited) { > +     inited = 1; > + > +     cpu_single_env = env; > +   } > + > +   return env; > +} > + > +int cpu_xen_exec(CPUState *env1) > +{ > +   return 0; > +} > + > +void cpu_reset(CPUXenState *env) > +{ > +} > + > +void cpu_dump_state(CPUState *env, FILE *f, > +           int (*cpu_fprintf)(FILE *f, const char *fmt, ...), > +           int flags) > +{ > +} > + > +/***********************************************************/ > +/* x86 mmu */ > +/* XXX: add PGE support */ > + > +void cpu_x86_set_a20(CPUXenState *env, int a20_state) > +{ > +} > + > +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) > +{ > +   return addr; > +} > diff --git a/target-xen/machine.c b/target-xen/machine.c > new file mode 100644 > index 0000000..e69de29 > diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h > new file mode 100644 > index 0000000..d1910d6 > --- /dev/null > +++ b/target-xen/qemu-xen.h > @@ -0,0 +1,30 @@ > +#ifndef QEMU_XEN_H > +#define QEMU_XEN_H > + > +#include "hw/xen_common.h" > + > +/* vl.c */ > + > +#if defined(__i386__) || defined(__x86_64__) > +#define phys_ram_addr(x) (qemu_map_cache(x, 0)) > +#elif defined(__ia64__) > +#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL) > +#endif > + > +/* xen_mapcache.c */ > + > +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock); > +void   qemu_invalidate_entry(uint8_t *buffer); > +void   qemu_invalidate_map_cache(void); > + > +#define mapcache_lock()  ((void)0) > +#define mapcache_unlock() ((void)0) > + > +/* target-xen/exec-dm.c */ > + > +int cpu_register_io_memory_fixed(int io_index, > +              CPUReadMemoryFunc * const *mem_read, > +              CPUWriteMemoryFunc * const *mem_write, > +              void *opaque); > + > +#endif /*QEMU_XEN_H*/ > diff --git a/target-xen/stub-functions.c b/target-xen/stub-functions.c > new file mode 100644 > index 0000000..0db6898 > --- /dev/null > +++ b/target-xen/stub-functions.c > @@ -0,0 +1,42 @@ > +#include "config.h" > +#include "disas.h" > +#include "hw/apic.h" > +#include "hw/pc.h" > +#include "cpu.h" > + > +/* disas */ > +struct syminfo *syminfos = NULL; > + > +/* apic */ > +void apic_deliver_pic_intr(DeviceState *d, int level) > +{ > +} > + > +int apic_get_interrupt(DeviceState *d) > +{ > +   return -1; > +} > + > +int apic_accept_pic_intr(DeviceState *d) > +{ > +   return 0; > +} > + > +/* vmmouse */ > +void *vmmouse_init(void *m) > +{ > +   return NULL; > +} > + > +/* cpu-exec */ > +volatile sig_atomic_t exit_request; > + > +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) > +{ > +   return NULL; > +} > + > +int qemu_cpu_has_work(CPUState *env) > +{ > +   return 0; > +} > diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c > new file mode 100644 > index 0000000..39daae2 > --- /dev/null > +++ b/target-xen/xen_mapcache.c > @@ -0,0 +1,14 @@ > +#include "qemu-xen.h" > + > +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock) > +{ > +   return phys_ram_addr(phys_addr); > +} > + > +void qemu_invalidate_map_cache(void) > +{ > +} > + > +void qemu_invalidate_entry(uint8_t *buffer) > +{ > +} > -- > 1.7.0.4 > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Aug-13 12:47 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
Blue Swirl writes ("[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen"):> I don''t understand why it would be a target, QEMU calls CPU > architectures targets. Isn''t it possible to have Xen for Sparc, PPC or > ARM? It should really be just a machine, not copy&paste from x86 > target.Qemu''s targets include much more of Qemu''s system emulation than is appropriate for Xen, because the hypervisor is doing more of the work. For example, there is no representation of the guest CPU state outside the hypervisor so Qemu doesn''t see that at all. So it makes sense to do Xen emulation in Qemu as a new target than just as a machine. Yes, in principle Xen for Sparc, PPC and ARM are possible; some of these have existed in the past although targets other than i386, itanium and amd64 aren''t currently supported by xen-unstable. So perhaps the currently-introduced xen target should be called target-i386-xen. However, in practice since in a Xen system Qemu doesn''t deal with CPU instructions these other targets will be much more like each other than (say) i386 is close to m68k. Or to put it all another way: from the point of view of Qemu, Xen is a weird kind of cpu architecture whose instruction emulation is done "by magic" and Qemu doesn''t need to care vary much about that. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 13:09 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 06/15] xen: Add the Xen platform pci device
Thanks for the very detailed review, all the comments make perfect sense, we''ll address them in the next version of the series. On Thu, 12 Aug 2010, Blue Swirl wrote:> On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote: > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > Introduce a new emulated PCI device, specific to fully virtualized Xen > > guests. The device is necessary for PV on HVM drivers to work. > > The code should be converted to qdev and VMState. > > > > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > > --- > > Makefile.target | 1 + > > hw/xen_machine_fv.c | 4 + > > hw/xen_platform.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++++++ > > hw/xen_platform.h | 9 + > > 4 files changed, 466 insertions(+), 0 deletions(-) > > create mode 100644 hw/xen_platform.c > > create mode 100644 hw/xen_platform.h > > > > diff --git a/Makefile.target b/Makefile.target > > index d1b63f2..1984cdd 100644 > > --- a/Makefile.target > > +++ b/Makefile.target > > @@ -324,6 +324,7 @@ obj-xen-y += pc.o > > obj-xen-y += piix_pci.o > > obj-xen-y += mc146818rtc.o > > obj-xen-y += xenstore.o > > +obj-xen-y += xen_platform.o > > > > obj-xen-y += xen_mapcache.o > > obj-xen-y += stub-functions.o > > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > > index 114addf..ec826e7 100644 > > --- a/hw/xen_machine_fv.c > > +++ b/hw/xen_machine_fv.c > > @@ -35,6 +35,7 @@ > > #include "xen_common.h" > > #include "xen_backend.h" > > #include "xenstore.h" > > +#include "xen_platform.h" > > #include "xen/hvm/hvm_info_table.h" > > > > #define MAX_IDE_BUS 2 > > @@ -93,6 +94,9 @@ static void xen_init_fv(ram_addr_t ram_size, > > > > pc_vga_init(pci_bus); > > > > + pci_xen_platform_init(pci_bus); > > + platform_fixed_ioport_init(); > > + > > /* init basic PC hardware */ > > pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state); > > > > diff --git a/hw/xen_platform.c b/hw/xen_platform.c > > new file mode 100644 > > index 0000000..85d3f8b > > --- /dev/null > > +++ b/hw/xen_platform.c > > @@ -0,0 +1,452 @@ > > +/* > > + * XEN platform pci device, formerly known as the event channel device > > + * > > + * Copyright (c) 2003-2004 Intel Corp. > > + * Copyright (c) 2006 XenSource > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a copy > > + * of this software and associated documentation files (the "Software"), to deal > > + * in the Software without restriction, including without limitation the rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > + * THE SOFTWARE. > > + */ > > + > > +#include "hw.h" > > +#include "pc.h" > > +#include "pci.h" > > +#include "irq.h" > > +#include "xen_common.h" > > +#include "net.h" > > +#include "xen_platform.h" > > +#include "xen_backend.h" > > +#include "qemu-log.h" > > + > > +#include <assert.h> > > +#include <xenguest.h> > > + > > +static int drivers_blacklisted; > > +static uint16_t driver_product_version; > > +static int throttling_disabled; > > +static char log_buffer[4096]; > > +static int log_buffer_off; > > + > > +static uint8_t platform_flags; > > A lot of static variables. Could you put these to PCIXenPlatformState? > > > + > > +#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */ > > + > > +typedef struct PCIXenPlatformState > > +{ > > + PCIDevice pci_dev; > > +} PCIXenPlatformState; > > + > > + > > +/* We throttle access to dom0 syslog, to avoid DOS attacks. This is > > + modelled as a token bucket, with one token for every byte of log. > > + The bucket size is 128KB (->1024 lines of 128 bytes each) and > > + refills at 256B/s. It starts full. The guest is blocked if no > > + tokens are available when it tries to generate a log message. */ > > +#define BUCKET_MAX_SIZE (128*1024) > > +#define BUCKET_FILL_RATE 256 > > + > > +static void throttle(unsigned count) > > +{ > > + static unsigned available; > > + static struct timespec last_refil; > > + static int started; > > + static int warned; > > + > > + struct timespec waiting_for, now; > > + double delay; > > + struct timespec ts; > > + > > + if (throttling_disabled) > > + return; > > + > > + if (!started) { > > + clock_gettime(CLOCK_MONOTONIC, &last_refil); > > + available = BUCKET_MAX_SIZE; > > + started = 1; > > + } > > + > > + if (count > BUCKET_MAX_SIZE) { > > + fprintf(stderr, "tried to get %d tokens, but bucket size is %d\n", > > + BUCKET_MAX_SIZE, count); > > + exit(1); > > + } > > + > > + if (available < count) { > > + /* The bucket is empty. Refil it */ > > + > > + /* When will it be full enough to handle this request? */ > > + delay = (double)(count - available) / BUCKET_FILL_RATE; > > + waiting_for = last_refil; > > + waiting_for.tv_sec += delay; > > + waiting_for.tv_nsec += (delay - (int)delay) * 1e9; > > + if (waiting_for.tv_nsec >= 1000000000) { > > + waiting_for.tv_nsec -= 1000000000; > > + waiting_for.tv_sec++; > > + } > > + > > + /* How long do we have to wait? (might be negative) */ > > + clock_gettime(CLOCK_MONOTONIC, &now); > > + ts.tv_sec = waiting_for.tv_sec - now.tv_sec; > > + ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec; > > + if (ts.tv_nsec < 0) { > > + ts.tv_sec--; > > + ts.tv_nsec += 1000000000; > > + } > > + > > + /* Wait for it. */ > > + if (ts.tv_sec > 0 || > > + (ts.tv_sec == 0 && ts.tv_nsec > 0)) { > > + if (!warned) { > > + fprintf(stderr, "throttling guest access to syslog"); > > + warned = 1; > > + } > > + while (nanosleep(&ts, &ts) < 0 && errno == EINTR) > > + ; > > + } > > + > > + /* Refil */ > > + clock_gettime(CLOCK_MONOTONIC, &now); > > + delay = (now.tv_sec - last_refil.tv_sec) + > > + (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9; > > + available += BUCKET_FILL_RATE * delay; > > + if (available > BUCKET_MAX_SIZE) > > + available = BUCKET_MAX_SIZE; > > + last_refil = now; > > + } > > + > > + assert(available >= count); > > + > > + available -= count; > > +} > > + > > +#define UNPLUG_ALL_IDE_DISKS 1 > > +#define UNPLUG_ALL_NICS 2 > > +#define UNPLUG_AUX_IDE_DISKS 4 > > These should go to the top of the file. Are they even used, the > function below doesn''t? > > > + > > +static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val) > > +{ > > + switch (addr - 0x10) { > > 0x10 should be a #define, which should be used... > > > + case 0: > > + /* Unplug devices. Value is a bitmask of which devices to > > + unplug, with bit 0 the IDE devices, bit 1 the network > > + devices, and bit 2 the non-primary-master IDE devices. */ > > + break; > > + case 2: > > + switch (val) { > > + case 1: > > + fprintf(stderr, "Citrix Windows PV drivers loaded in guest\n"); > > + break; > > + case 0: > > + fprintf(stderr, "Guest claimed to be running PV product 0?\n"); > > + break; > > + default: > > + fprintf(stderr, "Unknown PV product %d loaded in guest\n", val); > > + break; > > + } > > + driver_product_version = val; > > + break; > > + } > > +} > > + > > +static void platform_fixed_ioport_write4(void *opaque, uint32_t addr, > > + uint32_t val) > > +{ > > + switch (addr - 0x10) { > > ... here ... > > > + case 0: > > + /* PV driver version */ > > + break; > > + } > > +} > > + > > +static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val) > > +{ > > + switch (addr - 0x10) { > > ... here ... > > > + case 0: /* Platform flags */ { > > + hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ? > > + HVMMEM_ram_ro : HVMMEM_ram_rw; > > + if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) > > + fprintf(stderr,"platform_fixed_ioport: unable to change ro/rw " > > + "state of ROM memory area!\n"); > > Please introduce a macro (DPRINTF) and use that. > > > + else { > > + platform_flags = val & PFFLAG_ROM_LOCK; > > + fprintf(stderr,"platform_fixed_ioport: changed ro/rw " > > + "state of ROM memory area. now is %s state.\n", > > + (mem_type == HVMMEM_ram_ro ? "ro":"rw")); > > + } > > + break; > > + } > > + case 2: > > + /* Send bytes to syslog */ > > + if (val == ''\n'' || log_buffer_off == sizeof(log_buffer) - 1) { > > + /* Flush buffer */ > > + log_buffer[log_buffer_off] = 0; > > + throttle(log_buffer_off); > > + fprintf(stderr, "%s\n", log_buffer); > > + log_buffer_off = 0; > > + break; > > + } > > + log_buffer[log_buffer_off++] = val; > > + break; > > + } > > +} > > + > > +static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr) > > +{ > > + switch (addr - 0x10) { > > ... here ... > > > + case 0: > > + if (drivers_blacklisted) { > > + /* The drivers will recognise this magic number and refuse > > + * to do anything. */ > > + return 0xd249; > > + } else { > > + /* Magic value so that you can identify the interface. */ > > + return 0x49d2; > > + } > > + default: > > + return 0xffff; > > + } > > +} > > + > > +static uint32_t platform_fixed_ioport_read1(void *opaque, uint32_t addr) > > +{ > > + switch (addr - 0x10) { > > ... here ... > > > + case 0: > > + /* Platform flags */ > > + return platform_flags; > > + case 2: > > + /* Version number */ > > + return 1; > > + default: > > + return 0xff; > > + } > > +} > > + > > +static void platform_fixed_ioport_save(QEMUFile *f, void *opaque) > > +{ > > + qemu_put_8s(f, &platform_flags); > > +} > > + > > +static int platform_fixed_ioport_load(QEMUFile *f, void *opaque, int version_id) > > +{ > > + uint8_t flags; > > + > > + if (version_id > 1) > > + return -EINVAL; > > + > > + qemu_get_8s(f, &flags); > > + platform_fixed_ioport_write1(NULL, 0x10, flags); > > + > > + return 0; > > +} > > + > > +void platform_fixed_ioport_init(void) > > +{ > > + register_savevm(NULL, "platform_fixed_ioport", 0, 1, platform_fixed_ioport_save, > > + platform_fixed_ioport_load, NULL); > > Please use VMState instead. > > > + > > + register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL); > > and here and below. In fact, just s/0x10/XEN_PLATFORM_IOPORT/g. > > > + register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL); > > + register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL); > > + register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL); > > + register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL); > > + > > + platform_fixed_ioport_write1(NULL, 0x10, 0); > > Introduce a reset function which performs something similar. > > > +} > > + > > +static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr) > > +{ > > + addr &= 0xff; > > + > > + return (addr == 0) ? platform_fixed_ioport_read1(NULL, 0x10) : ~0u; > > Just use if. > > > +} > > + > > +static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) > > +{ > > + addr &= 0xff; > > + val &= 0xff; > > + > > + switch (addr) { > > + case 0: /* Platform flags */ > > + platform_fixed_ioport_write1(NULL, 0x10, val); > > + break; > > + case 8: > > + { > > + if (val == ''\n'' || log_buffer_off == sizeof(log_buffer) - 1) { > > + /* Flush buffer */ > > + log_buffer[log_buffer_off] = 0; > > + throttle(log_buffer_off); > > + fprintf(stderr, "%s\n", log_buffer); > > + log_buffer_off = 0; > > + break; > > + } > > + log_buffer[log_buffer_off++] = val; > > + } > > + break; > > + default: > > + break; > > + } > > +} > > + > > +static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type) > > +{ > > + PCIXenPlatformState *d = (PCIXenPlatformState *)pci_dev; > > Useless cast in C. Moreover, you should use DO_UPCAST or container_of. > > > + register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d); > > + register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d); > > +} > > + > > +static uint32_t platform_mmio_read(void *opaque, target_phys_addr_t addr) > > +{ > > + static int warnings = 0; > > + if (warnings < 5) { > > + fprintf(stderr, "Warning: attempted read from physical address " > > + "0x%"PRIx64" in xen platform mmio space\n", (uint64_t)addr); > > Instead of the cast, you should use TARGET_FMT_plx. > > > + warnings++; > > + } > > + return 0; > > +} > > + > > +static void platform_mmio_write(void *opaque, target_phys_addr_t addr, > > + uint32_t val) > > +{ > > + static int warnings = 0; > > + if (warnings < 5) { > > + fprintf(stderr, "Warning: attempted write of 0x%x to physical " > > + "address 0x%"PRIx64" in xen platform mmio space\n", > > + val, (uint64_t)addr); > > + warnings++; > > + } > > + return; > > +} > > + > > +static CPUReadMemoryFunc *platform_mmio_read_funcs[3] = { > > These should be ''const''. > > > + platform_mmio_read, > > + platform_mmio_read, > > + platform_mmio_read, > > +}; > > + > > +static CPUWriteMemoryFunc *platform_mmio_write_funcs[3] = { > > + platform_mmio_write, > > + platform_mmio_write, > > + platform_mmio_write, > > +}; > > + > > +static void platform_mmio_map(PCIDevice *d, int region_num, > > + pcibus_t addr, pcibus_t size, int type) > > +{ > > + int mmio_io_addr; > > + > > + mmio_io_addr = cpu_register_io_memory(platform_mmio_read_funcs, > > + platform_mmio_write_funcs, NULL); > > + > > + cpu_register_physical_memory(addr, 0x1000000, mmio_io_addr); > > +} > > + > > +struct pci_config_header { > > + uint16_t vendor_id; > > + uint16_t device_id; > > + uint16_t command; > > + uint16_t status; > > + uint8_t revision; > > + uint8_t api; > > + uint8_t subclass; > > + uint8_t class; > > + uint8_t cache_line_size; /* Units of 32 bit words */ > > + uint8_t latency_timer; /* In units of bus cycles */ > > + uint8_t header_type; /* Should be 0 */ > > + uint8_t bist; /* Built in self test */ > > + uint32_t base_address_regs[6]; > > + uint32_t reserved1; > > + uint16_t subsystem_vendor_id; > > + uint16_t subsystem_id; > > + uint32_t rom_addr; > > + uint32_t reserved3; > > + uint32_t reserved4; > > + uint8_t interrupt_line; > > + uint8_t interrupt_pin; > > + uint8_t min_gnt; > > + uint8_t max_lat; > > +}; > > Why can''t you use the facilities from pci.h? > > > + > > +static void xen_pci_save(QEMUFile *f, void *opaque) > > +{ > > + PCIXenPlatformState *d = opaque; > > + uint64_t t = 0; > > + > > + pci_device_save(&d->pci_dev, f); > > + qemu_put_be64s(f, &t); > > +} > > + > > +static int xen_pci_load(QEMUFile *f, void *opaque, int version_id) > > +{ > > + PCIXenPlatformState *d = opaque; > > + int ret; > > + > > + if (version_id > 3) > > + return -EINVAL; > > + > > + ret = pci_device_load(&d->pci_dev, f); > > + if (ret < 0) > > + return ret; > > + > > + if (version_id >= 2) { > > + if (version_id == 2) { > > + uint8_t flags; > > + qemu_get_8s(f, &flags); > > + xen_platform_ioport_writeb(d, 0, flags); > > + } > > + qemu_get_be64(f); > > + } > > + > > + return 0; > > +} > > + > > +void pci_xen_platform_init(PCIBus *bus) > > +{ > > + PCIXenPlatformState *d; > > + struct pci_config_header *pch; > > + > > + printf("Register xen platform.\n"); > > + d = (PCIXenPlatformState *)pci_register_device( > > + bus, "xen-platform", sizeof(PCIXenPlatformState), -1, NULL, NULL); > > + pch = (struct pci_config_header *)d->pci_dev.config; > > + pch->vendor_id = 0x5853; > > You should use pci_set_word etc. Please add 0x5853 to pci_ids.h. > > > + pch->device_id = 0x0001; > > + pch->command = 3; /* IO and memory access */ > > + pch->revision = 1; > > + pch->api = 0; > > + pch->subclass = 0x80; /* Other */ > > + pch->class = 0xff; /* Unclassified device class */ > > + pch->header_type = 0; > > + pch->interrupt_pin = 1; > > + > > + /* Microsoft WHQL requires non-zero subsystem IDs. */ > > + /* http://www.pcisig.com/reflector/msg02205.html. */ > > + pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id. */ > > + pch->subsystem_id = 0x0001; /* Hardcode sub-id as 1. */ > > + > > + pci_register_bar(&d->pci_dev, 0, 0x100, > > + PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map); > > + > > + /* reserve 16MB mmio address for share memory*/ > > + pci_register_bar(&d->pci_dev, 1, 0x1000000, > > + PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map); > > + > > + register_savevm(NULL, "platform", 0, 3, xen_pci_save, xen_pci_load, d); > > + printf("Done register platform.\n"); > > +} > > + > > diff --git a/hw/xen_platform.h b/hw/xen_platform.h > > new file mode 100644 > > index 0000000..6eeff22 > > --- /dev/null > > +++ b/hw/xen_platform.h > > @@ -0,0 +1,9 @@ > > +#ifndef XEN_PLATFORM_H > > +#define XEN_PLATFORM_H > > + > > +#include "hw/pci.h" > > + > > +void pci_xen_platform_init(PCIBus *bus); > > +void platform_fixed_ioport_init(void); > > + > > +#endif > > -- > > 1.7.0.4 > > > > > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 13:10 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 12/15] piix_pci: introduce a write_config notifier
On Thu, 12 Aug 2010, Blue Swirl wrote:> On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote: > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > Introduce a write config notifier in piix_pci, so that clients can be > > notified every time a pci config write happens. > > The patch also makes use of the notification mechanism in > > xen_machine_fv. > > Will the mechanism be used elsewhere? If not, I''d just add a call to > xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded > by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and > friends. >we were trying to avoid ifdef''s in piix_pci, but if you are OK with just a couple of them we''ll gladly remove the hook. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 13:10 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 09/15] xen: Initialize event channels and io rings
On Thu, 12 Aug 2010, Blue Swirl wrote:> > +static inline void read_physical(uint64_t addr, unsigned long size, void *val) > > +{ > > + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0); > > +} > > + > > +static inline void write_physical(uint64_t addr, unsigned long size, void *val) > > +{ > > + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1); > > +} > > Useless redirection? >I guess we can just use cpu_physical_memory_read/write instead of read_physical and write_physical here. Ok also to all the other comments. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 13:10 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 11/15] piix3: introduce register_set_irq and register_map_irq
On Thu, 12 Aug 2010, Blue Swirl wrote:> On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote: > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > This patch introduces a generic function registration mechanism for > > set_irq and map_irq in piix3, so that the two calls can be > > overridden with platform specific functions whenever needed. > > The patch also implements and registers the Xen specific version of the > > functions. > > I''d avoid the registration, see my comments for the other registration patch.sure _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 13:10 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
On Thu, 12 Aug 2010, Blue Swirl wrote:> On Thu, Aug 12, 2010 at 2:10 PM, <stefano.stabellini@eu.citrix.com> wrote: > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > Xen currently uses a different BIOS (hvmloader + rombios) therefore the > > Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. > > We plan on fixing this properly but at the moment we are just adding a > > new Xen specific acpi_piix4 implementation. > > I''d suppose the proper fix is to modify acpi_piix4 instead of copy&paste. >Yes, but we would need few xen specific hooks in acpi_piix4 to make the S state transitions work correctly; if you are OK with it we''ll proceed in that direction. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 13:10 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
On Thu, 12 Aug 2010, Blue Swirl wrote:> On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote: > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > This patch adds a new Xen device model target to Qemu, called > > target-xen. > > I don''t understand why it would be a target, QEMU calls CPU > architectures targets. Isn''t it possible to have Xen for Sparc, PPC or > ARM? It should really be just a machine, not copy&paste from x86 > target. >It is not possible to have Xen device models for Sparc, PPC or ARM: the only architecture that supports Xen HVM guests is x86 and x86_64. Also most of the x86 copy and paste are definitions or stubs that haven''t really changed in a very long time.> > +/* > > + * This next section was clone-and-hacked from the version in exec.c > > + * :-(. But the exec.c version is full of tcg-specific stuff and > > + * assumptions about phys_ram_base. > > Then fix those assumptions and introduce xen specific hooks, like KVM. >That comment goes back to the very first qemu-xen integration, it is not so relevant anymore. I don''t know kvm hooks well enough to be sure that something similar could work well for Xen too and honestly I don''t see many benefits in doing so. In particular I am afraid that taking that route might cause a much heavier impact on common code and APIs and ultimately could cause more problems than it solves. As you can see the current approach has the benefit of being self-contained and considering that the xen device model use case works only on x86, doesn''t do any cpu emulation and needs a specific set of emulated hardware, I think it makes sense to have its own target. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-13 17:35 UTC
Re: [Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
On Fri, Aug 13, 2010 at 12:47 PM, Ian Jackson <Ian.Jackson@eu.citrix.com> wrote:> Blue Swirl writes ("[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen"): >> I don''t understand why it would be a target, QEMU calls CPU >> architectures targets. Isn''t it possible to have Xen for Sparc, PPC or >> ARM? It should really be just a machine, not copy&paste from x86 >> target. > > Qemu''s targets include much more of Qemu''s system emulation than is > appropriate for Xen, because the hypervisor is doing more of the > work. Â For example, there is no representation of the guest CPU state > outside the hypervisor so Qemu doesn''t see that at all.But you could easily ignore QEMU''s CPU state, or even better would be to support some kind of CPU state synchronization. KVM also manages the CPU when it is charge, but at the transition points the state is synched with QEMU state. For example, what should happen to CPU on system reset on Xen? In this version, reset is completely ignored. About the other changes, for example cpu_physical_memory_map() seems to do very different things on Xen than QEMU. But this can be handled easily by adding some kind of indirection to exec.c or just: if (xen_enabled()) { xen_func(); } else { tcg_func(); } or add stubs for non-Xen case and then: xen_func(); if (!xen_enabled()) { tcg_func(); }> So it makes sense to do Xen emulation in Qemu as a new target than > just as a machine.It''s also possible to add a new x86 CPU model like ''xen-x86''.> Yes, in principle Xen for Sparc, PPC and ARM are possible; some of > these have existed in the past although targets other than i386, > itanium and amd64 aren''t currently supported by xen-unstable. Â So > perhaps the currently-introduced xen target should be called > target-i386-xen. Â However, in practice since in a Xen system Qemu > doesn''t deal with CPU instructions these other targets will be much > more like each other than (say) i386 is close to m68k. > > Or to put it all another way: from the point of view of Qemu, Xen is > a weird kind of cpu architecture whose instruction emulation is done > "by magic" and Qemu doesn''t need to care vary much about that.I don''t see how this is so different from KVM, which is integrated to QEMU cleanly. Even if the changes would be more invasive that way (like the memory changes which KVM hasn''t done so far), I''d still think that would be better for everyone than having two versions of the same code with some changes. They would eventually drift apart. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Blue Swirl
2010-Aug-13 17:46 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 03/15] xen: Add a new target to qemu: target-xen
On Fri, Aug 13, 2010 at 1:10 PM, Stefano Stabellini <stefano.stabellini@eu.citrix.com> wrote:> On Thu, 12 Aug 2010, Blue Swirl wrote: >> On Thu, Aug 12, 2010 at 2:09 PM, Â <stefano.stabellini@eu.citrix.com> wrote: >> > From: Anthony PERARD <anthony.perard@citrix.com> >> > >> > This patch adds a new Xen device model target to Qemu, called >> > target-xen. >> >> I don''t understand why it would be a target, QEMU calls CPU >> architectures targets. Isn''t it possible to have Xen for Sparc, PPC or >> ARM? It should really be just a machine, not copy&paste from x86 >> target. >> > > It is not possible to have Xen device models for Sparc, PPC or ARM: the > only architecture that supports Xen HVM guests is x86 and x86_64. > Also most of the x86 copy and paste are definitions or stubs that > haven''t really changed in a very long time.What about Itanium? The patch already adds some conditional code.>> > +/* >> > + * This next section was clone-and-hacked from the version in exec.c >> > + * :-(. Â But the exec.c version is full of tcg-specific stuff and >> > + * assumptions about phys_ram_base. >> >> Then fix those assumptions and introduce xen specific hooks, like KVM. >> > > That comment goes back to the very first qemu-xen integration, it is not > so relevant anymore. > I don''t know kvm hooks well enough to be sure that something similar > could work well for Xen too and honestly I don''t see many benefits in > doing so.In Makefile.target we have just these lines: obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o The stub functions return -ENOSYS. The benefit is that Xen code would then be fully integrated with QEMU. Xen would benefit from improvements to the shared code, vice versa for QEMU.> In particular I am afraid that taking that route might cause a much > heavier impact on common code and APIs and ultimately could cause more > problems than it solves. As you can see the current approach has the > benefit of being self-contained and considering that the xen device > model use case works only on x86, doesn''t do any cpu emulation and needs > a specific set of emulated hardware, I think it makes sense to have its > own target.I''m not afraid of the impact, from an architectural standpoint the completely integrated version would be much more preferable. Self-contained solution is not unlike out-of-tree version, it will bitrot and die. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 18:50 UTC
[Xen-devel] Re: [PATCH 03/15] xen: Add a new target to qemu: target-xen
On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > This patch adds a new Xen device model target to Qemu, called > target-xen. >A xen specific target is definitely the wrong approach. I understand the desire to avoid the TCG code. We would like to (optionally) do the same in KVM. The right way to do this though is to make it possible to build without TCG by wrapping the common interfaces in a function pointer table.> diff --git a/target-xen/exec-dm.c b/target-xen/exec-dm.c > new file mode 100644 > index 0000000..3d64695 > --- /dev/null > +++ b/target-xen/exec-dm.c >This takes a non-target specific file and makes it target specific. This is not a reasonable approach. What''s the issue with the existing exec.c? Regards, Anthony Liguori _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 18:53 UTC
[Xen-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > Introduce functions to read and write the state of the VM in xenstore. >This basically creates a new management interface for QEMU via the xenstore. Our management interface is QMP. If you want to maintain compatibility, you''ll need to write a QMP -> xenstore daemon that maps events appropriately. Regards, Anthony Liguori> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > --- > hw/xen_machine_fv.c | 9 ++++ > target-xen/helper.c | 7 +++ > target-xen/qemu-xen.h | 3 + > target-xen/xenstore.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ > target-xen/xenstore.h | 6 ++ > 5 files changed, 153 insertions(+), 0 deletions(-) > > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index ec826e7..a6e778a 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -36,10 +36,17 @@ > #include "xen_backend.h" > #include "xenstore.h" > #include "xen_platform.h" > +#include "qemu-xen.h" > #include "xen/hvm/hvm_info_table.h" > > #define MAX_IDE_BUS 2 > > +static void xen_vm_change_state_handler(void *opaque, int running, int reason) > +{ > + if (running) > + xen_main_loop_prepare(); > +} > + > static void xen_init_fv(ram_addr_t ram_size, > const char *boot_device, > const char *kernel_filename, > @@ -150,6 +157,8 @@ static void xen_init_fv(ram_addr_t ram_size, > } > > pc_pci_device_init(pci_bus); > + > + qemu_add_vm_change_state_handler(xen_vm_change_state_handler, NULL); > } > > static QEMUMachine xenfv_machine = { > diff --git a/target-xen/helper.c b/target-xen/helper.c > index d588e64..8cb7771 100644 > --- a/target-xen/helper.c > +++ b/target-xen/helper.c > @@ -19,6 +19,8 @@ > */ > > #include "cpu.h" > +#include "qemu-xen.h" > +#include "xenstore.h" > > CPUXenState *cpu_xen_init(const char *cpu_model) > { > @@ -67,3 +69,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) > { > return addr; > } > + > +void xen_main_loop_prepare(void) > +{ > + xenstore_record_dm_state("running"); > +} > diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h > index d1910d6..091ae07 100644 > --- a/target-xen/qemu-xen.h > +++ b/target-xen/qemu-xen.h > @@ -27,4 +27,7 @@ int cpu_register_io_memory_fixed(int io_index, > CPUWriteMemoryFunc * const *mem_write, > void *opaque); > > +/* target-xen/helper.c */ > +void xen_main_loop_prepare(void); > + > #endif /*QEMU_XEN_H*/ > diff --git a/target-xen/xenstore.c b/target-xen/xenstore.c > index 9f2e1ea..6eb6a30 100644 > --- a/target-xen/xenstore.c > +++ b/target-xen/xenstore.c > @@ -13,6 +13,60 @@ static void xenstore_process_event(void *opaque) > free(vec); > } > > +static const char *xenstore_get_guest_uuid(void) > +{ > + static char *already_computed = NULL; > + > + char *domain_path = NULL, *vm_path = NULL, *vm_value = NULL, *p = NULL; > + unsigned int len; > + > + if (already_computed) > + return already_computed; > + > + if (xen_xc == NULL) > + return NULL; > + > + domain_path = xs_get_domain_path(xenstore, xen_domid); > + if (domain_path == NULL) { > + fprintf(stderr, "xs_get_domain_path() error. domid %d.\n", xen_domid); > + goto out; > + } > + > + if (asprintf(&vm_path, "%s/vm", domain_path) == -1) { > + fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n"); > + goto out; > + } > + vm_value = xs_read(xenstore, XBT_NULL, vm_path,&len); > + if (vm_value == NULL) { > + fprintf(stderr, "xs_read(): uuid get error. %s.\n", vm_path); > + goto out; > + } > + > + if (strtok(vm_value, "/") == NULL) { > + fprintf(stderr, "failed to parse guest uuid\n"); > + goto out; > + } > + p = strtok(NULL, "/"); > + if (p == NULL) { > + fprintf(stderr, "failed to parse guest uuid\n"); > + goto out; > + } > + > + if (asprintf(&already_computed, "%s", p) == -1) { > + fprintf(stderr, "xenstore_get_guest_uuid(): out of memory.\n"); > + goto out; > + } > + > + fprintf(stderr, "Guest uuid = %s\n", already_computed); > + > +out: > + free(domain_path); > + free(vm_path); > + free(vm_value); > + > + return already_computed; > +} > + > int xen_dm_init(void) > { > xenstore = xs_daemon_open(); > @@ -29,6 +83,7 @@ int xen_dm_init(void) > xen_be_printf(NULL, 0, "can''t open xen interface\n"); > goto err; > } > + > return 0; > > err: > @@ -38,3 +93,76 @@ err: > > return -1; > } > + > +static char *xenstore_vm_key_path(int domid, const char *key) { > + const char *uuid; > + char *buf = NULL; > + > + if (xenstore == NULL) > + return NULL; > + > + uuid = xenstore_get_guest_uuid(); > + if (!uuid) > + return NULL; > + > + if (asprintf(&buf, "/vm/%s/%s", uuid, key) == -1) > + return NULL; > + > + return buf; > +} > + > +char *xenstore_vm_read(int domid, const char *key, unsigned int *len) > +{ > + char *path = NULL, *value = NULL; > + > + path = xenstore_vm_key_path(domid, key); > + if (!path) > + return NULL; > + > + value = xs_read(xenstore, XBT_NULL, path, len); > + if (value == NULL) { > + fprintf(stderr, "xs_read(%s): read error\n", path); > + } > + > + free(path); > + return value; > +} > + > +int xenstore_vm_write(int domid, const char *key, const char *value) > +{ > + char *path = NULL; > + int rc = -1; > + > + path = xenstore_vm_key_path(domid, key); > + if (!path) > + return 0; > + > + rc = xs_write(xenstore, XBT_NULL, path, value, strlen(value)); > + if (rc == 0) { > + fprintf(stderr, "xs_write(%s, %s): write error\n", path, key); > + } > + > + free(path); > + return rc; > +} > + > +void xenstore_record_dm(const char *subpath, const char *state) > +{ > + char *path = NULL; > + > + if (asprintf(&path, > + "/local/domain/0/device-model/%u/%s", xen_domid, subpath) == -1) { > + fprintf(stderr, "out of memory recording dm\n"); > + goto out; > + } > + if (!xs_write(xenstore, XBT_NULL, path, state, strlen(state))) > + fprintf(stderr, "error recording dm\n"); > + > +out: > + free(path); > +} > + > +void xenstore_record_dm_state(const char *state) > +{ > + xenstore_record_dm("state", state); > +} > diff --git a/target-xen/xenstore.h b/target-xen/xenstore.h > index 90baf79..c8144ea 100644 > --- a/target-xen/xenstore.h > +++ b/target-xen/xenstore.h > @@ -3,4 +3,10 @@ > > int xen_dm_init(void); > > +char *xenstore_vm_read(int domid, const char *key, unsigned int *len); > +int xenstore_vm_write(int domid, const char *key, const char *value); > + > +void xenstore_record_dm(const char *subpath, const char *state); > +void xenstore_record_dm_state(const char *state); > + > #endif /* !XENSTORE_H_ */ >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 18:54 UTC
[Xen-devel] Re: [PATCH 09/15] xen: Initialize event channels and io rings
On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > Open and bind event channels; map ioreq and buffered ioreq rings. > > Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > --- > hw/xen_machine_fv.c | 25 ++++ > target-xen/cpu.h | 1 + > target-xen/helper.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++++ > target-xen/qemu-xen.h | 2 + > 4 files changed, 390 insertions(+), 0 deletions(-) > > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index a6e778a..b1bc88d 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -22,6 +22,9 @@ > * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > * THE SOFTWARE. > */ > +#include "config.h" > + > +#include<sys/mman.h> > > #include "hw.h" > #include "pc.h" > @@ -71,12 +74,34 @@ static void xen_init_fv(ram_addr_t ram_size, > > CPUState *env; > > + unsigned long ioreq_pfn; > + extern void *shared_page; > + extern void *buffered_io_page; > + > /* Initialize backend core& drivers */ > if (xen_dm_init() != 0) { > fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__); > exit(1); > } > > + xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN,&ioreq_pfn); > + fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn); > + shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, > + PROT_READ|PROT_WRITE, ioreq_pfn); > + if (shared_page == NULL) { > + fprintf(stderr, "map shared IO page returned error %d handle=%p\n", errno, xen_xc); > + exit(-1); > + } > + > + xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_BUFIOREQ_PFN,&ioreq_pfn); > + fprintf(stderr, "buffered io page at pfn %lx\n", ioreq_pfn); > + buffered_io_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, > + PROT_READ|PROT_WRITE, ioreq_pfn); > + if (buffered_io_page == NULL) { > + fprintf(logfile, "map buffered IO page returned error %d\n", errno); > + exit(-1); > + } > + > /* Initialize a dummy CPU */ > if (cpu_model == NULL) { > #ifdef TARGET_X86_64 > diff --git a/target-xen/cpu.h b/target-xen/cpu.h > index 5a45d1c..573241f 100644 > --- a/target-xen/cpu.h > +++ b/target-xen/cpu.h > @@ -72,6 +72,7 @@ typedef struct CPUXenState { > > CPUXenState *cpu_xen_init(const char *cpu_model); > int cpu_xen_exec(CPUXenState *s); > +void cpu_xen_close(CPUXenState *s); > > int cpu_get_pic_interrupt(CPUXenState *s); > void cpu_set_ferr(CPUX86State *s); > diff --git a/target-xen/helper.c b/target-xen/helper.c > index 8cb7771..4571ac0 100644 > --- a/target-xen/helper.c > +++ b/target-xen/helper.c > @@ -18,25 +18,77 @@ > * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > > +#include "config.h" > + > +#include<inttypes.h> > + > +#include<xenctrl.h> > +#include<xen/hvm/ioreq.h> > + > #include "cpu.h" > #include "qemu-xen.h" > #include "xenstore.h" > +#include "hw/xen_backend.h" > + > +long time_offset = 0; > + > +shared_iopage_t *shared_page = NULL; > + > +#define BUFFER_IO_MAX_DELAY 100 > +buffered_iopage_t *buffered_io_page = NULL; > +QEMUTimer *buffered_io_timer; > + > +/* the evtchn fd for polling */ > +int xce_handle = -1; > + > +/* which vcpu we are serving */ > +int send_vcpu = 0; > + > +/* the evtchn port for polling the notification, */ > +evtchn_port_t *ioreq_local_port; > > CPUXenState *cpu_xen_init(const char *cpu_model) > { > CPUXenState *env = NULL; > static int inited; > + int i, rc; > > env = qemu_mallocz(sizeof(CPUXenState)); > if (!env) > return NULL; > cpu_exec_init(env); > > + /* There is no shared_page for PV, we''re done now */ > + if (shared_page == NULL) > + return env; > + > + ioreq_local_port > + (evtchn_port_t *)qemu_mallocz(smp_cpus * sizeof(evtchn_port_t)); > + if (!ioreq_local_port) > + return NULL; > + >You don''t need to check for NULL. There''s numerous CODING_STYLE issues in this file too (like C99 comments). Regards, Anthony Liguori> /* init various static tables */ > if (!inited) { > inited = 1; > > cpu_single_env = env; > + > + xce_handle = xc_evtchn_open(); > + if (xce_handle == -1) { > + perror("open"); > + return NULL; > + } > + > + /* FIXME: how about if we overflow the page here? */ > + for (i = 0; i< smp_cpus; i++) { > + rc = xc_evtchn_bind_interdomain( > + xce_handle, xen_domid, shared_page->vcpu_ioreq[i].vp_eport); > + if (rc == -1) { > + fprintf(stderr, "bind interdomain ioctl error %d\n", errno); > + return NULL; > + } > + ioreq_local_port[i] = rc; > + } > } > > return env; > @@ -70,7 +122,317 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) > return addr; > } > > +// get the ioreq packets from share mem > +static ioreq_t *__cpu_get_ioreq(int vcpu) > +{ > + ioreq_t *req =&shared_page->vcpu_ioreq[vcpu]; > + > + if (req->state != STATE_IOREQ_READY) { > + fprintf(stderr, "I/O request not ready: " > + "%x, ptr: %x, port: %"PRIx64", " > + "data: %"PRIx64", count: %u, size: %u\n", > + req->state, req->data_is_ptr, req->addr, > + req->data, req->count, req->size); > + return NULL; > + } > + > + xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */ > + > + req->state = STATE_IOREQ_INPROCESS; > + return req; > +} > + > +// use poll to get the port notification > +// ioreq_vec--out,the > +// retval--the number of ioreq packet > +static ioreq_t *cpu_get_ioreq(void) > +{ > + int i; > + evtchn_port_t port; > + > + port = xc_evtchn_pending(xce_handle); > + if (port != -1) { > + for ( i = 0; i< smp_cpus; i++ ) > + if ( ioreq_local_port[i] == port ) > + break; > + > + if ( i == smp_cpus ) { > + fprintf(stderr, "Fatal error while trying to get io event!\n"); > + exit(1); > + } > + > + // unmask the wanted port again > + xc_evtchn_unmask(xce_handle, port); > + > + // get the io packet from shared memory > + send_vcpu = i; > + return __cpu_get_ioreq(i); > + } > + > + // read error or read nothing > + return NULL; > +} > + > +static unsigned long do_inp(CPUState *env, unsigned long addr, > + unsigned long size) > +{ > + switch(size) { > + case 1: > + return cpu_inb(addr); > + case 2: > + return cpu_inw(addr); > + case 4: > + return cpu_inl(addr); > + default: > + fprintf(stderr, "inp: bad size: %lx %lx\n", addr, size); > + exit(-1); > + } > +} > + > +static void do_outp(CPUState *env, unsigned long addr, > + unsigned long size, unsigned long val) > +{ > + switch(size) { > + case 1: > + return cpu_outb(addr, val); > + case 2: > + return cpu_outw(addr, val); > + case 4: > + return cpu_outl(addr, val); > + default: > + fprintf(stderr, "outp: bad size: %lx %lx\n", addr, size); > + exit(-1); > + } > +} > + > +static inline void read_physical(uint64_t addr, unsigned long size, void *val) > +{ > + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 0); > +} > + > +static inline void write_physical(uint64_t addr, unsigned long size, void *val) > +{ > + return cpu_physical_memory_rw((target_phys_addr_t)addr, val, size, 1); > +} > + > +static void cpu_ioreq_pio(CPUState *env, ioreq_t *req) > +{ > + int i, sign; > + > + sign = req->df ? -1 : 1; > + > + if (req->dir == IOREQ_READ) { > + if (!req->data_is_ptr) { > + req->data = do_inp(env, req->addr, req->size); > + } else { > + unsigned long tmp; > + > + for (i = 0; i< req->count; i++) { > + tmp = do_inp(env, req->addr, req->size); > + write_physical((target_phys_addr_t) req->data > + + (sign * i * req->size), > + req->size,&tmp); > + } > + } > + } else if (req->dir == IOREQ_WRITE) { > + if (!req->data_is_ptr) { > + do_outp(env, req->addr, req->size, req->data); > + } else { > + for (i = 0; i< req->count; i++) { > + unsigned long tmp = 0; > + > + read_physical((target_phys_addr_t) req->data > + + (sign * i * req->size), > + req->size,&tmp); > + do_outp(env, req->addr, req->size, tmp); > + } > + } > + } > +} > + > +static void cpu_ioreq_move(CPUState *env, ioreq_t *req) > +{ > + int i, sign; > + > + sign = req->df ? -1 : 1; > + > + if (!req->data_is_ptr) { > + if (req->dir == IOREQ_READ) { > + for (i = 0; i< req->count; i++) { > + read_physical(req->addr > + + (sign * i * req->size), > + req->size,&req->data); > + } > + } else if (req->dir == IOREQ_WRITE) { > + for (i = 0; i< req->count; i++) { > + write_physical(req->addr > + + (sign * i * req->size), > + req->size,&req->data); > + } > + } > + } else { > + target_ulong tmp; > + > + if (req->dir == IOREQ_READ) { > + for (i = 0; i< req->count; i++) { > + read_physical(req->addr > + + (sign * i * req->size), > + req->size,&tmp); > + write_physical((target_phys_addr_t )req->data > + + (sign * i * req->size), > + req->size,&tmp); > + } > + } else if (req->dir == IOREQ_WRITE) { > + for (i = 0; i< req->count; i++) { > + read_physical((target_phys_addr_t) req->data > + + (sign * i * req->size), > + req->size,&tmp); > + write_physical(req->addr > + + (sign * i * req->size), > + req->size,&tmp); > + } > + } > + } > +} > + > +static void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req) > +{ > + char b[64]; > + > + time_offset += (unsigned long)req->data; > + > + fprintf(stderr, "Time offset set %ld, added offset %"PRId64"\n", > + time_offset, req->data); > + sprintf(b, "%ld", time_offset); > + xenstore_vm_write(xen_domid, "rtc/timeoffset", b); > +} > + > +static void __handle_ioreq(CPUState *env, ioreq_t *req) > +{ > + if (!req->data_is_ptr&& (req->dir == IOREQ_WRITE)&& > + (req->size< sizeof(target_ulong))) > + req->data&= ((target_ulong)1<< (8 * req->size)) - 1; > + > + switch (req->type) { > + case IOREQ_TYPE_PIO: > + cpu_ioreq_pio(env, req); > + break; > + case IOREQ_TYPE_COPY: > + cpu_ioreq_move(env, req); > + break; > + case IOREQ_TYPE_TIMEOFFSET: > + cpu_ioreq_timeoffset(env, req); > + break; > + case IOREQ_TYPE_INVALIDATE: > + qemu_invalidate_map_cache(); > + break; > + default: > + hw_error("Invalid ioreq type 0x%x\n", req->type); > + } > +} > + > +static void __handle_buffered_iopage(CPUState *env) > +{ > + buf_ioreq_t *buf_req = NULL; > + ioreq_t req; > + int qw; > + > + if (!buffered_io_page) > + return; > + > + while (buffered_io_page->read_pointer !> + buffered_io_page->write_pointer) { > + buf_req =&buffered_io_page->buf_ioreq[ > + buffered_io_page->read_pointer % IOREQ_BUFFER_SLOT_NUM]; > + req.size = 1UL<< buf_req->size; > + req.count = 1; > + req.addr = buf_req->addr; > + req.data = buf_req->data; > + req.state = STATE_IOREQ_READY; > + req.dir = buf_req->dir; > + req.df = 1; > + req.type = buf_req->type; > + req.data_is_ptr = 0; > + qw = (req.size == 8); > + if (qw) { > + buf_req =&buffered_io_page->buf_ioreq[ > + (buffered_io_page->read_pointer+1) % IOREQ_BUFFER_SLOT_NUM]; > + req.data |= ((uint64_t)buf_req->data)<< 32; > + } > + > + __handle_ioreq(env,&req); > + > + xen_mb(); > + buffered_io_page->read_pointer += qw ? 2 : 1; > + } > +} > + > +static void handle_buffered_io(void *opaque) > +{ > + CPUState *env = opaque; > + > + __handle_buffered_iopage(env); > + qemu_mod_timer(buffered_io_timer, BUFFER_IO_MAX_DELAY + > + qemu_get_clock(rt_clock)); > +} > + > +static void cpu_handle_ioreq(void *opaque) > +{ > + CPUState *env = opaque; > + ioreq_t *req = cpu_get_ioreq(); > + > + __handle_buffered_iopage(env); > + if (req) { > + __handle_ioreq(env, req); > + > + if (req->state != STATE_IOREQ_INPROCESS) { > + fprintf(stderr, "Badness in I/O request ... not in service?!: " > + "%x, ptr: %x, port: %"PRIx64", " > + "data: %"PRIx64", count: %u, size: %u\n", > + req->state, req->data_is_ptr, req->addr, > + req->data, req->count, req->size); > + destroy_hvm_domain(); > + return; > + } > + > + xen_wmb(); /* Update ioreq contents /then/ update state. */ > + > + req->state = STATE_IORESP_READY; > + xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); > + } > +} > + > void xen_main_loop_prepare(void) > { > + CPUState *env = cpu_single_env; > + > + int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle); > + > + buffered_io_timer = qemu_new_timer(rt_clock, handle_buffered_io, > + cpu_single_env); > + qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock)); > + > + if (evtchn_fd != -1) > + qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); > + > xenstore_record_dm_state("running"); > } > + > +void destroy_hvm_domain(void) > +{ > + xc_interface *xcHandle; > + int sts; > + > + xcHandle = xc_interface_open(NULL, NULL, 0); > + if (xcHandle< 0) > + fprintf(stderr, "Cannot acquire xenctrl handle\n"); > + else { > + sts = xc_domain_shutdown(xcHandle, xen_domid, SHUTDOWN_poweroff); > + if (sts != 0) > + fprintf(stderr, "? xc_domain_shutdown failed to issue poweroff, " > + "sts %d, errno %d\n", sts, errno); > + else > + fprintf(stderr, "Issued domain %d poweroff\n", xen_domid); > + xc_interface_close(xcHandle); > + } > +} > diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h > index 091ae07..79a4638 100644 > --- a/target-xen/qemu-xen.h > +++ b/target-xen/qemu-xen.h > @@ -22,12 +22,14 @@ void qemu_invalidate_map_cache(void); > > /* target-xen/exec-dm.c */ > > +void destroy_hvm_domain(void); > int cpu_register_io_memory_fixed(int io_index, > CPUReadMemoryFunc * const *mem_read, > CPUWriteMemoryFunc * const *mem_write, > void *opaque); > > /* target-xen/helper.c */ > +extern int xce_handle; > void xen_main_loop_prepare(void); > > #endif /*QEMU_XEN_H*/ >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 18:55 UTC
[Xen-devel] Re: [PATCH 10/15] xen: Introduce the Xen mapcache
On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > Introduce a mapcache to handle the 64bit address space of the guest > from a 32bit userland process (Qemu). > The mapcache maps chucks of guest memory on demand, unmaps them when > they are not needed anymore. > > Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > --- > hw/xen_machine_fv.c | 7 ++ > target-xen/qemu-xen.h | 15 +++ > target-xen/xen_mapcache.c | 233 +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 255 insertions(+), 0 deletions(-) > > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index b1bc88d..58237d6 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -84,6 +84,13 @@ static void xen_init_fv(ram_addr_t ram_size, > exit(1); > } > > +#if defined(__i386__) || defined(__x86_64__) > + if (qemu_map_cache_init()) { > + fprintf(stderr, "qemu_map_cache_init returned: error %d\n", errno); > + exit(-1); > + } > +#endif > + > xc_get_hvm_param(xen_xc, xen_domid, HVM_PARAM_IOREQ_PFN,&ioreq_pfn); > fprintf(stderr, "shared page at pfn %lx\n", ioreq_pfn); > shared_page = xc_map_foreign_range(xen_xc, xen_domid, XC_PAGE_SIZE, > diff --git a/target-xen/qemu-xen.h b/target-xen/qemu-xen.h > index 79a4638..e4a7030 100644 > --- a/target-xen/qemu-xen.h > +++ b/target-xen/qemu-xen.h > @@ -13,6 +13,21 @@ > > /* xen_mapcache.c */ > > +#if (defined(__i386__) || defined(__x86_64__))&& !defined(QEMU_TOOL) > +#define MAPCACHE > + > +#if defined(__i386__) > +#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ > +#define MCACHE_BUCKET_SHIFT 16 > +#elif defined(__x86_64__) > +#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ > +#define MCACHE_BUCKET_SHIFT 20 > +#endif > + > +#define MCACHE_BUCKET_SIZE (1UL<< MCACHE_BUCKET_SHIFT) > +#endif > + > +int qemu_map_cache_init(void); > uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock); > void qemu_invalidate_entry(uint8_t *buffer); > void qemu_invalidate_map_cache(void); > diff --git a/target-xen/xen_mapcache.c b/target-xen/xen_mapcache.c > index 39daae2..efe036c 100644 > --- a/target-xen/xen_mapcache.c > +++ b/target-xen/xen_mapcache.c > @@ -1,5 +1,237 @@ > +#include "config.h" > + > +#include "hw/xen_backend.h" > #include "qemu-xen.h" > > +#include<xen/hvm/params.h> > +#include<sys/mman.h> > + > +#if defined(MAPCACHE) > + > +#define BITS_PER_LONG (sizeof(long)*8) > +#define BITS_TO_LONGS(bits) \ > + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) > +#define DECLARE_BITMAP(name,bits) \ > + unsigned long name[BITS_TO_LONGS(bits)] > +#define test_bit(bit,map) \ > + (!!((map)[(bit)/BITS_PER_LONG]& (1UL<< ((bit)%BITS_PER_LONG)))) > + > +struct map_cache { > + unsigned long paddr_index; > + uint8_t *vaddr_base; > + DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>XC_PAGE_SHIFT); > + uint8_t lock; > + struct map_cache *next; > +}; > + > +struct map_cache_rev { > + uint8_t *vaddr_req; > + unsigned long paddr_index; > + QTAILQ_ENTRY(map_cache_rev) next; > +}; > >CODING_STYLE> +static struct map_cache *mapcache_entry; > +static unsigned long nr_buckets; > +QTAILQ_HEAD(map_cache_head, map_cache_rev) locked_entries = QTAILQ_HEAD_INITIALIZER(locked_entries); > + > +/* For most cases (>99.9%), the page address is the same. */ > +static unsigned long last_address_index = ~0UL; > +static uint8_t *last_address_vaddr; >Should refactor away global state.> +int qemu_map_cache_init(void) > +{ > + unsigned long size; > + > + nr_buckets = (((MAX_MCACHE_SIZE>> XC_PAGE_SHIFT) + > + (1UL<< (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)) - 1)>> > + (MCACHE_BUCKET_SHIFT - XC_PAGE_SHIFT)); > + > + /* > + * Use mmap() directly: lets us allocate a big hash table with no up-front > + * cost in storage space. The OS will allocate memory only for the buckets > + * that we actually use. All others will contain all zeroes. > + */ > + size = nr_buckets * sizeof(struct map_cache); > + size = (size + XC_PAGE_SIZE - 1)& ~(XC_PAGE_SIZE - 1); > + fprintf(stderr, "qemu_map_cache_init nr_buckets = %lx size %lu\n", nr_buckets, size); > + mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, > + MAP_SHARED|MAP_ANON, -1, 0); > + if (mapcache_entry == MAP_FAILED) { > + errno = ENOMEM; > + return -1; > + } > + > + return 0; > +} > + > +static void qemu_remap_bucket(struct map_cache *entry, > + unsigned long address_index) > +{ > + uint8_t *vaddr_base; > + xen_pfn_t pfns[MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT]; > + int err[MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT]; > + unsigned int i, j; > + > + if (entry->vaddr_base != NULL) { > + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); > + if (errno) { > + fprintf(stderr, "unmap fails %d\n", errno); > + exit(-1); > + } > + } > + > + for (i = 0; i< MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT; i++) { > + pfns[i] = (address_index<< (MCACHE_BUCKET_SHIFT-XC_PAGE_SHIFT)) + i; > + } > + > + vaddr_base = xc_map_foreign_bulk(xen_xc, xen_domid, PROT_READ|PROT_WRITE, > + pfns, err, > + MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT); > + if (vaddr_base == NULL) { > + fprintf(stderr, "xc_map_foreign_bulk error %d\n", errno); > + exit(-1); > + } > + > + entry->vaddr_base = vaddr_base; > + entry->paddr_index = address_index; > + > + for (i = 0; i< MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT; i += BITS_PER_LONG) { > + unsigned long word = 0; > + j = ((i + BITS_PER_LONG)> (MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT)) ? > + (MCACHE_BUCKET_SIZE>> XC_PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; > + while (j> 0) { > + word = (word<< 1) | !err[i + --j]; > + } > + entry->valid_mapping[i / BITS_PER_LONG] = word; > + } > +} > + > +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock) > +{ > + struct map_cache *entry, *pentry = NULL; > + unsigned long address_index = phys_addr>> MCACHE_BUCKET_SHIFT; > + unsigned long address_offset = phys_addr& (MCACHE_BUCKET_SIZE-1); > + > + if (address_index == last_address_index&& !lock) > + return last_address_vaddr + address_offset; > + > + entry =&mapcache_entry[address_index % nr_buckets]; > + > + while (entry&& entry->lock&& entry->paddr_index != address_index&& entry->vaddr_base) { > + pentry = entry; > + entry = entry->next; > + } > + if (!entry) { > + entry = qemu_mallocz(sizeof(struct map_cache)); > + pentry->next = entry; > + qemu_remap_bucket(entry, address_index); > + } else if (!entry->lock) { > + if (!entry->vaddr_base || entry->paddr_index != address_index || !test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) > + qemu_remap_bucket(entry, address_index); > + } > + > + if (!test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping)) { > + last_address_index = ~0UL; > + return NULL; > + } > + > + last_address_index = address_index; > + last_address_vaddr = entry->vaddr_base; > + if (lock) { > + struct map_cache_rev *reventry = qemu_mallocz(sizeof(struct map_cache_rev)); > + entry->lock++; > + reventry->vaddr_req = last_address_vaddr + address_offset; > + reventry->paddr_index = last_address_index; > + QTAILQ_INSERT_TAIL(&locked_entries, reventry, next); > + } > + > + return last_address_vaddr + address_offset; > +} > + > +void qemu_invalidate_entry(uint8_t *buffer) > +{ > + struct map_cache *entry = NULL, *pentry = NULL; > + struct map_cache_rev *reventry; > + unsigned long paddr_index; > + int found = 0; > + > + if (last_address_vaddr == buffer) > + last_address_index = ~0UL; > + > + QTAILQ_FOREACH(reventry,&locked_entries, next) { > + if (reventry->vaddr_req == buffer) { > + paddr_index = reventry->paddr_index; > + found = 1; > + break; > + } > + } > + if (!found) { > + fprintf(stderr, "qemu_invalidate_entry: could not find %p\n", buffer); > + QTAILQ_FOREACH(reventry,&locked_entries, next) { > + fprintf(stderr, " %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); > + } > + return; > + } > + QTAILQ_REMOVE(&locked_entries, reventry, next); > + qemu_free(reventry); > + > + entry =&mapcache_entry[paddr_index % nr_buckets]; > + while (entry&& entry->paddr_index != paddr_index) { > + pentry = entry; > + entry = entry->next; > + } > + if (!entry) { > + fprintf(stderr, "Trying to unmap address %p that is not in the mapcache!\n", buffer); > + return; > + } > + entry->lock--; > + if (entry->lock> 0 || pentry == NULL) > + return; > + > + pentry->next = entry->next; > + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); > + if (errno) { > + fprintf(stderr, "unmap fails %d\n", errno); > + exit(-1); > + } > + qemu_free(entry); > +} > + > +void qemu_invalidate_map_cache(void) > +{ > + unsigned long i; > + struct map_cache_rev *reventry; > + > + qemu_aio_flush(); > + > + QTAILQ_FOREACH(reventry,&locked_entries, next) { > + fprintf(stderr, "There should be no locked mappings at this time, but %lx -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); > + } > + > + mapcache_lock(); > + > + for (i = 0; i< nr_buckets; i++) { > + struct map_cache *entry =&mapcache_entry[i]; > + > + if (entry->vaddr_base == NULL) > + continue; > + > + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); > + if (errno) { > + fprintf(stderr, "unmap fails %d\n", errno); > + exit(-1); > + } > + > + entry->paddr_index = 0; > + entry->vaddr_base = NULL; > + } > + > + last_address_index = ~0UL; > + last_address_vaddr = NULL; > + > + mapcache_unlock(); > +} > +#else > uint8_t *qemu_map_cache(target_phys_addr_t phys_addr, uint8_t lock) > { > return phys_ram_addr(phys_addr); > @@ -12,3 +244,4 @@ void qemu_invalidate_map_cache(void) > void qemu_invalidate_entry(uint8_t *buffer) > { > } > +#endif /* !MAPCACHE */ >This should really tie into the RAMBlock infrastructure. Regards, Anthony Liguori _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 18:56 UTC
[Xen-devel] Re: [PATCH 14/15] xen: destroy the VM when shutdown is requested
On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > Handle shutdown and reset requests in helper.c. > > Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > --- > target-xen/helper.c | 17 +++++++++++++++++ > 1 files changed, 17 insertions(+), 0 deletions(-) > > diff --git a/target-xen/helper.c b/target-xen/helper.c > index 4571ac0..16e628c 100644 > --- a/target-xen/helper.c > +++ b/target-xen/helper.c > @@ -397,6 +397,23 @@ static void cpu_handle_ioreq(void *opaque) > > xen_wmb(); /* Update ioreq contents /then/ update state. */ > > + /* > + * We do this before we send the response so that the tools > + * have the opportunity to pick up on the reset before the > + * guest resumes and does a hlt with interrupts disabled which > + * causes Xen to powerdown the domain. > + */ > + if (vm_running) { > + if (qemu_shutdown_requested_get()) { > + fprintf(stderr, "shutdown requested in cpu_handle_ioreq\n"); > + destroy_hvm_domain(); > + } >The patches should not introduce fprintfs in expected paths. Regards, Anthony Liguori> + if (qemu_reset_requested_get()) { > + fprintf(stderr, "reset requested in cpu_handle_ioreq.\n"); > + qemu_system_reset(); > + } > + } > + > req->state = STATE_IORESP_READY; > xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); > } >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 18:57 UTC
[Xen-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote:> From: Anthony PERARD<anthony.perard@citrix.com> > > Xen currently uses a different BIOS (hvmloader + rombios) therefore the > Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. > We plan on fixing this properly but at the moment we are just adding a > new Xen specific acpi_piix4 implementation. > This patch is optional; without it the VM boots but it cannot shutdown > properly or go to S3. >What''s the long term plan? Will Xen adopt SeaBIOS or will you adapt your BIOS to cope with our ACPI implementation? Regards, Anthony Liguori> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> > --- > Makefile.target | 1 + > hw/xen_acpi_piix4.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/xen_common.h | 3 + > hw/xen_machine_fv.c | 6 +- > 4 files changed, 429 insertions(+), 5 deletions(-) > create mode 100644 hw/xen_acpi_piix4.c > > diff --git a/Makefile.target b/Makefile.target > index 1984cdd..a2d9217 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -325,6 +325,7 @@ obj-xen-y += piix_pci.o > obj-xen-y += mc146818rtc.o > obj-xen-y += xenstore.o > obj-xen-y += xen_platform.o > +obj-xen-y += xen_acpi_piix4.o > > obj-xen-y += xen_mapcache.o > obj-xen-y += stub-functions.o > diff --git a/hw/xen_acpi_piix4.c b/hw/xen_acpi_piix4.c > new file mode 100644 > index 0000000..3c65963 > --- /dev/null > +++ b/hw/xen_acpi_piix4.c > @@ -0,0 +1,424 @@ > + /* > + * PIIX4 ACPI controller emulation > + * > + * Winston liwen Wang, winston.l.wang@intel.com > + * Copyright (c) 2006 , Intel Corporation. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "hw.h" > +#include "pc.h" > +#include "pci.h" > +#include "sysemu.h" > +#include "acpi.h" > + > +#include "xen_backend.h" > +#include "xen_common.h" > +#include "qemu-log.h" > + > +#include<xen/hvm/ioreq.h> > +#include<xen/hvm/params.h> > + > +#define PIIX4ACPI_LOG_ERROR 0 > +#define PIIX4ACPI_LOG_INFO 1 > +#define PIIX4ACPI_LOG_DEBUG 2 > +#define PIIX4ACPI_LOGLEVEL PIIX4ACPI_LOG_INFO > +#define PIIX4ACPI_LOG(level, fmt, ...) do { if (level<= PIIX4ACPI_LOGLEVEL) qemu_log(fmt, ## __VA_ARGS__); } while (0) > + > +/* Sleep state type codes as defined by the \_Sx objects in the DSDT. */ > +/* These must be kept in sync with the DSDT (hvmloader/acpi/dsdt.asl) */ > +#define SLP_TYP_S4 (6<< 10) > +#define SLP_TYP_S3 (5<< 10) > +#define SLP_TYP_S5 (7<< 10) > + > +#define ACPI_DBG_IO_ADDR 0xb044 > +#define ACPI_PHP_IO_ADDR 0x10c0 > + > +#define PHP_EVT_ADD 0x0 > +#define PHP_EVT_REMOVE 0x3 > + > +/* The bit in GPE0_STS/EN to notify the pci hotplug event */ > +#define ACPI_PHP_GPE_BIT 3 > + > +#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn>> 1) > +#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg<< 1) | hilo) > + > +/* ioport to monitor cpu add/remove status */ > +#define PROC_BASE 0xaf00 > + > +typedef struct PCIAcpiState { > + PCIDevice dev; > + uint16_t pm1_control; /* pm1a_ECNT_BLK */ > + qemu_irq irq; > + qemu_irq cmos_s3; > +} PCIAcpiState; > + > +typedef struct GPEState { > + /* GPE0 block */ > + uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2]; > + uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2]; > + > + /* CPU bitmap */ > + uint8_t cpus_sts[32]; > + > + /* SCI IRQ level */ > + uint8_t sci_asserted; > + > +} GPEState; > + > +static GPEState gpe_state; > + > +static qemu_irq sci_irq; > + > +typedef struct AcpiDeviceState AcpiDeviceState; > +AcpiDeviceState *acpi_device_table; > + > +static const VMStateDescription vmstate_acpi = { > + .name = "PIIX4 ACPI", > + .version_id = 1, > + .fields = (VMStateField []) { > + VMSTATE_PCI_DEVICE(dev, PCIAcpiState), > + VMSTATE_UINT16(pm1_control, PCIAcpiState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void acpiPm1Control_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > + PCIAcpiState *s = opaque; > + s->pm1_control = (s->pm1_control& 0xff00) | (val& 0xff); > +} > + > +static uint32_t acpiPm1Control_readb(void *opaque, uint32_t addr) > +{ > + PCIAcpiState *s = opaque; > + /* Mask out the write-only bits */ > + return (uint8_t)(s->pm1_control& ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)); > +} > + > +static void acpi_shutdown(PCIAcpiState *s, uint32_t val) > +{ > + if (!(val& ACPI_BITMASK_SLEEP_ENABLE)) > + return; > + > + switch (val& ACPI_BITMASK_SLEEP_TYPE) { > + case SLP_TYP_S3: > + qemu_system_reset(); > + qemu_irq_raise(s->cmos_s3); > + xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3); > + break; > + case SLP_TYP_S4: > + case SLP_TYP_S5: > + qemu_system_shutdown_request(); > + break; > + default: > + break; > + } > +} > + > +static void acpiPm1ControlP1_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > + PCIAcpiState *s = opaque; > + > + val<<= 8; > + s->pm1_control = ((s->pm1_control& 0xff) | val)& ~ACPI_BITMASK_SLEEP_ENABLE; > + > + acpi_shutdown(s, val); > +} > + > +static uint32_t acpiPm1ControlP1_readb(void *opaque, uint32_t addr) > +{ > + PCIAcpiState *s = opaque; > + /* Mask out the write-only bits */ > + return (uint8_t)((s->pm1_control& ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE))>> 8); > +} > + > +static void acpiPm1Control_writew(void *opaque, uint32_t addr, uint32_t val) > +{ > + PCIAcpiState *s = opaque; > + > + s->pm1_control = val& ~ACPI_BITMASK_SLEEP_ENABLE; > + > + acpi_shutdown(s, val); > +} > + > +static uint32_t acpiPm1Control_readw(void *opaque, uint32_t addr) > +{ > + PCIAcpiState *s = opaque; > + /* Mask out the write-only bits */ > + return (s->pm1_control& ~(ACPI_BITMASK_GLOBAL_LOCK_RELEASE|ACPI_BITMASK_SLEEP_ENABLE)); > +} > + > +static void acpi_map(PCIDevice *pci_dev, int region_num, > + uint32_t addr, uint32_t size, int type) > +{ > + PCIAcpiState *d = (PCIAcpiState *)pci_dev; > + > + /* Byte access */ > + register_ioport_write(addr + 4, 1, 1, acpiPm1Control_writeb, d); > + register_ioport_read(addr + 4, 1, 1, acpiPm1Control_readb, d); > + register_ioport_write(addr + 4 + 1, 1, 1, acpiPm1ControlP1_writeb, d); > + register_ioport_read(addr + 4 +1, 1, 1, acpiPm1ControlP1_readb, d); > + > + /* Word access */ > + register_ioport_write(addr + 4, 2, 2, acpiPm1Control_writew, d); > + register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d); > +} > + > +static inline int test_bit(uint8_t *map, int bit) > +{ > + return ( map[bit / 8]& (1<< (bit % 8)) ); > +} > + > +static inline void set_bit(uint8_t *map, int bit) > +{ > + map[bit / 8] |= (1<< (bit % 8)); > +} > + > +static inline void clear_bit(uint8_t *map, int bit) > +{ > + map[bit / 8]&= ~(1<< (bit % 8)); > +} > + > +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) > +{ > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "ACPI: DBG: 0x%08x\n", val); > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val); > +} > + > +/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */ > +static uint32_t gpe_sts_read(void *opaque, uint32_t addr) > +{ > + GPEState *s = opaque; > + > + return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS]; > +} > + > +/* write 1 to clear specific GPE bits */ > +static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val) > +{ > + GPEState *s = opaque; > + int hotplugged = 0; > + > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val); > + > + hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT); > + s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS]&= ~val; > + if ( s->sci_asserted&& > + hotplugged&& > + !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) { > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "Clear the GPE0_STS bit for ACPI hotplug& deassert the IRQ.\n"); > + qemu_irq_lower(sci_irq); > + } > + > +} > + > +static uint32_t gpe_en_read(void *opaque, uint32_t addr) > +{ > + GPEState *s = opaque; > + > + return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)]; > +} > + > +/* write 0 to clear en bit */ > +static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val) > +{ > + GPEState *s = opaque; > + int reg_count; > + > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_DEBUG, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val); > + reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2); > + s->gpe0_en[reg_count] = val; > + /* If disable GPE bit right after generating SCI on it, > + * need deassert the intr to avoid redundant intrs > + */ > + if ( s->sci_asserted&& > + reg_count == (ACPI_PHP_GPE_BIT / 8)&& > + !(val& (1<< (ACPI_PHP_GPE_BIT % 8))) ) { > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "deassert due to disable GPE bit.\n"); > + s->sci_asserted = 0; > + qemu_irq_lower(sci_irq); > + } > + > +} > + > +static void gpe_save(QEMUFile* f, void* opaque) > +{ > + GPEState *s = (GPEState*)opaque; > + int i; > + > + for ( i = 0; i< ACPI_GPE0_BLK_LEN / 2; i++ ) { > + qemu_put_8s(f,&s->gpe0_sts[i]); > + qemu_put_8s(f,&s->gpe0_en[i]); > + } > + > + qemu_put_8s(f,&s->sci_asserted); > + if ( s->sci_asserted ) { > + PIIX4ACPI_LOG(PIIX4ACPI_LOG_INFO, "gpe_save with sci asserted!\n"); > + } > +} > + > +static int gpe_load(QEMUFile* f, void* opaque, int version_id) > +{ > + GPEState *s = (GPEState*)opaque; > + int i; > + if (version_id != 1) > + return -EINVAL; > + > + for ( i = 0; i< ACPI_GPE0_BLK_LEN / 2; i++ ) { > + qemu_get_8s(f,&s->gpe0_sts[i]); > + qemu_get_8s(f,&s->gpe0_en[i]); > + } > + > + qemu_get_8s(f,&s->sci_asserted); > + return 0; > +} > + > +static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr) > +{ > + uint32_t val = 0; > + GPEState *g = opaque; > + > + switch (addr) { > + case PROC_BASE ... PROC_BASE+31: > + val = g->cpus_sts[addr - PROC_BASE]; > + default: > + break; > + } > + > + return val; > +} > + > +static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val) > +{ > + /* GPEState *g = opaque; */ > + > + switch (addr) { > + case PROC_BASE ... PROC_BASE + 31: > + /* don''t allow to change cpus_sts from inside a guest */ > + break; > + default: > + break; > + } > +} > + > +static void gpe_acpi_init(void) > +{ > + GPEState *s =&gpe_state; > + memset(s, 0, sizeof(GPEState)); > + > + s->cpus_sts[0] = 1; > + > + register_ioport_read(PROC_BASE, 32, 1, gpe_cpus_readb, s); > + register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s); > + > + register_ioport_read(ACPI_GPE0_BLK_ADDRESS, > + ACPI_GPE0_BLK_LEN / 2, > + 1, > + gpe_sts_read, > + s); > + register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, > + ACPI_GPE0_BLK_LEN / 2, > + 1, > + gpe_en_read, > + s); > + > + register_ioport_write(ACPI_GPE0_BLK_ADDRESS, > + ACPI_GPE0_BLK_LEN / 2, > + 1, > + gpe_sts_write, > + s); > + register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, > + ACPI_GPE0_BLK_LEN / 2, > + 1, > + gpe_en_write, > + s); > + > + register_savevm(NULL, "gpe", 0, 1, gpe_save, gpe_load, s); > +} > + > +static int piix4_pm_xen_initfn(PCIDevice *dev) > +{ > + PCIAcpiState *s = DO_UPCAST(PCIAcpiState, dev, dev); > + uint8_t *pci_conf; > + > + pci_conf = s->dev.config; > + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); > + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3); > + pci_conf[0x08] = 0x01; /* B0 stepping */ > + pci_conf[0x09] = 0x00; /* base class */ > + pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); > + pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */ > + pci_conf[0x3d] = 0x01; /* Hardwired to PIRQA is used */ > + > + /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40 > + * to make shutdown work for IPF, due to IPF Guest Firmware > + * will enumerate pci devices. > + * > + * TODO: if Guest Firmware or Guest OS will change this PMBA, > + * More logic will be added. > + */ > + pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */ > + pci_conf[0x41] = 0x1f; > + pci_conf[0x42] = 0x00; > + pci_conf[0x43] = 0x00; > + > + s->pm1_control = ACPI_BITMASK_SCI_ENABLE; > + > + acpi_map((PCIDevice *)s, 0, 0x1f40, 0x10, PCI_BASE_ADDRESS_SPACE_IO); > + > + gpe_acpi_init(); > + > + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); > + > + return 0; > +} > + > +void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3) > +{ > + PCIDevice *dev; > + PCIAcpiState *s; > + > + sci_irq = sci_irq_spec; > + > + dev = pci_create(bus, devfn, "PIIX4 ACPI"); > + > + s = DO_UPCAST(PCIAcpiState, dev, dev); > + > + s->irq = sci_irq_spec; > + s->cmos_s3 = cmos_s3; > + > + qdev_init_nofail(&dev->qdev); > +} > + > +static PCIDeviceInfo piix4_pm_xen_info = { > + .qdev.name = "PIIX4 ACPI", > + .qdev.desc = "dm", > + .qdev.size = sizeof(PCIAcpiState), > + .qdev.vmsd =&vmstate_acpi, > + .init = piix4_pm_xen_initfn, > +}; > + > +static void piix4_pm_xen_register(void) > +{ > + pci_qdev_register(&piix4_pm_xen_info); > +} > + > +device_init(piix4_pm_xen_register); > diff --git a/hw/xen_common.h b/hw/xen_common.h > index 020fdd7..e1f07ba 100644 > --- a/hw/xen_common.h > +++ b/hw/xen_common.h > @@ -34,4 +34,7 @@ > /* hw/i8259-xen-stub.c */ > qemu_irq *i8259_xen_init(void); > > +/* hw/xen_acpi_piix4.c */ > +void piix4_pm_xen_init(PCIBus *bus, int devfn, qemu_irq sci_irq_spec, qemu_irq cmos_s3); > + > #endif /* QEMU_HW_XEN_COMMON_H */ > diff --git a/hw/xen_machine_fv.c b/hw/xen_machine_fv.c > index 77563db..bfda944 100644 > --- a/hw/xen_machine_fv.c > +++ b/hw/xen_machine_fv.c > @@ -92,7 +92,6 @@ static void xen_init_fv(ram_addr_t ram_size, > qemu_irq *isa_irq; > qemu_irq *i8259; > qemu_irq *cmos_s3; > - qemu_irq *smi_irq; > IsaIrqState *isa_irq_state; > DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; > FDCtrl *floppy_controller; > @@ -208,10 +207,7 @@ static void xen_init_fv(ram_addr_t ram_size, > > if (acpi_enabled) { > cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); > - smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); > - piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, > - isa_reserve_irq(9), *cmos_s3, *smi_irq, > - 0); > + piix4_pm_xen_init(pci_bus, piix3_devfn + 3, isa_reserve_irq(9), *cmos_s3); > } > > if (i440fx_state) { >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 19:09 UTC
[Xen-devel] Re: [PATCH 00/15] RFC xen device model support
Hi Stefano/Anthony, On 08/12/2010 09:08 AM, Stefano Stabellini wrote:> Hi all, > this is the long awaited patch series to add xen device model support in > qemu; the main author is Anthony Perard. >Thanks for sending this out. Overall, the series looks pretty good. I think there''s just a couple issues we need to address to get it into a mergable state. We definitely need to resolve the various CODING_STYLE issues. We should limit XenStore interactions to strictly be device model setup. Any management operations should be done through QMP. The main reason to take this approach is to ensure that we don''t end up with a more powerful interface via xenstore verses QMP or vice versa. The target changes are probably the most contentious. Fortunately, we have a very similar set of goals with KVM so I think we''ll be able to come up with a common solution to the problem. Regards, Anthony Liguori> Developing this series we tried to come up with the cleanest possible > solution from the qemu point of view, limiting the amount of changes to > common code as much as possible. The end result still requires a couple > of hooks in piix_pci but overall the impact should be very limited. > The current series gives you an upstream qemu device model able to boot > a Linux or a Windows HVM guest; some features are still missing > compared to the current qemu-xen, among which vga dirty bits, pci > passthrough and stubdomain support. > > For any of you that want to try it, this is the step by step guide: > > - clone a fresh copy of xen-unstable.hg, make and install; > note that the xen-unstable make system will clone a linux tree and a > qemu-xen tree by default: you can avoid the former just executing ''make > xen'' and ''make tools'' instead of ''make world''; > > - configure qemu using xen-dm-softmmu as target and extra-ldflags and > extra-cflags pointing at the xen-unstable build directory, something > like this should work: > > ./configure --target-list=xen-dm-softmmu --extra-cflags="-I$HOME/xen-unstable/dist/install/usr/include" --extra-ldflags="-L$HOME/xen-unstable/dist/install/usr/lib" --enable-xen > > - build qemu and install the newly compiled binary > (xen-dm-softmmu/qemu-system-xen); > > - edit your VM config file and modify device_model to point at it. > > > Currently only xl (not xend) knows how to spawn the new qemu device model > with the right command line options. > As you can see the build and test procedures are not straightforward > yet, but in the near future we plan to provide a way to select an > upstream qemu tree for use as xen device model directly from the > xen-unstable build system. > > The patch series adds a new target with the whole xen device model > machinery; each patch contains a detailed description. > This is the full list of patches and the diffstat: > > Anthony Perard (15): > xen: Update libxc calls > xen: Add xen_machine_fv > xen: Add a new target to qemu: target-xen > xen: xen_machine_fv, initialize xenstore > xen: add a 8259 Interrupt Controller > xen: Add the Xen platform pci device > xen: handle xenstore events > xen: Read and write the state of the VM in xenstore > xen: Initialize event channels and io rings > xen: Introduce the Xen mapcache > piix3: introduce register_set_irq and register_map_irq > piix_pci: introduce a write_config notifier > vl.c: Introduce getter for shutdown_requested and reset_requested. > xen: destroy the VM when shutdown is requested > > Makefile.target | 31 ++ > arch_init.c | 2 + > arch_init.h | 1 + > configure | 12 +- > default-configs/xen-dm-softmmu.mak | 24 + > hw/pc.h | 4 + > hw/piix_pci.c | 45 ++- > hw/xen_acpi_piix4.c | 424 ++++++++++++++++++ > hw/xen_backend.c | 10 +- > hw/xen_backend.h | 2 +- > hw/xen_common.h | 6 + > hw/xen_disk.c | 12 +- > hw/xen_domainbuild.c | 4 +- > hw/xen_machine_fv.c | 234 ++++++++++ > hw/xen_nic.c | 16 +- > hw/xen_platform.c | 452 ++++++++++++++++++++ > hw/xen_platform.h | 9 + > sysemu.h | 2 + > target-xen/cpu.h | 121 ++++++ > target-xen/exec-dm.c | 826 ++++++++++++++++++++++++++++++++++++ > target-xen/helper.c | 455 ++++++++++++++++++++ > target-xen/i8259-xen-stub.c | 63 +++ > target-xen/qemu-xen.h | 50 +++ > target-xen/stub-functions.c | 42 ++ > target-xen/xen_mapcache.c | 247 +++++++++++ > target-xen/xenstore.c | 168 ++++++++ > target-xen/xenstore.h | 12 + > vl.c | 10 + > 28 files changed, 3259 insertions(+), 25 deletions(-) > > > A git tree is available here: > > git://xenbits.xen.org/people/sstabellini/qemu-dm.git > > branch name qemu-dm-v1. > > > We are committed in providing the best solution for both qemu and xen > developers and users communities; we greatly appreciate any help you can > give us to improve the quality of this series, including comments, > critics, suggestions and of course patches :) > > Happy Hacking, > > Stefano >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 19:35 UTC
[Xen-devel] Re: [PATCH 00/15] RFC xen device model support
On Fri, 13 Aug 2010, Anthony Liguori wrote:> Hi Stefano/Anthony, > > On 08/12/2010 09:08 AM, Stefano Stabellini wrote: > > Hi all, > > this is the long awaited patch series to add xen device model support in > > qemu; the main author is Anthony Perard. > > > > Thanks for sending this out. Overall, the series looks pretty good. I > think there''s just a couple issues we need to address to get it into a > mergable state. >Thank you very much for taking the time to review our series!> We definitely need to resolve the various CODING_STYLE issues. >Of course, we''ll do in the next version.> We should limit XenStore interactions to strictly be device model > setup. Any management operations should be done through QMP. The main > reason to take this approach is to ensure that we don''t end up with a > more powerful interface via xenstore verses QMP or vice versa. >I want to be clear on this: I like QMP and I dislike xenstore, especially when it is used as an RPC mechanism. I have NO intention of transforming xenstore in a QMP alternative, in fact we removed quite a lot of xenstore interactions developing this series, in particular the whole disk setup (and it felt good :). Currently in qemu-xen we are using xenstore even for pci passthrough, but I certainly do not intend to make the same mistake again when we''ll add pci passthrough support to qemu this time. Implementing QMP support in libxl is definitely on our todo list.> The target changes are probably the most contentious. Fortunately, we > have a very similar set of goals with KVM so I think we''ll be able to > come up with a common solution to the problem. >Yes, this is the part that worries me the most. Do you think is reasonable to keep the new target for the time being or do you want us to try the other approach ASAP? If you really want us to drop the xen specific target we''ll need close guidance in how to proceed. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-13 19:37 UTC
[Xen-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
On Fri, 13 Aug 2010, Anthony Liguori wrote:> On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote: > > From: Anthony PERARD<anthony.perard@citrix.com> > > > > Xen currently uses a different BIOS (hvmloader + rombios) therefore the > > Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. > > We plan on fixing this properly but at the moment we are just adding a > > new Xen specific acpi_piix4 implementation. > > This patch is optional; without it the VM boots but it cannot shutdown > > properly or go to S3. > > > > What''s the long term plan? Will Xen adopt SeaBIOS or will you adapt > your BIOS to cope with our ACPI implementation? >I think it shouldn''t be too difficult to adapt our current BIOS, but we''ll need few xen specific hooks in acpi_piix4. The price that we''ll have to pay doing so is loosing live-migration compatibility with older xen installations. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 20:48 UTC
[Xen-devel] Re: [PATCH 00/15] RFC xen device model support
On 08/13/2010 02:35 PM, Stefano Stabellini wrote:>> We should limit XenStore interactions to strictly be device model >> setup. Any management operations should be done through QMP. The main >> reason to take this approach is to ensure that we don''t end up with a >> more powerful interface via xenstore verses QMP or vice versa. >> >> > I want to be clear on this: I like QMP and I dislike xenstore, > especially when it is used as an RPC mechanism. > I have NO intention of transforming xenstore in a QMP alternative, in > fact we removed quite a lot of xenstore interactions developing this > series, in particular the whole disk setup (and it felt good :). >Ah, fantastic :-)>> The target changes are probably the most contentious. Fortunately, we >> have a very similar set of goals with KVM so I think we''ll be able to >> come up with a common solution to the problem. >> >> > Yes, this is the part that worries me the most. > Do you think is reasonable to keep the new target for the time being or > do you want us to try the other approach ASAP? >Let''s figure out the right solution and then we''ll figure out the incremental approach. I don''t mind if you keep it in the next few rounds of the series but I don''t think we can merge it. A good way to start would be for ya''ll to take a look at the places where we hook for KVM. For instance, cpu_register_phys_memory_client. With an additional hook in the map()/unmap()/rw() path, you should be able to implement the map cache support and deal with memory in a sane way. I think that would allow us to separate the discussion of having xen hooks with removing TCG support in the Xen builds which as I said earlier, is something we also would like to do in KVM. Regards, Anthony Liguori> If you really want us to drop the xen specific target we''ll need > close guidance in how to proceed. >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-13 20:51 UTC
[Xen-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
On 08/13/2010 02:37 PM, Stefano Stabellini wrote:> On Fri, 13 Aug 2010, Anthony Liguori wrote: > >> On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote: >> >>> From: Anthony PERARD<anthony.perard@citrix.com> >>> >>> Xen currently uses a different BIOS (hvmloader + rombios) therefore the >>> Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. >>> We plan on fixing this properly but at the moment we are just adding a >>> new Xen specific acpi_piix4 implementation. >>> This patch is optional; without it the VM boots but it cannot shutdown >>> properly or go to S3. >>> >>> >> What''s the long term plan? Will Xen adopt SeaBIOS or will you adapt >> your BIOS to cope with our ACPI implementation? >> >> > I think it shouldn''t be too difficult to adapt our current BIOS, but > we''ll need few xen specific hooks in acpi_piix4. > The price that we''ll have to pay doing so is loosing live-migration > compatibility with older xen installations. >Does Xen migrate roms (like the BIOS) in such a way that the persist after a reboot? I noticed there was only one machine type defined. In our experience, to preserve compatibility with migration, it''s useful to have versioned machine names. We also have some special machine parameters to support compatibility with qdev. How does Xen handle hvm migration machine model compatibility? Regards, Anthony Liguori _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Paolo Bonzini
2010-Aug-15 14:12 UTC
[Xen-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
On 08/13/2010 02:53 PM, Anthony Liguori wrote:> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote: >> From: Anthony PERARD<anthony.perard@citrix.com> >> >> Introduce functions to read and write the state of the VM in xenstore. > > This basically creates a new management interface for QEMU via the > xenstore. > > Our management interface is QMP. If you want to maintain compatibility, > you''ll need to write a QMP -> xenstore daemon that maps events > appropriately.This would belong in xl/libxl. Paolo _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-16 11:10 UTC
[Xen-devel] Re: [PATCH 15/15] xen: Add a Xen specific ACPI Implementation to target-xen
On Fri, 13 Aug 2010, Anthony Liguori wrote:> On 08/13/2010 02:37 PM, Stefano Stabellini wrote: > > On Fri, 13 Aug 2010, Anthony Liguori wrote: > > > >> On 08/12/2010 09:10 AM, stefano.stabellini@eu.citrix.com wrote: > >> > >>> From: Anthony PERARD<anthony.perard@citrix.com> > >>> > >>> Xen currently uses a different BIOS (hvmloader + rombios) therefore the > >>> Qemu acpi_piix4 implementation wouldn''t work correctly with Xen. > >>> We plan on fixing this properly but at the moment we are just adding a > >>> new Xen specific acpi_piix4 implementation. > >>> This patch is optional; without it the VM boots but it cannot shutdown > >>> properly or go to S3. > >>> > >>> > >> What''s the long term plan? Will Xen adopt SeaBIOS or will you adapt > >> your BIOS to cope with our ACPI implementation? > >> > >> > > I think it shouldn''t be too difficult to adapt our current BIOS, but > > we''ll need few xen specific hooks in acpi_piix4. > > The price that we''ll have to pay doing so is loosing live-migration > > compatibility with older xen installations. > > > > Does Xen migrate roms (like the BIOS) in such a way that the persist > after a reboot? >No, I don''t think so. However it is common practice not to require any VM reboot on host upgrade.> I noticed there was only one machine type defined. In our experience, > to preserve compatibility with migration, it''s useful to have versioned > machine names. We also have some special machine parameters to support > compatibility with qdev. >Thanks for the tip, we''ll look into it. Knowing that we would have the BIOS problem mentioned above, we didn''t try yet any save/restore or migration compatibility between old qemu-xen and new qemu.> How does Xen handle hvm migration machine model compatibility? >We use per-device save state versions and we tend to use always the same set of devices. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-16 11:15 UTC
[Xen-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
On Sun, 15 Aug 2010, Paolo Bonzini wrote:> On 08/13/2010 02:53 PM, Anthony Liguori wrote: > > On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote: > >> From: Anthony PERARD<anthony.perard@citrix.com> > >> > >> Introduce functions to read and write the state of the VM in xenstore. > > > > This basically creates a new management interface for QEMU via the > > xenstore. > > > > Our management interface is QMP. If you want to maintain compatibility, > > you''ll need to write a QMP -> xenstore daemon that maps events > > appropriately. > > This would belong in xl/libxl.Yes, but considering that we don''t want a xenstore-based management interface I would gladly do without the compatibility daemon. We''ll try to reduce all the xenstore interaction to the bare minimum, and use QMP everywhere else. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Paolo Bonzini
2010-Aug-16 12:13 UTC
[Xen-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
On 08/16/2010 01:15 PM, Stefano Stabellini wrote:> On Sun, 15 Aug 2010, Paolo Bonzini wrote: >> On 08/13/2010 02:53 PM, Anthony Liguori wrote: >>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote: >>>> From: Anthony PERARD<anthony.perard@citrix.com> >>>> >>>> Introduce functions to read and write the state of the VM in xenstore. >>> >>> This basically creates a new management interface for QEMU via the >>> xenstore. >>> >>> Our management interface is QMP. If you want to maintain compatibility, >>> you''ll need to write a QMP -> xenstore daemon that maps events >>> appropriately. >> >> This would belong in xl/libxl. > > Yes, but considering that we don''t want a xenstore-based management > interface I would gladly do without the compatibility daemon. > We''ll try to reduce all the xenstore interaction to the bare minimum, > and use QMP everywhere else.Yes, I was just pointing out that you don''t need a new compatibility daemon. Since xl is already daemonizing itself to handle on_crash and friends, it could also set up all the watches it cares about, and convert them to QMP commands. It''s all more code that needs to be written of course, and boring stuff even. :) Paolo _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-16 12:59 UTC
[Xen-devel] Re: [PATCH 08/15] xen: Read and write the state of the VM in xenstore
On Mon, 16 Aug 2010, Paolo Bonzini wrote:> On 08/16/2010 01:15 PM, Stefano Stabellini wrote: > > On Sun, 15 Aug 2010, Paolo Bonzini wrote: > >> On 08/13/2010 02:53 PM, Anthony Liguori wrote: > >>> On 08/12/2010 09:09 AM, stefano.stabellini@eu.citrix.com wrote: > >>>> From: Anthony PERARD<anthony.perard@citrix.com> > >>>> > >>>> Introduce functions to read and write the state of the VM in xenstore. > >>> > >>> This basically creates a new management interface for QEMU via the > >>> xenstore. > >>> > >>> Our management interface is QMP. If you want to maintain compatibility, > >>> you''ll need to write a QMP -> xenstore daemon that maps events > >>> appropriately. > >> > >> This would belong in xl/libxl. > > > > Yes, but considering that we don''t want a xenstore-based management > > interface I would gladly do without the compatibility daemon. > > We''ll try to reduce all the xenstore interaction to the bare minimum, > > and use QMP everywhere else. > > Yes, I was just pointing out that you don''t need a new compatibility > daemon. Since xl is already daemonizing itself to handle on_crash and > friends, it could also set up all the watches it cares about, and > convert them to QMP commands. It''s all more code that needs to be > written of course, and boring stuff even. :)Well yes, but after all you cannot write interesting code all the time :) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Kevin Wolf
2010-Aug-16 13:42 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com:> From: Anthony PERARD <anthony.perard@citrix.com> > > Add the Xen FV (Fully Virtualized) machine to Qemu; > this is groundwork to add Xen device model support in Qemu. > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>Why does this need its own machine type? Shouldn''t an HVM machine really look like a PC? And indeed most of this code looks like a (slightly outdated) copy of pc_piix.c with !pci_enabled code paths removed. Kevin _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-16 14:04 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
On Mon, 16 Aug 2010, Kevin Wolf wrote:> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com: > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > Add the Xen FV (Fully Virtualized) machine to Qemu; > > this is groundwork to add Xen device model support in Qemu. > > > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > > Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > > Why does this need its own machine type? Shouldn''t an HVM machine really > look like a PC? And indeed most of this code looks like a (slightly > outdated) copy of pc_piix.c with !pci_enabled code paths removed.The main reason is that we need some xen specific initializations, as you can see from xen_init_fv. But considering that we have been asked to remove target-xen and that will cause a major refactoring of this series, xen_machine_fv could change significantly in the next iterations anyway... _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Kevin Wolf
2010-Aug-16 14:13 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
Am 16.08.2010 16:04, schrieb Stefano Stabellini:> On Mon, 16 Aug 2010, Kevin Wolf wrote: >> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com: >>> From: Anthony PERARD <anthony.perard@citrix.com> >>> >>> Add the Xen FV (Fully Virtualized) machine to Qemu; >>> this is groundwork to add Xen device model support in Qemu. >>> >>> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> >>> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> >> >> Why does this need its own machine type? Shouldn''t an HVM machine really >> look like a PC? And indeed most of this code looks like a (slightly >> outdated) copy of pc_piix.c with !pci_enabled code paths removed. > > The main reason is that we need some xen specific initializations, as you can > see from xen_init_fv.Right, there are some more Xen specific things added later. However, the main part of it is duplicated from pc_piix.c. I''m sure that with some refactoring we could call these functions instead of copying and modifying them. The problem with the latter is that they will inevitably diverge even for changes that make sense for both. I''m not even sure that the machine is the right place to do these Xen specific initializations (expect for the Xen platform PCI device). As far as I understand, the QEMUMachine is considered guest state whereas most of these initializations concern host state.> But considering that we have been asked to remove target-xen and that > will cause a major refactoring of this series, xen_machine_fv could > change significantly in the next iterations anyway...Basically, the request to remove target-xen and my comment both aim in the same direction, namely making Xen less special and integrate it better in existing structures. Kevin _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-16 14:38 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
On 08/16/2010 09:13 AM, Kevin Wolf wrote:> Am 16.08.2010 16:04, schrieb Stefano Stabellini: > >> On Mon, 16 Aug 2010, Kevin Wolf wrote: >> >>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com: >>> >>>> From: Anthony PERARD<anthony.perard@citrix.com> >>>> >>>> Add the Xen FV (Fully Virtualized) machine to Qemu; >>>> this is groundwork to add Xen device model support in Qemu. >>>> >>>> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> >>>> Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> >>>> >>> Why does this need its own machine type? Shouldn''t an HVM machine really >>> look like a PC? And indeed most of this code looks like a (slightly >>> outdated) copy of pc_piix.c with !pci_enabled code paths removed. >>> >> >> The main reason is that we need some xen specific initializations, as you can >> see from xen_init_fv. >> > Right, there are some more Xen specific things added later. However, the > main part of it is duplicated from pc_piix.c. I''m sure that with some > refactoring we could call these functions instead of copying and > modifying them. The problem with the latter is that they will inevitably > diverge even for changes that make sense for both. > > I''m not even sure that the machine is the right place to do these Xen > specific initializations (expect for the Xen platform PCI device). As > far as I understand, the QEMUMachine is considered guest state whereas > most of these initializations concern host state. >To be honest, I think we''ll need KVM, Xen, and QEMU specific machines. The right default set of hardware for all three is different. Going back to an old series of mine, they might share a MachineCore, but they''ll ultimately need to be different machines. Regards, Anthony Liguori> >> But considering that we have been asked to remove target-xen and that >> will cause a major refactoring of this series, xen_machine_fv could >> change significantly in the next iterations anyway... >> > Basically, the request to remove target-xen and my comment both aim in > the same direction, namely making Xen less special and integrate it > better in existing structures. > > Kevin > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Kevin Wolf
2010-Aug-16 14:51 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
Am 16.08.2010 16:38, schrieb Anthony Liguori:> On 08/16/2010 09:13 AM, Kevin Wolf wrote: >> Am 16.08.2010 16:04, schrieb Stefano Stabellini: >> >>> On Mon, 16 Aug 2010, Kevin Wolf wrote: >>> >>>> Am 12.08.2010 16:09, schrieb stefano.stabellini@eu.citrix.com: >>>> >>>>> From: Anthony PERARD<anthony.perard@citrix.com> >>>>> >>>>> Add the Xen FV (Fully Virtualized) machine to Qemu; >>>>> this is groundwork to add Xen device model support in Qemu. >>>>> >>>>> Signed-off-by: Anthony PERARD<anthony.perard@citrix.com> >>>>> Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com> >>>>> >>>> Why does this need its own machine type? Shouldn''t an HVM machine really >>>> look like a PC? And indeed most of this code looks like a (slightly >>>> outdated) copy of pc_piix.c with !pci_enabled code paths removed. >>>> >>> >>> The main reason is that we need some xen specific initializations, as you can >>> see from xen_init_fv. >>> >> Right, there are some more Xen specific things added later. However, the >> main part of it is duplicated from pc_piix.c. I''m sure that with some >> refactoring we could call these functions instead of copying and >> modifying them. The problem with the latter is that they will inevitably >> diverge even for changes that make sense for both. >> >> I''m not even sure that the machine is the right place to do these Xen >> specific initializations (expect for the Xen platform PCI device). As >> far as I understand, the QEMUMachine is considered guest state whereas >> most of these initializations concern host state. >> > > To be honest, I think we''ll need KVM, Xen, and QEMU specific machines. > > The right default set of hardware for all three is different.Right, I agree. This is why I put the exception for the platform device. There are probably some more devices for which the same applies. But these exceptions all about guest state. If qdev was finished, this would be a matter of having a different configuration file, right? This series, as I understand it, is adding much more to the Xen FV machine. Things that are not about which devices a VM contains, but about some implementation details of the host. Kevin _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-16 15:00 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
On Mon, 16 Aug 2010, Kevin Wolf wrote:> Right, I agree. This is why I put the exception for the platform device. > There are probably some more devices for which the same applies. > > But these exceptions all about guest state. If qdev was finished, this > would be a matter of having a different configuration file, right? > > This series, as I understand it, is adding much more to the Xen FV > machine. Things that are not about which devices a VM contains, but > about some implementation details of the host.We could probably move the mapcache initialization and the ioreq and buffered ioreq page setup to another place, but apart from that the rest is about emulated devices. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2010-Aug-16 15:07 UTC
[Xen-devel] Re: [Qemu-devel] [PATCH 02/15] xen: Add xen_machine_fv
On 08/16/2010 09:51 AM, Kevin Wolf wrote:> Am 16.08.2010 16:38, schrieb Anthony Liguori: > >> >> To be honest, I think we''ll need KVM, Xen, and QEMU specific machines. >> >> The right default set of hardware for all three is different. >> > Right, I agree. This is why I put the exception for the platform device. > There are probably some more devices for which the same applies. > > But these exceptions all about guest state. If qdev was finished, this > would be a matter of having a different configuration file, right? > > This series, as I understand it, is adding much more to the Xen FV > machine. Things that are not about which devices a VM contains, but > about some implementation details of the host. >Yeah, but dropping the target-xen will probably fix most of that stuff. Regards, Anthony Liguori> Kevin >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Gerd Hoffmann
2010-Aug-18 09:50 UTC
[Xen-devel] Re: [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
Hi,> I mean we can add them to libxc so that there is no need for this patch > anymore.That would be great. When adding the xen bits initially I''ve tried to avoid hard dependencies on specific xen versions. There are some ifdefs in the qemu code to support compiling with various xen versions (IIRC 3.1 -> 3.4 worked last time I''ve tried). I think the minimum supported range of xen versions should be the ones still actively maintained by xensource (I think this is 3.4, 4.0 and unstable right now). Supporting even older versions would be nice to have. cheers, Gerd _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Stefano Stabellini
2010-Aug-18 11:47 UTC
[Xen-devel] Re: [Qemu-devel] Re: [PATCH 01/15] xen: Update libxc calls
On Wed, 18 Aug 2010, Gerd Hoffmann wrote:> Hi, > > > I mean we can add them to libxc so that there is no need for this patch > > anymore. > > That would be great. When adding the xen bits initially I''ve tried to > avoid hard dependencies on specific xen versions. There are some ifdefs > in the qemu code to support compiling with various xen versions (IIRC > 3.1 -> 3.4 worked last time I''ve tried). I think the minimum supported > range of xen versions should be the ones still actively maintained by > xensource (I think this is 3.4, 4.0 and unstable right now). Supporting > even older versions would be nice to have. >I agree on the range of xen versions, but supporting even a wider range shouldn''t be too hard, it just requires few more ifdef''s. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Michael S. Tsirkin
2010-Sep-05 07:34 UTC
[Xen-devel] Re: [PATCH 12/15] piix_pci: introduce a write_config notifier
On Fri, Aug 13, 2010 at 02:10:01PM +0100, Stefano Stabellini wrote:> On Thu, 12 Aug 2010, Blue Swirl wrote: > > On Thu, Aug 12, 2010 at 2:09 PM, <stefano.stabellini@eu.citrix.com> wrote: > > > From: Anthony PERARD <anthony.perard@citrix.com> > > > > > > Introduce a write config notifier in piix_pci, so that clients can be > > > notified every time a pci config write happens. > > > The patch also makes use of the notification mechanism in > > > xen_machine_fv. > > > > Will the mechanism be used elsewhere? If not, I''d just add a call to > > xen_piix_pci_write_config_client() to piix_pci.c. It can be surrounded > > by Xen #ifdeffery, or you could introduce stubs like kvm-stub.c and > > friends. > > > > we were trying to avoid ifdef''s in piix_pci, but if you are OK with just a > couple of them we''ll gladly remove the hook. >I second this. Callbacks complicate code significantly. If there''s a single user we are better off without. -- MST _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Apparently Analagous Threads
- [PATCH V2] qemu-xen-traditionnal, Fix dirty logging during migration.
- [PATCH BUILD FIX 0/2] build xc_hvm_inject_msi on Xen < 4.2
- qemu-xen-dir + PCI passthrough = BOOM
- [PATCH v2 0/2] MSI/MSIX injection for Xen HVM guests
- [PATCH 0/0] MSI/MSIX injection for Xen HVM guests