Skip to content

Commit b8a1121

Browse files
committed
shell: add mailbox_hex and dbgwin_dump commands
Add two new SOF shell commands for poking at SRAM diagnostics regions from the live shell, without host-side tooling. sof mailbox_hex - list the four SOF mailbox regions (exception, dspbox, hostbox, debug) sof mailbox_hex <region> [off] [len] - hex-dump that region; off and len are clamped to the region size, default 256B sof dbgwin_dump - list all 15 ADSP debug- window slot descriptors (resource_id, type, vma, decoded type name, core) sof dbgwin_dump <slot> [len] - hex-dump one slot, max ADSP_DW_SLOT_SIZE (=4096) mailbox_hex uses the existing MAILBOX_*_BASE/SIZE macros from sof/lib/mailbox.h. dbgwin_dump re-derives window 2 base from the device tree (mem_window2) plus WIN2_OFFSET and mirrors struct adsp_debug_window from zephyr/soc/intel/intel_adsp/common/debug_window.c, accessed through an uncached pointer so it works whether or not CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER=y. Both commands share a small sof_shell_hex_dump() helper. Two new Kconfigs (default y): CONFIG_SOF_SHELL_MAILBOX_HEX CONFIG_SOF_SHELL_DBGWIN_DUMP (depends on SOC_FAMILY_INTEL_ADSP) Quick-win 5 was originally listed as crash_log/bt; pivoted because SOF's in-tree panic_dump() is not compiled on Zephyr (Zephyr installs its own fatal handler) and a live shell cannot backtrace its own CPU after a panic. mailbox_hex exception still surfaces whatever the platform-specific fatal path leaves there, covering the same diagnostic intent as far as is possible from a running shell. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 2482f44 commit b8a1121

3 files changed

Lines changed: 282 additions & 2 deletions

File tree

zephyr/Kconfig

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,33 @@ config SOF_SHELL_MTRACE_DUMP
517517
receive every byte. Useful when no host driver is attached
518518
(e.g. early bring-up over UART shell only).
519519

520+
config SOF_SHELL_MAILBOX_HEX
521+
bool "Hex-dump SOF mailbox regions"
522+
default y
523+
depends on SHELL
524+
help
525+
Enables 'sof mailbox_hex <region> [offset] [length]' which hex
526+
dumps one of the SOF mailbox regions (exception, dspbox, hostbox,
527+
debug). With no arguments lists the regions and their sizes. The
528+
length is clamped to the region size; default 256 bytes.
529+
530+
Useful for inspecting the panic dump area after a fatal error and
531+
for low-level IPC payload debugging.
532+
533+
config SOF_SHELL_DBGWIN_DUMP
534+
bool "Hex-dump ADSP debug-window slots"
535+
default y
536+
depends on SHELL && SOC_FAMILY_INTEL_ADSP
537+
help
538+
Enables 'sof dbgwin_dump [slot] [length]' which lists the
539+
descriptors of all ADSP debug-window slots (slot manager
540+
metadata in window 2 page 0) with a friendly type name, and
541+
hex-dumps the slot contents when a slot index is given.
542+
543+
This makes it possible to peek at gdb_stub, telemetry,
544+
critical_log, broken-marker and other slots from the shell
545+
without host-side tooling.
546+
520547
endmenu # SOF shell commands
521548

522549
config SOF_VREGIONS

zephyr/shell.md

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ debug or testing. Items get ticked off as commands land on `topic/shell`.
9090
| Logging / trace | `log_status`, `mtrace_dump` (snapshot) | **DONE (task 4)** &mdash; runtime per-source `log_level` deferred (needs `CONFIG_LOG_RUNTIME_FILTERING`, see notes) |
9191
| Telemetry / perf | `perf_status`, `perf_reset`, `cpu_load` | TODO |
9292
| Notifications | `notify_subscribers`, `notify_stats` | TODO |
93-
| Debug window / mailbox | `dbgwin_dump <slot>`, `mailbox_hex` | TODO |
93+
| **Debug window / mailbox** | `dbgwin_dump <slot>`, `mailbox_hex` | **DONE (task 5)** |
9494
| Crash / panic | `crash_log`, `crash_clear`, `panic_info`, `bt`, `regs` | TODO |
9595
| Heap walk | `heap_walk <zone>`, `heap_blocks`, `obj_pool_stats` | TODO |
9696
| Probes | `probe_init`, `probe_add <buf_id>`, `probe_remove`, `probe_dma_status` | TODO |
@@ -113,7 +113,7 @@ debug or testing. Items get ticked off as commands land on `topic/shell`.
113113
2. **`buffer_list` / `buffer_info`** &mdash; DONE.
114114
3. **`sched_tasks` / `sched_load`** &mdash; DONE.
115115
4. **`log_status` / `mtrace_dump`** &mdash; DONE.
116-
5. `crash_log` / `bt` &mdash; pair with the `crash-*` artifacts in the tree.
116+
5. **`mailbox_hex` / `dbgwin_dump`** &mdash; DONE (was originally `crash_log`/`bt`; pivoted because SOF panic.c isn't built on Zephyr and `bt` of a running CPU from itself isn't meaningful).
117117
6. `perf_status` &mdash; wraps SOF telemetry counters.
118118
7. `dai_list` / `dma_chan_status` &mdash; link/DMA blind spot.
119119
8. `kctl_get/set` &mdash; today only doable via tplg/IPC.
@@ -265,3 +265,47 @@ debug or testing. Items get ticked off as commands land on `topic/shell`.
265265
future option could format output in pages or filter by severity.
266266
- A `mtrace_dump --consume` mode (advance `host_ptr`) is intentionally
267267
not provided to avoid silently breaking host-side tooling.
268+
269+
## Task 5 &mdash; `mailbox_hex` / `dbgwin_dump`
270+
271+
### Commands
272+
273+
| Command | Description |
274+
|---|---|
275+
| `sof mailbox_hex` | List the four SOF mailbox regions (exception, dspbox, hostbox, debug) with their base address and size. |
276+
| `sof mailbox_hex <region> [off] [len]` | Hex-dump a mailbox region; offset and length are clamped to the region size. Default length 256 bytes. |
277+
| `sof dbgwin_dump` | List all 15 ADSP debug-window slot descriptors (resource_id, type, vma, decoded type name, core). |
278+
| `sof dbgwin_dump <slot> [len]` | Hex-dump a single slot (max `ADSP_DW_SLOT_SIZE` = 4096 bytes); default length 256. |
279+
280+
### Implementation
281+
282+
- `mailbox_hex` uses the `MAILBOX_*_BASE` / `MAILBOX_*_SIZE` macros
283+
from [src/include/sof/lib/mailbox.h](src/include/sof/lib/mailbox.h);
284+
the four region records are a static table.
285+
- `dbgwin_dump` re-derives the window 2 base from the device tree
286+
(`mem_window2`) plus `WIN2_OFFSET`, mirrors
287+
`struct adsp_debug_window` from
288+
[zephyr/soc/intel/intel_adsp/common/debug_window.c](../../zephyr/soc/intel/intel_adsp/common/debug_window.c)
289+
and reads through an uncached pointer so we always see the
290+
slot-manager state (works whether or not
291+
`CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER=y`).
292+
- A small shared `sof_shell_hex_dump()` helper handles the 16-byte
293+
hex+ASCII rows and is built whenever either command is enabled.
294+
- Two new Kconfigs (default `y`):
295+
- `CONFIG_SOF_SHELL_MAILBOX_HEX`
296+
- `CONFIG_SOF_SHELL_DBGWIN_DUMP` (depends on `SOC_FAMILY_INTEL_ADSP`)
297+
- Shell commands in [zephyr/sof_shell.c](zephyr/sof_shell.c).
298+
299+
### Notes / follow-ups
300+
301+
- The original quick-win was `crash_log`/`bt`; pivoted because SOF's
302+
in-tree `panic_dump()` is not compiled on Zephyr (Zephyr installs
303+
its own fatal handler) and a running shell can't backtrace its own
304+
CPU after a panic. `mailbox_hex exception` still surfaces whatever
305+
the platform-specific fatal path leaves there, so the same
306+
diagnostic intent is covered as far as it can be from a live shell.
307+
- A future `panic_decode` could parse a known on-target oops layout
308+
(Zephyr coredump or telemetry slot) once one is standardised on
309+
ACE.
310+
- `dbgwin_dump` is read-only. We do not implement a write/seize
311+
command to avoid corrupting host-visible state.

zephyr/sof_shell.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,203 @@ __cold static int cmd_sof_mtrace_dump(const struct shell *sh,
19501950

19511951
#endif /* CONFIG_SOF_SHELL_MTRACE_DUMP */
19521952

1953+
#if CONFIG_SOF_SHELL_MAILBOX_HEX || CONFIG_SOF_SHELL_DBGWIN_DUMP
1954+
1955+
static void sof_shell_hex_dump(const struct shell *sh, uintptr_t base,
1956+
size_t off, size_t len)
1957+
{
1958+
const uint8_t *p = (const uint8_t *)(base + off);
1959+
size_t i, j;
1960+
1961+
for (i = 0; i < len; i += 16) {
1962+
size_t row = MIN((size_t)16, len - i);
1963+
char ascii[17];
1964+
1965+
shell_fprintf(sh, SHELL_NORMAL, "%08lx ",
1966+
(unsigned long)(off + i));
1967+
for (j = 0; j < 16; j++) {
1968+
if (j < row)
1969+
shell_fprintf(sh, SHELL_NORMAL, " %02x", p[i + j]);
1970+
else
1971+
shell_fprintf(sh, SHELL_NORMAL, " ");
1972+
ascii[j] = (j < row && p[i + j] >= 0x20 && p[i + j] < 0x7f) ?
1973+
(char)p[i + j] : '.';
1974+
}
1975+
ascii[16] = '\0';
1976+
shell_fprintf(sh, SHELL_NORMAL, " %s\n", ascii);
1977+
}
1978+
}
1979+
1980+
#endif
1981+
1982+
#if CONFIG_SOF_SHELL_MAILBOX_HEX
1983+
1984+
#include <sof/lib/mailbox.h>
1985+
1986+
struct sof_shell_mb_region {
1987+
const char *name;
1988+
uintptr_t base;
1989+
size_t size;
1990+
};
1991+
1992+
static const struct sof_shell_mb_region sof_shell_mb_regions[] = {
1993+
{ "exception", MAILBOX_EXCEPTION_BASE, MAILBOX_EXCEPTION_SIZE },
1994+
{ "dspbox", MAILBOX_DSPBOX_BASE, MAILBOX_DSPBOX_SIZE },
1995+
{ "hostbox", MAILBOX_HOSTBOX_BASE, MAILBOX_HOSTBOX_SIZE },
1996+
{ "debug", MAILBOX_DEBUG_BASE, MAILBOX_DEBUG_SIZE },
1997+
};
1998+
1999+
__cold static int cmd_sof_mailbox_hex(const struct shell *sh,
2000+
size_t argc, char *argv[])
2001+
{
2002+
const struct sof_shell_mb_region *r = NULL;
2003+
size_t off = 0, len;
2004+
char *end = NULL;
2005+
int i;
2006+
2007+
if (argc < 2) {
2008+
shell_print(sh, "Mailbox regions:");
2009+
for (i = 0; i < ARRAY_SIZE(sof_shell_mb_regions); i++)
2010+
shell_print(sh, " %-10s base 0x%08lx size %zu",
2011+
sof_shell_mb_regions[i].name,
2012+
(unsigned long)sof_shell_mb_regions[i].base,
2013+
sof_shell_mb_regions[i].size);
2014+
shell_print(sh, "Usage: sof mailbox_hex <region> [offset] [length]");
2015+
return 0;
2016+
}
2017+
2018+
for (i = 0; i < ARRAY_SIZE(sof_shell_mb_regions); i++) {
2019+
if (!strcmp(argv[1], sof_shell_mb_regions[i].name)) {
2020+
r = &sof_shell_mb_regions[i];
2021+
break;
2022+
}
2023+
}
2024+
if (!r) {
2025+
shell_print(sh, "Unknown region '%s'", argv[1]);
2026+
return -EINVAL;
2027+
}
2028+
2029+
if (argc > 2) {
2030+
off = strtoul(argv[2], &end, 0);
2031+
if (end == argv[2] || off >= r->size) {
2032+
shell_print(sh, "Bad offset (max 0x%zx)", r->size);
2033+
return -EINVAL;
2034+
}
2035+
}
2036+
2037+
len = MIN((size_t)256, r->size - off);
2038+
if (argc > 3) {
2039+
len = strtoul(argv[3], &end, 0);
2040+
if (end == argv[3])
2041+
return -EINVAL;
2042+
len = MIN(len, r->size - off);
2043+
}
2044+
2045+
shell_print(sh, "%s @ 0x%08lx + 0x%zx, %zu bytes:",
2046+
r->name, (unsigned long)r->base, off, len);
2047+
sof_shell_hex_dump(sh, r->base, off, len);
2048+
return 0;
2049+
}
2050+
2051+
#endif /* CONFIG_SOF_SHELL_MAILBOX_HEX */
2052+
2053+
#if CONFIG_SOF_SHELL_DBGWIN_DUMP
2054+
2055+
#include <adsp_memory.h>
2056+
#include <adsp_debug_window.h>
2057+
2058+
/* Mirror struct used by zephyr/soc/intel/intel_adsp/common/debug_window.c.
2059+
* We map window 2 directly so we can read descriptors and slot data without
2060+
* depending on slot-manager internals.
2061+
*/
2062+
struct sof_shell_dw {
2063+
struct adsp_dw_desc descs[ADSP_DW_DESC_COUNT];
2064+
uint8_t reserved[ADSP_DW_PAGE0_SLOT_OFFSET -
2065+
ADSP_DW_DESC_COUNT * sizeof(struct adsp_dw_desc)];
2066+
uint8_t partial_page0[ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET];
2067+
uint8_t slots[ADSP_DW_SLOT_COUNT][ADSP_DW_SLOT_SIZE];
2068+
} __packed;
2069+
2070+
#define SOF_SHELL_DW_BASE \
2071+
(DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window2), memory)) + WIN2_OFFSET)
2072+
2073+
static const char *dw_type_name(uint32_t type)
2074+
{
2075+
switch (type & ADSP_DW_SLOT_TYPE_MASK) {
2076+
case ADSP_DW_SLOT_UNUSED & ADSP_DW_SLOT_TYPE_MASK:
2077+
return type ? "?" : "unused";
2078+
case ADSP_DW_SLOT_CRITICAL_LOG & ADSP_DW_SLOT_TYPE_MASK:
2079+
return "critical_log";
2080+
case ADSP_DW_SLOT_DEBUG_LOG & ADSP_DW_SLOT_TYPE_MASK:
2081+
return "debug_log";
2082+
case ADSP_DW_SLOT_GDB_STUB & ADSP_DW_SLOT_TYPE_MASK:
2083+
return "gdb_stub";
2084+
case ADSP_DW_SLOT_TELEMETRY & ADSP_DW_SLOT_TYPE_MASK:
2085+
return "telemetry";
2086+
case ADSP_DW_SLOT_TRACE & ADSP_DW_SLOT_TYPE_MASK:
2087+
return "trace";
2088+
case ADSP_DW_SLOT_SHELL & ADSP_DW_SLOT_TYPE_MASK:
2089+
return "shell";
2090+
case ADSP_DW_SLOT_DEBUG_STREAM & ADSP_DW_SLOT_TYPE_MASK:
2091+
return "debug_stream";
2092+
case ADSP_DW_SLOT_BROKEN & ADSP_DW_SLOT_TYPE_MASK:
2093+
return "broken";
2094+
default:
2095+
return "?";
2096+
}
2097+
}
2098+
2099+
__cold static int cmd_sof_dbgwin_dump(const struct shell *sh,
2100+
size_t argc, char *argv[])
2101+
{
2102+
volatile struct sof_shell_dw *dw =
2103+
(volatile struct sof_shell_dw *)
2104+
sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)
2105+
SOF_SHELL_DW_BASE);
2106+
int slot, i;
2107+
size_t len = 256;
2108+
char *end = NULL;
2109+
2110+
if (argc < 2) {
2111+
shell_print(sh,
2112+
"ADSP debug window @ 0x%08lx (%d slots, %u bytes each)",
2113+
(unsigned long)SOF_SHELL_DW_BASE,
2114+
ADSP_DW_SLOT_COUNT, ADSP_DW_SLOT_SIZE);
2115+
shell_print(sh, " slot res_id type vma name");
2116+
for (i = 0; i < ADSP_DW_SLOT_COUNT; i++) {
2117+
shell_print(sh,
2118+
" %3d 0x%08x 0x%08x 0x%08x %s (core %u)",
2119+
i, dw->descs[i].resource_id, dw->descs[i].type,
2120+
dw->descs[i].vma, dw_type_name(dw->descs[i].type),
2121+
dw->descs[i].type & ADSP_DW_SLOT_CORE_MASK);
2122+
}
2123+
shell_print(sh, "Usage: sof dbgwin_dump <slot> [length]");
2124+
return 0;
2125+
}
2126+
2127+
slot = strtol(argv[1], &end, 0);
2128+
if (end == argv[1] || slot < 0 || slot >= ADSP_DW_SLOT_COUNT) {
2129+
shell_print(sh, "Bad slot (0..%d)", ADSP_DW_SLOT_COUNT - 1);
2130+
return -EINVAL;
2131+
}
2132+
2133+
if (argc > 2) {
2134+
len = strtoul(argv[2], &end, 0);
2135+
if (end == argv[2])
2136+
return -EINVAL;
2137+
}
2138+
len = MIN(len, (size_t)ADSP_DW_SLOT_SIZE);
2139+
2140+
shell_print(sh, "Slot %d type=0x%08x (%s, core %u) vma=0x%08x; %zu bytes:",
2141+
slot, dw->descs[slot].type, dw_type_name(dw->descs[slot].type),
2142+
dw->descs[slot].type & ADSP_DW_SLOT_CORE_MASK,
2143+
dw->descs[slot].vma, len);
2144+
sof_shell_hex_dump(sh, (uintptr_t)dw->slots[slot], 0, len);
2145+
return 0;
2146+
}
2147+
2148+
#endif /* CONFIG_SOF_SHELL_DBGWIN_DUMP */
2149+
19532150
SHELL_STATIC_SUBCMD_SET_CREATE(sof_commands,
19542151
SHELL_CMD(test_inject_sched_gap, NULL,
19552152
"Inject a gap to audio scheduling\n",
@@ -2138,6 +2335,18 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sof_commands,
21382335
cmd_sof_mtrace_dump),
21392336
#endif
21402337

2338+
#if CONFIG_SOF_SHELL_MAILBOX_HEX
2339+
SHELL_CMD_ARG(mailbox_hex, NULL,
2340+
"Hex-dump a mailbox region: <region> [offset] [length]\n",
2341+
cmd_sof_mailbox_hex, 1, 3),
2342+
#endif
2343+
2344+
#if CONFIG_SOF_SHELL_DBGWIN_DUMP
2345+
SHELL_CMD_ARG(dbgwin_dump, NULL,
2346+
"List ADSP debug-window slots, or hex-dump one: [slot] [length]\n",
2347+
cmd_sof_dbgwin_dump, 1, 2),
2348+
#endif
2349+
21412350
SHELL_SUBCMD_SET_END
21422351
);
21432352

0 commit comments

Comments
 (0)