From 98abf9b1f795271a8bafb74b97e856aafb185eb9 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 17 Aug 2006 16:08:01 +0100 Subject: [HVM] Linux driver for the xen platform pseudo-PCI device. Signed-off-by: Steven Smith --- unmodified_drivers/linux-2.6/Makefile | 3 + unmodified_drivers/linux-2.6/mkbuildtree | 41 ++++ unmodified_drivers/linux-2.6/overrides.mk | 12 + unmodified_drivers/linux-2.6/platform-pci/Kbuild | 7 + unmodified_drivers/linux-2.6/platform-pci/evtchn.c | 173 +++++++++++++ .../linux-2.6/platform-pci/platform-pci.c | 268 +++++++++++++++++++++ .../linux-2.6/platform-pci/platform-pci.h | 43 ++++ .../linux-2.6/platform-pci/xen_support.c | 39 +++ 8 files changed, 586 insertions(+) create mode 100644 unmodified_drivers/linux-2.6/Makefile create mode 100644 unmodified_drivers/linux-2.6/mkbuildtree create mode 100644 unmodified_drivers/linux-2.6/overrides.mk create mode 100644 unmodified_drivers/linux-2.6/platform-pci/Kbuild create mode 100644 unmodified_drivers/linux-2.6/platform-pci/evtchn.c create mode 100644 unmodified_drivers/linux-2.6/platform-pci/platform-pci.c create mode 100644 unmodified_drivers/linux-2.6/platform-pci/platform-pci.h create mode 100644 unmodified_drivers/linux-2.6/platform-pci/xen_support.c (limited to 'unmodified_drivers') diff --git a/unmodified_drivers/linux-2.6/Makefile b/unmodified_drivers/linux-2.6/Makefile new file mode 100644 index 0000000000..37353776d7 --- /dev/null +++ b/unmodified_drivers/linux-2.6/Makefile @@ -0,0 +1,3 @@ +include $(M)/overrides.mk + +obj-m += platform-pci/ diff --git a/unmodified_drivers/linux-2.6/mkbuildtree b/unmodified_drivers/linux-2.6/mkbuildtree new file mode 100644 index 0000000000..618b5c594f --- /dev/null +++ b/unmodified_drivers/linux-2.6/mkbuildtree @@ -0,0 +1,41 @@ +#! /bin/sh + +C=$PWD + +XEN=$C/../../xen +XL=$C/../../linux-2.6-xen-sparse + +ln -sf ${XL}/drivers/xen/core/features.c platform-pci + +mkdir -p include +mkdir -p include/xen +mkdir -p include/public +mkdir -p include/asm + +lndir -silent ${XL}/include/xen include/xen +ln -sf ${XEN}/include/public include/xen/interface + +# Need to be quite careful here: we don't want the files we link in to +# risk overriding the native Linux ones (in particular, system.h must +# be native and not xenolinux). +uname=`uname -m` +case "$uname" +in +"x86_64") + ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/hypervisor.h include/asm + ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/hypercall.h include/asm + ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/synch_bitops.h include/asm + ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/maddr.h include/asm + ln -sf ${XL}/include/asm-i386 include/asm-i386 + ;; +i[34567]86) + ln -sf ${XL}/include/asm-i386/mach-xen/asm/hypervisor.h include/asm + ln -sf ${XL}/include/asm-i386/mach-xen/asm/hypercall.h include/asm + ln -sf ${XL}/include/asm-i386/mach-xen/asm/synch_bitops.h include/asm + ln -sf ${XL}/include/asm-i386/mach-xen/asm/maddr.h include/asm + ;; +*) + echo unknown architecture $uname + exit 1 + ;; +esac diff --git a/unmodified_drivers/linux-2.6/overrides.mk b/unmodified_drivers/linux-2.6/overrides.mk new file mode 100644 index 0000000000..74ef12c4c9 --- /dev/null +++ b/unmodified_drivers/linux-2.6/overrides.mk @@ -0,0 +1,12 @@ +# Hack: we need to use the config which was used to build the kernel, +# except that that won't have the right headers etc., so duplicate +# some of the mach-xen infrastructure in here. +# +# (i.e. we need the native config for things like -mregparm, but +# a Xen kernel to find the right headers) +EXTRA_CFLAGS += -DCONFIG_VMX -DCONFIG_VMX_GUEST -DCONFIG_X86_XEN +EXTRA_CFLAGS += -DCONFIG_XEN_SHADOW_MODE -DCONFIG_XEN_SHADOW_TRANSLATE +EXTRA_CFLAGS += -DCONFIG_XEN_BLKDEV_GRANT -DXEN_EVTCHN_MASK_OPS +EXTRA_CFLAGS += -DCONFIG_XEN_NETDEV_GRANT_RX -DCONFIG_XEN_NETDEV_GRANT_TX +EXTRA_CFLAGS += -D__XEN_INTERFACE_VERSION__=0x00030202 +EXTRA_CFLAGS += -I$(M)/include diff --git a/unmodified_drivers/linux-2.6/platform-pci/Kbuild b/unmodified_drivers/linux-2.6/platform-pci/Kbuild new file mode 100644 index 0000000000..0e85e50ff0 --- /dev/null +++ b/unmodified_drivers/linux-2.6/platform-pci/Kbuild @@ -0,0 +1,7 @@ +include $(M)/overrides.mk + +obj-m := xen-platform-pci.o + +EXTRA_CFLAGS += -I$(M)/platform-pci + +xen-platform-pci-objs := evtchn.o platform-pci.o xen_support.o features.o diff --git a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c new file mode 100644 index 0000000000..2f5cfc71f0 --- /dev/null +++ b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c @@ -0,0 +1,173 @@ +/****************************************************************************** + * evtchn.c + * + * A simplified event channel for para-drivers in unmodified linux + * + * Copyright (c) 2002-2005, K A Fraser + * Copyright (c) 2005, + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (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 +#include +#include +#include +#include +#include +#include "platform-pci.h" + +void *shared_info_area; + +#define MAX_EVTCHN 256 +static struct +{ + irqreturn_t(*handler) (int, void *, struct pt_regs *); + void *dev_id; +} evtchns[MAX_EVTCHN]; + +void mask_evtchn(int port) +{ + shared_info_t *s = shared_info_area; + synch_set_bit(port, &s->evtchn_mask[0]); +} +EXPORT_SYMBOL(mask_evtchn); + +void unmask_evtchn(int port) +{ + unsigned int cpu; + shared_info_t *s = shared_info_area; + vcpu_info_t *vcpu_info; + + preempt_disable(); + cpu = smp_processor_id(); + vcpu_info = &s->vcpu_info[cpu]; + + /* Slow path (hypercall) if this is a non-local port. We only + ever bind event channels to vcpu 0 in HVM guests. */ + if (unlikely(cpu != 0)) { + evtchn_unmask_t op = { .port = port }; + (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, + &op); + preempt_enable(); + return; + } + + synch_clear_bit(port, &s->evtchn_mask[0]); + + /* + * The following is basically the equivalent of + * 'hw_resend_irq'. Just like a real IO-APIC we 'lose the + * interrupt edge' if the channel is masked. + */ + if (synch_test_bit(port, &s->evtchn_pending[0]) && + !synch_test_and_set_bit(port / BITS_PER_LONG, + &vcpu_info->evtchn_pending_sel)) { + vcpu_info->evtchn_upcall_pending = 1; + if (!vcpu_info->evtchn_upcall_mask) + force_evtchn_callback(); + } + preempt_enable(); +} +EXPORT_SYMBOL(unmask_evtchn); + +int +bind_evtchn_to_irqhandler(unsigned int evtchn, + irqreturn_t(*handler) (int, void *, + struct pt_regs *), + unsigned long irqflags, const char *devname, + void *dev_id) +{ + if (evtchn >= MAX_EVTCHN) + return -EINVAL; + evtchns[evtchn].handler = handler; + evtchns[evtchn].dev_id = dev_id; + unmask_evtchn(evtchn); + return evtchn; +} + +EXPORT_SYMBOL(bind_evtchn_to_irqhandler); + +void unbind_from_irqhandler(unsigned int evtchn, void *dev_id) +{ + if (evtchn >= MAX_EVTCHN) + return; + + mask_evtchn(evtchn); + evtchns[evtchn].handler = NULL; +} + +EXPORT_SYMBOL(unbind_from_irqhandler); + +void notify_remote_via_irq(int irq) +{ + int evtchn = irq; + notify_remote_via_evtchn(evtchn); +} + +EXPORT_SYMBOL(notify_remote_via_irq); + +irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int l1i, l2i, port; + int cpu = smp_processor_id(); + irqreturn_t(*handler) (int, void *, struct pt_regs *); + shared_info_t *s = shared_info_area; + vcpu_info_t *v = &s->vcpu_info[cpu]; + unsigned long l1, l2; + + v->evtchn_upcall_pending = 0; + /* NB. No need for a barrier here -- XCHG is a barrier + * on x86. */ + l1 = xchg(&v->evtchn_pending_sel, 0); + while (l1 != 0) + { + l1i = __ffs(l1); + l1 &= ~(1 << l1i); + + l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i]; + while (l2 != 0) + { + l2i = __ffs(l2); + + port = (l1i * BITS_PER_LONG) + l2i; + synch_clear_bit(port, &s->evtchn_pending[0]); + if ((handler = evtchns[port].handler) != NULL) + { + handler(port, evtchns[port].dev_id, + regs); + } + else + { + printk(KERN_WARNING "unexpected event channel upcall on port %d!\n", port); + } + l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i]; + } + } + return IRQ_HANDLED; +} + +void force_evtchn_callback(void) +{ + evtchn_interrupt(0, NULL, NULL); +} +EXPORT_SYMBOL(force_evtchn_callback); diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c new file mode 100644 index 0000000000..941608d12f --- /dev/null +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @@ -0,0 +1,268 @@ +/****************************************************************************** + * evtchn-pci.c + * xen event channel fake PCI device driver + * Copyright (C) 2005, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "platform-pci.h" + +#define DRV_NAME "xen-platform-pci" +#define DRV_VERSION "0.10" +#define DRV_RELDATE "03/03/2005" + +char hypercall_page[PAGE_SIZE]; +EXPORT_SYMBOL(hypercall_page); + +// Used to be xiaofeng.ling@intel.com +MODULE_AUTHOR("ssmith@xensource.com"); +MODULE_DESCRIPTION("Xen platform PCI device"); +MODULE_LICENSE("GPL"); + + +unsigned long *phys_to_machine_mapping; +EXPORT_SYMBOL(phys_to_machine_mapping); + +static int __init init_xen_info(void) +{ + unsigned long shared_info_frame; + struct xen_add_to_physmap xatp; + extern void *shared_info_area; + + setup_xen_features(); + + shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT; + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = shared_info_frame; + BUG_ON(HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)); + shared_info_area = + ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE); + + if (!shared_info_area) + panic("can't map shared info\n"); + + phys_to_machine_mapping = NULL; + + return 0; +} + +static void __devexit platform_pci_remove(struct pci_dev *pdev) +{ + long ioaddr, iolen; + long mmio_addr, mmio_len; + + ioaddr = pci_resource_start(pdev, 0); + iolen = pci_resource_len(pdev, 0); + mmio_addr = pci_resource_start(pdev, 1); + mmio_len = pci_resource_len(pdev, 1); + + release_region(ioaddr, iolen); + release_mem_region(mmio_addr, mmio_len); + + pci_set_drvdata(pdev, NULL); + free_irq(pdev->irq, pdev); +} + +static unsigned long platform_mmio; +static unsigned long platform_mmio_alloc; +static unsigned long platform_mmiolen; + +unsigned long alloc_xen_mmio(unsigned long len) +{ + unsigned long addr; + + addr = 0; + if (platform_mmio_alloc + len <= platform_mmiolen) + { + addr = platform_mmio + platform_mmio_alloc; + platform_mmio_alloc += len; + } else { + panic("ran out of xen mmio space"); + } + return addr; +} + +/* Lifted from hvmloader.c */ +static int get_hypercall_page(void) +{ + void *tmp_hypercall_page; + uint32_t eax, ebx, ecx, edx; + char signature[13]; + + cpuid(0x40000000, &eax, &ebx, &ecx, &edx); + *(uint32_t*)(signature + 0) = ebx; + *(uint32_t*)(signature + 4) = ecx; + *(uint32_t*)(signature + 8) = edx; + signature[12] = 0; + + if (strcmp("XenVMMXenVMM", signature) || eax < 0x40000002) { + printk(KERN_WARNING + "Detected Xen platform device but not Xen VMM? (sig %s, eax %x)\n", + signature, eax); + return -EINVAL; + } + + cpuid(0x40000001, &eax, &ebx, &ecx, &edx); + + printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff); + + cpuid(0x40000002, &eax, &ebx, &ecx, &edx); + + if (eax != 1) { + printk(KERN_WARNING + "This Xen version uses a %d page hypercall area," + "but these modules only support 1 page.\n", + eax); + return -EINVAL; + } + + tmp_hypercall_page = (void *)__get_free_page(GFP_KERNEL); + if (!tmp_hypercall_page) + return -ENOMEM; + memset(tmp_hypercall_page, 0xcc, PAGE_SIZE); + if (wrmsr_safe(ebx, virt_to_phys(tmp_hypercall_page), 0)) + panic("Can't do wrmsr; not running on Xen?\n"); + memcpy(hypercall_page, tmp_hypercall_page, PAGE_SIZE); + free_page((unsigned long)tmp_hypercall_page); + + return 0; +} + +static int __devinit platform_pci_init(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int i, ret; + long ioaddr, iolen; + long mmio_addr, mmio_len; + + i = pci_enable_device(pdev); + if (i) + return i; + + ioaddr = pci_resource_start(pdev, 0); + iolen = pci_resource_len(pdev, 0); + + mmio_addr = pci_resource_start(pdev, 1); + mmio_len = pci_resource_len(pdev, 1); + + if (mmio_addr == 0 || ioaddr == 0) { + printk(KERN_WARNING DRV_NAME ":no resources found\n"); + return -ENOENT; + } + + if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) + { + printk(KERN_ERR ":MEM I/O resource 0x%lx @ 0x%lx busy\n", + mmio_addr, mmio_len); + return -EBUSY; + } + + if (request_region(ioaddr, iolen, DRV_NAME) == NULL) + { + printk(KERN_ERR DRV_NAME ":I/O resource 0x%lx @ 0x%lx busy\n", + iolen, ioaddr); + release_mem_region(mmio_addr, mmio_len); + return -EBUSY; + } + + platform_mmio = mmio_addr; + platform_mmiolen = mmio_len; + + ret = get_hypercall_page(); + if (ret < 0) + goto out; + + + if ((ret = init_xen_info())) + goto out; + + if ((ret = request_irq(pdev->irq, evtchn_interrupt, SA_SHIRQ, + "xen-platform-pci", pdev))) { + goto out; + } + + if ((ret = set_callback_irq(pdev->irq))) + goto out; + + out: + if (ret) { + release_mem_region(mmio_addr, mmio_len); + release_region(ioaddr, iolen); + } + + return ret; +} + +#define XEN_PLATFORM_VENDOR_ID 0xfffd +#define XEN_PLATFORM_DEVICE_ID 0x0101 +static struct pci_device_id platform_pci_tbl[] __devinitdata = { + {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, platform_pci_tbl); + +static struct pci_driver platform_driver = { + name: DRV_NAME, + probe: platform_pci_init, + remove: __devexit_p(platform_pci_remove), + id_table: platform_pci_tbl, +}; + +static int pci_device_registered; + +static int __init platform_pci_module_init(void) +{ + int rc; + + rc = pci_module_init(&platform_driver); + if (rc) + printk(KERN_INFO DRV_NAME ":No platform pci device model found\n"); + else + pci_device_registered = 1; + + return rc; +} + +static void __exit platform_pci_module_cleanup(void) +{ + printk(KERN_INFO DRV_NAME ":Do platform module cleanup\n"); + /* disable hypervisor for callback irq */ + set_callback_irq(0); + if (pci_device_registered) + pci_unregister_driver(&platform_driver); +} + +module_init(platform_pci_module_init); +module_exit(platform_pci_module_cleanup); diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h new file mode 100644 index 0000000000..8af732c69f --- /dev/null +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * evtchn-pci.h + * module driver support in unmodified Linux + * Copyright (C) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#ifndef __XEN_SUPPORT_H +#define __XEN_SUPPORT_H +#include +#include +#include + +static inline int set_callback_irq(int irq) +{ + struct xen_hvm_param a; + + a.domid = DOMID_SELF; + a.index = HVM_PARAM_CALLBACK_IRQ; + a.value = irq; + return HYPERVISOR_hvm_op(HVMOP_set_param, &a); +} + +unsigned long alloc_xen_mmio(unsigned long len); + +void setup_xen_features(void); + +irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +#endif diff --git a/unmodified_drivers/linux-2.6/platform-pci/xen_support.c b/unmodified_drivers/linux-2.6/platform-pci/xen_support.c new file mode 100644 index 0000000000..c3a6bec595 --- /dev/null +++ b/unmodified_drivers/linux-2.6/platform-pci/xen_support.c @@ -0,0 +1,39 @@ +/****************************************************************************** + * support.c + * Xen module support functions. + * Copyright (C) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include "platform-pci.h" + +EXPORT_SYMBOL(xen_machphys_update); +void xen_machphys_update(unsigned long mfn, unsigned long pfn) +{ + BUG(); +} + +void balloon_update_driver_allowance(long delta) +{ +} + +EXPORT_SYMBOL(balloon_update_driver_allowance); -- cgit v1.2.3