From 359584a494fde0cc66e6b5dce36c1c038d33d0fc Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Mon, 2 Mar 2026 14:18:45 +0100 Subject: [PATCH 1/2] fast-get: add error logging for access grant failures Add LOG_ERR messages when memory partition grants fail to improve debuggability of userspace access issues. Signed-off-by: Tomasz Leman --- zephyr/lib/fast-get.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zephyr/lib/fast-get.c b/zephyr/lib/fast-get.c index a7d23f999120..500055c99816 100644 --- a/zephyr/lib/fast-get.c +++ b/zephyr/lib/fast-get.c @@ -194,6 +194,7 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size) int err = fast_get_access_grant(k_current_get(), ret, size); if (err < 0) { + LOG_ERR("failed to grant additional access err=%d", err); ret = NULL; goto out; } @@ -233,6 +234,7 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size) int err = fast_get_access_grant(entry->thread, ret, size); if (err < 0) { + LOG_ERR("failed to grant access err=%d", err); sof_heap_free(NULL, ret); ret = NULL; goto out; From e02ab4d93f837e255eb0164a26bc8d6a0f9fcb49 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Mon, 2 Mar 2026 14:23:16 +0100 Subject: [PATCH 2/2] fast-get: fix crash by freeing buffer before removing partition Fix crash in fast_put() when freeing large buffers (>2048 bytes) by freeing the heap memory BEFORE removing the memory domain partition. The previous code removed the partition first, making the memory inaccessible to the current thread. When sof_heap_free() then tried to access the heap metadata, it caused a load prohibited exception. The fix reorders operations: 1. Free the buffer while partition still grants access 2. Remove the partition to prevent partition table leaks This crash manifested during pipeline deletion with 44.1kHz family sample rates (88200, 44100, etc.) which use large SRC coefficient buffers requiring userspace partition management. Fixes: b9270920d491 ("fast-get: enable sharing between userspace threads") Signed-off-by: Tomasz Leman --- zephyr/lib/fast-get.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/zephyr/lib/fast-get.c b/zephyr/lib/fast-get.c index 500055c99816..85dd28027023 100644 --- a/zephyr/lib/fast-get.c +++ b/zephyr/lib/fast-get.c @@ -279,21 +279,36 @@ void fast_put(struct k_heap *heap, const void *sram_ptr) } entry->refcount--; + if (!entry->refcount) { #if CONFIG_USERSPACE - if (entry->size > FAST_GET_MAX_COPY_SIZE && entry->thread) { - struct k_mem_partition part = { - .start = (uintptr_t)entry->sram_ptr, - .size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE), - .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB, - }; - - LOG_DBG("remove %#zx @ %p", part.size, entry->sram_ptr); - k_mem_domain_remove_partition(entry->thread->mem_domain_info.mem_domain, &part); - } -#endif + /* For large buffers, we need to: + * 1. Free the heap buffer FIRST (while partition still grants us access) + * 2. Then remove the partition (to prevent partition leaks) + * This order is critical - we must free while we still have access. + */ + if (entry->size > FAST_GET_MAX_COPY_SIZE) { + struct k_mem_partition part; + struct k_mem_domain *domain = entry->thread->mem_domain_info.mem_domain; + void *addr = entry->sram_ptr; + + sof_heap_free(heap, addr); + + part.start = (uintptr_t)addr; + part.size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE); + part.attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB; + + int err = k_mem_domain_remove_partition(domain, &part); + + if (err < 0) + LOG_WRN("partition removal failed err=%d", err); + + } else +#endif /* CONFIG_USERSPACE */ + { + /* Small buffers have no partitions, just free */ + sof_heap_free(heap, entry->sram_ptr); + } - if (!entry->refcount) { - sof_heap_free(heap, entry->sram_ptr); memset(entry, 0, sizeof(*entry)); } out: