xref: /illumos-gate/usr/src/cmd/mdb/i86xpv/modules/xpv/xpv.c (revision 892ad1623e11186cba8b2eb40d70318d2cb89605)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev /*
22843e1988Sjohnlev  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23843e1988Sjohnlev  * Use is subject to license terms.
24843e1988Sjohnlev  */
2528e4da25SMatthew Ahrens /*
2628e4da25SMatthew Ahrens  * Copyright (c) 2012 by Delphix. All rights reserved.
2728e4da25SMatthew Ahrens  */
28843e1988Sjohnlev 
29843e1988Sjohnlev #include <mdb/mdb_modapi.h>
30843e1988Sjohnlev #include <mdb/mdb_ks.h>
31843e1988Sjohnlev #include <mdb/mdb_ctf.h>
32843e1988Sjohnlev #include <mdb/mdb_gelf.h>
33843e1988Sjohnlev #include <mdb/mdb_target_impl.h>
34843e1988Sjohnlev #include <mdb/mdb_kvm.h>
35843e1988Sjohnlev #include <mdb/mdb.h>
36843e1988Sjohnlev #include <xen/public/xen.h>
37843e1988Sjohnlev #include <xen/public/arch-x86/xen.h>
38843e1988Sjohnlev #include <errno.h>
39843e1988Sjohnlev 
40843e1988Sjohnlev static mdb_ctf_id_t domain_type;
41843e1988Sjohnlev 
42843e1988Sjohnlev /*
43843e1988Sjohnlev  * Some constants found in the non-public sched.h header file
44843e1988Sjohnlev  */
45843e1988Sjohnlev #define	MAX_EVTCHNS		NR_EVENT_CHANNELS
46843e1988Sjohnlev #define	EVTCHNS_PER_BUCKET	128
47843e1988Sjohnlev #define	NR_EVTCHN_BUCKETS	(MAX_EVTCHNS / EVTCHNS_PER_BUCKET)
48843e1988Sjohnlev 
49843e1988Sjohnlev /*
50843e1988Sjohnlev  * "struct domain" is an internal Xen structure.  Rather than trying to
51843e1988Sjohnlev  * keep the mdb source in sync with Xen, we use CTF to extract the
52843e1988Sjohnlev  * interesting bits from the binary, and stash them in the structure
53843e1988Sjohnlev  * defined below.
54843e1988Sjohnlev  */
5528e4da25SMatthew Ahrens typedef struct mdb_xpv_domain {
56843e1988Sjohnlev 	short		domain_id;
57843e1988Sjohnlev 	int		tot_pages;
58843e1988Sjohnlev 	int		max_pages;
59843e1988Sjohnlev 	int		xenheap_pages;
60843e1988Sjohnlev 	ulong_t		domain_flags;
61843e1988Sjohnlev 	char		is_hvm;
62843e1988Sjohnlev 	struct vcpu	*vcpu[MAX_VIRT_CPUS];
63843e1988Sjohnlev 	struct evtchn	*evtchn[NR_EVTCHN_BUCKETS];
64843e1988Sjohnlev 	struct domain	*next_in_list;
6528e4da25SMatthew Ahrens } mdb_xpv_domain_t;
66843e1988Sjohnlev 
67843e1988Sjohnlev static uintptr_t
get_dom0_addr()68843e1988Sjohnlev get_dom0_addr()
69843e1988Sjohnlev {
70843e1988Sjohnlev 	GElf_Sym sym;
71843e1988Sjohnlev 	uintptr_t addr;
72843e1988Sjohnlev 
73843e1988Sjohnlev 	if ((mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, "dom0", &sym)) == 1) {
74843e1988Sjohnlev 		mdb_warn("can't find symbol 'dom0'");
75843e1988Sjohnlev 		return (0);
76843e1988Sjohnlev 	}
77843e1988Sjohnlev 
78843e1988Sjohnlev 	if (sym.st_size != sizeof (uintptr_t)) {
79843e1988Sjohnlev 		mdb_printf("Symbol 'dom0' found, but with the wrong size\n");
80843e1988Sjohnlev 		return (0);
81843e1988Sjohnlev 	}
82843e1988Sjohnlev 
83843e1988Sjohnlev 	if (mdb_vread(&addr, sym.st_size, sym.st_value) == -1) {
84843e1988Sjohnlev 		mdb_warn("can't read data for symbol 'dom0'");
85843e1988Sjohnlev 		return (0);
86843e1988Sjohnlev 	}
87843e1988Sjohnlev 
88843e1988Sjohnlev 	return (addr);
89843e1988Sjohnlev }
90843e1988Sjohnlev 
91843e1988Sjohnlev typedef struct domain_walk {
92843e1988Sjohnlev 	uint_t dw_step;
93843e1988Sjohnlev } domain_walk_t;
94843e1988Sjohnlev 
95843e1988Sjohnlev int
domain_walk_init(mdb_walk_state_t * wsp)96843e1988Sjohnlev domain_walk_init(mdb_walk_state_t *wsp)
97843e1988Sjohnlev {
98843e1988Sjohnlev 	domain_walk_t *dwp;
99843e1988Sjohnlev 
100*892ad162SToomas Soome 	if (wsp->walk_addr == 0)
101*892ad162SToomas Soome 		if ((wsp->walk_addr = get_dom0_addr()) == 0)
102843e1988Sjohnlev 			return (WALK_ERR);
103843e1988Sjohnlev 
104843e1988Sjohnlev 	dwp = mdb_alloc(sizeof (domain_walk_t), UM_SLEEP);
105843e1988Sjohnlev 	dwp->dw_step = FALSE;
106843e1988Sjohnlev 	wsp->walk_data = dwp;
107843e1988Sjohnlev 	return (WALK_NEXT);
108843e1988Sjohnlev }
109843e1988Sjohnlev 
110843e1988Sjohnlev int
domain_walk_step(mdb_walk_state_t * wsp)111843e1988Sjohnlev domain_walk_step(mdb_walk_state_t *wsp)
112843e1988Sjohnlev {
113843e1988Sjohnlev 	domain_walk_t *dwp = (domain_walk_t *)wsp->walk_data;
11428e4da25SMatthew Ahrens 	mdb_xpv_domain_t dom;
115843e1988Sjohnlev 	int status;
116843e1988Sjohnlev 
117*892ad162SToomas Soome 	if (wsp->walk_addr == 0)
118843e1988Sjohnlev 		return (WALK_DONE);
119843e1988Sjohnlev 
120843e1988Sjohnlev 	status = wsp->walk_callback(wsp->walk_addr, (void *)wsp->walk_addr,
121843e1988Sjohnlev 	    wsp->walk_cbdata);
122843e1988Sjohnlev 
12328e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&dom, "struct domain", "mdb_xpv_domain_t",
12428e4da25SMatthew Ahrens 	    wsp->walk_addr, 0) != 0)
125843e1988Sjohnlev 		return (WALK_ERR);
126843e1988Sjohnlev 	wsp->walk_addr = (uintptr_t)dom.next_in_list;
127843e1988Sjohnlev 
128843e1988Sjohnlev 	dwp->dw_step = TRUE;
129843e1988Sjohnlev 	return (status);
130843e1988Sjohnlev }
131843e1988Sjohnlev 
132843e1988Sjohnlev void
domain_walk_fini(mdb_walk_state_t * wsp)133843e1988Sjohnlev domain_walk_fini(mdb_walk_state_t *wsp)
134843e1988Sjohnlev {
135843e1988Sjohnlev 	domain_walk_t *dwp = (domain_walk_t *)wsp->walk_data;
136843e1988Sjohnlev 
137843e1988Sjohnlev 	mdb_free(dwp, sizeof (domain_walk_t));
138843e1988Sjohnlev }
139843e1988Sjohnlev 
140843e1988Sjohnlev typedef struct vcpu_walk {
141843e1988Sjohnlev 	uint_t vw_count;
142843e1988Sjohnlev 	uint_t vw_step;
143843e1988Sjohnlev } vcpu_walk_t;
144843e1988Sjohnlev 
145843e1988Sjohnlev int
vcpu_walk_init(mdb_walk_state_t * wsp)146843e1988Sjohnlev vcpu_walk_init(mdb_walk_state_t *wsp)
147843e1988Sjohnlev {
148843e1988Sjohnlev 	vcpu_walk_t *vwp;
149843e1988Sjohnlev 	uintptr_t off;
150843e1988Sjohnlev 
151*892ad162SToomas Soome 	if (wsp->walk_addr == 0)
152*892ad162SToomas Soome 		if ((wsp->walk_addr = get_dom0_addr()) == 0)
153843e1988Sjohnlev 			return (WALK_ERR);
154843e1988Sjohnlev 
155843e1988Sjohnlev 	if (mdb_ctf_offsetof(domain_type, "vcpu", &off)) {
156843e1988Sjohnlev 		mdb_warn("can't find per-domain vcpu information");
157843e1988Sjohnlev 		return (WALK_ERR);
158843e1988Sjohnlev 	}
159843e1988Sjohnlev 
160843e1988Sjohnlev 	wsp->walk_addr = wsp->walk_addr + (off / NBBY);
161843e1988Sjohnlev 	vwp = mdb_alloc(sizeof (vcpu_walk_t), UM_SLEEP);
162843e1988Sjohnlev 	vwp->vw_step = FALSE;
163843e1988Sjohnlev 	vwp->vw_count = 0;
164843e1988Sjohnlev 	wsp->walk_data = vwp;
165843e1988Sjohnlev 	return (WALK_NEXT);
166843e1988Sjohnlev }
167843e1988Sjohnlev 
168843e1988Sjohnlev int
vcpu_walk_step(mdb_walk_state_t * wsp)169843e1988Sjohnlev vcpu_walk_step(mdb_walk_state_t *wsp)
170843e1988Sjohnlev {
171843e1988Sjohnlev 	vcpu_walk_t *vwp = (vcpu_walk_t *)wsp->walk_data;
172843e1988Sjohnlev 	uintptr_t vcpu_ptr;
173843e1988Sjohnlev 	int status;
174843e1988Sjohnlev 
175843e1988Sjohnlev 	if (vwp->vw_count++ >= MAX_VIRT_CPUS)
176843e1988Sjohnlev 		return (WALK_DONE);
177*892ad162SToomas Soome 	if ((wsp->walk_addr == 0) ||
178843e1988Sjohnlev 	    (mdb_vread(&vcpu_ptr, sizeof (uintptr_t), wsp->walk_addr) == -1) ||
179843e1988Sjohnlev 	    (vcpu_ptr == 0))
180843e1988Sjohnlev 		return (WALK_DONE);
181843e1988Sjohnlev 
182843e1988Sjohnlev 	status = wsp->walk_callback(vcpu_ptr, (void *)vcpu_ptr,
183843e1988Sjohnlev 	    wsp->walk_cbdata);
184843e1988Sjohnlev 
185843e1988Sjohnlev 	wsp->walk_addr = wsp->walk_addr + sizeof (uintptr_t);
186843e1988Sjohnlev 	vwp->vw_step = TRUE;
187843e1988Sjohnlev 	return (status);
188843e1988Sjohnlev }
189843e1988Sjohnlev 
190843e1988Sjohnlev void
vcpu_walk_fini(mdb_walk_state_t * wsp)191843e1988Sjohnlev vcpu_walk_fini(mdb_walk_state_t *wsp)
192843e1988Sjohnlev {
193843e1988Sjohnlev 	vcpu_walk_t *vwp = (vcpu_walk_t *)wsp->walk_data;
194843e1988Sjohnlev 
195843e1988Sjohnlev 	mdb_free(vwp, sizeof (vcpu_walk_t));
196843e1988Sjohnlev }
197843e1988Sjohnlev 
198843e1988Sjohnlev int
domain(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)199843e1988Sjohnlev domain(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
200843e1988Sjohnlev {
20128e4da25SMatthew Ahrens 	mdb_xpv_domain_t dom;
202843e1988Sjohnlev 	uintptr_t off, vcpu_addr, evtchn_addr;
203843e1988Sjohnlev 
204843e1988Sjohnlev 	if (!mdb_ctf_type_valid(domain_type)) {
205843e1988Sjohnlev 		mdb_warn("Can't parse Xen domain info.\n");
206843e1988Sjohnlev 		return (DCMD_ERR);
207843e1988Sjohnlev 	}
208843e1988Sjohnlev 
209843e1988Sjohnlev 	if (!(flags & DCMD_ADDRSPEC)) {
210843e1988Sjohnlev 		if (mdb_walk_dcmd("domain", "domain", argc, argv) == -1) {
211843e1988Sjohnlev 			mdb_warn("can't walk domains");
212843e1988Sjohnlev 			return (DCMD_ERR);
213843e1988Sjohnlev 		}
214843e1988Sjohnlev 		return (DCMD_OK);
215843e1988Sjohnlev 	}
216843e1988Sjohnlev 
217843e1988Sjohnlev 	if (DCMD_HDRSPEC(flags))
218843e1988Sjohnlev 		mdb_printf("%?s %3s %8s %8s %8s %3s %?s %?s\n",
219843e1988Sjohnlev 		    "ADDR", "ID", "TPAGES", "MPAGES", "FLAGS", "HVM",
220843e1988Sjohnlev 		    "VCPU", "EVTCHN");
221843e1988Sjohnlev 
22228e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&dom, "struct domain", "mdb_xpv_domain_t", addr,
22328e4da25SMatthew Ahrens 	    0) != 0)
224843e1988Sjohnlev 		return (DCMD_ERR);
225843e1988Sjohnlev 
226843e1988Sjohnlev 	if (mdb_ctf_offsetof(domain_type, "vcpu", &off)) {
227843e1988Sjohnlev 		mdb_warn("can't find per-domain vcpu information");
228843e1988Sjohnlev 		return (DCMD_ERR);
229843e1988Sjohnlev 	}
230843e1988Sjohnlev 	vcpu_addr = addr + (off / NBBY);
231843e1988Sjohnlev 	if (mdb_ctf_offsetof(domain_type, "evtchn", &off)) {
232843e1988Sjohnlev 		mdb_warn("can't find per-domain event channel information");
233843e1988Sjohnlev 		return (DCMD_ERR);
234843e1988Sjohnlev 	}
235843e1988Sjohnlev 	evtchn_addr = addr + (off / NBBY);
236843e1988Sjohnlev 	mdb_printf("%?lx %3d %8x %8x %8x %3d %?lx %?lx\n",
237843e1988Sjohnlev 	    addr, dom.domain_id, dom.tot_pages, dom.max_pages, dom.domain_flags,
238843e1988Sjohnlev 	    dom.is_hvm, vcpu_addr, evtchn_addr);
239843e1988Sjohnlev 
240843e1988Sjohnlev 	return (DCMD_OK);
241843e1988Sjohnlev }
242843e1988Sjohnlev 
243843e1988Sjohnlev static const mdb_dcmd_t dcmds[] = {
244843e1988Sjohnlev 	{ "domain", ":", "display Xen domain info", domain },
245843e1988Sjohnlev 	{ NULL }
246843e1988Sjohnlev };
247843e1988Sjohnlev 
248843e1988Sjohnlev static const mdb_walker_t walkers[] = {
249843e1988Sjohnlev 	{ "domain", "walk list of Xen domains",
250843e1988Sjohnlev 		domain_walk_init, domain_walk_step, domain_walk_fini },
251843e1988Sjohnlev 	{ "vcpu", "walk a Xen domain's vcpus",
252843e1988Sjohnlev 		vcpu_walk_init, vcpu_walk_step, vcpu_walk_fini },
253843e1988Sjohnlev 	{ NULL }
254843e1988Sjohnlev };
255843e1988Sjohnlev 
256843e1988Sjohnlev static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
257843e1988Sjohnlev 
25828e4da25SMatthew Ahrens typedef struct mdb_xpv_panic_info {
25928e4da25SMatthew Ahrens 	int pi_version;
26028e4da25SMatthew Ahrens } mdb_xpv_panic_info_t;
26128e4da25SMatthew Ahrens 
262843e1988Sjohnlev const mdb_modinfo_t *
_mdb_init(void)263843e1988Sjohnlev _mdb_init(void)
264843e1988Sjohnlev {
265843e1988Sjohnlev 	uintptr_t pip;
26628e4da25SMatthew Ahrens 	mdb_xpv_panic_info_t pi;
267843e1988Sjohnlev 
26828e4da25SMatthew Ahrens 	if (mdb_readsym(&pip, sizeof (pip), "xpv_panic_info") == -1) {
269843e1988Sjohnlev 		mdb_warn("failed to read xpv panic_info pointer");
270843e1988Sjohnlev 		return (NULL);
271843e1988Sjohnlev 	}
27228e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&pi, "struct panic_info", "mdb_xpv_panic_info_t",
27328e4da25SMatthew Ahrens 	    pip, 0) == -1)
274843e1988Sjohnlev 		return (NULL);
275843e1988Sjohnlev 
276843e1988Sjohnlev 	if (pi.pi_version != PANIC_INFO_VERSION) {
277843e1988Sjohnlev 		mdb_warn("unrecognized hypervisor panic format");
278843e1988Sjohnlev 		return (NULL);
279843e1988Sjohnlev 	}
280843e1988Sjohnlev 
281843e1988Sjohnlev 	if (mdb_ctf_lookup_by_name("struct domain", &domain_type) != 0) {
282843e1988Sjohnlev 		mdb_warn("Can't parse Xen domain info: "
283843e1988Sjohnlev 		    "'struct domain' not found.\n");
284843e1988Sjohnlev 		mdb_ctf_type_invalidate(&domain_type);
285843e1988Sjohnlev 	}
286843e1988Sjohnlev 
287843e1988Sjohnlev 	return (&modinfo);
288843e1988Sjohnlev }
289