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