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 */ 25*28e4da25SMatthew Ahrens /* 26*28e4da25SMatthew Ahrens * Copyright (c) 2012 by Delphix. All rights reserved. 27*28e4da25SMatthew 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 */ 55*28e4da25SMatthew 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; 65*28e4da25SMatthew Ahrens } mdb_xpv_domain_t; 66843e1988Sjohnlev 67843e1988Sjohnlev static uintptr_t 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 96843e1988Sjohnlev domain_walk_init(mdb_walk_state_t *wsp) 97843e1988Sjohnlev { 98843e1988Sjohnlev domain_walk_t *dwp; 99843e1988Sjohnlev 100843e1988Sjohnlev if (wsp->walk_addr == NULL) 101843e1988Sjohnlev if ((wsp->walk_addr = get_dom0_addr()) == NULL) 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 111843e1988Sjohnlev domain_walk_step(mdb_walk_state_t *wsp) 112843e1988Sjohnlev { 113843e1988Sjohnlev domain_walk_t *dwp = (domain_walk_t *)wsp->walk_data; 114*28e4da25SMatthew Ahrens mdb_xpv_domain_t dom; 115843e1988Sjohnlev int status; 116843e1988Sjohnlev 117843e1988Sjohnlev if (wsp->walk_addr == NULL) 118843e1988Sjohnlev return (WALK_DONE); 119843e1988Sjohnlev 120843e1988Sjohnlev status = wsp->walk_callback(wsp->walk_addr, (void *)wsp->walk_addr, 121843e1988Sjohnlev wsp->walk_cbdata); 122843e1988Sjohnlev 123*28e4da25SMatthew Ahrens if (mdb_ctf_vread(&dom, "struct domain", "mdb_xpv_domain_t", 124*28e4da25SMatthew 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 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 146843e1988Sjohnlev vcpu_walk_init(mdb_walk_state_t *wsp) 147843e1988Sjohnlev { 148843e1988Sjohnlev vcpu_walk_t *vwp; 149843e1988Sjohnlev uintptr_t off; 150843e1988Sjohnlev 151843e1988Sjohnlev if (wsp->walk_addr == NULL) 152843e1988Sjohnlev if ((wsp->walk_addr = get_dom0_addr()) == NULL) 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 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); 177843e1988Sjohnlev if ((wsp->walk_addr == NULL) || 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 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 199843e1988Sjohnlev domain(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 200843e1988Sjohnlev { 201*28e4da25SMatthew 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 222*28e4da25SMatthew Ahrens if (mdb_ctf_vread(&dom, "struct domain", "mdb_xpv_domain_t", addr, 223*28e4da25SMatthew 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 258*28e4da25SMatthew Ahrens typedef struct mdb_xpv_panic_info { 259*28e4da25SMatthew Ahrens int pi_version; 260*28e4da25SMatthew Ahrens } mdb_xpv_panic_info_t; 261*28e4da25SMatthew Ahrens 262843e1988Sjohnlev const mdb_modinfo_t * 263843e1988Sjohnlev _mdb_init(void) 264843e1988Sjohnlev { 265843e1988Sjohnlev uintptr_t pip; 266*28e4da25SMatthew Ahrens mdb_xpv_panic_info_t pi; 267843e1988Sjohnlev 268*28e4da25SMatthew 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 } 272*28e4da25SMatthew Ahrens if (mdb_ctf_vread(&pi, "struct panic_info", "mdb_xpv_panic_info_t", 273*28e4da25SMatthew 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