xref: /illumos-gate/usr/src/cmd/mdb/i86xpv/modules/xpv/xpv.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * Copyright (c) 2012 by Delphix. All rights reserved.
27  */
28 
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_ks.h>
31 #include <mdb/mdb_ctf.h>
32 #include <mdb/mdb_gelf.h>
33 #include <mdb/mdb_target_impl.h>
34 #include <mdb/mdb_kvm.h>
35 #include <mdb/mdb.h>
36 #include <xen/public/xen.h>
37 #include <xen/public/arch-x86/xen.h>
38 #include <errno.h>
39 
40 static mdb_ctf_id_t domain_type;
41 
42 /*
43  * Some constants found in the non-public sched.h header file
44  */
45 #define	MAX_EVTCHNS		NR_EVENT_CHANNELS
46 #define	EVTCHNS_PER_BUCKET	128
47 #define	NR_EVTCHN_BUCKETS	(MAX_EVTCHNS / EVTCHNS_PER_BUCKET)
48 
49 /*
50  * "struct domain" is an internal Xen structure.  Rather than trying to
51  * keep the mdb source in sync with Xen, we use CTF to extract the
52  * interesting bits from the binary, and stash them in the structure
53  * defined below.
54  */
55 typedef struct mdb_xpv_domain {
56 	short		domain_id;
57 	int		tot_pages;
58 	int		max_pages;
59 	int		xenheap_pages;
60 	ulong_t		domain_flags;
61 	char		is_hvm;
62 	struct vcpu	*vcpu[MAX_VIRT_CPUS];
63 	struct evtchn	*evtchn[NR_EVTCHN_BUCKETS];
64 	struct domain	*next_in_list;
65 } mdb_xpv_domain_t;
66 
67 static uintptr_t
68 get_dom0_addr()
69 {
70 	GElf_Sym sym;
71 	uintptr_t addr;
72 
73 	if ((mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, "dom0", &sym)) == 1) {
74 		mdb_warn("can't find symbol 'dom0'");
75 		return (0);
76 	}
77 
78 	if (sym.st_size != sizeof (uintptr_t)) {
79 		mdb_printf("Symbol 'dom0' found, but with the wrong size\n");
80 		return (0);
81 	}
82 
83 	if (mdb_vread(&addr, sym.st_size, sym.st_value) == -1) {
84 		mdb_warn("can't read data for symbol 'dom0'");
85 		return (0);
86 	}
87 
88 	return (addr);
89 }
90 
91 typedef struct domain_walk {
92 	uint_t dw_step;
93 } domain_walk_t;
94 
95 int
96 domain_walk_init(mdb_walk_state_t *wsp)
97 {
98 	domain_walk_t *dwp;
99 
100 	if (wsp->walk_addr == 0)
101 		if ((wsp->walk_addr = get_dom0_addr()) == 0)
102 			return (WALK_ERR);
103 
104 	dwp = mdb_alloc(sizeof (domain_walk_t), UM_SLEEP);
105 	dwp->dw_step = FALSE;
106 	wsp->walk_data = dwp;
107 	return (WALK_NEXT);
108 }
109 
110 int
111 domain_walk_step(mdb_walk_state_t *wsp)
112 {
113 	domain_walk_t *dwp = (domain_walk_t *)wsp->walk_data;
114 	mdb_xpv_domain_t dom;
115 	int status;
116 
117 	if (wsp->walk_addr == 0)
118 		return (WALK_DONE);
119 
120 	status = wsp->walk_callback(wsp->walk_addr, (void *)wsp->walk_addr,
121 	    wsp->walk_cbdata);
122 
123 	if (mdb_ctf_vread(&dom, "struct domain", "mdb_xpv_domain_t",
124 	    wsp->walk_addr, 0) != 0)
125 		return (WALK_ERR);
126 	wsp->walk_addr = (uintptr_t)dom.next_in_list;
127 
128 	dwp->dw_step = TRUE;
129 	return (status);
130 }
131 
132 void
133 domain_walk_fini(mdb_walk_state_t *wsp)
134 {
135 	domain_walk_t *dwp = (domain_walk_t *)wsp->walk_data;
136 
137 	mdb_free(dwp, sizeof (domain_walk_t));
138 }
139 
140 typedef struct vcpu_walk {
141 	uint_t vw_count;
142 	uint_t vw_step;
143 } vcpu_walk_t;
144 
145 int
146 vcpu_walk_init(mdb_walk_state_t *wsp)
147 {
148 	vcpu_walk_t *vwp;
149 	uintptr_t off;
150 
151 	if (wsp->walk_addr == 0)
152 		if ((wsp->walk_addr = get_dom0_addr()) == 0)
153 			return (WALK_ERR);
154 
155 	if (mdb_ctf_offsetof(domain_type, "vcpu", &off)) {
156 		mdb_warn("can't find per-domain vcpu information");
157 		return (WALK_ERR);
158 	}
159 
160 	wsp->walk_addr = wsp->walk_addr + (off / NBBY);
161 	vwp = mdb_alloc(sizeof (vcpu_walk_t), UM_SLEEP);
162 	vwp->vw_step = FALSE;
163 	vwp->vw_count = 0;
164 	wsp->walk_data = vwp;
165 	return (WALK_NEXT);
166 }
167 
168 int
169 vcpu_walk_step(mdb_walk_state_t *wsp)
170 {
171 	vcpu_walk_t *vwp = (vcpu_walk_t *)wsp->walk_data;
172 	uintptr_t vcpu_ptr;
173 	int status;
174 
175 	if (vwp->vw_count++ >= MAX_VIRT_CPUS)
176 		return (WALK_DONE);
177 	if ((wsp->walk_addr == 0) ||
178 	    (mdb_vread(&vcpu_ptr, sizeof (uintptr_t), wsp->walk_addr) == -1) ||
179 	    (vcpu_ptr == 0))
180 		return (WALK_DONE);
181 
182 	status = wsp->walk_callback(vcpu_ptr, (void *)vcpu_ptr,
183 	    wsp->walk_cbdata);
184 
185 	wsp->walk_addr = wsp->walk_addr + sizeof (uintptr_t);
186 	vwp->vw_step = TRUE;
187 	return (status);
188 }
189 
190 void
191 vcpu_walk_fini(mdb_walk_state_t *wsp)
192 {
193 	vcpu_walk_t *vwp = (vcpu_walk_t *)wsp->walk_data;
194 
195 	mdb_free(vwp, sizeof (vcpu_walk_t));
196 }
197 
198 int
199 domain(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
200 {
201 	mdb_xpv_domain_t dom;
202 	uintptr_t off, vcpu_addr, evtchn_addr;
203 
204 	if (!mdb_ctf_type_valid(domain_type)) {
205 		mdb_warn("Can't parse Xen domain info.\n");
206 		return (DCMD_ERR);
207 	}
208 
209 	if (!(flags & DCMD_ADDRSPEC)) {
210 		if (mdb_walk_dcmd("domain", "domain", argc, argv) == -1) {
211 			mdb_warn("can't walk domains");
212 			return (DCMD_ERR);
213 		}
214 		return (DCMD_OK);
215 	}
216 
217 	if (DCMD_HDRSPEC(flags))
218 		mdb_printf("%?s %3s %8s %8s %8s %3s %?s %?s\n",
219 		    "ADDR", "ID", "TPAGES", "MPAGES", "FLAGS", "HVM",
220 		    "VCPU", "EVTCHN");
221 
222 	if (mdb_ctf_vread(&dom, "struct domain", "mdb_xpv_domain_t", addr,
223 	    0) != 0)
224 		return (DCMD_ERR);
225 
226 	if (mdb_ctf_offsetof(domain_type, "vcpu", &off)) {
227 		mdb_warn("can't find per-domain vcpu information");
228 		return (DCMD_ERR);
229 	}
230 	vcpu_addr = addr + (off / NBBY);
231 	if (mdb_ctf_offsetof(domain_type, "evtchn", &off)) {
232 		mdb_warn("can't find per-domain event channel information");
233 		return (DCMD_ERR);
234 	}
235 	evtchn_addr = addr + (off / NBBY);
236 	mdb_printf("%?lx %3d %8x %8x %8x %3d %?lx %?lx\n",
237 	    addr, dom.domain_id, dom.tot_pages, dom.max_pages, dom.domain_flags,
238 	    dom.is_hvm, vcpu_addr, evtchn_addr);
239 
240 	return (DCMD_OK);
241 }
242 
243 static const mdb_dcmd_t dcmds[] = {
244 	{ "domain", ":", "display Xen domain info", domain },
245 	{ NULL }
246 };
247 
248 static const mdb_walker_t walkers[] = {
249 	{ "domain", "walk list of Xen domains",
250 		domain_walk_init, domain_walk_step, domain_walk_fini },
251 	{ "vcpu", "walk a Xen domain's vcpus",
252 		vcpu_walk_init, vcpu_walk_step, vcpu_walk_fini },
253 	{ NULL }
254 };
255 
256 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
257 
258 typedef struct mdb_xpv_panic_info {
259 	int pi_version;
260 } mdb_xpv_panic_info_t;
261 
262 const mdb_modinfo_t *
263 _mdb_init(void)
264 {
265 	uintptr_t pip;
266 	mdb_xpv_panic_info_t pi;
267 
268 	if (mdb_readsym(&pip, sizeof (pip), "xpv_panic_info") == -1) {
269 		mdb_warn("failed to read xpv panic_info pointer");
270 		return (NULL);
271 	}
272 	if (mdb_ctf_vread(&pi, "struct panic_info", "mdb_xpv_panic_info_t",
273 	    pip, 0) == -1)
274 		return (NULL);
275 
276 	if (pi.pi_version != PANIC_INFO_VERSION) {
277 		mdb_warn("unrecognized hypervisor panic format");
278 		return (NULL);
279 	}
280 
281 	if (mdb_ctf_lookup_by_name("struct domain", &domain_type) != 0) {
282 		mdb_warn("Can't parse Xen domain info: "
283 		    "'struct domain' not found.\n");
284 		mdb_ctf_type_invalidate(&domain_type);
285 	}
286 
287 	return (&modinfo);
288 }
289