Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions soc/intel/intel_adsp/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
25 changes: 17 additions & 8 deletions soc/intel/intel_adsp/common/include/adsp_debug_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,6 @@
#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 @@ -94,6 +86,21 @@ 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_PAGE0_SLOT_OFFSET -
Expand All @@ -108,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
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
22 changes: 22 additions & 0 deletions subsys/logging/backends/log_backend_adsp_mtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,41 @@ struct adsp_debug_slot {
uint8_t data[ADSP_DW_SLOT_SIZE - sizeof(uint32_t) * 2];
} __packed;

#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
static struct adsp_debug_slot *slot;
#endif

static void mtrace_init(void)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
struct adsp_dw_desc slot_desc = { .type = MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE), };

if (slot) {
return;
}

slot = (struct adsp_debug_slot *)adsp_dw_request_slot(&slot_desc, NULL);
#else
if (ADSP_DW->descs[ADSP_DW_SLOT_NUM_MTRACE].type == MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE)) {
return;
}

ADSP_DW->descs[ADSP_DW_SLOT_NUM_MTRACE].type = MTRACE_LOGGING_SLOT_TYPE(MTRACE_CORE);
#endif
}

static size_t mtrace_out(int8_t *str, size_t len, size_t *space_left)
{
#ifdef CONFIG_INTEL_ADSP_DEBUG_SLOT_MANAGER
/* Debug slot is not allocated */
if (!slot) {
return 0;
}
#else
struct adsp_debug_slot *slot = (struct adsp_debug_slot *)
ADSP_DW->slots[ADSP_DW_SLOT_NUM_MTRACE];
#endif

uint8_t *data = slot->data;
uint32_t r = slot->host_ptr;
uint32_t w = slot->dsp_ptr;
Expand Down
Loading