1df62b8a2SRoger Pau Monné /* 2df62b8a2SRoger Pau Monné * Copyright (c) 2015 Roger Pau Monné <roger.pau@citrix.com> 3df62b8a2SRoger Pau Monné * All rights reserved. 4df62b8a2SRoger Pau Monné * 5df62b8a2SRoger Pau Monné * Redistribution and use in source and binary forms, with or without 6df62b8a2SRoger Pau Monné * modification, are permitted provided that the following conditions 7df62b8a2SRoger Pau Monné * are met: 8df62b8a2SRoger Pau Monné * 1. Redistributions of source code must retain the above copyright 9df62b8a2SRoger Pau Monné * notice, this list of conditions and the following disclaimer. 10df62b8a2SRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright 11df62b8a2SRoger Pau Monné * notice, this list of conditions and the following disclaimer in the 12df62b8a2SRoger Pau Monné * documentation and/or other materials provided with the distribution. 13df62b8a2SRoger Pau Monné * 14df62b8a2SRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15df62b8a2SRoger Pau Monné * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16df62b8a2SRoger Pau Monné * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17df62b8a2SRoger Pau Monné * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18df62b8a2SRoger Pau Monné * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19df62b8a2SRoger Pau Monné * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20df62b8a2SRoger Pau Monné * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21df62b8a2SRoger Pau Monné * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22df62b8a2SRoger Pau Monné * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23df62b8a2SRoger Pau Monné * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24df62b8a2SRoger Pau Monné * SUCH DAMAGE. 25df62b8a2SRoger Pau Monné */ 26df62b8a2SRoger Pau Monné 27df62b8a2SRoger Pau Monné #include <sys/cdefs.h> 28df62b8a2SRoger Pau Monné __FBSDID("$FreeBSD$"); 29df62b8a2SRoger Pau Monné 30df62b8a2SRoger Pau Monné #include "opt_stack.h" 31df62b8a2SRoger Pau Monné #include "opt_ddb.h" 32df62b8a2SRoger Pau Monné 33df62b8a2SRoger Pau Monné #include <sys/param.h> 34df62b8a2SRoger Pau Monné #include <sys/systm.h> 35df62b8a2SRoger Pau Monné #include <sys/bus.h> 36df62b8a2SRoger Pau Monné #include <sys/kernel.h> 37e2e050c8SConrad Meyer #include <sys/lock.h> 38df62b8a2SRoger Pau Monné #include <sys/module.h> 39e2e050c8SConrad Meyer #include <sys/mutex.h> 40df62b8a2SRoger Pau Monné #include <sys/pcpu.h> 41df62b8a2SRoger Pau Monné #include <sys/smp.h> 42df62b8a2SRoger Pau Monné #include <sys/stack.h> 43df62b8a2SRoger Pau Monné #include <sys/sbuf.h> 44df62b8a2SRoger Pau Monné 45df62b8a2SRoger Pau Monné #include <xen/xen-os.h> 46df62b8a2SRoger Pau Monné #include <xen/xen_intr.h> 47df62b8a2SRoger Pau Monné #include <xen/hypervisor.h> 48df62b8a2SRoger Pau Monné 49df62b8a2SRoger Pau Monné /* 50df62b8a2SRoger Pau Monné * Xen debug device 51df62b8a2SRoger Pau Monné * 52df62b8a2SRoger Pau Monné * Handles the VIRQ_DEBUG interrupt and prints the backtrace of each 53df62b8a2SRoger Pau Monné * vCPU on the Xen console. 54df62b8a2SRoger Pau Monné */ 55df62b8a2SRoger Pau Monné 56df62b8a2SRoger Pau Monné DPCPU_DEFINE(xen_intr_handle_t, xendebug_handler); 57df62b8a2SRoger Pau Monné static struct mtx lock; 58df62b8a2SRoger Pau Monné static struct sbuf *buf; 59df62b8a2SRoger Pau Monné 60df62b8a2SRoger Pau Monné static int 61df62b8a2SRoger Pau Monné xendebug_drain(void *arg, const char *str, int len) 62df62b8a2SRoger Pau Monné { 63df62b8a2SRoger Pau Monné 64df62b8a2SRoger Pau Monné HYPERVISOR_console_write(__DECONST(char *, str), len); 65df62b8a2SRoger Pau Monné return (len); 66df62b8a2SRoger Pau Monné } 67df62b8a2SRoger Pau Monné 68df62b8a2SRoger Pau Monné extern void 69df62b8a2SRoger Pau Monné stack_capture(struct stack *st, register_t rbp); 70df62b8a2SRoger Pau Monné 71df62b8a2SRoger Pau Monné static int 72*d893d9e9SElliott Mitchell xendebug_filter(void *arg __unused) 73df62b8a2SRoger Pau Monné { 74df62b8a2SRoger Pau Monné #if defined(STACK) && defined(DDB) 75df62b8a2SRoger Pau Monné struct stack st; 76df62b8a2SRoger Pau Monné 77df62b8a2SRoger Pau Monné stack_zero(&st); 78df62b8a2SRoger Pau Monné stack_save(&st); 79df62b8a2SRoger Pau Monné 80df62b8a2SRoger Pau Monné mtx_lock_spin(&lock); 81df62b8a2SRoger Pau Monné sbuf_clear(buf); 82df62b8a2SRoger Pau Monné xc_printf("Printing stack trace vCPU%d\n", PCPU_GET(vcpu_id)); 83df62b8a2SRoger Pau Monné stack_sbuf_print_ddb(buf, &st); 84df62b8a2SRoger Pau Monné sbuf_finish(buf); 85df62b8a2SRoger Pau Monné mtx_unlock_spin(&lock); 86df62b8a2SRoger Pau Monné #endif 87df62b8a2SRoger Pau Monné 88df62b8a2SRoger Pau Monné return (FILTER_HANDLED); 89df62b8a2SRoger Pau Monné } 90df62b8a2SRoger Pau Monné 91df62b8a2SRoger Pau Monné static void 92df62b8a2SRoger Pau Monné xendebug_identify(driver_t *driver, device_t parent) 93df62b8a2SRoger Pau Monné { 94df62b8a2SRoger Pau Monné 95df62b8a2SRoger Pau Monné KASSERT(xen_domain(), 96df62b8a2SRoger Pau Monné ("Trying to add Xen debug device to non-xen guest")); 97df62b8a2SRoger Pau Monné 98ac959cf5SJulien Grall if (!xen_has_percpu_evtchn()) 99df62b8a2SRoger Pau Monné return; 100df62b8a2SRoger Pau Monné 101df62b8a2SRoger Pau Monné if (BUS_ADD_CHILD(parent, 0, "debug", 0) == NULL) 102df62b8a2SRoger Pau Monné panic("Unable to add Xen debug device."); 103df62b8a2SRoger Pau Monné } 104df62b8a2SRoger Pau Monné 105df62b8a2SRoger Pau Monné static int 106df62b8a2SRoger Pau Monné xendebug_probe(device_t dev) 107df62b8a2SRoger Pau Monné { 108df62b8a2SRoger Pau Monné 109df62b8a2SRoger Pau Monné device_set_desc(dev, "Xen debug handler"); 110df62b8a2SRoger Pau Monné return (BUS_PROBE_NOWILDCARD); 111df62b8a2SRoger Pau Monné } 112df62b8a2SRoger Pau Monné 113df62b8a2SRoger Pau Monné static int 114df62b8a2SRoger Pau Monné xendebug_attach(device_t dev) 115df62b8a2SRoger Pau Monné { 116df62b8a2SRoger Pau Monné int i, error; 117df62b8a2SRoger Pau Monné 118df62b8a2SRoger Pau Monné mtx_init(&lock, "xen-dbg", NULL, MTX_SPIN); 119df62b8a2SRoger Pau Monné buf = sbuf_new(NULL, NULL, 1024, SBUF_FIXEDLEN); 120df62b8a2SRoger Pau Monné if (buf == NULL) 121df62b8a2SRoger Pau Monné panic("Unable to create sbuf for stack dump"); 122df62b8a2SRoger Pau Monné sbuf_set_drain(buf, xendebug_drain, NULL); 123df62b8a2SRoger Pau Monné 124df62b8a2SRoger Pau Monné /* Bind an event channel to a VIRQ on each VCPU. */ 125df62b8a2SRoger Pau Monné CPU_FOREACH(i) { 126df62b8a2SRoger Pau Monné error = xen_intr_bind_virq(dev, VIRQ_DEBUG, i, xendebug_filter, 127df62b8a2SRoger Pau Monné NULL, NULL, INTR_TYPE_TTY, 128df62b8a2SRoger Pau Monné DPCPU_ID_PTR(i, xendebug_handler)); 129df62b8a2SRoger Pau Monné if (error != 0) { 130df62b8a2SRoger Pau Monné printf("Failed to bind VIRQ_DEBUG to vCPU %d: %d", 131df62b8a2SRoger Pau Monné i, error); 132df62b8a2SRoger Pau Monné continue; 133df62b8a2SRoger Pau Monné } 134df62b8a2SRoger Pau Monné xen_intr_describe(DPCPU_ID_GET(i, xendebug_handler), "d%d", i); 135df62b8a2SRoger Pau Monné } 136df62b8a2SRoger Pau Monné 137df62b8a2SRoger Pau Monné return (0); 138df62b8a2SRoger Pau Monné } 139df62b8a2SRoger Pau Monné 140df62b8a2SRoger Pau Monné static device_method_t xendebug_methods[] = { 141df62b8a2SRoger Pau Monné DEVMETHOD(device_identify, xendebug_identify), 142df62b8a2SRoger Pau Monné DEVMETHOD(device_probe, xendebug_probe), 143df62b8a2SRoger Pau Monné DEVMETHOD(device_attach, xendebug_attach), 144df62b8a2SRoger Pau Monné 145df62b8a2SRoger Pau Monné DEVMETHOD_END 146df62b8a2SRoger Pau Monné }; 147df62b8a2SRoger Pau Monné 148df62b8a2SRoger Pau Monné static driver_t xendebug_driver = { 149df62b8a2SRoger Pau Monné "debug", 150df62b8a2SRoger Pau Monné xendebug_methods, 151df62b8a2SRoger Pau Monné 0, 152df62b8a2SRoger Pau Monné }; 153df62b8a2SRoger Pau Monné 154df62b8a2SRoger Pau Monné devclass_t xendebug_devclass; 155df62b8a2SRoger Pau Monné 156df62b8a2SRoger Pau Monné DRIVER_MODULE(xendebug, xenpv, xendebug_driver, xendebug_devclass, 0, 0); 157df62b8a2SRoger Pau Monné MODULE_DEPEND(xendebug, xenpv, 1, 1, 1); 158