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