Home | History | Annotate | Line # | Download | only in xenbus
xenbus_comms.c revision 1.23
      1  1.23    bouyer /* $NetBSD: xenbus_comms.c,v 1.23 2020/05/06 16:50:13 bouyer Exp $ */
      2   1.1    bouyer /******************************************************************************
      3   1.1    bouyer  * xenbus_comms.c
      4   1.1    bouyer  *
      5   1.1    bouyer  * Low level code to talks to Xen Store: ringbuffer and event channel.
      6   1.1    bouyer  *
      7   1.1    bouyer  * Copyright (C) 2005 Rusty Russell, IBM Corporation
      8   1.1    bouyer  *
      9   1.1    bouyer  * This file may be distributed separately from the Linux kernel, or
     10   1.1    bouyer  * incorporated into other software packages, subject to the following license:
     11   1.1    bouyer  *
     12   1.1    bouyer  * Permission is hereby granted, free of charge, to any person obtaining a copy
     13   1.1    bouyer  * of this source file (the "Software"), to deal in the Software without
     14   1.1    bouyer  * restriction, including without limitation the rights to use, copy, modify,
     15   1.1    bouyer  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
     16   1.1    bouyer  * and to permit persons to whom the Software is furnished to do so, subject to
     17   1.1    bouyer  * the following conditions:
     18   1.1    bouyer  *
     19   1.1    bouyer  * The above copyright notice and this permission notice shall be included in
     20   1.1    bouyer  * all copies or substantial portions of the Software.
     21   1.1    bouyer  *
     22   1.1    bouyer  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     23   1.1    bouyer  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     24   1.1    bouyer  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     25   1.1    bouyer  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     26   1.1    bouyer  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     27   1.1    bouyer  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     28   1.1    bouyer  * IN THE SOFTWARE.
     29   1.1    bouyer  */
     30   1.1    bouyer 
     31   1.2    bouyer #include <sys/cdefs.h>
     32  1.23    bouyer __KERNEL_RCSID(0, "$NetBSD: xenbus_comms.c,v 1.23 2020/05/06 16:50:13 bouyer Exp $");
     33   1.2    bouyer 
     34   1.2    bouyer #include <sys/types.h>
     35   1.2    bouyer #include <sys/null.h>
     36   1.2    bouyer #include <sys/errno.h>
     37   1.2    bouyer #include <sys/param.h>
     38   1.2    bouyer #include <sys/proc.h>
     39   1.2    bouyer #include <sys/systm.h>
     40  1.23    bouyer #include <sys/mutex.h>
     41   1.2    bouyer 
     42  1.10    cegger #include <xen/xen.h>	/* for xendomain_is_dom0() */
     43  1.22    bouyer #include <xen/intr.h>	/* for xendomain_is_dom0() */
     44   1.5    bouyer #include <xen/hypervisor.h>
     45   1.5    bouyer #include <xen/evtchn.h>
     46   1.5    bouyer #include <xen/xenbus.h>
     47   1.1    bouyer #include "xenbus_comms.h"
     48   1.1    bouyer 
     49   1.2    bouyer #undef XENDEBUG
     50   1.2    bouyer #ifdef XENDEBUG
     51   1.2    bouyer #define XENPRINTF(x) printf x
     52   1.2    bouyer #else
     53   1.2    bouyer #define XENPRINTF(x)
     54   1.2    bouyer #endif
     55   1.2    bouyer 
     56  1.16    cherry static struct intrhand *ih;
     57   1.2    bouyer struct xenstore_domain_interface *xenstore_interface;
     58  1.23    bouyer static kmutex_t xenstore_lock;
     59  1.23    bouyer static kcondvar_t xenstore_cv;
     60   1.2    bouyer 
     61  1.15   msaitoh extern int xenstored_ready;
     62   1.2    bouyer // static DECLARE_WORK(probe_work, xenbus_probe, NULL);
     63   1.2    bouyer 
     64   1.2    bouyer static int wake_waiting(void *);
     65   1.2    bouyer static int check_indexes(XENSTORE_RING_IDX, XENSTORE_RING_IDX);
     66   1.4  christos static void *get_output_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
     67   1.2    bouyer     char *, uint32_t *);
     68   1.4  christos static const void *get_input_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
     69   1.2    bouyer     const char *, uint32_t *);
     70   1.1    bouyer 
     71   1.1    bouyer 
     72   1.2    bouyer static inline struct xenstore_domain_interface *
     73   1.2    bouyer xenstore_domain_interface(void)
     74   1.1    bouyer {
     75   1.2    bouyer 	return xenstore_interface;
     76   1.1    bouyer }
     77   1.1    bouyer 
     78   1.2    bouyer static int
     79   1.2    bouyer wake_waiting(void *arg)
     80   1.1    bouyer {
     81   1.8    cegger 	if (__predict_false(xenstored_ready == 0 && xendomain_is_dom0())) {
     82  1.23    bouyer 		xb_xenstored_make_ready();
     83   1.1    bouyer 	}
     84   1.1    bouyer 
     85  1.23    bouyer 	mutex_enter(&xenstore_lock);
     86  1.23    bouyer 	cv_broadcast(&xenstore_cv);
     87  1.23    bouyer 	mutex_exit(&xenstore_lock);
     88   1.2    bouyer 	return 1;
     89   1.1    bouyer }
     90   1.1    bouyer 
     91   1.2    bouyer static int
     92   1.2    bouyer check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
     93   1.1    bouyer {
     94   1.1    bouyer 	return ((prod - cons) <= XENSTORE_RING_SIZE);
     95   1.1    bouyer }
     96   1.1    bouyer 
     97   1.2    bouyer static void *
     98   1.2    bouyer get_output_chunk(XENSTORE_RING_IDX cons,
     99   1.1    bouyer 			      XENSTORE_RING_IDX prod,
    100   1.1    bouyer 			      char *buf, uint32_t *len)
    101   1.1    bouyer {
    102   1.1    bouyer 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
    103   1.1    bouyer 	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
    104   1.1    bouyer 		*len = XENSTORE_RING_SIZE - (prod - cons);
    105   1.1    bouyer 	return buf + MASK_XENSTORE_IDX(prod);
    106   1.1    bouyer }
    107   1.1    bouyer 
    108   1.2    bouyer static const void *
    109   1.2    bouyer get_input_chunk(XENSTORE_RING_IDX cons,
    110   1.1    bouyer 				   XENSTORE_RING_IDX prod,
    111   1.1    bouyer 				   const char *buf, uint32_t *len)
    112   1.1    bouyer {
    113   1.1    bouyer 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
    114   1.1    bouyer 	if ((prod - cons) < *len)
    115   1.1    bouyer 		*len = prod - cons;
    116   1.1    bouyer 	return buf + MASK_XENSTORE_IDX(cons);
    117   1.1    bouyer }
    118   1.1    bouyer 
    119   1.2    bouyer int
    120   1.2    bouyer xb_write(const void *data, unsigned len)
    121   1.1    bouyer {
    122   1.1    bouyer 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    123   1.1    bouyer 	XENSTORE_RING_IDX cons, prod;
    124   1.1    bouyer 
    125  1.23    bouyer 	mutex_enter(&xenstore_lock);
    126   1.1    bouyer 	while (len != 0) {
    127   1.1    bouyer 		void *dst;
    128   1.1    bouyer 		unsigned int avail;
    129   1.1    bouyer 
    130   1.2    bouyer 		while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) {
    131  1.23    bouyer 			XENPRINTF(("xb_write cv_wait\n"));
    132  1.23    bouyer 			cv_wait(&xenstore_cv, &xenstore_lock);
    133  1.23    bouyer 			XENPRINTF(("xb_write cv_wait done\n"));
    134   1.2    bouyer 		}
    135   1.1    bouyer 
    136   1.1    bouyer 		/* Read indexes, then verify. */
    137   1.1    bouyer 		cons = intf->req_cons;
    138   1.1    bouyer 		prod = intf->req_prod;
    139  1.12       jym 		xen_rmb();
    140   1.2    bouyer 		if (!check_indexes(cons, prod)) {
    141  1.23    bouyer 			mutex_exit(&xenstore_lock);
    142   1.2    bouyer 			return EIO;
    143   1.2    bouyer 		}
    144   1.1    bouyer 
    145   1.1    bouyer 		dst = get_output_chunk(cons, prod, intf->req, &avail);
    146   1.1    bouyer 		if (avail == 0)
    147   1.1    bouyer 			continue;
    148   1.1    bouyer 		if (avail > len)
    149   1.1    bouyer 			avail = len;
    150   1.1    bouyer 
    151   1.1    bouyer 		memcpy(dst, data, avail);
    152   1.2    bouyer 		data = (const char *)data + avail;
    153   1.1    bouyer 		len -= avail;
    154   1.1    bouyer 
    155   1.1    bouyer 		/* Other side must not see new header until data is there. */
    156  1.12       jym 		xen_rmb();
    157   1.1    bouyer 		intf->req_prod += avail;
    158  1.12       jym 		xen_rmb();
    159   1.1    bouyer 
    160   1.2    bouyer 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
    161   1.1    bouyer 	}
    162  1.23    bouyer 	mutex_exit(&xenstore_lock);
    163   1.1    bouyer 	return 0;
    164   1.1    bouyer }
    165   1.1    bouyer 
    166   1.2    bouyer int
    167   1.2    bouyer xb_read(void *data, unsigned len)
    168   1.1    bouyer {
    169   1.1    bouyer 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    170   1.1    bouyer 	XENSTORE_RING_IDX cons, prod;
    171   1.1    bouyer 
    172  1.23    bouyer 	mutex_enter(&xenstore_lock);
    173   1.2    bouyer 
    174   1.1    bouyer 	while (len != 0) {
    175   1.1    bouyer 		unsigned int avail;
    176   1.1    bouyer 		const char *src;
    177   1.1    bouyer 
    178   1.2    bouyer 		while (intf->rsp_cons == intf->rsp_prod)
    179  1.23    bouyer 			cv_wait(&xenstore_cv, &xenstore_lock);
    180   1.1    bouyer 
    181   1.1    bouyer 		/* Read indexes, then verify. */
    182   1.1    bouyer 		cons = intf->rsp_cons;
    183   1.1    bouyer 		prod = intf->rsp_prod;
    184  1.12       jym 		xen_rmb();
    185   1.2    bouyer 		if (!check_indexes(cons, prod)) {
    186   1.2    bouyer 			XENPRINTF(("xb_read EIO\n"));
    187  1.23    bouyer 			mutex_exit(&xenstore_lock);
    188   1.2    bouyer 			return EIO;
    189   1.2    bouyer 		}
    190   1.1    bouyer 
    191   1.1    bouyer 		src = get_input_chunk(cons, prod, intf->rsp, &avail);
    192   1.1    bouyer 		if (avail == 0)
    193   1.1    bouyer 			continue;
    194   1.1    bouyer 		if (avail > len)
    195   1.1    bouyer 			avail = len;
    196   1.1    bouyer 
    197   1.1    bouyer 		/* We must read header before we read data. */
    198  1.12       jym 		xen_rmb();
    199   1.1    bouyer 
    200   1.1    bouyer 		memcpy(data, src, avail);
    201   1.2    bouyer 		data = (char *)data + avail;
    202   1.1    bouyer 		len -= avail;
    203   1.1    bouyer 
    204   1.1    bouyer 		/* Other side must not see free space until we've copied out */
    205  1.12       jym 		xen_rmb();
    206   1.1    bouyer 		intf->rsp_cons += avail;
    207  1.12       jym 		xen_rmb();
    208   1.1    bouyer 
    209   1.2    bouyer 		XENPRINTF(("Finished read of %i bytes (%i to go)\n",
    210   1.2    bouyer 		    avail, len));
    211   1.1    bouyer 
    212   1.2    bouyer 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
    213   1.1    bouyer 	}
    214  1.23    bouyer 	mutex_exit(&xenstore_lock);
    215   1.1    bouyer 	return 0;
    216   1.1    bouyer }
    217   1.1    bouyer 
    218   1.9       jym /* Set up interrupt handler of store event channel. */
    219   1.2    bouyer int
    220   1.7    cegger xb_init_comms(device_t dev)
    221   1.1    bouyer {
    222  1.14       jym 	int evtchn;
    223  1.14       jym 
    224  1.23    bouyer 	mutex_init(&xenstore_lock, MUTEX_DEFAULT, IPL_TTY);
    225  1.23    bouyer 	cv_init(&xenstore_cv, "xsio");
    226  1.23    bouyer 
    227  1.14       jym 	evtchn = xen_start_info.store_evtchn;
    228   1.1    bouyer 
    229  1.21    cherry 	ih = xen_intr_establish_xname(-1, &xen_pic, evtchn, IST_LEVEL, IPL_TTY,
    230  1.23    bouyer 	    wake_waiting, NULL, true, device_xname(dev));
    231  1.16    cherry 
    232  1.20    cherry 	hypervisor_unmask_event(evtchn);
    233  1.14       jym 	aprint_verbose_dev(dev, "using event channel %d\n", evtchn);
    234  1.13       jym 
    235   1.1    bouyer 	return 0;
    236   1.1    bouyer }
    237   1.1    bouyer 
    238  1.14       jym void
    239  1.14       jym xb_suspend_comms(device_t dev)
    240  1.14       jym {
    241  1.14       jym 	int evtchn;
    242  1.14       jym 
    243  1.14       jym 	evtchn = xen_start_info.store_evtchn;
    244  1.14       jym 
    245  1.14       jym 	hypervisor_mask_event(evtchn);
    246  1.21    cherry 	xen_intr_disestablish(ih);
    247  1.14       jym 	aprint_verbose_dev(dev, "removed event channel %d\n", evtchn);
    248  1.14       jym }
    249  1.14       jym 
    250   1.1    bouyer /*
    251   1.1    bouyer  * Local variables:
    252   1.1    bouyer  *  c-file-style: "linux"
    253   1.1    bouyer  *  indent-tabs-mode: t
    254   1.1    bouyer  *  c-indent-level: 8
    255   1.1    bouyer  *  c-basic-offset: 8
    256   1.1    bouyer  *  tab-width: 8
    257   1.1    bouyer  * End:
    258   1.1    bouyer  */
    259