Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/xen Implement new ioctl, needed by Xen 4.13:
details: https://anonhg.NetBSD.org/src/rev/4fb9610574aa
branches: trunk
changeset: 1010470:4fb9610574aa
user: bouyer <bouyer%NetBSD.org@localhost>
date: Tue May 26 10:11:56 2020 +0000
description:
Implement new ioctl, needed by Xen 4.13:
IOCTL_PRIVCMD_MMAPBATCH_V2
IOCTL_PRIVCMD_MMAP_RESOURCE
IOCTL_GNTDEV_MMAP_GRANT_REF
IOCTL_GNTDEV_ALLOC_GRANT_REF
diffstat:
sys/arch/xen/include/xenio.h | 85 ++++-
sys/arch/xen/xen/privcmd.c | 727 ++++++++++++++++++++++++++++++++++--------
2 files changed, 665 insertions(+), 147 deletions(-)
diffs (truncated from 942 to 300 lines):
diff -r 5bf6a115ef7f -r 4fb9610574aa sys/arch/xen/include/xenio.h
--- a/sys/arch/xen/include/xenio.h Tue May 26 10:10:31 2020 +0000
+++ b/sys/arch/xen/include/xenio.h Tue May 26 10:11:56 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: xenio.h,v 1.11 2016/07/07 06:55:40 msaitoh Exp $ */
+/* $NetBSD: xenio.h,v 1.12 2020/05/26 10:11:56 bouyer Exp $ */
/******************************************************************************
* privcmd.h
@@ -114,9 +114,92 @@
*/
#define IOCTL_PRIVCMD_INITDOMAIN_EVTCHN \
_IOR('P', 5, int)
+
#define IOCTL_PRIVCMD_MMAPBATCH_V2 \
_IOW('P', 6, privcmd_mmapbatch_v2_t)
+/*
+ * @cmd: IOCTL_PRIVCMD_MMAP_RESOURCE
+ * @arg &privcmd_mmap_resource_t
+ * Return:
+ * map the specified resource at the provided virtual address
+ */
+
+typedef struct privcmd_mmap_resource {
+ domid_t dom;
+ uint32_t type;
+ uint32_t id;
+ uint32_t idx;
+ uint64_t num;
+ uint64_t addr;
+} privcmd_mmap_resource_t;
+
+#define IOCTL_PRIVCMD_MMAP_RESOURCE \
+ _IOW('P', 7, privcmd_mmap_resource_t)
+
+/*
+ * @cmd: IOCTL_GNTDEV_MMAP_GRANT_REF
+ * @arg &ioctl_gntdev_mmap_grant_ref
+ * Return:
+ * map the grant references at the virtual address provided by caller
+ * The grant ref already exists (e.g. comes from a remote domain)
+ */
+struct ioctl_gntdev_grant_ref {
+ /* The domain ID of the grant to be mapped. */
+ uint32_t domid;
+ /* The grant reference of the grant to be mapped. */
+ uint32_t ref;
+};
+
+struct ioctl_gntdev_grant_notify {
+ ssize_t offset;
+ uint32_t action;
+ uint32_t event_channel_port;
+};
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+struct ioctl_gntdev_mmap_grant_ref {
+ /* The number of grants to be mapped. */
+ uint32_t count;
+ uint32_t pad;
+ /* The virtual address where they should be mapped */
+ void *va;
+ /* notify action */
+ struct ioctl_gntdev_grant_notify notify;
+ /* Array of grant references, of size @count. */
+ struct ioctl_gntdev_grant_ref *refs;
+};
+
+#define IOCTL_GNTDEV_MMAP_GRANT_REF \
+ _IOW('P', 8, struct ioctl_gntdev_mmap_grant_ref)
+
+/*
+ * @cmd: IOCTL_GNTDEV_ALLOC_GRANT_REF
+ * @arg &ioctl_gntdev_alloc_grant_ref
+ * Return:
+ * Allocate local memory and grant it to a remote domain.
+ * local memory is mmaped at the virtual address provided by caller
+ */
+
+struct ioctl_gntdev_alloc_grant_ref {
+ /* IN parameters */
+ uint16_t domid;
+ uint16_t flags;
+ uint32_t count;
+ void *va;
+ /* notify action */
+ struct ioctl_gntdev_grant_notify notify;
+ /* Variable OUT parameter */
+ uint32_t *gref_ids;
+};
+
+#define IOCTL_GNTDEV_ALLOC_GRANT_REF \
+ _IOW('P', 9, struct ioctl_gntdev_alloc_grant_ref)
+
+#define GNTDEV_ALLOC_FLAG_WRITABLE 0x01
+
+
/* Interface to /dev/xenevt */
/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
#define EVTCHN_RESET _IO('E', 1)
diff -r 5bf6a115ef7f -r 4fb9610574aa sys/arch/xen/xen/privcmd.c
--- a/sys/arch/xen/xen/privcmd.c Tue May 26 10:10:31 2020 +0000
+++ b/sys/arch/xen/xen/privcmd.c Tue May 26 10:11:56 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: privcmd.c,v 1.57 2020/05/05 17:02:01 bouyer Exp $ */
+/* $NetBSD: privcmd.c,v 1.58 2020/05/26 10:11:56 bouyer Exp $ */
/*-
* Copyright (c) 2004 Christian Limpach.
@@ -27,7 +27,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: privcmd.c,v 1.57 2020/05/05 17:02:01 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: privcmd.c,v 1.58 2020/05/26 10:11:56 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -47,29 +47,68 @@
#include <xen/hypervisor.h>
#include <xen/xen.h>
#include <xen/xenio.h>
+#include <xen/granttables.h>
#define PRIVCMD_MODE (S_IRUSR)
/* Magic value is used to mark invalid pages.
* This must be a value within the page-offset.
* Page-aligned values including 0x0 are used by the guest.
- */
+ */
#define INVALID_PAGE 0xfff
+typedef enum _privcmd_type {
+ PTYPE_PRIVCMD,
+ PTYPE_GNTDEV_REF,
+ PTYPE_GNTDEV_ALLOC
+} privcmd_type;
+
+struct privcmd_object_privcmd {
+ paddr_t *maddr; /* array of machine address to map */
+ int domid;
+ bool no_translate;
+};
+
+struct privcmd_object_gntref {
+ struct ioctl_gntdev_grant_notify notify;
+ struct gnttab_map_grant_ref ops[1]; /* variable length */
+};
+
+struct privcmd_object_gntalloc {
+ vaddr_t gntva; /* granted area mapped in kernel */
+ uint16_t domid;
+ uint16_t flags;
+ struct ioctl_gntdev_grant_notify notify;
+ uint32_t gref_ids[1]; /* variable length */
+};
+
struct privcmd_object {
struct uvm_object uobj;
- paddr_t *maddr; /* array of machine address to map */
+ privcmd_type type;
int npages;
- int domid;
+ union {
+ struct privcmd_object_privcmd pc;
+ struct privcmd_object_gntref gr;
+ struct privcmd_object_gntalloc ga;
+ } u;
};
+#define PGO_GNTREF_LEN(count) \
+ (sizeof(struct privcmd_object) + \
+ sizeof(struct gnttab_map_grant_ref) * ((count) - 1))
+
+#define PGO_GNTA_LEN(count) \
+ (sizeof(struct privcmd_object) + \
+ sizeof(uint32_t) * ((count) - 1))
+
int privcmd_nobjects = 0;
static void privpgop_reference(struct uvm_object *);
static void privpgop_detach(struct uvm_object *);
static int privpgop_fault(struct uvm_faultinfo *, vaddr_t , struct vm_page **,
- int, int, vm_prot_t, int);
-static int privcmd_map_obj(struct vm_map *, vaddr_t, paddr_t *, int, int);
+ int, int, vm_prot_t, int);
+static int privcmd_map_obj(struct vm_map *, vaddr_t,
+ struct privcmd_object *, vm_prot_t);
static int
@@ -252,6 +291,414 @@
}
}
+static vm_prot_t
+privcmd_get_map_prot(struct vm_map *map, vaddr_t start, off_t size)
+{
+ vm_prot_t prot;
+
+ vm_map_lock_read(map);
+ /* get protections. This also check for validity of mapping */
+ if (uvm_map_checkprot(map, start, start + size - 1, VM_PROT_WRITE))
+ prot = VM_PROT_READ | VM_PROT_WRITE;
+ else if (uvm_map_checkprot(map, start, start + size - 1, VM_PROT_READ))
+ prot = VM_PROT_READ;
+ else {
+ printf("privcmd_get_map_prot 0x%lx -> 0x%lx "
+ "failed\n",
+ start, (unsigned long)(start + size - 1));
+ prot = UVM_PROT_NONE;
+ }
+ vm_map_unlock_read(map);
+ return prot;
+}
+
+static int
+privcmd_mmap(struct vop_ioctl_args *ap)
+{
+ int i, j;
+ privcmd_mmap_t *mcmd = ap->a_data;
+ privcmd_mmap_entry_t mentry;
+ vaddr_t va;
+ paddr_t ma;
+ struct vm_map *vmm = &curlwp->l_proc->p_vmspace->vm_map;
+ paddr_t *maddr;
+ struct privcmd_object *obj;
+ vm_prot_t prot;
+ int error;
+
+ for (i = 0; i < mcmd->num; i++) {
+ error = copyin(&mcmd->entry[i], &mentry, sizeof(mentry));
+ if (error)
+ return EINVAL;
+ if (mentry.npages == 0)
+ return EINVAL;
+ if (mentry.va > VM_MAXUSER_ADDRESS)
+ return EINVAL;
+ va = mentry.va & ~PAGE_MASK;
+ prot = privcmd_get_map_prot(vmm, va, mentry.npages * PAGE_SIZE);
+ if (prot == UVM_PROT_NONE)
+ return EINVAL;
+ maddr = kmem_alloc(sizeof(paddr_t) * mentry.npages,
+ KM_SLEEP);
+ ma = ((paddr_t)mentry.mfn) << PGSHIFT;
+ for (j = 0; j < mentry.npages; j++) {
+ maddr[j] = ma;
+ ma += PAGE_SIZE;
+ }
+ obj = kmem_alloc(sizeof(*obj), KM_SLEEP);
+ obj->type = PTYPE_PRIVCMD;
+ obj->u.pc.maddr = maddr;
+ obj->u.pc.no_translate = false;
+ obj->npages = mentry.npages;
+ obj->u.pc.domid = mcmd->dom;
+ error = privcmd_map_obj(vmm, va, obj, prot);
+ if (error)
+ return error;
+ }
+ return 0;
+}
+
+static int
+privcmd_mmapbatch(struct vop_ioctl_args *ap)
+{
+ int i;
+ privcmd_mmapbatch_t* pmb = ap->a_data;
+ vaddr_t va0;
+ u_long mfn;
+ paddr_t ma;
+ struct vm_map *vmm;
+ vaddr_t trymap;
+ paddr_t *maddr;
+ struct privcmd_object *obj;
+ vm_prot_t prot;
+ int error;
+
+ vmm = &curlwp->l_proc->p_vmspace->vm_map;
+ va0 = pmb->addr & ~PAGE_MASK;
+
+ if (pmb->num == 0)
+ return EINVAL;
+ if (va0 > VM_MAXUSER_ADDRESS)
+ return EINVAL;
+ if (((VM_MAXUSER_ADDRESS - va0) >> PGSHIFT) < pmb->num)
+ return EINVAL;
+
+ prot = privcmd_get_map_prot(vmm, va0, PAGE_SIZE);
+ if (prot == UVM_PROT_NONE)
+ return EINVAL;
+
+ maddr = kmem_alloc(sizeof(paddr_t) * pmb->num, KM_SLEEP);
+ /* get a page of KVA to check mappins */
+ trymap = uvm_km_alloc(kernel_map, PAGE_SIZE, PAGE_SIZE,
+ UVM_KMF_VAONLY);
+ if (trymap == 0) {
+ kmem_free(maddr, sizeof(paddr_t) * pmb->num);
Home |
Main Index |
Thread Index |
Old Index