Add dom0 operation support for Xen3. Probably buggy, but it's enouth to have

xend and xenstored starting; xm info and xm list works.
This commit is contained in:
bouyer 2006-05-07 10:18:28 +00:00
parent 96d1fdec03
commit c8a960c560
3 changed files with 291 additions and 74 deletions

View File

@ -0,0 +1,89 @@
/* $NetBSD: xenio3.h,v 1.1 2006/05/07 10:18:28 bouyer Exp $ */
/******************************************************************************
* evtchn.h
*
* Interface to /dev/xen/evtchn.
*
* Copyright (c) 2003-2005, K A Fraser
*
* 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.
*/
#ifndef __LINUX_PUBLIC_EVTCHN_H__
#define __LINUX_PUBLIC_EVTCHN_H__
/*
* Bind a fresh port to VIRQ @virq.
* Return allocated port.
*/
#define IOCTL_EVTCHN_BIND_VIRQ \
_IOWR('E', 4, struct ioctl_evtchn_bind_virq)
struct ioctl_evtchn_bind_virq {
unsigned int virq;
unsigned int port;
};
/*
* Bind a fresh port to remote <@remote_domain, @remote_port>.
* Return allocated port.
*/
#define IOCTL_EVTCHN_BIND_INTERDOMAIN \
_IOWR('E', 5, struct ioctl_evtchn_bind_interdomain)
struct ioctl_evtchn_bind_interdomain {
unsigned int remote_domain, remote_port;
unsigned int port;
};
/*
* Allocate a fresh port for binding to @remote_domain.
* Return allocated port.
*/
#define IOCTL_EVTCHN_BIND_UNBOUND_PORT \
_IOWR('E', 6, struct ioctl_evtchn_bind_unbound_port)
struct ioctl_evtchn_bind_unbound_port {
unsigned int remote_domain;
unsigned int port;
};
/*
* Unbind previously allocated @port.
*/
#define IOCTL_EVTCHN_UNBIND \
_IOW('E', 7, struct ioctl_evtchn_unbind)
struct ioctl_evtchn_unbind {
unsigned int port;
};
/*
* Send event to previously allocated @port.
*/
#define IOCTL_EVTCHN_NOTIFY \
_IOW('E', 8, struct ioctl_evtchn_notify)
struct ioctl_evtchn_notify {
unsigned int port;
};
/* Clear and reinitialise the event buffer. Clear error condition. */
#define IOCTL_EVTCHN_RESET \
_IO('E', 9)
#endif /* __LINUX_PUBLIC_EVTCHN_H__ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: xenevt.c,v 1.7 2005/12/12 22:56:50 jld Exp $ */
/* $NetBSD: xenevt.c,v 1.8 2006/05/07 10:18:28 bouyer Exp $ */
/*
* Copyright (c) 2005 Manuel Bouyer.
@ -30,6 +30,7 @@
*
*/
#include "opt_xen.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@ -42,8 +43,14 @@
#include <sys/proc.h>
#include <sys/conf.h>
#include <uvm/uvm_extern.h>
#include <machine/hypervisor.h>
#include <machine/xenpmap.h>
#include <machine/xenio.h>
#ifdef XEN3
#include <machine/xenio3.h>
#endif
#include <machine/xen.h>
extern struct evcnt softxenevt_evtcnt;
@ -59,40 +66,53 @@ extern struct evcnt softxenevt_evtcnt;
*/
void xenevtattach(int);
static int xenevt_read(struct file *, off_t *, struct uio *,
static int xenevt_fread(struct file *, off_t *, struct uio *,
struct ucred *, int);
static int xenevt_write(struct file *, off_t *, struct uio *,
static int xenevt_fwrite(struct file *, off_t *, struct uio *,
struct ucred *, int);
static int xenevt_ioctl(struct file *, u_long, void *, struct lwp *);
static int xenevt_poll(struct file *, int, struct lwp *);
static int xenevt_close(struct file *, struct lwp *);
/* static int xenevt_kqfilter(struct file *, struct knote *); */
static int xenevt_fioctl(struct file *, u_long, void *, struct lwp *);
static int xenevt_fpoll(struct file *, int, struct lwp *);
static int xenevt_fclose(struct file *, struct lwp *);
/* static int xenevt_fkqfilter(struct file *, struct knote *); */
static const struct fileops xenevt_fileops = {
xenevt_read,
xenevt_write,
xenevt_ioctl,
xenevt_fread,
xenevt_fwrite,
xenevt_fioctl,
fnullop_fcntl,
xenevt_poll,
xenevt_fpoll,
fbadop_stat,
xenevt_close,
/* xenevt_kqfilter */ fnullop_kqfilter
xenevt_fclose,
/* xenevt_fkqfilter */ fnullop_kqfilter
};
dev_type_open(xenevtopen);
dev_type_read(xenevtread);
dev_type_mmap(xenevtmmap);
const struct cdevsw xenevt_cdevsw = {
xenevtopen, noclose, noread, nowrite, noioctl,
nostop, notty, nopoll, nommap, nokqfilter,
xenevtopen, nullclose, xenevtread, nowrite, noioctl,
nostop, notty, nopoll, xenevtmmap, nokqfilter,
};
/* minor numbers */
#define DEV_EVT 0
#define DEV_XSD 1
/* per-instance datas */
#define XENEVT_RING_SIZE 2048
#define XENEVT_RING_MASK 2047
#ifndef XEN3
typedef uint16_t evtchn_port_t;
#endif
#define BYTES_PER_PORT (sizeof(evtchn_port_t) / sizeof(uint8_t))
struct xenevt_d {
struct simplelock lock;
STAILQ_ENTRY(xenevt_d) pendingq;
boolean_t pending;
u_int16_t ring[2048];
evtchn_port_t ring[2048];
u_int ring_read; /* pointer of the reader */
u_int ring_write; /* pointer of the writer */
u_int flags;
@ -109,7 +129,7 @@ STAILQ_HEAD(, xenevt_d) devevent_pending =
STAILQ_HEAD_INITIALIZER(devevent_pending);
static void xenevt_donotify(struct xenevt_d *);
static void xenevt_record(struct xenevt_d *, int);
static void xenevt_record(struct xenevt_d *, evtchn_port_t);
/* called at boot time */
void
@ -192,7 +212,7 @@ xenevt_donotify(struct xenevt_d *d)
}
static void
xenevt_record(struct xenevt_d *d, int port)
xenevt_record(struct xenevt_d *d, evtchn_port_t port)
{
/*
@ -219,26 +239,94 @@ xenevtopen(dev_t dev, int flags, int mode, struct lwp *l)
struct file *fp;
int fd, error;
/* falloc() will use the descriptor for us. */
if ((error = falloc(l->l_proc, &fp, &fd)) != 0)
switch(minor(dev)) {
case DEV_EVT:
/* falloc() will use the descriptor for us. */
if ((error = falloc(l->l_proc, &fp, &fd)) != 0)
return error;
d = malloc(sizeof(*d), M_DEVBUF, M_WAITOK | M_ZERO);
simple_lock_init(&d->lock);
return fdclone(l, fp, fd, flags, &xenevt_fileops, d);
#ifdef XEN3
case DEV_XSD:
/* no clone for /dev/xsd_kva */
return (0);
#endif
default:
break;
}
return ENODEV;
}
/* read from device: only for /dev/xsd_kva, xenevt is done though fread */
int
xenevtread(dev_t dev, struct uio *uio, int flags)
{
#ifdef XEN3
#define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
if (minor(dev) == DEV_XSD) {
char strbuf[LD_STRLEN], *bf;
int off, error;
size_t len;
off = (int)uio->uio_offset;
if (off < 0)
return EINVAL;
len = snprintf(strbuf, sizeof(strbuf), "%ld\n",
xen_start_info.store_mfn);
if (off >= len) {
bf = strbuf;
len = 0;
} else {
bf = &strbuf[off];
len -= off;
}
error = uiomove(bf, len, uio);
return error;
}
#endif
return ENODEV;
}
d = malloc(sizeof(*d), M_DEVBUF, M_WAITOK | M_ZERO);
simple_lock_init(&d->lock);
return fdclone(l, fp, fd, flags, &xenevt_fileops, d);
/* mmap: only for xsd_kva */
paddr_t
xenevtmmap(dev_t dev, off_t off, int prot)
{
#ifdef XEN3
if (minor(dev) == DEV_XSD) {
/* only one page, so off is always 0 */
if (off != 0)
return -1;
return x86_btop(
xpmap_mtop(xen_start_info.store_mfn << PAGE_SHIFT));
}
#endif
return -1;
}
static int
xenevt_close(struct file *fp, struct lwp *l)
xenevt_fclose(struct file *fp, struct lwp *l)
{
struct xenevt_d *d = fp->f_data;
int i;
for (i = 0; i < NR_EVENT_CHANNELS; i++ ) {
if (devevent[i] == d) {
#ifdef XEN3
evtchn_op_t op = { 0 };
int error;
#endif
hypervisor_mask_event(i);
devevent[i] = NULL;
#ifdef XEN3
op.cmd = EVTCHNOP_close;
op.u.close.port = i;
if ((error = HYPERVISOR_event_channel_op(&op))) {
printf("xenevt_fclose: error %d from "
"hypervisor\n", -error);
}
#endif
}
}
free(d, M_DEVBUF);
@ -248,7 +336,7 @@ xenevt_close(struct file *fp, struct lwp *l)
}
static int
xenevt_read(struct file *fp, off_t *offp, struct uio *uio,
xenevt_fread(struct file *fp, off_t *offp, struct uio *uio,
struct ucred *cred, int flags)
{
struct xenevt_d *d = fp->f_data;
@ -289,25 +377,25 @@ xenevt_read(struct file *fp, off_t *offp, struct uio *uio,
return error;
}
uio_len = uio->uio_resid >> 1;
uio_len = uio->uio_resid / BYTES_PER_PORT;
if (ring_read <= ring_write)
len = ring_write - ring_read;
else
len = XENEVT_RING_SIZE - ring_read;
if (len > uio_len)
len = uio_len;
error = uiomove(&d->ring[ring_read], len << 1, uio);
error = uiomove(&d->ring[ring_read], len * BYTES_PER_PORT, uio);
if (error)
return error;
ring_read = (ring_read + len) & XENEVT_RING_MASK;
uio_len = uio->uio_resid >> 1;
uio_len = uio->uio_resid / BYTES_PER_PORT;
if (uio_len == 0)
goto done;
/* ring wrapped, read the second part */
len = ring_write - ring_read;
if (len > uio_len)
len = uio_len;
error = uiomove(&d->ring[ring_read], len << 1, uio);
error = uiomove(&d->ring[ring_read], len * BYTES_PER_PORT, uio);
if (error)
return error;
ring_read = (ring_read + len) & XENEVT_RING_MASK;
@ -323,7 +411,7 @@ done:
}
static int
xenevt_write(struct file *fp, off_t *offp, struct uio *uio,
xenevt_fwrite(struct file *fp, off_t *offp, struct uio *uio,
struct ucred *cred, int flags)
{
struct xenevt_d *d = fp->f_data;
@ -348,16 +436,94 @@ xenevt_write(struct file *fp, off_t *offp, struct uio *uio,
}
static int
xenevt_ioctl(struct file *fp, u_long cmd, void *addr, struct lwp *l)
xenevt_fioctl(struct file *fp, u_long cmd, void *addr, struct lwp *l)
{
struct xenevt_d *d = fp->f_data;
#ifdef XEN3
evtchn_op_t op = { 0 };
int error;
#else
u_int *arg = addr;
#endif
switch(cmd) {
case EVTCHN_RESET:
#ifdef XEN3
case IOCTL_EVTCHN_RESET:
#endif
d->ring_read = d->ring_write = 0;
d->flags = 0;
break;
#ifdef XEN3
case IOCTL_EVTCHN_BIND_VIRQ:
{
struct ioctl_evtchn_bind_virq *bind_virq = addr;
op.cmd = EVTCHNOP_bind_virq;
op.u.bind_virq.virq = bind_virq->virq;
op.u.bind_virq.vcpu = 0;
if ((error = HYPERVISOR_event_channel_op(&op))) {
printf("IOCTL_EVTCHN_BIND_VIRQ failed: virq %d error %d\n", bind_virq->virq, error);
return -error;
}
bind_virq->port = op.u.bind_virq.port;
devevent[bind_virq->port] = d;
hypervisor_unmask_event(bind_virq->port);
break;
}
case IOCTL_EVTCHN_BIND_INTERDOMAIN:
{
struct ioctl_evtchn_bind_interdomain *bind_intd = addr;
op.cmd = EVTCHNOP_bind_interdomain;
op.u.bind_interdomain.remote_dom = bind_intd->remote_domain;
op.u.bind_interdomain.remote_port = bind_intd->remote_port;
if ((error = HYPERVISOR_event_channel_op(&op)))
return error;
bind_intd->port = op.u.bind_interdomain.local_port;
devevent[bind_intd->port] = d;
hypervisor_unmask_event(bind_intd->port);
break;
}
case IOCTL_EVTCHN_BIND_UNBOUND_PORT:
{
struct ioctl_evtchn_bind_unbound_port *bind_unbound = addr;
op.cmd = EVTCHNOP_alloc_unbound;
op.u.alloc_unbound.dom = DOMID_SELF;
op.u.alloc_unbound.remote_dom = bind_unbound->remote_domain;
if ((error = HYPERVISOR_event_channel_op(&op)))
return error;
bind_unbound->port = op.u.alloc_unbound.port;
devevent[bind_unbound->port] = d;
hypervisor_unmask_event(bind_unbound->port);
break;
}
case IOCTL_EVTCHN_UNBIND:
{
struct ioctl_evtchn_unbind *unbind = addr;
if (unbind->port > NR_EVENT_CHANNELS)
return EINVAL;
if (devevent[unbind->port] != d)
return ENOTCONN;
devevent[unbind->port] = NULL;
hypervisor_mask_event(unbind->port);
op.cmd = EVTCHNOP_close;
op.u.close.port = unbind->port;
if ((error = HYPERVISOR_event_channel_op(&op)))
return error;
break;
}
case IOCTL_EVTCHN_NOTIFY:
{
struct ioctl_evtchn_notify *notify = addr;
if (notify->port > NR_EVENT_CHANNELS)
return EINVAL;
if (devevent[notify->port] != d)
return ENOTCONN;
hypervisor_notify_via_evtchn(notify->port);
break;
}
#else /* !XEN3 */
case EVTCHN_BIND:
if (*arg > NR_EVENT_CHANNELS)
return EINVAL;
@ -374,6 +540,7 @@ xenevt_ioctl(struct file *fp, u_long cmd, void *addr, struct lwp *l)
devevent[*arg] = NULL;
hypervisor_mask_event(*arg);
break;
#endif /* !XEN3 */
case FIONBIO:
break;
default:
@ -389,7 +556,7 @@ xenevt_ioctl(struct file *fp, u_long cmd, void *addr, struct lwp *l)
*/
static int
xenevt_poll(struct file *fp, int events, struct lwp *l)
xenevt_fpoll(struct file *fp, int events, struct lwp *l)
{
struct xenevt_d *d = fp->f_data;
int revents = events & (POLLOUT | POLLWRNORM); /* we can always write */

View File

@ -1,4 +1,4 @@
/* $NetBSD: xenbus_dev.c,v 1.3 2006/04/11 22:09:09 bouyer Exp $ */
/* $NetBSD: xenbus_dev.c,v 1.4 2006/05/07 10:18:28 bouyer Exp $ */
/*
* xenbus_dev.c
*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.3 2006/04/11 22:09:09 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.4 2006/05/07 10:18:28 bouyer Exp $");
#include "opt_xen.h"
@ -58,7 +58,6 @@ static int xenbus_dev_read(void *);
static int xenbus_dev_write(void *);
static int xenbus_dev_open(void *);
static int xenbus_dev_close(void *);
static int xsd_mfn_read(void *);
static int xsd_port_read(void *);
struct xenbus_dev_transaction {
@ -76,9 +75,6 @@ static const struct kernfs_fileop xenbus_fileops[] = {
};
#define XSD_MODE (S_IRUSR)
static const struct kernfs_fileop xsd_mfn_fileops[] = {
{ .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_mfn_read },
};
static const struct kernfs_fileop xsd_port_fileops[] = {
{ .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read },
};
@ -95,11 +91,6 @@ xenbus_kernfs_init()
PRIVCMD_MODE);
kernfs_addentry(kernxen_pkt, dkt);
kfst = KERNFS_ALLOCTYPE(xsd_mfn_fileops);
KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
KERNFS_INITENTRY(dkt, DT_REG, "xsd_mfn", NULL, kfst, VREG, XSD_MODE);
kernfs_addentry(kernxen_pkt, dkt);
kfst = KERNFS_ALLOCTYPE(xsd_port_fileops);
KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL, kfst, VREG, XSD_MODE);
@ -323,36 +314,6 @@ xenbus_dev_close(void *v)
}
#define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
static int
xsd_mfn_read(void *v)
{
struct vop_read_args /* {
struct vnode *a_vp;
struct uio *a_uio;
int a_ioflag;
struct ucred *a_cred;
} */ *ap = v;
struct uio *uio = ap->a_uio;
int off, error;
size_t len;
char strbuf[LD_STRLEN], *bf;
off = (int)uio->uio_offset;
if (off < 0)
return EINVAL;
len = snprintf(strbuf, sizeof(strbuf), "%ld\n",
xen_start_info.store_mfn);
if (off >= len) {
bf = strbuf;
len = 0;
} else {
bf = &strbuf[off];
len -= off;
}
error = uiomove(bf, len, uio);
return error;
}
static int
xsd_port_read(void *v)