Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion soc/intel/intel_adsp/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ config MEMORY_WIN_1_SIZE

config MEMORY_WIN_2_SIZE
int "Size of memory window 2"
default 8192
default 12288
help
Size of memory window 2.

Expand All @@ -80,6 +80,15 @@ config MEMORY_WIN_3_SIZE

This window is used for trace.

config INTEL_ADSP_DEBUG_SLOT_MANAGER
bool "Debug slot manager"
help
If selected the debug slot allocation can be only done via
the manager API, direct debug window access and tampering is
forbidden.
The API use allows dynamic slot allocation instead of static
and error prone slot usage.

config ADSP_CLOCK
bool
help
Expand Down
4 changes: 4 additions & 0 deletions soc/intel/intel_adsp/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ zephyr_library_sources(

zephyr_library_sources_ifdef(CONFIG_ADSP_CLOCK clk.c)

zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
debug_window.c
)

if(CONFIG_SMP OR CONFIG_MP_MAX_NUM_CPUS GREATER 1)
zephyr_library_sources(multiprocessing.c)
endif()
Expand Down
158 changes: 158 additions & 0 deletions soc/intel/intel_adsp/common/debug_window.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/* Copyright (c) 2025 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#include <adsp_memory.h>
#include <adsp_debug_window.h>
#include <zephyr/cache.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(debug_window, CONFIG_SOC_LOG_LEVEL);

struct adsp_debug_window {
struct adsp_dw_desc descs[ADSP_DW_DESC_COUNT];
uint8_t reserved[ADSP_DW_PAGE0_SLOT_OFFSET -
ADSP_DW_DESC_COUNT * sizeof(struct adsp_dw_desc)];
uint8_t partial_page0[ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET];
uint8_t slots[ADSP_DW_SLOT_COUNT][ADSP_DW_SLOT_SIZE];
} __packed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confused - you already have this structure in adsp_debug_window.h?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is only there if the CONF_INTEL_ADSP_DEBUG_SLOT_MANAGER is not enabled.
No one should have any knowledge on how the debug window is partitioned, they just ask for a slot and use the slot which is assigned to them, that's all they need to know.

In other words: when the slot manager is enabled I want to make sure that no one can side step and hack into the system.


#define WIN2_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window2), memory))
#define WIN2_SLOTS ((HP_SRAM_WIN2_SIZE / ADSP_DW_PAGE_SIZE) - 1)
#define ADSP_DW_FULL_SLOTS MIN(WIN2_SLOTS, ADSP_DW_SLOT_COUNT)

#define ADSP_DW ((volatile struct adsp_debug_window *) \
(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \
(WIN2_MBASE + WIN2_OFFSET))))

static int adsp_dw_find_slot(uint32_t type, bool prefer_partial)
{
int i;

if (prefer_partial) {
if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == type) {
return ADSP_DW_SLOT_COUNT;
}
}

for (i = 0; i < ADSP_DW_FULL_SLOTS; i++) {
if (ADSP_DW->descs[i].type == type) {
return i;
}
}

if (!prefer_partial) {
if (ADSP_DW->descs[ADSP_DW_SLOT_COUNT].type == type) {
return ADSP_DW_SLOT_COUNT;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do I understand it correctly, that this function only returns a valid slot index if it already has the desired type? If so, then why the preference? We should never have 2 slots with the same type, so shouldn't matter what the preference is. Just search them all. I don't see a need for that parameter here at all.
Update: oh, I see, this function is also used to find an "unused" slot... That's where you need the preference. This function is called 3 times: twice to find an already allocated slot and once to find a free one. Maybe we could make looking for the existing one a separate function with no preference - even with braces with each if and for it should be like 10 lines of code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why would we want another function when we can use this? When looking for occupied slot with a given type, yes the preference does not matter, but we eventually still need to check the full slots and the partial anyways.


return -ENOENT;
}

volatile void *adsp_dw_request_slot(struct adsp_dw_desc *dw_desc, size_t *slot_size)
{
int slot_idx;

if (!dw_desc->type) {
return NULL;
}

/* Check if a slot have been allocated for this type */
slot_idx = adsp_dw_find_slot(dw_desc->type, !!slot_size);
if (slot_idx < 0) {
/* Look for an empty slot */
slot_idx = adsp_dw_find_slot(ADSP_DW_SLOT_UNUSED, !!slot_size);
if (slot_idx < 0) {
LOG_INF("No available slot for %#x", dw_desc->type);
return NULL;
}
}

ADSP_DW->descs[slot_idx].resource_id = dw_desc->resource_id;
ADSP_DW->descs[slot_idx].type = dw_desc->type;
ADSP_DW->descs[slot_idx].vma = dw_desc->vma;

if (slot_size) {
*slot_size = ADSP_DW_SLOT_SIZE;
}

if (slot_idx == ADSP_DW_SLOT_COUNT) {
if (slot_size) {
*slot_size -= ADSP_DW_PAGE0_SLOT_OFFSET;
}

LOG_DBG("Allocating partial page0 to be used for %#x", dw_desc->type);

return ADSP_DW->partial_page0;
}

LOG_DBG("Allocating debug slot %d to be used for %#x", slot_idx, dw_desc->type);

return ADSP_DW->slots[slot_idx];
}

volatile void *adsp_dw_seize_slot(uint32_t slot_index, struct adsp_dw_desc *dw_desc,
size_t *slot_size)
{
if ((slot_index >= ADSP_DW_FULL_SLOTS && slot_index != ADSP_DW_SLOT_COUNT) ||
!dw_desc->type) {
return NULL;
}

if (slot_index < ADSP_DW_FULL_SLOTS) {
if (ADSP_DW->descs[slot_index].type != ADSP_DW_SLOT_UNUSED) {
LOG_INF("Overtaking debug slot %d, used by %#x for %#x", slot_index,
ADSP_DW->descs[slot_index].type, dw_desc->type);
}

if (slot_size) {
*slot_size = ADSP_DW_SLOT_SIZE;
}

ADSP_DW->descs[slot_index].resource_id = dw_desc->resource_id;
ADSP_DW->descs[slot_index].type = dw_desc->type;
ADSP_DW->descs[slot_index].vma = dw_desc->vma;

return ADSP_DW->slots[slot_index];
}

/* The caller is not prepared to handle partial debug slot */
if (!slot_size) {
return NULL;
}

if (ADSP_DW->descs[slot_index].type != ADSP_DW_SLOT_UNUSED) {
LOG_INF("Overtaking partial page0, used by %#x for %#x",
ADSP_DW->descs[slot_index].type, dw_desc->type);
}

*slot_size = ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET;

ADSP_DW->descs[slot_index].resource_id = dw_desc->resource_id;
ADSP_DW->descs[slot_index].type = dw_desc->type;
ADSP_DW->descs[slot_index].vma = dw_desc->vma;

return ADSP_DW->partial_page0;
}

void adsp_dw_release_slot(uint32_t type)
{
int slot_idx;

slot_idx = adsp_dw_find_slot(type, true);

if (slot_idx < 0) {
return;
}

if (slot_idx == ADSP_DW_SLOT_COUNT) {
LOG_DBG("Releasing partial page0 used by %#x", type);
} else {
LOG_DBG("Releasing debug slot %d used by %#x", slot_idx, type);
}

ADSP_DW->descs[slot_idx].resource_id = 0;
ADSP_DW->descs[slot_idx].type = ADSP_DW_SLOT_UNUSED;
ADSP_DW->descs[slot_idx].vma = 0;
}
24 changes: 24 additions & 0 deletions soc/intel/intel_adsp/common/gdbstub_backend_sram.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,25 @@ static inline int ring_have_data(const volatile struct gdb_sram_ring *ring)
return ring->head != ring->tail;
}

#ifndef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
#define RX_UNCACHED (uint8_t *) (HP_SRAM_WIN2_BASE + SOF_GDB_WINDOW_OFFSET)
#define TX_UNCACHED (uint8_t *) (RX_UNCACHED + sizeof(struct gdb_sram_ring))
#endif

static volatile struct gdb_sram_ring *rx;
static volatile struct gdb_sram_ring *tx;

void z_gdb_backend_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
__ASSERT_NO_MSG(rx && tx);
#else
__ASSERT_NO_MSG(sizeof(ADSP_DW->descs) <= SOF_GDB_WINDOW_OFFSET);

rx = sys_cache_uncached_ptr_get(RX_UNCACHED);
tx = sys_cache_uncached_ptr_get(TX_UNCACHED);
#endif

rx->head = rx->tail = 0;
tx->head = tx->tail = 0;
}
Expand Down Expand Up @@ -96,7 +103,24 @@ unsigned char z_gdb_getchar(void)

static int gdbstub_backend_sram_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_GDB_STUB, };
size_t slot_size;
char *slot_addr;

/* Force use the partial page0 slot */
slot_addr = (char *)adsp_dw_request_slot(&slot_desc, &slot_size);

if (!slot_addr) {
return -ENOMEM;
}

rx = sys_cache_uncached_ptr_get(slot_addr);
tx = sys_cache_uncached_ptr_get(slot_addr + sizeof(struct gdb_sram_ring));
#else
ADSP_DW->descs[ADSP_DW_SLOT_NUM_GDB].type = ADSP_DW_SLOT_GDB_STUB;
#endif

return 0;
}

Expand Down
52 changes: 43 additions & 9 deletions soc/intel/intel_adsp/common/include/adsp_debug_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,36 @@
* u32 res_id;
* u32 type;
* u32 vma;
*
* The descriptor layout is:
*
* --------------------
* | Desc0 - slot0 |
* --------------------
* | Desc1 - slot1 |
* --------------------
* | Desc2 - slot2 |
* --------------------
* | ... |
* --------------------
* | Desc13 - slot13 |
* --------------------
* | Desc14 - slot14 |
* --------------------
*
* Additional descriptor to descibe the function of the partial slot at page0:
*
* --------------------------
* | Desc15 - page0 + 1024 |
* --------------------------
*/

#define ADSP_DW_PAGE_SIZE 0x1000
#define ADSP_DW_SLOT_SIZE ADSP_DW_PAGE_SIZE
#define ADSP_DW_SLOT_COUNT 15
#define ADSP_DW_PAGE0_SLOT_OFFSET 1024
#define ADSP_DW_DESC_COUNT (ADSP_DW_SLOT_COUNT + 1)

/* debug window slots usage, mutually exclusive options can reuse slots */
#define ADSP_DW_SLOT_NUM_SHELL 0
#define ADSP_DW_SLOT_NUM_MTRACE 0
#define ADSP_DW_SLOT_NUM_TRACE 1
#define ADSP_DW_SLOT_NUM_TELEMETRY 1
/* this uses remaining space in the first page after descriptors */
#define ADSP_DW_SLOT_NUM_GDB (ADSP_DW_DESC_COUNT - 1)

/* debug log slot types */
#define ADSP_DW_SLOT_UNUSED 0x00000000
#define ADSP_DW_SLOT_CRITICAL_LOG 0x54524300
Expand All @@ -71,9 +86,26 @@ struct adsp_dw_desc {
uint32_t vma;
} __packed;

#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
volatile void *adsp_dw_request_slot(struct adsp_dw_desc *dw_desc, size_t *slot_size);
volatile void *adsp_dw_seize_slot(uint32_t slot_index, struct adsp_dw_desc *dw_desc,
size_t *slot_size);
void adsp_dw_release_slot(uint32_t type);
#else /* CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER */

/* debug window slots usage, mutually exclusive options can reuse slots */
#define ADSP_DW_SLOT_NUM_SHELL 0
#define ADSP_DW_SLOT_NUM_MTRACE 0
#define ADSP_DW_SLOT_NUM_TRACE 1
#define ADSP_DW_SLOT_NUM_TELEMETRY 1
/* this uses remaining space in the first page after descriptors */
#define ADSP_DW_SLOT_NUM_GDB (ADSP_DW_DESC_COUNT - 1)

struct adsp_debug_window {
struct adsp_dw_desc descs[ADSP_DW_DESC_COUNT];
uint8_t reserved[ADSP_DW_SLOT_SIZE - ADSP_DW_DESC_COUNT * sizeof(struct adsp_dw_desc)];
uint8_t reserved[ADSP_DW_PAGE0_SLOT_OFFSET -
ADSP_DW_DESC_COUNT * sizeof(struct adsp_dw_desc)];
uint8_t partial_page0[ADSP_DW_SLOT_SIZE - ADSP_DW_PAGE0_SLOT_OFFSET];
uint8_t slots[ADSP_DW_SLOT_COUNT][ADSP_DW_SLOT_SIZE];
} __packed;

Expand All @@ -83,4 +115,6 @@ struct adsp_debug_window {
(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \
(WIN2_MBASE + WIN2_OFFSET))))

#endif /* CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER */

#endif
3 changes: 2 additions & 1 deletion soc/intel/intel_adsp/tools/cavstool.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

DEBUG_SLOT_SIZE = 4096
DEBUG_SLOT_SHELL = 0
DEBUG_SLOT_SHELL_TYPE = 0x73686c6c
SHELL_RX_SIZE = 256
SHELL_MAX_VALID_SLOT_SIZE = 16777216

Expand Down Expand Up @@ -769,7 +770,7 @@ def debug_slot_offset_by_type(the_type, timeout_s=0.2):
return None

def shell_base_offset():
return debug_offset() + DEBUG_SLOT_SIZE * (1 + DEBUG_SLOT_SHELL)
return debug_slot_offset_by_type(DEBUG_SLOT_SHELL_TYPE)

def read_from_shell_memwindow_winstream(last_seq):
offset = shell_base_offset() + SHELL_RX_SIZE
Expand Down
29 changes: 27 additions & 2 deletions subsys/debug/coredump/coredump_backend_intel_adsp_mem_window.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,27 @@ LOG_MODULE_REGISTER(coredump, CONFIG_DEBUG_COREDUMP_LOG_LEVEL);
static int error;
static uint32_t mem_wptr;

#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
static void *coredump_slot_addr;
#endif

static void coredump_mem_window_backend_start(void)
{
/* Reset error & mem write ptr */
error = 0;
mem_wptr = 0;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = ADSP_DW_SLOT_TELEMETRY, };

/* Forcably take debug slot 1 */
coredump_slot_addr = (void *)adsp_dw_seize_slot(1, &slot_desc, NULL);
if (!coredump_slot_addr) {
/* Try to get the first slot if slot 1 is not available as fallback */
coredump_slot_addr = (void *)adsp_dw_seize_slot(0, &slot_desc, NULL);
}
#else
ADSP_DW->descs[1].type = ADSP_DW_SLOT_TELEMETRY;
#endif

while (LOG_PROCESS()) {
;
Expand All @@ -46,10 +61,20 @@ static void coredump_mem_window_backend_end(void)

static void coredump_mem_window_backend_buffer_output(uint8_t *buf, size_t buflen)
{
uint32_t *mem_window_separator = (uint32_t *)(ADSP_DW->slots[1]);
uint8_t *mem_window_sink = (uint8_t *)(ADSP_DW->slots[1]) + 4 + mem_wptr;
uint8_t *coredump_data = buf;
size_t data_left;
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
uint32_t *mem_window_separator = (uint32_t *)coredump_slot_addr;
uint8_t *mem_window_sink = (uint8_t *)coredump_slot_addr + 4 + mem_wptr;

if (!coredump_slot_addr) {
return;
}
#else
uint32_t *mem_window_separator = (uint32_t *)(ADSP_DW->slots[1]);
uint8_t *mem_window_sink = (uint8_t *)(ADSP_DW->slots[1]) + 4 + mem_wptr;
#endif

/* Default place for telemetry dump is in memory window. Each data is easily find using
* separator. For telemetry that separator is 0x0DEC0DEB.
*/
Expand Down
Loading