From: Rusty Russell <rusty@rustcorp.com.au>
To: Xen Mailing List <xen-devel@lists.xensource.com>
Subject: [PATCH 2/9] Linux kernel infrastructure for Xen Share access
Date: Tue, 06 Jun 2006 15:58:21 +1000 [thread overview]
Message-ID: <1149573502.5183.46.camel@localhost.localdomain> (raw)
In-Reply-To: <1149572143.5183.25.camel@localhost.localdomain>
On the Linux kernel side, we provide some wrappers for accessing
shared pages. They are currently reference-counted, because a future
patch allows userspace to access shared pages, and the Xen interface
will refuse the second request for access by the same domain.
The entire hypercall interface is arch-wrapped, which is probably
overkill, but I wasn't entirely sure of the needs of non-x86
architectures. Some of this should almost certainly be in common code.
diff -r 6d476981e3a5 -r 07a00d96357d linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/share.h
--- /dev/null Sun May 28 14:49:17 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/share.h Wed May 31 05:33:38 2006
@@ -0,0 +1,62 @@
+#ifndef __ASM_XEN_I386_SHARE_H
+#define __ASM_XEN_I386_SHARE_H
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <xen/interface/share.h>
+
+struct xen_share
+{
+ struct list_head list;
+ atomic_t use;
+ share_ref_t share_ref;
+ unsigned num_pages;
+ void *addr;
+ int event_channel;
+ int peerid;
+ int irq;
+ struct list_head handlers;
+};
+
+struct xen_share_handler
+{
+ struct list_head list;
+ void (*handler)(struct xen_share_handler *h);
+};
+
+/* Map a shared area. Returns PTR_ERR(errno) on fail. */
+struct xen_share *xen_share_get(share_ref_t share_ref, unsigned pages);
+
+/* Set up handler for events. */
+void xen_share_add_handler(struct xen_share *s, struct xen_share_handler *h);
+
+/* Remove handler. */
+void xen_share_remove_handler(struct xen_share *s,
+ struct xen_share_handler *h);
+
+/* Unmap a shared area (irq unbound if not done already). */
+void xen_share_put(struct xen_share *share);
+
+/* Register this sg list (physical kernel addresses). Returns 0 on success. */
+int xen_sg_register(struct xen_share *share, int dirmask, u32 queue, u32 *lenp,
+ unsigned int num_sgs, const struct xen_sg sg[]);
+
+/* Unregister this sg list: give first phys address of sg. */
+void xen_sg_unregister(struct xen_share *share, unsigned long sgaddr);
+
+/* Transfer this sg list (physical kernel addresses). Returns len xferred. */
+int xen_sg_xfer(struct xen_share *share, u32 queue, int dir,
+ unsigned int num_sgs, const struct xen_sg sg[]);
+
+/* Place watch on this trigger. Returns 0 on success. */
+int xen_share_watch(struct xen_share *share, int triggernum, u32 *resultp);
+
+/* Remove watch on this trigger. */
+void xen_share_unwatch(struct xen_share *share, int triggernum);
+
+/* Trigger a watch. Returns num watching on success. */
+int xen_share_trigger(struct xen_share *share, int triggernum);
+
+/* Map a share into a vma (for userspace mmap). */
+int xen_share_map(struct xen_share *share, struct vm_area_struct *vma);
+#endif /* __ASM_XEN_I386_SHARE_H */
diff -r 6d476981e3a5 -r 07a00d96357d linux-2.6-xen-sparse/arch/i386/kernel/share-xen.c
--- /dev/null Sun May 28 14:49:17 2006
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/share-xen.c Wed May 31 05:33:38 2006
@@ -0,0 +1,280 @@
+/* x86 layer for share hypercalls.
+ * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 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 <linux/sched.h>
+#include <linux/page-flags.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
+#include <asm/share.h>
+#include <asm/io.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+
+/* We only request each area from the hypervisor once, so track them. */
+static DECLARE_MUTEX(share_lock);
+static spinlock_t handler_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(shares);
+
+static int get_evtchn_port(void)
+{
+ int err;
+ struct evtchn_alloc_unbound evtchn = { .dom = DOMID_SELF,
+ .remote_dom = DOMID_SELF };
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &evtchn);
+ if (err)
+ return err;
+
+ return evtchn.port;
+}
+
+static void close_evtchn_port(int port)
+{
+ struct evtchn_close evtchn;
+ evtchn.port = port;
+ BUG_ON(HYPERVISOR_event_channel_op(EVTCHNOP_close, &evtchn) != 0);
+}
+
+static struct xen_share *get_share(share_ref_t share_ref)
+{
+ struct xen_share *i;
+
+ list_for_each_entry(i, &shares, list) {
+ if (i->share_ref == share_ref) {
+ atomic_inc(&i->use);
+ return i;
+ }
+ }
+ return NULL;
+}
+
+static irqreturn_t share_irq(int irq, void *share_, struct pt_regs *regs)
+{
+ struct xen_share *share = share_;
+ struct xen_share_handler *h;
+
+ list_for_each_entry(h, &share->handlers, list)
+ h->handler(h);
+ return IRQ_HANDLED;
+}
+
+struct xen_share *create_share(share_ref_t share_ref, unsigned pages)
+{
+ pgprot_t prot;
+ int err;
+ struct vm_struct *vma;
+ struct xen_share *share;
+
+ share = kmalloc(sizeof(struct xen_share), GFP_KERNEL);
+ if (!share) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ share->share_ref = share_ref;
+ share->num_pages = pages;
+ atomic_set(&share->use, 1);
+ INIT_LIST_HEAD(&share->handlers);
+ vma = get_vm_area(pages * PAGE_SIZE, VM_IOREMAP);
+ if (!vma) {
+ err = -ENOMEM;
+ goto free_share;
+ }
+
+ share->event_channel = get_evtchn_port();
+ if (share->event_channel < 0) {
+ err = share->event_channel;
+ goto free_vma;
+ }
+
+ err = bind_evtchn_to_irqhandler(share->event_channel, share_irq,
+ SA_SHIRQ, "xenshare", share);
+ if (err < 0)
+ goto close_evtchn;
+ share->irq = err;
+
+ share->peerid = HYPERVISOR_share(XEN_SHARE_get, share_ref,
+ share->event_channel, 0, 0);
+ if (share->peerid < 0) {
+ err = share->peerid;
+ goto unbind_evtchn;
+ }
+
+ prot = __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+ err = direct_kernel_remap_pfn_range((unsigned long)vma->addr,
+ share_ref, pages * PAGE_SIZE,
+ prot, DOMID_SELF);
+ if (err)
+ goto put_share;
+ share->addr = vma->addr;
+ list_add(&share->list, &shares);
+
+ return share;
+
+put_share:
+ BUG_ON(HYPERVISOR_share(XEN_SHARE_drop,share->share_ref,0,0,0) != 0);
+unbind_evtchn:
+ unbind_from_irqhandler(share->irq, share);
+ goto free_vma;
+close_evtchn:
+ close_evtchn_port(share->event_channel);
+free_vma:
+ kfree(vma);
+free_share:
+ kfree(share);
+fail:
+ return ERR_PTR(err);
+}
+
+/* Map a shared area. Returns PTR_ERR(errno) on fail. */
+struct xen_share *xen_share_get(share_ref_t share_ref, unsigned pages)
+{
+ struct xen_share *share;
+
+ down(&share_lock);
+ share = get_share(share_ref);
+ if (share)
+ BUG_ON(share->num_pages != pages);
+ else
+ share = create_share(share_ref, pages);
+ up(&share_lock);
+
+ return share;
+}
+
+void xen_share_add_handler(struct xen_share *s, struct xen_share_handler *h)
+{
+ spin_lock_irq(&handler_lock);
+ list_add(&h->list, &s->handlers);
+ spin_unlock_irq(&handler_lock);
+}
+
+/* Remove irq handler. */
+void xen_share_remove_handler(struct xen_share *s, struct xen_share_handler *h)
+{
+ BUG_ON(list_empty(&s->handlers));
+ spin_lock_irq(&handler_lock);
+ list_del(&h->list);
+ spin_unlock_irq(&handler_lock);
+}
+
+/* Unmap a shared area. */
+void xen_share_put(struct xen_share *share)
+{
+ down(&share_lock);
+ if (atomic_dec_and_test(&share->use)) {
+ BUG_ON(!list_empty(&share->handlers));
+ unbind_from_irqhandler(share->irq, share);
+
+ /* This also kfrees vma. */
+ vunmap(share->addr);
+ BUG_ON(HYPERVISOR_share(XEN_SHARE_drop, share->share_ref, 0,
+ 0, 0) != 0);
+ list_del(&share->list);
+ kfree(share);
+ }
+ up(&share_lock);
+}
+
+/* Register this sg list (physical kernel addresses). Returns 0 on success. */
+int xen_sg_register(struct xen_share *s, int dirmask, u32 queue, u32 *lenp,
+ unsigned int num_sgs, const struct xen_sg sg[])
+{
+ struct xen_sg new_sg[XEN_SG_MAX];
+ unsigned int i;
+
+ /* We feed machine addresses to hypervisor. */
+ for (i = 0; i < num_sgs; i++) {
+ new_sg[i].addr = phys_to_machine(sg[i].addr);
+ new_sg[i].len = sg[i].len;
+ }
+
+ return HYPERVISOR_share(XEN_SHARE_sg_register, s->share_ref,
+ xen_share_sg_arg(queue, num_sgs, dirmask),
+ (long)new_sg,
+ virt_to_machine(lenp));
+}
+
+/* Unregister this sg list. */
+void xen_sg_unregister(struct xen_share *s, unsigned long addr)
+{
+ BUG_ON(HYPERVISOR_share(XEN_SHARE_sg_unregister, s->share_ref,
+ phys_to_machine(addr), 0, 0) != 0);
+}
+
+/* Transfer this sg list (physical kernel addresses). Returns len xferred. */
+int xen_sg_xfer(struct xen_share *s, u32 queue, int dir,
+ unsigned int num_sgs, const struct xen_sg sg[])
+{
+ struct xen_sg new_sg[XEN_SG_MAX];
+ unsigned int i;
+
+ /* Hypervisor wants virtual addresses here. */
+ for (i = 0; i < num_sgs; i++) {
+ new_sg[i].addr = (long)phys_to_virt(sg[i].addr);
+ new_sg[i].len = sg[i].len;
+ }
+
+ return HYPERVISOR_share(XEN_SHARE_sg_xfer, s->share_ref,
+ xen_share_sg_arg(queue, num_sgs, dir),
+ (long)new_sg, 0);
+}
+
+/* Place watch on this trigger. Returns 0 on success. */
+int xen_share_watch(struct xen_share *s, int triggernum, u32 *resultp)
+{
+ return HYPERVISOR_share(XEN_SHARE_watch, s->share_ref, triggernum,
+ virt_to_machine(resultp), 0);
+}
+
+/* Remove watch on this trigger. */
+void xen_share_unwatch(struct xen_share *s, int triggernum)
+{
+ BUG_ON(HYPERVISOR_share(XEN_SHARE_unwatch, s->share_ref, triggernum,
+ 0, 0) != 0);
+}
+
+/* Trigger a watch. Returns num watching on success. */
+int xen_share_trigger(struct xen_share *s, int trigger)
+{
+ return HYPERVISOR_share(XEN_SHARE_trigger, s->share_ref, trigger,0,0);
+}
+
+int xen_share_map(struct xen_share *s, struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+ return direct_remap_pfn_range(vma, vma->vm_start,
+ s->share_ref,
+ s->num_pages * PAGE_SIZE,
+ vma->vm_page_prot, DOMID_SELF);
+}
+
+EXPORT_SYMBOL_GPL(xen_share_get);
+EXPORT_SYMBOL_GPL(xen_share_put);
+EXPORT_SYMBOL_GPL(xen_share_map);
+EXPORT_SYMBOL_GPL(xen_share_trigger);
+EXPORT_SYMBOL_GPL(xen_share_watch);
+EXPORT_SYMBOL_GPL(xen_share_unwatch);
+EXPORT_SYMBOL_GPL(xen_sg_xfer);
+EXPORT_SYMBOL_GPL(xen_sg_register);
+EXPORT_SYMBOL_GPL(xen_sg_unregister);
+EXPORT_SYMBOL_GPL(xen_share_add_handler);
+EXPORT_SYMBOL_GPL(xen_share_remove_handler);
diff -r 6d476981e3a5 -r 07a00d96357d linux-2.6-xen-sparse/arch/i386/kernel/Makefile
--- a/linux-2.6-xen-sparse/arch/i386/kernel/Makefile Sun May 28 14:49:17 2006
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/Makefile Wed May 31 05:33:38 2006
@@ -88,6 +88,7 @@
include $(srctree)/scripts/Makefile.xen
obj-y += fixup.o
+obj-y += share-xen.o
microcode-$(subst m,y,$(CONFIG_MICROCODE)) := microcode-xen.o
n-obj-xen := i8259.o timers/ reboot.o smpboot.o trampoline.o
diff -r 6d476981e3a5 -r 07a00d96357d linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c Sun May 28 14:49:17 2006
+++ b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c Wed May 31 05:33:38 2006
@@ -123,8 +123,11 @@
/* Same as remap_pfn_range(). */
vma->vm_flags |= VM_IO | VM_RESERVED;
+ /* FIXME: xenshare needs to pass DOMID_SELF. Check it's save to remove
+ * the check.
if (domid == DOMID_SELF)
return -EINVAL;
+ */
return __direct_remap_pfn_range(
vma->vm_mm, address, mfn, size, prot, domid);
diff -r 6d476981e3a5 -r 07a00d96357d linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h Sun May 28 14:49:17 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h Wed May 31 05:33:38 2006
@@ -359,5 +359,11 @@
return _hypercall2(int, xenoprof_op, op, arg);
}
+static inline long
+HYPERVISOR_share(
+ int op, long arg1, long arg2, long arg3, long arg4)
+{
+ return _hypercall5(long, share_op, op, arg1, arg2, arg3, arg4);
+}
#endif /* __HYPERCALL_H__ */
diff -r 6d476981e3a5 -r 07a00d96357d patches/linux-2.6.12/get_vm_area.patch
--- /dev/null Sun May 28 14:49:17 2006
+++ b/patches/linux-2.6.12/get_vm_area.patch Wed May 31 05:33:38 2006
@@ -0,0 +1,9 @@
+diff -Naur linux-2.6.12/mm/vmalloc.c linux-2.6.12.post/mm/vmalloc.c
+--- linux-2.6.12/mm/vmalloc.c 2005-06-18 05:48:29.000000000 +1000
++++ linux-2.6.12.post/mm/vmalloc.c 2006-01-10 16:56:36.000000000 +1100
+@@ -247,6 +247,7 @@
+ {
+ return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
+ }
++EXPORT_SYMBOL(get_vm_area);
+
--
ccontrol: http://ccontrol.ozlabs.org
next prev parent reply other threads:[~2006-06-06 5:58 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-06 5:35 [PATCH 1/9] Xen Share: Simplified I/O Mechanism Rusty Russell
2006-06-06 5:50 ` [PATCH 3/9] privcmd interface addition to support share operations from Dom0 userspace Rusty Russell
2006-06-06 5:51 ` [PATCH 4/9] /dev/xenshare for accessing/mapping shared pages from userspace Rusty Russell
2006-06-06 5:52 ` [PATCH 5/9] Vdevice share in start_info Rusty Russell
2006-06-06 5:54 ` [PATCH 6/9] Linux support for vdevice bus Rusty Russell
2006-06-07 10:03 ` Jacob Gorm Hansen
2006-06-07 10:58 ` Rusty Russell
2006-06-07 11:09 ` Jacob Gorm Hansen
2006-06-06 5:55 ` [PATCH 7/9] vdevice tool for manipulating " Rusty Russell
2006-06-06 5:57 ` [PATCH 8/9] Xen Share Net Device Rusty Russell
2006-06-06 5:58 ` Rusty Russell [this message]
2006-06-14 17:26 ` [PATCH 2/9] Linux kernel infrastructure for Xen Share access Mike D. Day
2006-06-06 5:59 ` [PATCH 9/9] Simple Xenshare Block Device and userspace backend Rusty Russell
2006-06-06 14:31 ` [PATCH 1/9] Xen Share: Simplified I/O Mechanism Harry Butterworth
2006-06-07 2:24 ` Rusty Russell
2006-06-06 14:47 ` Harry Butterworth
2006-06-07 2:35 ` Rusty Russell
2006-06-07 13:31 ` Harry Butterworth
2006-06-14 17:46 ` Mike D. Day
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1149573502.5183.46.camel@localhost.localdomain \
--to=rusty@rustcorp.com.au \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.