1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * 29 * xenbus_comms.c 30 * 31 * Low level code to talks to Xen Store: ringbuffer and event channel. 32 * 33 * Copyright (C) 2005 Rusty Russell, IBM Corporation 34 * 35 * This file may be distributed separately from the Linux kernel, or 36 * incorporated into other software packages, subject to the following license: 37 * 38 * Permission is hereby granted, free of charge, to any person obtaining a copy 39 * of this source file (the "Software"), to deal in the Software without 40 * restriction, including without limitation the rights to use, copy, modify, 41 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 42 * and to permit persons to whom the Software is furnished to do so, subject to 43 * the following conditions: 44 * 45 * The above copyright notice and this permission notice shall be included in 46 * all copies or substantial portions of the Software. 47 * 48 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 53 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 54 * IN THE SOFTWARE. 55 */ 56 57 #pragma ident "%Z%%M% %I% %E% SMI" 58 59 #include <sys/types.h> 60 #include <vm/hat.h> 61 #include <vm/as.h> 62 #include <sys/bootconf.h> 63 #include <vm/seg_kmem.h> 64 #ifdef XPV_HVM_DRIVER 65 #include <sys/pc_mmu.h> 66 #include <sys/xpv_support.h> 67 #include <sys/hypervisor.h> 68 #else 69 #include <vm/kboot_mmu.h> 70 #include <sys/bootinfo.h> 71 #include <sys/hypervisor.h> 72 #include <sys/evtchn_impl.h> 73 #endif 74 #include <sys/condvar.h> 75 #include <sys/mutex.h> 76 #include <sys/atomic.h> 77 #include <sys/mman.h> 78 #include <sys/errno.h> 79 #include <sys/cmn_err.h> 80 #include <sys/avintr.h> 81 #include <xen/sys/xenbus_comms.h> 82 #include <xen/public/io/xs_wire.h> 83 84 static int xenbus_irq; 85 static ddi_umem_cookie_t xb_cookie; /* cookie for xenbus comm page */ 86 extern caddr_t xb_addr; /* va of xenbus comm page */ 87 88 static kcondvar_t xb_wait_cv; 89 static kmutex_t xb_wait_lock; 90 91 #define xs_domain_interface(ra) ((struct xenstore_domain_interface *)(ra)) 92 93 /*ARGSUSED*/ 94 static uint_t 95 xenbus_intr(void *unused) 96 { 97 mutex_enter(&xb_wait_lock); 98 cv_broadcast(&xb_wait_cv); 99 mutex_exit(&xb_wait_lock); 100 return (DDI_INTR_CLAIMED); 101 } 102 103 static int 104 check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) 105 { 106 return ((prod - cons) <= XENSTORE_RING_SIZE); 107 } 108 109 static void * 110 get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, 111 char *buf, uint32_t *len) 112 { 113 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); 114 if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) 115 *len = XENSTORE_RING_SIZE - (prod - cons); 116 return ((void *)(buf + MASK_XENSTORE_IDX(prod))); 117 } 118 119 static const void * 120 get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, 121 const char *buf, uint32_t *len) 122 { 123 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); 124 if ((prod - cons) < *len) 125 *len = prod - cons; 126 return ((void *)(buf + MASK_XENSTORE_IDX(cons))); 127 } 128 129 130 int 131 xb_write(const void *data, unsigned len) 132 { 133 volatile struct xenstore_domain_interface *intf = 134 xs_domain_interface(xb_addr); 135 XENSTORE_RING_IDX cons, prod; 136 extern int do_polled_io; 137 138 while (len != 0) { 139 void *dst; 140 unsigned int avail; 141 142 mutex_enter(&xb_wait_lock); 143 while ((intf->req_prod - intf->req_cons) == 144 XENSTORE_RING_SIZE) { 145 if (interrupts_unleashed && !do_polled_io) { 146 if (cv_wait_sig(&xb_wait_cv, 147 &xb_wait_lock) == 0) { 148 mutex_exit(&xb_wait_lock); 149 return (EINTR); 150 } 151 } else { /* polled mode needed for early probes */ 152 (void) HYPERVISOR_yield(); 153 } 154 } 155 mutex_exit(&xb_wait_lock); 156 /* Read indexes, then verify. */ 157 cons = intf->req_cons; 158 prod = intf->req_prod; 159 membar_enter(); 160 if (!check_indexes(cons, prod)) 161 return (EIO); 162 163 dst = get_output_chunk(cons, prod, (char *)intf->req, &avail); 164 if (avail == 0) 165 continue; 166 if (avail > len) 167 avail = len; 168 169 (void) memcpy(dst, data, avail); 170 data = (void *)((uintptr_t)data + avail); 171 len -= avail; 172 173 /* Other side must not see new header until data is there. */ 174 membar_producer(); 175 intf->req_prod += avail; 176 177 /* This implies mb() before other side sees interrupt. */ 178 ec_notify_via_evtchn(xen_info->store_evtchn); 179 } 180 181 return (0); 182 } 183 184 int 185 xb_read(void *data, unsigned len) 186 { 187 volatile struct xenstore_domain_interface *intf = 188 xs_domain_interface(xb_addr); 189 XENSTORE_RING_IDX cons, prod; 190 extern int do_polled_io; 191 192 while (len != 0) { 193 unsigned int avail; 194 const char *src; 195 196 mutex_enter(&xb_wait_lock); 197 while (intf->rsp_cons == intf->rsp_prod) { 198 if (interrupts_unleashed && !do_polled_io) { 199 if (cv_wait_sig(&xb_wait_cv, 200 &xb_wait_lock) == 0) { 201 mutex_exit(&xb_wait_lock); 202 return (EINTR); 203 } 204 } else { /* polled mode needed for early probes */ 205 (void) HYPERVISOR_yield(); 206 } 207 } 208 mutex_exit(&xb_wait_lock); 209 /* Read indexes, then verify. */ 210 cons = intf->rsp_cons; 211 prod = intf->rsp_prod; 212 membar_enter(); 213 if (!check_indexes(cons, prod)) 214 return (EIO); 215 216 src = get_input_chunk(cons, prod, (char *)intf->rsp, &avail); 217 if (avail == 0) 218 continue; 219 if (avail > len) 220 avail = len; 221 222 /* We must read header before we read data. */ 223 membar_consumer(); 224 225 (void) memcpy(data, src, avail); 226 data = (void *)((uintptr_t)data + avail); 227 len -= avail; 228 229 /* Other side must not see free space until we've copied out */ 230 membar_enter(); 231 intf->rsp_cons += avail; 232 233 /* Implies mb(): they will see new header. */ 234 ec_notify_via_evtchn(xen_info->store_evtchn); 235 } 236 237 return (0); 238 } 239 240 void 241 xb_suspend(void) 242 { 243 rem_avintr(NULL, IPL_XENBUS, (avfunc)xenbus_intr, xenbus_irq); 244 } 245 246 void 247 xb_setup_intr(void) 248 { 249 #ifdef XPV_HVM_DRIVER 250 ec_bind_evtchn_to_handler(xen_info->store_evtchn, IPL_XENBUS, 251 xenbus_intr, NULL); 252 #else 253 xenbus_irq = ec_bind_evtchn_to_irq(xen_info->store_evtchn); 254 if (xenbus_irq < 0) { 255 cmn_err(CE_WARN, "Couldn't bind xenbus event channel"); 256 return; 257 } 258 if (!add_avintr(NULL, IPL_XENBUS, (avfunc)xenbus_intr, "xenbus", 259 xenbus_irq, NULL, NULL, NULL, NULL)) 260 cmn_err(CE_WARN, "XENBUS add intr failed\n"); 261 #endif 262 } 263 264 /* 265 * Set up our xenstore page and event channel. Domain 0 needs to allocate a 266 * page and event channel; other domains use what we are told. 267 */ 268 void 269 xb_init(void) 270 { 271 int err; 272 273 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 274 275 if (xb_addr != NULL) 276 return; 277 278 xb_addr = ddi_umem_alloc(PAGESIZE, DDI_UMEM_SLEEP, 279 &xb_cookie); 280 xen_info->store_mfn = pfn_to_mfn(hat_getpfnum(kas.a_hat, 281 xb_addr)); 282 283 err = xen_alloc_unbound_evtchn(0, 284 (int *)&xen_info->store_evtchn); 285 ASSERT(err == 0); 286 } else { 287 /* 288 * This is harmless on first boot, but needed for resume and 289 * migrate. We use kbm_map_ma() as a shortcut instead of 290 * directly using HYPERVISOR_update_va_mapping(). 291 */ 292 ASSERT(xb_addr != NULL); 293 kbm_map_ma(mfn_to_ma(xen_info->store_mfn), 294 (uintptr_t)xb_addr, 0); 295 } 296 297 ASSERT(xen_info->store_evtchn); 298 } 299 300 void * 301 xb_xenstore_cookie(void) 302 { 303 ASSERT(DOMAIN_IS_INITDOMAIN(xen_info)); 304 return (xb_cookie); 305 } 306