summaryrefslogtreecommitdiff
path: root/usr/src/cmd/mdb/common/modules
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/mdb/common/modules')
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/Makefile.files1
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/ctxop.c3
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/genunix.c105
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/refhash.c61
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/refhash.h35
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/zone.c46
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/zone.h1
-rw-r--r--usr/src/cmd/mdb/common/modules/ipc/ipc.c5
-rw-r--r--usr/src/cmd/mdb/common/modules/libc/libc.c28
-rw-r--r--usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c67
-rw-r--r--usr/src/cmd/mdb/common/modules/random/random.c16
-rw-r--r--usr/src/cmd/mdb/common/modules/xhci/xhci.c893
12 files changed, 1165 insertions, 96 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
index 315a3df138..4e1900c44b 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
+++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
@@ -72,6 +72,7 @@ GENUNIX_SRCS = \
pci.c \
pg.c \
rctl.c \
+ refhash.c \
refstr.c \
sobj.c \
streams.c \
diff --git a/usr/src/cmd/mdb/common/modules/genunix/ctxop.c b/usr/src/cmd/mdb/common/modules/genunix/ctxop.c
index d78432b743..c8a59ce9ac 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/ctxop.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/ctxop.c
@@ -27,8 +27,9 @@
* Copyright 2018 Joyent, Inc.
*/
-#include <mdb/mdb_modapi.h>
+#include <sys/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
+#include <sys/thread.h>
#include "ctxop.h"
struct ctxop_walk_state {
diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c
index 4a48514d81..30449f0631 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c
@@ -99,6 +99,7 @@
#include "pci.h"
#include "pg.h"
#include "rctl.h"
+#include "refhash.h"
#include "sobj.h"
#include "streams.h"
#include "sysevent.h"
@@ -116,10 +117,6 @@
*/
#define NINTR 16
-#define KILOS 10
-#define MEGS 20
-#define GIGS 30
-
#ifndef STACK_BIAS
#define STACK_BIAS 0
#endif
@@ -2136,24 +2133,24 @@ typedef struct datafmt {
} datafmt_t;
static datafmt_t kmemfmt[] = {
- { "cache ", "name ",
- "-------------------------", "%-25s " },
- { " buf", " size", "------", "%6u " },
- { " buf", "in use", "------", "%6u " },
- { " buf", " total", "------", "%6u " },
- { " memory", " in use", "----------", "%10lu%c " },
- { " alloc", " succeed", "---------", "%9u " },
- { "alloc", " fail", "-----", "%5u " },
+ { "cache ", "name ",
+ "------------------------------", "%-30s " },
+ { " buf", " size", "-----", "%5H " },
+ { " buf", " in use", "---------", "%9u " },
+ { " buf", " total", "---------", "%9u " },
+ { "memory", "in use", "------", "%6lH " },
+ { " alloc", " succeed", "----------", "%10u " },
+ { "alloc", " fail", "-----", "%5u" },
{ NULL, NULL, NULL, NULL }
};
static datafmt_t vmemfmt[] = {
- { "vmem ", "name ",
- "-------------------------", "%-*s " },
- { " memory", " in use", "----------", "%9llu%c " },
- { " memory", " total", "-----------", "%10llu%c " },
- { " memory", " import", "----------", "%9llu%c " },
- { " alloc", " succeed", "---------", "%9llu " },
+ { "vmem ", "name ",
+ "------------------------------", "%-*s " },
+ { " memory", " in use", "---------", "%9llH " },
+ { " memory", " total", "----------", "%10llH " },
+ { " memory", " import", "---------", "%9llH " },
+ { " alloc", " succeed", "----------", "%10llu " },
{ "alloc", " fail", "-----", "%5llu " },
{ NULL, NULL, NULL, NULL }
};
@@ -2205,15 +2202,9 @@ typedef struct kmastat_vmem {
int kv_fail;
} kmastat_vmem_t;
-typedef struct kmastat_args {
- kmastat_vmem_t **ka_kvpp;
- uint_t ka_shift;
-} kmastat_args_t;
-
static int
-kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_args_t *kap)
+kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_vmem_t **kvpp)
{
- kmastat_vmem_t **kvpp = kap->ka_kvpp;
kmastat_vmem_t *kv;
datafmt_t *dfp = kmemfmt;
int magsize;
@@ -2254,9 +2245,7 @@ out:
mdb_printf((dfp++)->fmt, cp->cache_bufsize);
mdb_printf((dfp++)->fmt, total - avail);
mdb_printf((dfp++)->fmt, total);
- mdb_printf((dfp++)->fmt, meminuse >> kap->ka_shift,
- kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' :
- kap->ka_shift == KILOS ? 'K' : 'B');
+ mdb_printf((dfp++)->fmt, meminuse);
mdb_printf((dfp++)->fmt, alloc);
mdb_printf((dfp++)->fmt, cp->cache_alloc_fail);
mdb_printf("\n");
@@ -2265,9 +2254,8 @@ out:
}
static int
-kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap)
+kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_vmem_t *kv)
{
- kmastat_vmem_t *kv = *kap->ka_kvpp;
size_t len;
while (kv != NULL && kv->kv_addr != addr)
@@ -2276,20 +2264,18 @@ kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap)
if (kv == NULL || kv->kv_alloc == 0)
return (WALK_NEXT);
- len = MIN(17, strlen(v->vm_name));
+ len = MIN(22, strlen(v->vm_name));
- mdb_printf("Total [%s]%*s %6s %6s %6s %10lu%c %9u %5u\n", v->vm_name,
- 17 - len, "", "", "", "",
- kv->kv_meminuse >> kap->ka_shift,
- kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' :
- kap->ka_shift == KILOS ? 'K' : 'B', kv->kv_alloc, kv->kv_fail);
+ mdb_printf("Total [%s]%*s %5s %9s %9s %6lH %10u %5u\n", v->vm_name,
+ 22 - len, "", "", "", "",
+ kv->kv_meminuse, kv->kv_alloc, kv->kv_fail);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
-kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp)
+kmastat_vmem(uintptr_t addr, const vmem_t *v, const void *ignored)
{
datafmt_t *dfp = vmemfmt;
const vmem_kstat_t *vkp = &v->vm_kstat;
@@ -2307,16 +2293,10 @@ kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp)
}
mdb_printf("%*s", ident, "");
- mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name);
- mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64 >> *shiftp,
- *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
- *shiftp == KILOS ? 'K' : 'B');
- mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64 >> *shiftp,
- *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
- *shiftp == KILOS ? 'K' : 'B');
- mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64 >> *shiftp,
- *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' :
- *shiftp == KILOS ? 'K' : 'B');
+ mdb_printf((dfp++)->fmt, 30 - ident, v->vm_name);
+ mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64);
+ mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64);
+ mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64);
mdb_printf((dfp++)->fmt, vkp->vk_alloc.value.ui64);
mdb_printf((dfp++)->fmt, vkp->vk_fail.value.ui64);
@@ -2331,44 +2311,35 @@ kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
kmastat_vmem_t *kv = NULL;
datafmt_t *dfp;
- kmastat_args_t ka;
-
- ka.ka_shift = 0;
- if (mdb_getopts(argc, argv,
- 'k', MDB_OPT_SETBITS, KILOS, &ka.ka_shift,
- 'm', MDB_OPT_SETBITS, MEGS, &ka.ka_shift,
- 'g', MDB_OPT_SETBITS, GIGS, &ka.ka_shift, NULL) != argc)
- return (DCMD_USAGE);
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->hdr1);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->hdr1);
mdb_printf("\n");
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->hdr2);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->hdr2);
mdb_printf("\n");
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->dashes);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes);
mdb_printf("\n");
- ka.ka_kvpp = &kv;
- if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &ka) == -1) {
+ if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &kv) == -1) {
mdb_warn("can't walk 'kmem_cache'");
return (DCMD_ERR);
}
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->dashes);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes);
mdb_printf("\n");
- if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, &ka) == -1) {
+ if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, kv) == -1) {
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
- mdb_printf("%s ", dfp->dashes);
+ mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes);
mdb_printf("\n");
mdb_printf("\n");
@@ -2385,7 +2356,7 @@ kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_printf("%s ", dfp->dashes);
mdb_printf("\n");
- if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, &ka.ka_shift) == -1) {
+ if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, NULL) == -1) {
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
@@ -4481,6 +4452,8 @@ static const mdb_dcmd_t dcmds[] = {
/* from zone.c */
{ "zid2zone", ":", "find the zone_t with the given zone id",
zid2zone },
+ { "zdid2zone", ":", "find the zone_t with the given zone debug id",
+ zdid2zone },
{ "zone", "?[-r [-v]]", "display kernel zone(s)", zoneprt },
{ "zsd", ":[-v] [zsd_key]", "display zone-specific-data entries for "
"selected zones", zsd },
@@ -4802,6 +4775,10 @@ static const mdb_walker_t walkers[] = {
{ "rctl_val", "given a rctl_t, walk all rctl_val entries associated",
rctl_val_walk_init, rctl_val_walk_step },
+ /* from refhash.c */
+ { REFHASH_WALK_NAME, REFHASH_WALK_DESC,
+ refhash_walk_init, refhash_walk_step, NULL },
+
/* from sobj.c */
{ "blocked", "walk threads blocked on a given sobj",
blocked_walk_init, blocked_walk_step, NULL },
diff --git a/usr/src/cmd/mdb/common/modules/genunix/refhash.c b/usr/src/cmd/mdb/common/modules/genunix/refhash.c
new file mode 100644
index 0000000000..4b4c92dc14
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/genunix/refhash.c
@@ -0,0 +1,61 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018, Joyent, Inc.
+ */
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_ctf.h>
+
+#include <inttypes.h>
+#include <sys/refhash.h>
+
+typedef struct refhash_walk_data {
+ size_t rwd_offset;
+} refhash_walk_data_t;
+
+int
+refhash_walk_init(mdb_walk_state_t *wsp)
+{
+ refhash_t refh = { 0 };
+ refhash_walk_data_t *rwd;
+ int offset;
+
+ /* mdb_ctf_offsetof_by_name() will print any errors */
+ if ((offset = mdb_ctf_offsetof_by_name("refhash_t", "rh_objs")) == -1)
+ return (WALK_ERR);
+
+ if (mdb_vread(&refh, sizeof (refhash_t), wsp->walk_addr) == -1) {
+ mdb_warn("failed to read refhash_t at %#lx", wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ rwd = wsp->walk_data = mdb_zalloc(sizeof (*rwd), UM_SLEEP | UM_GC);
+ rwd->rwd_offset = refh.rh_link_off;
+
+ wsp->walk_addr += offset;
+ if (mdb_layered_walk("list", wsp) == -1) {
+ mdb_warn("can't walk refhash_t");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+int
+refhash_walk_step(mdb_walk_state_t *wsp)
+{
+ refhash_walk_data_t *rwd = wsp->walk_data;
+ uintptr_t addr = wsp->walk_addr - rwd->rwd_offset;
+
+ return (wsp->walk_callback(addr, wsp->walk_layer, wsp->walk_cbdata));
+}
diff --git a/usr/src/cmd/mdb/common/modules/genunix/refhash.h b/usr/src/cmd/mdb/common/modules/genunix/refhash.h
new file mode 100644
index 0000000000..1e91ced8d5
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/genunix/refhash.h
@@ -0,0 +1,35 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018, Joyent, Inc.
+ */
+
+#ifndef _REFHASH_H
+#define _REFHASH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define REFHASH_WALK_NAME "refhash"
+#define REFHASH_WALK_DESC "walk a refhash"
+
+struct mdb_walk_state;
+
+extern int refhash_walk_init(struct mdb_walk_state *);
+extern int refhash_walk_step(struct mdb_walk_state *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REFHASH_H */
diff --git a/usr/src/cmd/mdb/common/modules/genunix/zone.c b/usr/src/cmd/mdb/common/modules/genunix/zone.c
index 49cd3e7b6e..57545d94a3 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/zone.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/zone.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc. All rights reserved.
*/
#include <mdb/mdb_param.h>
@@ -34,9 +34,9 @@
#define ZONE_NAMELEN 20
#ifdef _LP64
-#define ZONE_PATHLEN 32
+#define ZONE_PATHLEN 25
#else
-#define ZONE_PATHLEN 40
+#define ZONE_PATHLEN 33
#endif
/*
@@ -52,7 +52,8 @@ char *zone_status_names[] = {
"empty", /* ZONE_IS_EMPTY */
"down", /* ZONE_IS_DOWN */
"dying", /* ZONE_IS_DYING */
- "dead" /* ZONE_IS_DEAD */
+ "dead", /* ZONE_IS_DEAD */
+ "free" /* ZONE_IS_FREE */
};
static int
@@ -80,6 +81,31 @@ zid2zone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_OK);
}
+static int
+zdid_lookup_cb(uintptr_t addr, const zone_t *zone, void *arg)
+{
+ zoneid_t zdid = *(uintptr_t *)arg;
+ if (zone->zone_did == zdid)
+ mdb_printf("%p\n", addr);
+
+ return (WALK_NEXT);
+}
+
+/*ARGSUSED*/
+int
+zdid2zone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ if (!(flags & DCMD_ADDRSPEC) || argc != 0)
+ return (DCMD_USAGE);
+
+ if (mdb_walk("zone", (mdb_walk_cb_t)zdid_lookup_cb, &addr) == -1) {
+ mdb_warn("failed to walk zone");
+ return (DCMD_ERR);
+ }
+
+ return (DCMD_OK);
+}
+
int
zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
@@ -122,10 +148,10 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
*/
if (DCMD_HDRSPEC(flags)) {
if (ropt_given == FALSE)
- mdb_printf("%<u>%?s %6s %-13s %-20s %-s%</u>\n",
+ mdb_printf("%<u>%?s %4s %-13s %-19s %-s%</u>\n",
"ADDR", "ID", "STATUS", "NAME", "PATH");
else
- mdb_printf("%<u>%?s %6s %10s %10s %-20s%</u>\n",
+ mdb_printf("%<u>%?s %6s %10s %10s %-19s%</u>\n",
"ADDR", "ID", "REFS", "CREFS", "NAME");
}
@@ -164,7 +190,7 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
statusp = zone_status_names[zn.zone_status];
else
statusp = "???";
- mdb_printf("%0?p %6d %-13s %-20s %s\n", addr, zn.zone_id,
+ mdb_printf("%0?p %4d %-13s %-19s %s\n", addr, zn.zone_id,
statusp, name, path);
} else {
/*
@@ -172,7 +198,7 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
* Display the zone's subsystem-specific reference counts if
* the user specified the '-v' option.
*/
- mdb_printf("%0?p %6d %10u %10u %-20s\n", addr, zn.zone_id,
+ mdb_printf("%0?p %6d %10u %10u %-19s\n", addr, zn.zone_id,
zn.zone_ref, zn.zone_cred_ref, name);
if (vopt_given == TRUE) {
GElf_Sym subsys_names_sym;
@@ -410,7 +436,7 @@ zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
* Prepare to output the specified zone's ZSD information.
*/
if (DCMD_HDRSPEC(flags))
- mdb_printf("%<u>%-20s %?s %?s %8s%</u>\n", "ZONE", "KEY",
+ mdb_printf("%<u>%-19s %?s %?s %8s%</u>\n", "ZONE", "KEY",
"VALUE", "FLAGS");
len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zone.zone_name);
if (len > 0) {
@@ -419,7 +445,7 @@ zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
} else {
(void) strcpy(name, "??");
}
- mdb_printf("%-20s ", name);
+ mdb_printf("%-19s ", name);
/*
* Display the requested ZSD entries.
diff --git a/usr/src/cmd/mdb/common/modules/genunix/zone.h b/usr/src/cmd/mdb/common/modules/genunix/zone.h
index 0881f9bbae..94a383e41c 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/zone.h
+++ b/usr/src/cmd/mdb/common/modules/genunix/zone.h
@@ -34,6 +34,7 @@ extern "C" {
#endif
extern int zid2zone(uintptr_t, uint_t, int argc, const mdb_arg_t *);
+extern int zdid2zone(uintptr_t, uint_t, int argc, const mdb_arg_t *);
extern int zoneprt(uintptr_t, uint_t, int argc, const mdb_arg_t *);
extern int zone_walk_init(mdb_walk_state_t *);
diff --git a/usr/src/cmd/mdb/common/modules/ipc/ipc.c b/usr/src/cmd/mdb/common/modules/ipc/ipc.c
index bc87716015..04db8f7fcf 100644
--- a/usr/src/cmd/mdb/common/modules/ipc/ipc.c
+++ b/usr/src/cmd/mdb/common/modules/ipc/ipc.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
#include <mdb/mdb_modapi.h>
@@ -228,7 +229,9 @@ shm_print(kshmid_t *shmid, uintptr_t addr)
printtime_nice("ctime: ", shmid->shm_ctime);
mdb_printf("sptinfo: %-?p sptseg: %-?p\n",
shmid->shm_sptinfo, shmid->shm_sptseg);
- mdb_printf("sptprot: <%lb>\n", shmid->shm_sptprot, prot_flag_bits);
+ mdb_printf("opts: rmpend: %d prot: <%b>\n",
+ ((shmid->shm_opts & SHM_RM_PENDING) != 0),
+ (shmid->shm_opts & SHM_PROT_MASK), prot_flag_bits);
}
diff --git a/usr/src/cmd/mdb/common/modules/libc/libc.c b/usr/src/cmd/mdb/common/modules/libc/libc.c
index 69f4beda74..8ee6af407e 100644
--- a/usr/src/cmd/mdb/common/modules/libc/libc.c
+++ b/usr/src/cmd/mdb/common/modules/libc/libc.c
@@ -138,6 +138,8 @@ d_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack));
mdb_printf(" mcontext = 0x%p\n",
addr + OFFSETOF(ucontext_t, uc_mcontext));
+ mdb_printf(" brand = 0x%p 0x%p 0x%p\n",
+ uc.uc_brand_data[0], uc.uc_brand_data[1], uc.uc_brand_data[2]);
return (DCMD_OK);
}
@@ -849,14 +851,19 @@ d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
prt_addr(uberdata.all_lwps, 1),
prt_addr(uberdata.all_zombies, 0));
- HD("nthreads nzombies ndaemons pid sigacthandler");
- mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n",
+ HD("nthreads nzombies ndaemons pid");
+ mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d\n",
OFFSET(nthreads),
uberdata.nthreads,
uberdata.nzombies,
uberdata.ndaemons,
- (int)uberdata.pid,
- prt_addr((void *)uberdata.sigacthandler, 0));
+ (int)uberdata.pid);
+
+ HD("sigacthandler setctxt");
+ mdb_printf(OFFSTR "%s %s\n",
+ OFFSET(sigacthandler),
+ prt_addr((void *)uberdata.sigacthandler, 1),
+ prt_addr((void *)uberdata.setctxt, 1));
HD("lwp_stacks lwp_laststack nfreestack stk_cache");
mdb_printf(OFFSTR "%s %s %-10d %d\n",
@@ -879,12 +886,17 @@ d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
prt_addr(uberdata.ulwp_replace_last, 1),
prt_addr(uberdata.atforklist, 0));
- HD("robustlocks robustlist progname");
- mdb_printf(OFFSTR "%s %s %s\n",
+ HD("robustlocks robustlist");
+ mdb_printf(OFFSTR "%s %s\n",
OFFSET(robustlocks),
prt_addr(uberdata.robustlocks, 1),
- prt_addr(uberdata.robustlist, 1),
- prt_addr(uberdata.progname, 0));
+ prt_addr(uberdata.robustlist, 1));
+
+ HD("progname ub_broot");
+ mdb_printf(OFFSTR "%s %s\n",
+ OFFSET(progname),
+ prt_addr(uberdata.progname, 1),
+ prt_addr(uberdata.ub_broot, 1));
HD("tdb_bootstrap tdb_sync_addr_hash tdb_'count tdb_'fail");
mdb_printf(OFFSTR "%s %s %-10d %d\n",
diff --git a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
index 85f3839c96..68b2e9d362 100644
--- a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
+++ b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c
@@ -60,6 +60,12 @@
#define MDB_PATH_NELEM 256 /* Maximum path components */
+/*
+ * Due to mdb_param.h shenanigans, there's no simple way to include string.h
+ * here...
+ */
+extern char *strtok(char *restrict, const char *restrict);
+
typedef struct mdb_path {
size_t mdp_nelem; /* Number of components */
uint_t mdp_complete; /* Path completely resolved? */
@@ -1811,18 +1817,73 @@ mdb_get_lbolt(void)
return ((ts/nsec) - lbi.lbi_debug_time);
}
+#define startswith(a, b) (strncmp((a), (b), strlen(b)) == 0)
+
+/*
+ * Dig out the branch and revision of the illumos-joyent repo, if we were
+ * provided with it. This is a rather fragile JSON parser, in that it requires
+ * JSON formatted exactly as per the boot_archive.gitstatus file that
+ * "buildversion" is built from.
+ */
void
mdb_print_buildversion(void)
{
+ boolean_t in_joyent = B_FALSE;
GElf_Sym sym;
- if (mdb_lookup_by_name("buildversion", &sym) != 0)
- return;
+ if (mdb_lookup_by_name("buildversion", &sym) != 0) {
+ /* Older kernels used this name. */
+ if (mdb_lookup_by_name("gitstatus_start", &sym) != 0)
+ return;
+ }
char *str = mdb_zalloc(4096, UM_SLEEP | UM_GC);
if (mdb_readstr(str, 4096, sym.st_value) < 1)
return;
- mdb_printf("build version: %s\n", str);
+ /*
+ * Each line is of the form
+ *
+ * "repo": "smartos-live",
+ */
+ for (char *line = strtok(str, "\n"); line != NULL;
+ line = strtok(NULL, "\n")) {
+ /* skip whitespace and first " */
+ line += strspn(line, " \t\"");
+
+ if (startswith(line, "repo")) {
+ line += sizeof ("repo") - 1;
+ line += strspn(line, " \t\":");
+
+ if (startswith(line, "illumos-joyent"))
+ in_joyent = B_TRUE;
+ else if (in_joyent)
+ return;
+ continue;
+ }
+
+ if (!in_joyent)
+ continue;
+
+ if (startswith(line, "branch")) {
+ char *trail = strrchr(line, '"');
+ if (trail != NULL)
+ *trail = '\0';
+ line += sizeof ("branch") - 1;
+ line += strspn(line, " \t\":");
+ mdb_printf("git branch: %s\n", line);
+ continue;
+ }
+
+ if (startswith(line, "rev")) {
+ char *trail = strrchr(line, '"');
+ if (trail != NULL)
+ *trail = '\0';
+ line += sizeof ("rev") - 1;
+ line += strspn(line, " \t\":");
+ mdb_printf("git rev: %s\n", line);
+ continue;
+ }
+ }
}
diff --git a/usr/src/cmd/mdb/common/modules/random/random.c b/usr/src/cmd/mdb/common/modules/random/random.c
index a1b41f0eb8..2da56dae32 100644
--- a/usr/src/cmd/mdb/common/modules/random/random.c
+++ b/usr/src/cmd/mdb/common/modules/random/random.c
@@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
#include <sys/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
@@ -39,10 +41,9 @@ rnd_get_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
rnd_stats_t rnd_stats, rnd_stats_cpu;
uint32_t random_max_ncpus;
- size_t rndmag_t_size;
+ size_t rndmag_pad_t_size;
ulong_t rndmag_t_offset;
uintptr_t rndmag;
- mdb_ctf_id_t rndmag_id;
int i;
if ((flags & DCMD_ADDRSPEC) || argc != 0)
@@ -53,23 +54,20 @@ rnd_get_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_ERR);
}
- if ((mdb_ctf_lookup_by_name("rndmag_t", &rndmag_id) != 0) ||
- (mdb_ctf_offsetof(rndmag_id, "rm_stats", &rndmag_t_offset) != 0) ||
+ if (((rndmag_t_offset = mdb_ctf_offsetof_by_name("rndmag_t", "rm_stats")) == -1) ||
(mdb_readvar(&random_max_ncpus, "random_max_ncpus") == -1) ||
(mdb_readvar(&rndmag, "rndmag") == -1) ||
- ((rndmag_t_size = mdb_ctf_type_size(rndmag_id)) == 0)) {
+ ((rndmag_pad_t_size = mdb_ctf_sizeof_by_name("rndmag_pad_t")) == -1)) {
/* Can't find per-cpu stats. Don't add them in. */
random_max_ncpus = 0;
}
- rndmag_t_offset /= 8;
-
/*
* Read and aggregate per-cpu stats if we have them.
*/
for (i = 0; i < random_max_ncpus; i++) {
mdb_vread(&rnd_stats_cpu, sizeof (rnd_stats_cpu),
- rndmag + rndmag_t_offset + i * rndmag_t_size);
+ rndmag + rndmag_t_offset + i * rndmag_pad_t_size);
rnd_stats.rs_rndOut += rnd_stats_cpu.rs_rndOut;
rnd_stats.rs_rndcOut += rnd_stats_cpu.rs_rndcOut;
diff --git a/usr/src/cmd/mdb/common/modules/xhci/xhci.c b/usr/src/cmd/mdb/common/modules/xhci/xhci.c
new file mode 100644
index 0000000000..1a1882e738
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/xhci/xhci.c
@@ -0,0 +1,893 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <sys/mdb_modapi.h>
+#include <sys/usb/hcd/xhci/xhci.h>
+
+#define XHCI_MDB_TRB_INDENT 4
+
+static const char *xhci_mdb_epctx_eptypes[] = {
+ "Not Valid",
+ "ISOCH OUT",
+ "BULK OUT",
+ "INTR OUT",
+ "CONTROL",
+ "ISOCH IN",
+ "BULK IN",
+ "INTR IN"
+};
+
+static const char *xhci_mdb_epctx_states[] = {
+ "Disabled",
+ "Running",
+ "Halted",
+ "Stopped",
+ "Error",
+ "<Unknown>",
+ "<Unknown>",
+ "<Unknown>"
+};
+
+static const mdb_bitmask_t xhci_mdb_trb_flags[] = {
+ { "C", XHCI_TRB_CYCLE, XHCI_TRB_CYCLE },
+ { "ENT", XHCI_TRB_ENT, XHCI_TRB_ENT },
+ { "ISP", XHCI_TRB_ISP, XHCI_TRB_ISP },
+ { "NS", XHCI_TRB_NOSNOOP, XHCI_TRB_NOSNOOP },
+ { "CH", XHCI_TRB_CHAIN, XHCI_TRB_CHAIN },
+ { "IOC", XHCI_TRB_IOC, XHCI_TRB_IOC },
+ { "IDT", XHCI_TRB_IDT, XHCI_TRB_IDT },
+ { "BEI", XHCI_TRB_BEI, XHCI_TRB_BEI },
+ { NULL, 0, 0 }
+};
+
+typedef struct xhci_mdb_walk_endpoint {
+ xhci_device_t xmwe_device;
+ uint_t xmwe_ep;
+} xhci_mdb_walk_endpoint_t;
+
+static const char *
+xhci_mdb_trb_code_to_str(int code)
+{
+ switch (code) {
+ case XHCI_CODE_INVALID:
+ return ("Invalid");
+ case XHCI_CODE_SUCCESS:
+ return ("Success");
+ case XHCI_CODE_DATA_BUF:
+ return ("Data Overrun or Underrun");
+ case XHCI_CODE_BABBLE:
+ return ("Babble");
+ case XHCI_CODE_TXERR:
+ return ("Transaction Error");
+ case XHCI_CODE_TRB:
+ return ("Invalid TRB");
+ case XHCI_CODE_STALL:
+ return ("Stall");
+ case XHCI_CODE_RESOURCE:
+ return ("No Resources Available");
+ case XHCI_CODE_BANDWIDTH:
+ return ("No Bandwidth Available");
+ case XHCI_CODE_NO_SLOTS:
+ return ("No Slots Available");
+ case XHCI_CODE_STREAM_TYPE:
+ return ("Stream Context Type Detected");
+ case XHCI_CODE_SLOT_NOT_ON:
+ return ("Slot disabled");
+ case XHCI_CODE_ENDP_NOT_ON:
+ return ("Endpoint disabled");
+ case XHCI_CODE_SHORT_XFER:
+ return ("Short Transfer");
+ case XHCI_CODE_RING_UNDERRUN:
+ return ("Isoch. Ring Underrun");
+ case XHCI_CODE_RING_OVERRUN:
+ return ("Isoch. Ring Overrun");
+ case XHCI_CODE_VF_RING_FULL:
+ return ("VF Ring Full");
+ case XHCI_CODE_PARAMETER:
+ return ("Invalid Context Paramenter");
+ case XHCI_CODE_BW_OVERRUN:
+ return ("Bandwidth Overrun");
+ case XHCI_CODE_CONTEXT_STATE:
+ return ("Illegal Context Transition");
+ case XHCI_CODE_NO_PING_RESP:
+ return ("Failed to Complete Periodic Transfer");
+ case XHCI_CODE_EV_RING_FULL:
+ return ("Event Ring Full");
+ case XHCI_CODE_INCOMPAT_DEV:
+ return ("Incompatible Device");
+ case XHCI_CODE_MISSED_SRV:
+ return ("Missed Isoch. Service Window");
+ case XHCI_CODE_CMD_RING_STOP:
+ return ("Command Ring Stop");
+ case XHCI_CODE_CMD_ABORTED:
+ return ("Command Aborted");
+ case XHCI_CODE_XFER_STOPPED:
+ return ("Transfer Stopped");
+ case XHCI_CODE_XFER_STOPINV:
+ return ("Invalid Transfer Length");
+ case XHCI_CODE_XFER_STOPSHORT:
+ return ("Stopped before End of Transfer Descriptor");
+ case XHCI_CODE_MELAT:
+ return ("Max Exit Latency too large");
+ case XHCI_CODE_RESERVED:
+ return ("Reserved");
+ case XHCI_CODE_ISOC_OVERRUN:
+ return ("Isochronus Overrun");
+ case XHCI_CODE_EVENT_LOST:
+ return ("Event Lost");
+ case XHCI_CODE_UNDEFINED:
+ return ("Undefined Fatal Error");
+ case XHCI_CODE_INVALID_SID:
+ return ("Invalid Stream ID");
+ case XHCI_CODE_SEC_BW:
+ return ("Secondary Bandwith Allocation Failure");
+ case XHCI_CODE_SPLITERR:
+ return ("USB2 SPlit Transaction Error");
+ default:
+ break;
+ }
+
+ if (code >= 192 && code <= 223)
+ return ("Vendor Defined Error");
+ if (code >= 224 && code <= 255)
+ return ("Vendor Defined Info");
+
+ return ("Reserved");
+}
+
+static const char *
+xhci_mdb_trb_type_to_str(int code)
+{
+ /*
+ * The macros for the types are all already shifted over based on their
+ * place in the TRB, so shift there again ourselves.
+ */
+ switch (code << 10) {
+ case XHCI_TRB_TYPE_NORMAL:
+ return ("Normal");
+ case XHCI_TRB_TYPE_SETUP:
+ return ("Setup");
+ case XHCI_TRB_TYPE_DATA:
+ return ("Data");
+ case XHCI_TRB_TYPE_STATUS:
+ return ("Status");
+ case XHCI_TRB_TYPE_LINK:
+ return ("Link");
+ case XHCI_TRB_TYPE_EVENT:
+ return ("Event");
+ case XHCI_TRB_TYPE_NOOP:
+ return ("No-Op");
+ case XHCI_CMD_ENABLE_SLOT:
+ return ("Enable Slot");
+ case XHCI_CMD_DISABLE_SLOT:
+ return ("Disable Slot");
+ case XHCI_CMD_ADDRESS_DEVICE:
+ return ("Address Device");
+ case XHCI_CMD_CONFIG_EP:
+ return ("Configure Endpoint");
+ case XHCI_CMD_EVAL_CTX:
+ return ("Evaluate Context");
+ case XHCI_CMD_RESET_EP:
+ return ("Reset Endpoint");
+ case XHCI_CMD_STOP_EP:
+ return ("Stop Endpoint");
+ case XHCI_CMD_SET_TR_DEQ:
+ return ("Set Transfer Ring Dequeue Pointer");
+ case XHCI_CMD_RESET_DEV:
+ return ("Reset Device");
+ case XHCI_CMD_FEVENT:
+ return ("Force Event");
+ case XHCI_CMD_NEG_BW:
+ return ("Negotiate Bandwidth");
+ case XHCI_CMD_SET_LT:
+ return ("Set Latency Tolerance");
+ case XHCI_CMD_GET_BW:
+ return ("Get Bandwidth");
+ case XHCI_CMD_FHEADER:
+ return ("Force Header");
+ case XHCI_CMD_NOOP:
+ return ("No-Op Command");
+ case XHCI_EVT_XFER:
+ return ("Transfer Event");
+ case XHCI_EVT_CMD_COMPLETE:
+ return ("Command Completion Event");
+ case XHCI_EVT_PORT_CHANGE:
+ return ("Port Status Change Event");
+ case XHCI_EVT_BW_REQUEST:
+ return ("Bandwidth Request Event");
+ case XHCI_EVT_DOORBELL:
+ return ("Doorbell Event");
+ case XHCI_EVT_HOST_CTRL:
+ return ("Host Controller Event");
+ case XHCI_EVT_DEVICE_NOTIFY:
+ return ("Device Notification Event");
+ case XHCI_EVT_MFINDEX_WRAP:
+ return ("MFINDEX Wrap Event");
+ default:
+ break;
+ }
+
+ if (code >= 43 && code <= 63)
+ return ("Vendor Defiend");
+ return ("Reserved");
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_epctx(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ uint32_t info, info2, txinfo;
+ xhci_endpoint_context_t epctx;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("::xhci_epctx requires an address\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&epctx, sizeof (epctx), addr) != sizeof (epctx)) {
+ mdb_warn("failed to read xhci_endpoint_context_t at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ info = LE_32(epctx.xec_info);
+ info2 = LE_32(epctx.xec_info2);
+ txinfo = LE_32(epctx.xec_txinfo);
+
+ mdb_printf("Endpoint State: %s (%d)\n",
+ xhci_mdb_epctx_states[XHCI_EPCTX_STATE(info)],
+ XHCI_EPCTX_STATE(info));
+
+ mdb_printf("Mult: %d\n", XHCI_EPCTX_GET_MULT(info));
+ mdb_printf("Max Streams: %d\n", XHCI_EPCTX_GET_MAXP_STREAMS(info));
+ mdb_printf("LSA: %d\n", XHCI_EPCTX_GET_LSA(info));
+ mdb_printf("Interval: %d\n", XHCI_EPCTX_GET_IVAL(info));
+ mdb_printf("Max ESIT Hi: %d\n", XHCI_EPCTX_GET_MAX_ESIT_HI(info));
+
+ mdb_printf("CErr: %d\n", XHCI_EPCTX_GET_CERR(info2));
+ mdb_printf("EP Type: %s (%d)\n",
+ xhci_mdb_epctx_eptypes[XHCI_EPCTX_GET_EPTYPE(info2)],
+ XHCI_EPCTX_GET_EPTYPE(info2));
+ mdb_printf("Host Initiate Disable: %d\n", XHCI_EPCTX_GET_HID(info2));
+ mdb_printf("Max Burst: %d\n", XHCI_EPCTX_GET_MAXB(info2));
+ mdb_printf("Max Packet Size: %d\n", XHCI_EPCTX_GET_MPS(info2));
+
+ mdb_printf("Ring DCS: %d\n", LE_64(epctx.xec_dequeue) & 0x1);
+ mdb_printf("Ring PA: 0x%lx\n", LE_64(epctx.xec_dequeue) & ~0xf);
+
+ mdb_printf("Average TRB Length: %d\n", XHCI_EPCTX_AVG_TRB_LEN(txinfo));
+ mdb_printf("Max ESIT: %d\n", XHCI_EPCTX_GET_MAX_ESIT_PAYLOAD(txinfo));
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_slotctx(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ uint32_t info, info2, tt, state;
+ xhci_slot_context_t sctx;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("::xhci_slotctx requires an address\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&sctx, sizeof (sctx), addr) != sizeof (sctx)) {
+ mdb_warn("failed to read xhci_slot_context_t at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ info = LE_32(sctx.xsc_info);
+ info2 = LE_32(sctx.xsc_info2);
+ tt = LE_32(sctx.xsc_tt);
+ state = LE_32(sctx.xsc_state);
+
+ mdb_printf("Route: 0x%x\n", XHCI_SCTX_GET_ROUTE(info));
+
+ mdb_printf("Slot Speed: ");
+ switch (XHCI_SCTX_GET_SPEED(info)) {
+ case XHCI_SPEED_FULL:
+ mdb_printf("Full");
+ break;
+ case XHCI_SPEED_LOW:
+ mdb_printf("Low");
+ break;
+ case XHCI_SPEED_HIGH:
+ mdb_printf("High");
+ break;
+ case XHCI_SPEED_SUPER:
+ mdb_printf("Super");
+ break;
+ default:
+ mdb_printf("Unknown");
+ break;
+ }
+ mdb_printf(" (%d)\n", XHCI_SCTX_GET_SPEED(info));
+
+
+ mdb_printf("MTT: %d\n", XHCI_SCTX_GET_MTT(info));
+ mdb_printf("HUB: %d\n", XHCI_SCTX_GET_HUB(info));
+ mdb_printf("DCI: %d\n", XHCI_SCTX_GET_DCI(info));
+
+ mdb_printf("Max Exit Latency: %d\n", XHCI_SCTX_GET_MAX_EL(info2));
+ mdb_printf("Root Hub Port: %d\n", XHCI_SCTX_GET_RHPORT(info2));
+ mdb_printf("Hub Number of Ports: %d\n", XHCI_SCTX_GET_NPORTS(info2));
+
+ mdb_printf("TT Hub Slot id: %d\n", XHCI_SCTX_GET_TT_HUB_SID(tt));
+ mdb_printf("TT Port Number: %d\n", XHCI_SCTX_GET_TT_PORT_NUM(tt));
+ mdb_printf("TT Think Time: %d\n", XHCI_SCTX_GET_TT_THINK_TIME(tt));
+ mdb_printf("IRQ Target: %d\n", XHCI_SCTX_GET_IRQ_TARGET(tt));
+
+ mdb_printf("Device Address: 0x%x\n", XHCI_SCTX_GET_DEV_ADDR(state));
+ mdb_printf("Slot State: ");
+ switch (XHCI_SCTX_GET_SLOT_STATE(state)) {
+ case XHCI_SLOT_DIS_ENAB:
+ mdb_printf("Disabled/Enabled");
+ break;
+ case XHCI_SLOT_DEFAULT:
+ mdb_printf("Default");
+ break;
+ case XHCI_SLOT_ADDRESSED:
+ mdb_printf("Addressed");
+ break;
+ case XHCI_SLOT_CONFIGURED:
+ mdb_printf("Configured");
+ break;
+ default:
+ mdb_printf("Unknown");
+ break;
+ }
+ mdb_printf(" (%d)\n", XHCI_SCTX_GET_SLOT_STATE(state));
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_print_transfer_event(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("Transfer Length (Remain): %d\n", XHCI_TRB_REMAIN(status));
+ mdb_printf("Completion Code: %s (%d)\n",
+ xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
+ XHCI_TRB_GET_CODE(status));
+
+ mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags));
+ mdb_printf("Event Data: %d\n", XHCI_TRB_GET_ED(flags));
+ mdb_printf("Endpoint ID: %d\n", XHCI_TRB_GET_EP(flags));
+ mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_print_command_event(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("Command Param: 0x%x\n", XHCI_TRB_REMAIN(status));
+ mdb_printf("Completion Code: %s (%d)\n",
+ xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
+ XHCI_TRB_GET_CODE(status));
+
+ mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags));
+ /* Skip VF ID as we don't support VFs */
+ mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_psc(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("Port: %d\n", XHCI_TRB_PORTID(pa));
+ mdb_printf("Completion Code: %s (%d)\n",
+ xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)),
+ XHCI_TRB_GET_CODE(status));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_print_normal_trb(uint64_t pa, uint32_t status, uint32_t flags)
+{
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("TRB Length: %d bytes\n", XHCI_TRB_LEN(status));
+ mdb_printf("TRB TD Size: %d packets\n", XHCI_TRB_GET_TDREM(status));
+ mdb_printf("TRB Interrupt: %d\n", XHCI_TRB_GET_INTR(status));
+ mdb_printf("TRB Flags: %b (0x%x)\n", flags, xhci_mdb_trb_flags,
+ XHCI_TRB_GET_FLAGS(flags));
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_trb(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ xhci_trb_t trb;
+ uint64_t pa;
+ uint32_t status, trbflags, type;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("::xhci_trb expects an address\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&trb, sizeof (trb), addr) != sizeof (trb)) {
+ mdb_warn("failed to read xhci_trb_t at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+ pa = LE_64(trb.trb_addr);
+ status = LE_32(trb.trb_status);
+ trbflags = LE_32(trb.trb_flags);
+
+ type = XHCI_TRB_GET_TYPE(trbflags);
+
+ if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
+ mdb_printf("\n");
+
+ mdb_set_dot(addr + sizeof (xhci_trb_t));
+ mdb_printf("%s TRB (%d)\n", xhci_mdb_trb_type_to_str(type), type);
+ mdb_inc_indent(XHCI_MDB_TRB_INDENT);
+
+ switch (XHCI_RING_TYPE_SHIFT(type)) {
+ case XHCI_EVT_XFER:
+ return (xhci_mdb_print_transfer_event(pa, status, trbflags));
+ case XHCI_EVT_CMD_COMPLETE:
+ return (xhci_mdb_print_command_event(pa, status, trbflags));
+ case XHCI_EVT_PORT_CHANGE:
+ return (xhci_mdb_print_psc(pa, status, trbflags));
+ case XHCI_TRB_TYPE_NORMAL:
+ return (xhci_mdb_print_normal_trb(pa, status, trbflags));
+ }
+
+ /*
+ * Just print generic information if we don't have a specific printer
+ * for that TRB type.
+ */
+ mdb_printf("TRB Address: 0x%lx\n", pa);
+ mdb_printf("TRB Status: 0x%x\n", status);
+ mdb_printf("TRB Flags: 0x%x\n", trbflags);
+ mdb_dec_indent(XHCI_MDB_TRB_INDENT);
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_walk_xhci_init(mdb_walk_state_t *wsp)
+{
+ GElf_Sym sym;
+ uintptr_t addr;
+
+ if (wsp->walk_addr != 0) {
+ mdb_warn("::walk xhci only supports global walks\n");
+ return (WALK_ERR);
+ }
+
+ if (mdb_lookup_by_obj("xhci", "xhci_soft_state", &sym) != 0) {
+ mdb_warn("failed to find xhci_soft_state symbol");
+ return (WALK_ERR);
+ }
+
+ if (mdb_vread(&addr, sizeof (addr), sym.st_value) != sizeof (addr)) {
+ mdb_warn("failed to read xhci_soft_state at %p", addr);
+ return (WALK_ERR);
+ }
+
+ wsp->walk_addr = addr;
+ if (mdb_layered_walk("softstate", wsp) != 0) {
+ mdb_warn("failed to walk softstate");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_walk_xhci_step(mdb_walk_state_t *wsp)
+{
+ xhci_t xhci;
+
+ if (mdb_vread(&xhci, sizeof (xhci), wsp->walk_addr) != sizeof (xhci)) {
+ mdb_warn("failed to read xhci_t at %p", wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ return (wsp->walk_callback(wsp->walk_addr, &xhci, wsp->walk_cbdata));
+}
+
+static int
+xhci_mdb_walk_xhci_device_init(mdb_walk_state_t *wsp)
+{
+ uintptr_t addr;
+
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk xhci_device requires an xhci_t\n");
+ return (WALK_ERR);
+ }
+
+ addr = wsp->walk_addr;
+ addr += offsetof(xhci_t, xhci_usba);
+ addr += offsetof(xhci_usba_t, xa_devices);
+ wsp->walk_addr = (uintptr_t)addr;
+ if (mdb_layered_walk("list", wsp) != 0) {
+ mdb_warn("failed to walk list");
+ return (WALK_ERR);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_walk_xhci_device_step(mdb_walk_state_t *wsp)
+{
+ xhci_device_t xd;
+
+ if (mdb_vread(&xd, sizeof (xd), wsp->walk_addr) != sizeof (xd)) {
+ mdb_warn("failed to read xhci_device_t at %p", wsp->walk_addr);
+ return (WALK_ERR);
+ }
+
+ return (wsp->walk_callback(wsp->walk_addr, &xd, wsp->walk_cbdata));
+}
+
+static int
+xhci_mdb_walk_xhci_endpoint_init(mdb_walk_state_t *wsp)
+{
+ xhci_mdb_walk_endpoint_t *xm;
+ xhci_device_t *xd;
+
+ if (wsp->walk_addr == 0) {
+ mdb_warn("::walk xhci_endpoint requires an xhci_device_t\n");
+ return (WALK_ERR);
+ }
+
+ xm = mdb_alloc(sizeof (xhci_mdb_walk_endpoint_t), UM_SLEEP | UM_GC);
+ xm->xmwe_ep = 0;
+ xd = &xm->xmwe_device;
+ if (mdb_vread(xd, sizeof (*xd), wsp->walk_addr) != sizeof (*xd)) {
+ mdb_warn("failed to read xhci_endpoint_t at %p",
+ wsp->walk_addr);
+ return (WALK_ERR);
+ }
+ wsp->walk_data = xm;
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_walk_xhci_endpoint_step(mdb_walk_state_t *wsp)
+{
+ int ret;
+ uintptr_t addr;
+ xhci_mdb_walk_endpoint_t *xm = wsp->walk_data;
+
+ if (xm->xmwe_ep >= XHCI_NUM_ENDPOINTS)
+ return (WALK_DONE);
+
+ addr = (uintptr_t)xm->xmwe_device.xd_endpoints[xm->xmwe_ep];
+ if (addr != (uintptr_t)NULL) {
+ xhci_endpoint_t xe;
+
+ if (mdb_vread(&xe, sizeof (xe), addr) != sizeof (xe)) {
+ mdb_warn("failed to read xhci_endpoint_t at %p",
+ xm->xmwe_device.xd_endpoints[xm->xmwe_ep]);
+ return (WALK_ERR);
+ }
+
+ ret = wsp->walk_callback(addr, &xe, wsp->walk_cbdata);
+ } else {
+ ret = WALK_NEXT;
+ }
+ xm->xmwe_ep++;
+
+ return (ret);
+}
+
+typedef struct xhci_mdb_find {
+ int xmf_slot;
+ int xmf_ep;
+ uintptr_t xmf_addr;
+} xhci_mdb_find_t;
+
+static int
+xhci_mdb_find_endpoint_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const xhci_endpoint_t *xep = data;
+ xhci_mdb_find_t *xmf = arg;
+
+ /*
+ * The endpoints that are presented here are off by one from the actual
+ * endpoint ID in the xhci_endpoint_t, as we're really displaying the
+ * index into the device input context.
+ */
+ if (xep->xep_num + 1 == xmf->xmf_ep) {
+ xmf->xmf_addr = addr;
+ return (WALK_DONE);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_find_device_cb(uintptr_t addr, const void *data, void *arg)
+{
+ const xhci_device_t *xd = data;
+ xhci_mdb_find_t *xmf = arg;
+
+ if (xd->xd_slot == xmf->xmf_slot) {
+ if (xmf->xmf_ep == -1) {
+ xmf->xmf_addr = addr;
+ return (WALK_DONE);
+ }
+
+ if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_find_endpoint_cb,
+ xmf, addr) == -1) {
+ mdb_warn("failed to walk xhci_endpoint at %p", addr);
+ return (WALK_ERR);
+ }
+
+ return (WALK_DONE);
+ }
+
+ return (WALK_NEXT);
+}
+
+static int
+xhci_mdb_find(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ uintptr_t ep, slot;
+ boolean_t ep_set, slot_set;
+ xhci_mdb_find_t xmf;
+
+ if ((flags & DCMD_ADDRSPEC) == 0)
+ return (DCMD_USAGE);
+
+ ep_set = slot_set = B_FALSE;
+ if (mdb_getopts(argc, argv, 'e', MDB_OPT_UINTPTR_SET, &ep_set, &ep,
+ 's', MDB_OPT_UINTPTR_SET, &slot_set, &slot, NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (!slot_set) {
+ mdb_warn("-s is required\n");
+ return (DCMD_USAGE);
+ }
+
+ xmf.xmf_slot = (int)slot;
+ if (ep_set)
+ xmf.xmf_ep = (int)ep;
+ else
+ xmf.xmf_ep = -1;
+ xmf.xmf_addr = 0;
+
+ if (mdb_pwalk("xhci`xhci_device", xhci_mdb_find_device_cb,
+ &xmf, addr) == -1) {
+ mdb_warn("failed to walk xhci_device at %p", addr);
+ return (DCMD_ERR);
+ }
+
+ if (xmf.xmf_addr == 0) {
+ if (ep_set) {
+ mdb_warn("failed to find xhci_endpoint_t for slot %d "
+ "and endpoint %d\n", slot, ep);
+ } else {
+ mdb_warn("failed to find xhci_device_t for slot %d\n",
+ slot);
+ }
+ return (DCMD_ERR);
+ }
+
+ mdb_printf("%p\n", xmf.xmf_addr);
+ return (DCMD_OK);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_endpoint_count(uintptr_t addr, const void *ep, void *arg)
+{
+ int *countp = arg;
+
+ *countp += 1;
+ return (WALK_NEXT);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_endpoint_summary(uintptr_t addr, const void *ep, void *arg)
+{
+ const xhci_device_t *xd = arg;
+ const xhci_endpoint_t *xep = ep;
+ const char *type;
+ const char *state;
+ xhci_endpoint_context_t epctx;
+ int eptype;
+
+ if (mdb_vread(&epctx, sizeof (epctx),
+ (uintptr_t)xd->xd_endout[xep->xep_num]) != sizeof (epctx)) {
+ mdb_warn("failed to read endpoint context at %p",
+ xd->xd_endout[xep->xep_num]);
+ return (WALK_ERR);
+ }
+
+ eptype = XHCI_EPCTX_GET_EPTYPE(LE_32(epctx.xec_info2));
+ type = xhci_mdb_epctx_eptypes[eptype];
+ state = xhci_mdb_epctx_states[XHCI_EPCTX_STATE(LE_32(epctx.xec_info))];
+
+ mdb_printf("%-4d %-10s %-10s 0x%-04x 0x%-04x\n", xep->xep_num, type,
+ state, xep->xep_ring.xr_head, xep->xep_ring.xr_tail);
+
+ return (WALK_NEXT);
+}
+
+/* ARGSUSED */
+static int
+xhci_mdb_print_device(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ int count;
+ xhci_device_t xd;
+ usba_device_t ud;
+ char product[256], mfg[256];
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ return (mdb_eval("::walk xhci`xhci | ::walk xhci`xhci_device | "
+ "::xhci_device"));
+ }
+
+ if (mdb_vread(&xd, sizeof (xd), addr) != sizeof (xd)) {
+ mdb_warn("failed to read xhci_device_t at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+ if (mdb_vread(&ud, sizeof (ud), (uintptr_t)xd.xd_usbdev) !=
+ sizeof (ud)) {
+ mdb_warn("failed to read usba_device_t at %p\n", xd.xd_usbdev);
+ return (DCMD_ERR);
+ }
+
+ if (ud.usb_mfg_str == NULL || mdb_readstr(mfg, sizeof (mfg),
+ (uintptr_t)ud.usb_mfg_str) <= 0) {
+ (void) strlcpy(mfg, "Unknown Manufacturer", sizeof (mfg));
+ }
+
+ if (ud.usb_product_str == NULL || mdb_readstr(product, sizeof (product),
+ (uintptr_t)ud.usb_product_str) <= 0) {
+ (void) strlcpy(product, "Unknown Product", sizeof (product));
+ }
+
+ mdb_printf("%<b>%s - %s%</b>\n", mfg, product);
+
+ count = 0;
+ if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_endpoint_count, &count,
+ addr) == -1) {
+ mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+ mdb_printf("Port %02d | Slot %02d | # Endpoints %02d\n", xd.xd_port,
+ xd.xd_slot, count);
+ mdb_printf("%<u>%-4s %-10s %-10s %-6s %-6s%</u>\n", "EP", "Type",
+ "State", "Head", "Tail");
+
+ if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_print_endpoint_summary,
+ &xd, addr) == -1) {
+ mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
+ return (DCMD_ERR);
+ }
+
+
+ mdb_printf("\n");
+
+ return (DCMD_OK);
+}
+
+static int
+xhci_mdb_find_trb(uintptr_t addr, uint_t flags, int argc,
+ const mdb_arg_t *argv)
+{
+ xhci_ring_t xr;
+ uint64_t base, max, target;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ mdb_warn("missing required xhci_ring_t\n");
+ return (DCMD_USAGE);
+ }
+
+ if (argc == 0) {
+ mdb_warn("missing required PA of ring\n");
+ return (DCMD_USAGE);
+ }
+
+ if (argc > 1) {
+ mdb_warn("too many arguments\n");
+ return (DCMD_USAGE);
+ }
+
+ if (mdb_vread(&xr, sizeof (xr), addr) != sizeof (xr)) {
+ mdb_warn("failed to read xhci_ring_t at %p", addr);
+ return (DCMD_USAGE);
+ }
+
+ if (argv[0].a_type == MDB_TYPE_IMMEDIATE) {
+ target = argv[0].a_un.a_val;
+ } else if (argv[0].a_type == MDB_TYPE_STRING) {
+ target = mdb_strtoull(argv[0].a_un.a_str);
+ } else {
+ mdb_warn("argument is an unknown supported type: %d\n",
+ argv[0].a_type);
+ return (DCMD_USAGE);
+ }
+ target = roundup(target, sizeof (xhci_trb_t));
+
+ base = xr.xr_dma.xdb_cookies[0].dmac_laddress;
+ max = base + xr.xr_ntrb * sizeof (xhci_trb_t);
+
+ if (target < base || target > max) {
+ mdb_warn("target address %p is outside the range of PAs for "
+ "TRBs in the ring [%p, %p)", target, base, max);
+ return (DCMD_ERR);
+ }
+ target -= base;
+ mdb_printf("0x%" PRIx64 "\n", target + (uintptr_t)xr.xr_trb);
+
+ return (DCMD_OK);
+}
+
+static const mdb_dcmd_t xhci_dcmds[] = {
+ { "xhci_epctx", ":", "print endpoint context",
+ xhci_mdb_print_epctx, NULL },
+ { "xhci_slotctx", ":", "print slot context",
+ xhci_mdb_print_slotctx, NULL },
+ { "xhci_trb", ":", "print TRB",
+ xhci_mdb_print_trb, NULL },
+ { "xhci_find", ": -s slot [-e endpiont]",
+ "find given xhci slot or endpoint",
+ xhci_mdb_find, NULL },
+ { "xhci_device", ":", "device summary",
+ xhci_mdb_print_device, NULL },
+ { "xhci_find_trb", ": pa", "find trb with PA in ring",
+ xhci_mdb_find_trb, NULL },
+ { NULL }
+};
+
+static const mdb_walker_t xhci_walkers[] = {
+ { "xhci", "walk list of xhci_t structures",
+ xhci_mdb_walk_xhci_init, xhci_mdb_walk_xhci_step, NULL },
+ { "xhci_device", "walk list of xhci_device_t structures",
+ xhci_mdb_walk_xhci_device_init, xhci_mdb_walk_xhci_device_step,
+ NULL },
+ { "xhci_endpoint", "walk list of xhci_endpoint_t structures",
+ xhci_mdb_walk_xhci_endpoint_init, xhci_mdb_walk_xhci_endpoint_step,
+ NULL },
+ { NULL }
+};
+
+static const mdb_modinfo_t xhci_modinfo = {
+ MDB_API_VERSION, xhci_dcmds, xhci_walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+ return (&xhci_modinfo);
+}