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