xref: /freebsd/sys/dev/xen/debug/debug.c (revision df62b8a25f4792a6cd788a2b8e9982466b0ebcb3)
1*df62b8a2SRoger Pau Monné /*
2*df62b8a2SRoger Pau Monné  * Copyright (c) 2015 Roger Pau Monné <roger.pau@citrix.com>
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
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
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
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
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
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